lib/modulesync.rb in modulesync-2.2.0 vs lib/modulesync.rb in modulesync-2.3.0

- old
+ new

@@ -1,5 +1,6 @@ +require 'English' require 'fileutils' require 'pathname' require 'modulesync/cli' require 'modulesync/constants' @@ -16,14 +17,14 @@ include Constants def self.config_defaults { - :project_root => 'modules/', + :project_root => 'modules/', :managed_modules_conf => 'managed_modules.yml', - :configs => '.', - :tag_pattern => '%s' + :configs => '.', + :tag_pattern => '%s', } end def self.options @options @@ -42,12 +43,12 @@ Find.find(local_template_dir).find_all { |p| p =~ /.erb$/ && !File.directory?(p) } .collect { |p| p.chomp('.erb') } .to_a else $stderr.puts "#{local_template_dir} does not exist." \ - ' Check that you are working in your module configs directory or' \ - ' that you have passed in the correct directory with -c.' + ' Check that you are working in your module configs directory or' \ + ' that you have passed in the correct directory with -c.' exit 1 end end def self.relative_names(file_list, path) @@ -60,11 +61,11 @@ negative_filter = options[:negative_filter] managed_modules = Util.parse_config(config_file) if managed_modules.empty? $stderr.puts "No modules found in #{config_file}." \ - ' Check that you specified the right :configs directory and :managed_modules_conf file.' + ' Check that you specified the right :configs directory and :managed_modules_conf file.' exit 1 end managed_modules.select! { |m| m =~ Regexp.new(filter) } unless filter.nil? managed_modules.reject! { |m| m =~ Regexp.new(negative_filter) } unless negative_filter.nil? managed_modules.map { |given_name, options| PuppetModule.new(given_name, options) } @@ -80,11 +81,10 @@ hook.deactivate end end def self.manage_file(puppet_module, filename, settings, options) - namespace = settings.additional_settings[:namespace] module_name = settings.additional_settings[:puppet_module] configs = settings.build_file_configs(filename) target_file = puppet_module.path(filename) if configs['delete'] Renderer.remove(target_file) @@ -93,25 +93,30 @@ begin erb = Renderer.build(templatename) # Meta data passed to the template as @metadata[:name] metadata = { :module_name => module_name, - :workdir => puppet_module.working_directory, + :workdir => puppet_module.working_directory, :target_file => target_file, } template = Renderer.render(erb, configs, metadata) Renderer.sync(template, target_file) - rescue StandardError => e + rescue StandardError $stderr.puts "#{puppet_module.given_name}: Error while rendering file: '#{filename}'" raise end end end def self.manage_module(puppet_module, module_files, defaults) puts "Syncing '#{puppet_module.given_name}'" - puppet_module.repository.prepare_workspace(options[:branch]) unless options[:offline] + # NOTE: #prepare_workspace now supports to execute only offline operations + # but we totally skip the workspace preparation to keep the current behavior + unless options[:offline] + puppet_module.repository.prepare_workspace(branch: options[:branch], + operate_offline: false) + end module_configs = Util.parse_config puppet_module.path(MODULE_CONF_FILE) settings = Settings.new(defaults[GLOBAL_DEFAULTS_KEY] || {}, defaults, module_configs[GLOBAL_DEFAULTS_KEY] || {}, @@ -127,27 +132,26 @@ files_to_manage = settings.managed_files(module_files) files_to_manage.each { |filename| manage_file(puppet_module, filename, settings, options) } if options[:noop] puts "Using no-op. Files in '#{puppet_module.given_name}' may be changed but will not be committed." - puppet_module.repository.show_changes(options) - options[:pr] && \ - pr(puppet_module).manage(puppet_module.repository_namespace, puppet_module.repository_name, options) + changed = puppet_module.repository.show_changes(options) + changed && options[:pr] && puppet_module.open_pull_request elsif !options[:offline] pushed = puppet_module.repository.submit_changes(files_to_manage, options) # Only bump/tag if pushing didn't fail (i.e. there were changes) if pushed && options[:bump] new = puppet_module.bump(options[:message], options[:changelog]) puppet_module.repository.tag(new, options[:tag_pattern]) if options[:tag] end - pushed && options[:pr] && \ - pr(puppet_module).manage(puppet_module.repository_namespace, puppet_module.repository_name, options) + pushed && options[:pr] && puppet_module.open_pull_request end end def self.config_path(file, options) return file if Pathname.new(file).absolute? + File.join(options[:configs], file) end def config_path(file, options) self.class.config_path(file, options) @@ -155,74 +159,108 @@ def self.update(cli_options) @options = config_defaults.merge(cli_options) defaults = Util.parse_config(config_path(CONF_FILE, options)) - if options[:pr] - unless options[:branch] - $stderr.puts 'A branch must be specified with --branch to use --pr!' - raise - end - - @pr = create_pr_manager if options[:pr] - end - local_template_dir = config_path(MODULE_FILES_DIR, options) local_files = find_template_files(local_template_dir) module_files = relative_names(local_files, local_template_dir) errors = false # managed_modules is either an array or a hash managed_modules.each do |puppet_module| - begin - manage_module(puppet_module, module_files, defaults) - rescue ModuleSync::Error, Git::GitExecuteError => e - message = e.message || "Error during '#{options[:command]}'" - $stderr.puts "#{puppet_module.given_name}: #{message}" - exit 1 unless options[:skip_broken] - errors = true - $stdout.puts "Skipping '#{puppet_module.given_name}' as update process failed" - rescue StandardError => e - raise unless options[:skip_broken] - errors = true - $stdout.puts "Skipping '#{puppet_module.given_name}' as update process failed" - end + manage_module(puppet_module, module_files, defaults) + rescue ModuleSync::Error, Git::GitExecuteError => e + message = e.message || 'Error during `update`' + $stderr.puts "#{puppet_module.given_name}: #{message}" + exit 1 unless options[:skip_broken] + errors = true + $stdout.puts "Skipping '#{puppet_module.given_name}' as update process failed" + rescue StandardError + raise unless options[:skip_broken] + + errors = true + $stdout.puts "Skipping '#{puppet_module.given_name}' as update process failed" end exit 1 if errors && options[:fail_on_warnings] end - def self.pr(puppet_module) - module_options = puppet_module.options - github_conf = module_options[:github] - gitlab_conf = module_options[:gitlab] + def self.clone(cli_options) + @options = config_defaults.merge(cli_options) - if !github_conf.nil? - base_url = github_conf[:base_url] || ENV.fetch('GITHUB_BASE_URL', 'https://api.github.com') - require 'modulesync/pr/github' - ModuleSync::PR::GitHub.new(github_conf[:token], base_url) - elsif !gitlab_conf.nil? - base_url = gitlab_conf[:base_url] || ENV.fetch('GITLAB_BASE_URL', 'https://gitlab.com/api/v4') - require 'modulesync/pr/gitlab' - ModuleSync::PR::GitLab.new(gitlab_conf[:token], base_url) - elsif @pr.nil? - $stderr.puts 'No GitHub or GitLab token specified for --pr!' - raise - else - @pr + managed_modules.each do |puppet_module| + puppet_module.repository.clone unless puppet_module.repository.cloned? end end - def self.create_pr_manager - github_token = ENV.fetch('GITHUB_TOKEN', '') - gitlab_token = ENV.fetch('GITLAB_TOKEN', '') + def self.execute(cli_options) + @options = config_defaults.merge(cli_options) - if !github_token.empty? - require 'modulesync/pr/github' - ModuleSync::PR::GitHub.new(github_token, ENV.fetch('GITHUB_BASE_URL', 'https://api.github.com')) - elsif !gitlab_token.empty? - require 'modulesync/pr/gitlab' - ModuleSync::PR::GitLab.new(gitlab_token, ENV.fetch('GITLAB_BASE_URL', 'https://gitlab.com/api/v4')) - else - warn '--pr specified without environment variables GITHUB_TOKEN or GITLAB_TOKEN' + errors = {} + managed_modules.each do |puppet_module| + $stdout.puts "#{puppet_module.given_name}:" + + puppet_module.repository.clone unless puppet_module.repository.cloned? + puppet_module.repository.switch branch: @options[:branch] + + command_args = cli_options[:command_args] + local_script = File.expand_path command_args[0] + command_args[0] = local_script if File.exist?(local_script) + + # Remove bundler-related env vars to allow the subprocess to run `bundle` + command_env = ENV.reject { |k, _v| k.match?(/(^BUNDLE|^SOURCE_DATE_EPOCH$|^GEM_|RUBY)/) } + + result = system command_env, *command_args, unsetenv_others: true, chdir: puppet_module.working_directory + unless result + message = "Command execution failed ('#{@options[:command_args].join ' '}': #{$CHILD_STATUS})" + raise Thor::Error, message if @options[:fail_fast] + + errors.merge!( + puppet_module.given_name => message, + ) + $stderr.puts message + end + + $stdout.puts '' + end + + unless errors.empty? + raise Thor::Error, <<~MSG + Error(s) during `execute` command: + #{errors.map { |name, message| " * #{name}: #{message}" }.join "\n"} + MSG + end + + exit 1 unless errors.empty? + end + + def self.reset(cli_options) + @options = config_defaults.merge(cli_options) + if @options[:branch].nil? + raise Thor::Error, + "Error: 'branch' option is missing, please set it in configuration or in command line." + end + + managed_modules.each do |puppet_module| + puppet_module.repository.reset_workspace( + branch: @options[:branch], + source_branch: @options[:source_branch], + operate_offline: @options[:offline], + ) + end + end + + def self.push(cli_options) + @options = config_defaults.merge(cli_options) + + if @options[:branch].nil? + raise Thor::Error, + "Error: 'branch' option is missing, please set it in configuration or in command line." + end + + managed_modules.each do |puppet_module| + puppet_module.repository.push branch: @options[:branch], remote_branch: @options[:remote_branch] + rescue ModuleSync::Error => e + raise Thor::Error, "#{puppet_module.given_name}: #{e.message}" end end end