bolt 2.35.0 → 2.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +1 -0
- data/lib/bolt/analytics.rb +27 -8
- data/lib/bolt/apply_result.rb +3 -3
- data/lib/bolt/bolt_option_parser.rb +38 -15
- data/lib/bolt/cli.rb +13 -87
- data/lib/bolt/config.rb +131 -52
- data/lib/bolt/config/options.rb +42 -4
- data/lib/bolt/config/transport/base.rb +10 -19
- data/lib/bolt/config/transport/local.rb +0 -7
- data/lib/bolt/config/transport/ssh.rb +8 -14
- data/lib/bolt/config/validator.rb +231 -0
- data/lib/bolt/executor.rb +5 -17
- data/lib/bolt/outputter/rainbow.rb +1 -1
- data/lib/bolt/plugin.rb +0 -7
- data/lib/bolt/project.rb +30 -36
- data/lib/bolt/project_manager.rb +199 -0
- data/lib/bolt/{project_migrator/config.rb → project_manager/config_migrator.rb} +41 -4
- data/lib/bolt/{project_migrator/inventory.rb → project_manager/inventory_migrator.rb} +3 -3
- data/lib/bolt/{project_migrator/base.rb → project_manager/migrator.rb} +2 -2
- data/lib/bolt/{project_migrator/modules.rb → project_manager/module_migrator.rb} +3 -3
- data/lib/bolt/puppetdb/config.rb +1 -2
- data/lib/bolt/shell/bash.rb +1 -1
- data/lib/bolt/task/run.rb +1 -1
- data/lib/bolt/transport/ssh/exec_connection.rb +6 -2
- data/lib/bolt/util.rb +14 -7
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/base_config.rb +3 -1
- data/lib/bolt_server/config.rb +3 -1
- data/lib/bolt_server/schemas/partials/task.json +2 -2
- data/lib/bolt_server/transport_app.rb +5 -5
- data/libexec/apply_catalog.rb +1 -1
- data/libexec/custom_facts.rb +1 -1
- data/libexec/query_resources.rb +1 -1
- metadata +8 -13
- data/lib/bolt/project_migrator.rb +0 -80
    
        data/lib/bolt/executor.rb
    CHANGED
    
    | @@ -256,10 +256,10 @@ module Bolt | |
| 256 256 | 
             
                  @logger.trace { "Failed to submit analytics event: #{e.message}" }
         | 
| 257 257 | 
             
                end
         | 
| 258 258 |  | 
| 259 | 
            -
                def with_node_logging(description, batch)
         | 
| 260 | 
            -
                  @logger. | 
| 259 | 
            +
                def with_node_logging(description, batch, log_level = :info)
         | 
| 260 | 
            +
                  @logger.send(log_level, "#{description} on #{batch.map(&:safe_name)}")
         | 
| 261 261 | 
             
                  result = yield
         | 
| 262 | 
            -
                  @logger. | 
| 262 | 
            +
                  @logger.send(log_level, result.to_json)
         | 
| 263 263 | 
             
                  result
         | 
| 264 264 | 
             
                end
         | 
| 265 265 |  | 
| @@ -289,32 +289,20 @@ module Bolt | |
| 289 289 | 
             
                  end
         | 
| 290 290 | 
             
                end
         | 
| 291 291 |  | 
| 292 | 
            -
                def run_task(targets, task, arguments, options = {}, position = [])
         | 
| 292 | 
            +
                def run_task(targets, task, arguments, options = {}, position = [], log_level = :info)
         | 
| 293 293 | 
             
                  description = options.fetch(:description, "task #{task.name}")
         | 
| 294 294 | 
             
                  log_action(description, targets) do
         | 
| 295 295 | 
             
                    options[:run_as] = run_as if run_as && !options.key?(:run_as)
         | 
| 296 296 | 
             
                    arguments['_task'] = task.name
         | 
| 297 297 |  | 
| 298 298 | 
             
                    batch_execute(targets) do |transport, batch|
         | 
| 299 | 
            -
                      with_node_logging("Running task #{task.name} with '#{arguments.to_json}'", batch) do
         | 
| 299 | 
            +
                      with_node_logging("Running task #{task.name} with '#{arguments.to_json}'", batch, log_level) do
         | 
| 300 300 | 
             
                        transport.batch_task(batch, task, arguments, options, position, &method(:publish_event))
         | 
| 301 301 | 
             
                      end
         | 
| 302 302 | 
             
                    end
         | 
| 303 303 | 
             
                  end
         | 
| 304 304 | 
             
                end
         | 
| 305 305 |  | 
| 306 | 
            -
                def run_task_with_minimal_logging(targets, task, arguments, options = {})
         | 
| 307 | 
            -
                  description = options.fetch(:description, "task #{task.name}")
         | 
| 308 | 
            -
                  log_action(description, targets) do
         | 
| 309 | 
            -
                    options[:run_as] = run_as if run_as && !options.key?(:run_as)
         | 
| 310 | 
            -
                    arguments['_task'] = task.name
         | 
| 311 | 
            -
             | 
| 312 | 
            -
                    batch_execute(targets) do |transport, batch|
         | 
| 313 | 
            -
                      transport.batch_task(batch, task, arguments, options, [], &method(:publish_event))
         | 
| 314 | 
            -
                    end
         | 
| 315 | 
            -
                  end
         | 
| 316 | 
            -
                end
         | 
| 317 | 
            -
             | 
| 318 306 | 
             
                def run_task_with(target_mapping, task, options = {}, position = [])
         | 
| 319 307 | 
             
                  targets = target_mapping.keys
         | 
| 320 308 | 
             
                  description = options.fetch(:description, "task #{task.name}")
         | 
    
        data/lib/bolt/plugin.rb
    CHANGED
    
    | @@ -122,13 +122,6 @@ module Bolt | |
| 122 122 | 
             
                def self.setup(config, pal, analytics = Bolt::Analytics::NoopClient.new)
         | 
| 123 123 | 
             
                  plugins = new(config, pal, analytics)
         | 
| 124 124 |  | 
| 125 | 
            -
                  # Initialize any plugins referenced in plugin config. This will also indirectly
         | 
| 126 | 
            -
                  # initialize any plugins they depend on.
         | 
| 127 | 
            -
                  if plugins.reference?(config.plugins)
         | 
| 128 | 
            -
                    msg = "The 'plugins' setting cannot be set by a plugin reference"
         | 
| 129 | 
            -
                    raise PluginError.new(msg, 'bolt/plugin-error')
         | 
| 130 | 
            -
                  end
         | 
| 131 | 
            -
             | 
| 132 125 | 
             
                  config.plugins.each_key do |plugin|
         | 
| 133 126 | 
             
                    plugins.by_name(plugin)
         | 
| 134 127 | 
             
                  end
         | 
    
        data/lib/bolt/project.rb
    CHANGED
    
    | @@ -2,19 +2,14 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            require 'pathname'
         | 
| 4 4 | 
             
            require 'bolt/config'
         | 
| 5 | 
            +
            require 'bolt/config/validator'
         | 
| 5 6 | 
             
            require 'bolt/pal'
         | 
| 6 7 | 
             
            require 'bolt/module'
         | 
| 7 8 |  | 
| 8 9 | 
             
            module Bolt
         | 
| 9 10 | 
             
              class Project
         | 
| 10 11 | 
             
                BOLTDIR_NAME = 'Boltdir'
         | 
| 11 | 
            -
                 | 
| 12 | 
            -
                  "name"  => "The name of the project",
         | 
| 13 | 
            -
                  "plans" => "An array of plan names to show, if they exist in the project."\
         | 
| 14 | 
            -
                             "These plans are included in `bolt plan show` and `Get-BoltPlan` output",
         | 
| 15 | 
            -
                  "tasks" => "An array of task names to show, if they exist in the project."\
         | 
| 16 | 
            -
                             "These tasks are included in `bolt task show` and `Get-BoltTask` output"
         | 
| 17 | 
            -
                }.freeze
         | 
| 12 | 
            +
                CONFIG_NAME  = 'bolt-project.yaml'
         | 
| 18 13 |  | 
| 19 14 | 
             
                attr_reader :path, :data, :config_file, :inventory_file, :hiera_config,
         | 
| 20 15 | 
             
                            :puppetfile, :rerunfile, :type, :resource_types, :logs, :project_file,
         | 
| @@ -37,7 +32,7 @@ module Bolt | |
| 37 32 |  | 
| 38 33 | 
             
                  if (dir + BOLTDIR_NAME).directory?
         | 
| 39 34 | 
             
                    create_project(dir + BOLTDIR_NAME, 'embedded', logs)
         | 
| 40 | 
            -
                  elsif (dir + 'bolt.yaml').file? || (dir +  | 
| 35 | 
            +
                  elsif (dir + 'bolt.yaml').file? || (dir + CONFIG_NAME).file?
         | 
| 41 36 | 
             
                    create_project(dir, 'local', logs)
         | 
| 42 37 | 
             
                  elsif dir.root?
         | 
| 43 38 | 
             
                    default_project(logs)
         | 
| @@ -73,21 +68,37 @@ module Bolt | |
| 73 68 | 
             
                    )
         | 
| 74 69 | 
             
                  end
         | 
| 75 70 |  | 
| 76 | 
            -
                  project_file = File.join(fullpath,  | 
| 77 | 
            -
                  data | 
| 78 | 
            -
                  default | 
| 79 | 
            -
                  exist | 
| 71 | 
            +
                  project_file = File.join(fullpath, CONFIG_NAME)
         | 
| 72 | 
            +
                  data         = Bolt::Util.read_optional_yaml_hash(File.expand_path(project_file), 'project')
         | 
| 73 | 
            +
                  default      = type =~ /user|system/ ? 'default ' : ''
         | 
| 74 | 
            +
                  exist        = File.exist?(File.expand_path(project_file))
         | 
| 75 | 
            +
                  deprecations = []
         | 
| 76 | 
            +
             | 
| 80 77 | 
             
                  logs << { info: "Loaded #{default}project from '#{fullpath}'" } if exist
         | 
| 81 | 
            -
                  new(data, path, type, logs)
         | 
| 82 | 
            -
                end
         | 
| 83 78 |  | 
| 84 | 
            -
             | 
| 85 | 
            -
                   | 
| 79 | 
            +
                  # Validate the config against the schema. This will raise a single error
         | 
| 80 | 
            +
                  # with all validation errors.
         | 
| 81 | 
            +
                  schema = Bolt::Config::OPTIONS.slice(*Bolt::Config::BOLT_PROJECT_OPTIONS)
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                  Bolt::Config::Validator.new.tap do |validator|
         | 
| 84 | 
            +
                    validator.validate(data, schema, project_file)
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                    validator.warnings.each { |warning| logs << { warn: warning } }
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                    validator.deprecations.each do |dep|
         | 
| 89 | 
            +
                      deprecations << { type: "#{CONFIG_NAME} #{dep[:option]}", msg: dep[:message] }
         | 
| 90 | 
            +
                    end
         | 
| 91 | 
            +
                  end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                  new(data, path, type, logs, deprecations)
         | 
| 94 | 
            +
                end
         | 
| 86 95 |  | 
| 87 | 
            -
             | 
| 96 | 
            +
                def initialize(raw_data, path, type = 'option', logs = [], deprecations = [])
         | 
| 97 | 
            +
                  @path         = Pathname.new(path).expand_path
         | 
| 98 | 
            +
                  @project_file = @path + CONFIG_NAME
         | 
| 99 | 
            +
                  @logs         = logs
         | 
| 100 | 
            +
                  @deprecations = deprecations
         | 
| 88 101 |  | 
| 89 | 
            -
                  @logs = logs
         | 
| 90 | 
            -
                  @deprecations = []
         | 
| 91 102 | 
             
                  if (@path + 'bolt.yaml').file? && project_file?
         | 
| 92 103 | 
             
                    msg = "Project-level configuration in bolt.yaml is deprecated if using bolt-project.yaml. "\
         | 
| 93 104 | 
             
                      "Transport config should be set in inventory.yaml, all other config should be set in "\
         | 
| @@ -198,23 +209,6 @@ module Bolt | |
| 198 209 | 
             
                    message = "No project name is specified in bolt-project.yaml. Project-level content will not be available."
         | 
| 199 210 | 
             
                    @logs << { warn: message }
         | 
| 200 211 | 
             
                  end
         | 
| 201 | 
            -
             | 
| 202 | 
            -
                  %w[tasks plans].each do |conf|
         | 
| 203 | 
            -
                    unless @data.fetch(conf, []).is_a?(Array)
         | 
| 204 | 
            -
                      raise Bolt::ValidationError, "'#{conf}' in bolt-project.yaml must be an array"
         | 
| 205 | 
            -
                    end
         | 
| 206 | 
            -
                  end
         | 
| 207 | 
            -
             | 
| 208 | 
            -
                  if @data['modules']
         | 
| 209 | 
            -
                    unless @data['modules'].is_a?(Array)
         | 
| 210 | 
            -
                      raise Bolt::ValidationError, "'modules' in bolt-project.yaml must be an array"
         | 
| 211 | 
            -
                    end
         | 
| 212 | 
            -
             | 
| 213 | 
            -
                    @data['modules'].each do |spec|
         | 
| 214 | 
            -
                      next if spec.is_a?(Hash) || spec.is_a?(String)
         | 
| 215 | 
            -
                      raise Bolt::ValidationError, "Module specification #{spec.inspect} must be a hash or string"
         | 
| 216 | 
            -
                    end
         | 
| 217 | 
            -
                  end
         | 
| 218 212 | 
             
                end
         | 
| 219 213 |  | 
| 220 214 | 
             
                def check_deprecated_file
         | 
| @@ -0,0 +1,199 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'bolt/project_manager/config_migrator'
         | 
| 4 | 
            +
            require 'bolt/project_manager/inventory_migrator'
         | 
| 5 | 
            +
            require 'bolt/project_manager/module_migrator'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Bolt
         | 
| 8 | 
            +
              class ProjectManager
         | 
| 9 | 
            +
                INVENTORY_TEMPLATE = <<~INVENTORY
         | 
| 10 | 
            +
                  # This is an example inventory.yaml
         | 
| 11 | 
            +
                  # To read more about inventory files, see https://pup.pt/bolt-inventory
         | 
| 12 | 
            +
                  #
         | 
| 13 | 
            +
                  # groups:
         | 
| 14 | 
            +
                  #   - name: linux
         | 
| 15 | 
            +
                  #     targets:
         | 
| 16 | 
            +
                  #       - target1.example.com
         | 
| 17 | 
            +
                  #       - target2.example.com
         | 
| 18 | 
            +
                  #     config:
         | 
| 19 | 
            +
                  #       transport: ssh
         | 
| 20 | 
            +
                  #       ssh:
         | 
| 21 | 
            +
                  #         private-key: /path/to/private_key.pem
         | 
| 22 | 
            +
                  #   - name: windows
         | 
| 23 | 
            +
                  #     targets:
         | 
| 24 | 
            +
                  #       - name: win1
         | 
| 25 | 
            +
                  #         uri: target3.example.com
         | 
| 26 | 
            +
                  #       - name: win2
         | 
| 27 | 
            +
                  #         uri: target4.example.com
         | 
| 28 | 
            +
                  #     config:
         | 
| 29 | 
            +
                  #       transport: winrm
         | 
| 30 | 
            +
                  # config:
         | 
| 31 | 
            +
                  #   ssh:
         | 
| 32 | 
            +
                  #     host-key-check: false
         | 
| 33 | 
            +
                  #   winrm:
         | 
| 34 | 
            +
                  #     user: Administrator
         | 
| 35 | 
            +
                  #     password: Bolt!
         | 
| 36 | 
            +
                  #     ssl: false
         | 
| 37 | 
            +
                INVENTORY
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def initialize(config, outputter, pal)
         | 
| 40 | 
            +
                  @config    = config
         | 
| 41 | 
            +
                  @outputter = outputter
         | 
| 42 | 
            +
                  @pal       = pal
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                # Creates a new project at the specified directory.
         | 
| 46 | 
            +
                #
         | 
| 47 | 
            +
                def create(path, name, modules)
         | 
| 48 | 
            +
                  require 'bolt/module_installer'
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  project       = Pathname.new(File.expand_path(path))
         | 
| 51 | 
            +
                  old_config    = project + 'bolt.yaml'
         | 
| 52 | 
            +
                  config        = project + 'bolt-project.yaml'
         | 
| 53 | 
            +
                  puppetfile    = project + 'Puppetfile'
         | 
| 54 | 
            +
                  moduledir     = project + '.modules'
         | 
| 55 | 
            +
                  inventoryfile = project + 'inventory.yaml'
         | 
| 56 | 
            +
                  project_name  = name || File.basename(project)
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  if config.exist?
         | 
| 59 | 
            +
                    if modules
         | 
| 60 | 
            +
                      command = Bolt::Util.powershell? ? 'Add-BoltModule -Module' : 'bolt module add'
         | 
| 61 | 
            +
                      raise Bolt::Error.new(
         | 
| 62 | 
            +
                        "Found existing project directory with #{config.basename} at #{project}, "\
         | 
| 63 | 
            +
                        "unable to initialize project with modules. To add modules to the project, "\
         | 
| 64 | 
            +
                        "run '#{command} <module>' instead.",
         | 
| 65 | 
            +
                        'bolt/existing-project-error'
         | 
| 66 | 
            +
                      )
         | 
| 67 | 
            +
                    else
         | 
| 68 | 
            +
                      raise Bolt::Error.new(
         | 
| 69 | 
            +
                        "Found existing project directory with #{config.basename} at #{project}, "\
         | 
| 70 | 
            +
                        "unable to initialize project.",
         | 
| 71 | 
            +
                        'bolt/existing-project-error'
         | 
| 72 | 
            +
                      )
         | 
| 73 | 
            +
                    end
         | 
| 74 | 
            +
                  elsif old_config.exist?
         | 
| 75 | 
            +
                    command = Bolt::Util.powershell? ? 'Update-BoltProject' : 'bolt project migrate'
         | 
| 76 | 
            +
                    raise Bolt::Error.new(
         | 
| 77 | 
            +
                      "Found existing project directory with #{old_config.basename} at #{project}, "\
         | 
| 78 | 
            +
                      "unable to initialize project. #{old_config.basename} is deprecated. To "\
         | 
| 79 | 
            +
                      "update the project to current best practices, run '#{command}'.",
         | 
| 80 | 
            +
                      'bolt/existing-project-error'
         | 
| 81 | 
            +
                    )
         | 
| 82 | 
            +
                  elsif modules && puppetfile.exist?
         | 
| 83 | 
            +
                    raise Bolt::Error.new(
         | 
| 84 | 
            +
                      "Found existing Puppetfile at #{puppetfile}, unable to initialize project "\
         | 
| 85 | 
            +
                      "with modules.",
         | 
| 86 | 
            +
                      'bolt/existing-puppetfile-error'
         | 
| 87 | 
            +
                    )
         | 
| 88 | 
            +
                  elsif project_name !~ Bolt::Module::MODULE_NAME_REGEX
         | 
| 89 | 
            +
                    if name
         | 
| 90 | 
            +
                      raise Bolt::ValidationError,
         | 
| 91 | 
            +
                            "The provided project name '#{project_name}' is invalid; project name must "\
         | 
| 92 | 
            +
                            "begin with a lowercase letter and can include lowercase letters, "\
         | 
| 93 | 
            +
                            "numbers, and underscores."
         | 
| 94 | 
            +
                    else
         | 
| 95 | 
            +
                      command = Bolt::Util.powershell? ? 'New-BoltProject -Name' : 'bolt project init'
         | 
| 96 | 
            +
                      raise Bolt::ValidationError,
         | 
| 97 | 
            +
                            "The current directory name '#{project_name}' is an invalid project name. "\
         | 
| 98 | 
            +
                            "Please specify a name using '#{command} <name>'."
         | 
| 99 | 
            +
                    end
         | 
| 100 | 
            +
                  end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  # If modules were specified, resolve and install first. We want to error
         | 
| 103 | 
            +
                  # early here and not initialize the project if the modules cannot be
         | 
| 104 | 
            +
                  # resolved and installed.
         | 
| 105 | 
            +
                  if modules
         | 
| 106 | 
            +
                    Bolt::ModuleInstaller.new(@outputter, @pal).install(modules, puppetfile, moduledir)
         | 
| 107 | 
            +
                  end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                  data = { 'name' => project_name }
         | 
| 110 | 
            +
                  data['modules'] = modules || []
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                  begin
         | 
| 113 | 
            +
                    File.write(config.to_path, data.to_yaml)
         | 
| 114 | 
            +
                  rescue StandardError => e
         | 
| 115 | 
            +
                    raise Bolt::FileError.new("Could not create bolt-project.yaml at #{project}: #{e.message}", nil)
         | 
| 116 | 
            +
                  end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                  unless inventoryfile.exist?
         | 
| 119 | 
            +
                    begin
         | 
| 120 | 
            +
                      File.write(inventoryfile.to_path, INVENTORY_TEMPLATE)
         | 
| 121 | 
            +
                    rescue StandardError => e
         | 
| 122 | 
            +
                      raise Bolt::FileError.new("Could not create inventory.yaml at #{project}: #{e.message}", nil)
         | 
| 123 | 
            +
                    end
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                  @outputter.print_message("Successfully created Bolt project at #{project}")
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                  0
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                # Migrates a project to use the latest file versions and best practices.
         | 
| 132 | 
            +
                #
         | 
| 133 | 
            +
                def migrate
         | 
| 134 | 
            +
                  unless $stdin.tty?
         | 
| 135 | 
            +
                    raise Bolt::Error.new(
         | 
| 136 | 
            +
                      "stdin is not a tty, unable to migrate project",
         | 
| 137 | 
            +
                      'bolt/stdin-not-a-tty-error'
         | 
| 138 | 
            +
                    )
         | 
| 139 | 
            +
                  end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                  @outputter.print_message("Migrating project #{@config.project.path}\n\n")
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                  @outputter.print_action_step(
         | 
| 144 | 
            +
                    "Migrating a Bolt project may make irreversible changes to the project's "\
         | 
| 145 | 
            +
                    "configuration and inventory files. Before continuing, make sure the "\
         | 
| 146 | 
            +
                    "project has a backup or uses a version control system."
         | 
| 147 | 
            +
                  )
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                  return 0 unless Bolt::Util.prompt_yes_no("Continue with project migration?", @outputter)
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                  @outputter.print_message('')
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                  ok = migrate_inventory && migrate_config && migrate_modules
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                  if ok
         | 
| 156 | 
            +
                    @outputter.print_message("Project successfully migrated")
         | 
| 157 | 
            +
                  else
         | 
| 158 | 
            +
                    @outputter.print_error("Project could not be migrated completely")
         | 
| 159 | 
            +
                  end
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                  ok ? 0 : 1
         | 
| 162 | 
            +
                end
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                # Migrates the project-level configuration file to the latest version.
         | 
| 165 | 
            +
                #
         | 
| 166 | 
            +
                private def migrate_config
         | 
| 167 | 
            +
                  migrator = ConfigMigrator.new(@outputter)
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                  migrator.migrate(
         | 
| 170 | 
            +
                    @config.project.config_file,
         | 
| 171 | 
            +
                    @config.project.project_file,
         | 
| 172 | 
            +
                    @config.inventoryfile || @config.project.inventory_file,
         | 
| 173 | 
            +
                    @config.project.backup_dir
         | 
| 174 | 
            +
                  )
         | 
| 175 | 
            +
                end
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                # Migrates the inventory file to the latest version.
         | 
| 178 | 
            +
                #
         | 
| 179 | 
            +
                private def migrate_inventory
         | 
| 180 | 
            +
                  migrator = InventoryMigrator.new(@outputter)
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                  migrator.migrate(
         | 
| 183 | 
            +
                    @config.inventoryfile || @config.project.inventory_file,
         | 
| 184 | 
            +
                    @config.project.backup_dir
         | 
| 185 | 
            +
                  )
         | 
| 186 | 
            +
                end
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                # Migrates the project's modules to use current best practices.
         | 
| 189 | 
            +
                #
         | 
| 190 | 
            +
                private def migrate_modules
         | 
| 191 | 
            +
                  migrator = ModuleMigrator.new(@outputter)
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                  migrator.migrate(
         | 
| 194 | 
            +
                    @config.project,
         | 
| 195 | 
            +
                    @config.modulepath
         | 
| 196 | 
            +
                  )
         | 
| 197 | 
            +
                end
         | 
| 198 | 
            +
              end
         | 
| 199 | 
            +
            end
         | 
| @@ -1,12 +1,13 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require 'bolt/ | 
| 3 | 
            +
            require 'bolt/project_manager/migrator'
         | 
| 4 4 |  | 
| 5 5 | 
             
            module Bolt
         | 
| 6 | 
            -
              class  | 
| 7 | 
            -
                class  | 
| 6 | 
            +
              class ProjectManager
         | 
| 7 | 
            +
                class ConfigMigrator < Migrator
         | 
| 8 8 | 
             
                  def migrate(config_file, project_file, inventory_file, backup_dir)
         | 
| 9 | 
            -
                    bolt_yaml_to_bolt_project(config_file, project_file, inventory_file, backup_dir)
         | 
| 9 | 
            +
                    bolt_yaml_to_bolt_project(config_file, project_file, inventory_file, backup_dir) &&
         | 
| 10 | 
            +
                      update_options(project_file)
         | 
| 10 11 | 
             
                  end
         | 
| 11 12 |  | 
| 12 13 | 
             
                  private def bolt_yaml_to_bolt_project(config_file, project_file, inventory_file, backup_dir)
         | 
| @@ -63,6 +64,42 @@ module Bolt | |
| 63 64 |  | 
| 64 65 | 
             
                    true
         | 
| 65 66 | 
             
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  private def update_options(project_file)
         | 
| 69 | 
            +
                    return true unless File.exist?(project_file)
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                    @outputter.print_message("Updating project configuration options\n\n")
         | 
| 72 | 
            +
                    data     = Bolt::Util.read_yaml_hash(project_file, 'config')
         | 
| 73 | 
            +
                    modified = false
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                    [%w[apply_settings apply-settings], %w[plugin_hooks plugin-hooks]].each do |old, new|
         | 
| 76 | 
            +
                      next unless data.key?(old)
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                      if data.key?(new)
         | 
| 79 | 
            +
                        @outputter.print_action_step("Removing deprecated option '#{old}'")
         | 
| 80 | 
            +
                        data.delete(old)
         | 
| 81 | 
            +
                      else
         | 
| 82 | 
            +
                        @outputter.print_action_step("Updating deprecated option '#{old}' to '#{new}'")
         | 
| 83 | 
            +
                        data[new] = data.delete(old)
         | 
| 84 | 
            +
                      end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                      modified = true
         | 
| 87 | 
            +
                    end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                    if modified
         | 
| 90 | 
            +
                      begin
         | 
| 91 | 
            +
                        File.write(project_file, data.to_yaml)
         | 
| 92 | 
            +
                      rescue StandardError => e
         | 
| 93 | 
            +
                        raise Bolt::FileError.new("#{e.message}; unable to write config.", project_file)
         | 
| 94 | 
            +
                      end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                      @outputter.print_action_step("Successfully updated project configuration #{project_file}")
         | 
| 97 | 
            +
                    else
         | 
| 98 | 
            +
                      @outputter.print_action_step("Project configuration is up to date, nothing to do.")
         | 
| 99 | 
            +
                    end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                    true
         | 
| 102 | 
            +
                  end
         | 
| 66 103 | 
             
                end
         | 
| 67 104 | 
             
              end
         | 
| 68 105 | 
             
            end
         | 
| @@ -1,10 +1,10 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require 'bolt/ | 
| 3 | 
            +
            require 'bolt/project_manager/migrator'
         | 
| 4 4 |  | 
| 5 5 | 
             
            module Bolt
         | 
| 6 | 
            -
              class  | 
| 7 | 
            -
                class  | 
| 6 | 
            +
              class ProjectManager
         | 
| 7 | 
            +
                class InventoryMigrator < Migrator
         | 
| 8 8 | 
             
                  def migrate(inventory_file, backup_dir)
         | 
| 9 9 | 
             
                    inventory1to2(inventory_file, backup_dir)
         | 
| 10 10 | 
             
                  end
         |