bolt 2.33.1 → 2.37.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Puppetfile +1 -1
- data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/catch_errors.rb +1 -3
- data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +17 -6
- data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +56 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +24 -6
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +27 -8
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +21 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +18 -1
- data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +24 -6
- data/lib/bolt/analytics.rb +27 -8
- data/lib/bolt/apply_result.rb +3 -3
- data/lib/bolt/bolt_option_parser.rb +48 -16
- data/lib/bolt/cli.rb +95 -227
- data/lib/bolt/config.rb +145 -54
- data/lib/bolt/config/options.rb +76 -10
- data/lib/bolt/config/transport/base.rb +10 -19
- data/lib/bolt/config/transport/local.rb +0 -7
- data/lib/bolt/config/transport/options.rb +1 -1
- data/lib/bolt/config/transport/ssh.rb +8 -14
- data/lib/bolt/config/validator.rb +231 -0
- data/lib/bolt/error.rb +33 -3
- data/lib/bolt/executor.rb +92 -6
- data/lib/bolt/inventory/group.rb +2 -1
- data/lib/bolt/module_installer.rb +1 -1
- data/lib/bolt/module_installer/specs/forge_spec.rb +5 -4
- data/lib/bolt/module_installer/specs/git_spec.rb +4 -3
- data/lib/bolt/outputter/human.rb +21 -9
- data/lib/bolt/outputter/rainbow.rb +1 -1
- data/lib/bolt/pal.rb +19 -7
- data/lib/bolt/pal/yaml_plan.rb +7 -0
- data/lib/bolt/plan_creator.rb +160 -0
- data/lib/bolt/plugin.rb +42 -13
- data/lib/bolt/plugin/cache.rb +76 -0
- data/lib/bolt/plugin/module.rb +4 -4
- data/lib/bolt/project.rb +46 -40
- data/lib/bolt/project_manager.rb +199 -0
- data/lib/bolt/{project_migrator/config.rb → project_manager/config_migrator.rb} +43 -5
- data/lib/bolt/{project_migrator/inventory.rb → project_manager/inventory_migrator.rb} +5 -5
- 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/client.rb +3 -2
- data/lib/bolt/puppetdb/config.rb +9 -8
- data/lib/bolt/rerun.rb +1 -5
- data/lib/bolt/shell/bash.rb +8 -2
- data/lib/bolt/shell/powershell.rb +17 -1
- data/lib/bolt/task/run.rb +1 -1
- data/lib/bolt/transport/orch.rb +0 -5
- data/lib/bolt/transport/orch/connection.rb +10 -3
- data/lib/bolt/transport/remote.rb +1 -1
- data/lib/bolt/transport/ssh/exec_connection.rb +6 -2
- data/lib/bolt/util.rb +41 -7
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt/yarn.rb +23 -0
- data/lib/bolt_server/base_config.rb +3 -1
- data/lib/bolt_server/config.rb +3 -1
- data/lib/bolt_server/file_cache.rb +2 -0
- data/lib/bolt_server/plugin.rb +13 -0
- data/lib/bolt_server/plugin/puppet_connect_data.rb +37 -0
- data/lib/bolt_server/schemas/connect-data.json +22 -0
- data/lib/bolt_server/schemas/partials/task.json +2 -2
- data/lib/bolt_server/transport_app.rb +72 -13
- data/lib/bolt_spec/plans/mock_executor.rb +4 -1
- data/libexec/apply_catalog.rb +1 -1
- data/libexec/custom_facts.rb +1 -1
- data/libexec/query_resources.rb +1 -1
- metadata +15 -13
- data/lib/bolt/project_migrator.rb +0 -80
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'bolt/error'
|
5
|
+
require 'bolt/util'
|
6
|
+
|
7
|
+
module Bolt
|
8
|
+
class Plugin
|
9
|
+
class Cache
|
10
|
+
attr_reader :reference, :cache_file, :default_config, :id
|
11
|
+
|
12
|
+
def initialize(reference, cache_file, default_config)
|
13
|
+
@reference = reference
|
14
|
+
@cache_file = cache_file
|
15
|
+
@default_config = default_config
|
16
|
+
end
|
17
|
+
|
18
|
+
def read_and_clean_cache
|
19
|
+
return if ttl == 0
|
20
|
+
validate
|
21
|
+
|
22
|
+
# Luckily we don't need to use a serious hash algorithm
|
23
|
+
require 'digest/bubblebabble'
|
24
|
+
r = reference.select { |k, _| k == '_cache' }.sort.to_s
|
25
|
+
@id = Digest::SHA2.bubblebabble(r)[0..20]
|
26
|
+
|
27
|
+
unmodified = true
|
28
|
+
# First remove any cache entries past their ttl
|
29
|
+
# This prevents removing plugins from leaving orphaned cache entries
|
30
|
+
cache.delete_if do |_, entry|
|
31
|
+
expired = Time.now - Time.parse(entry['mtime']) >= entry['ttl']
|
32
|
+
unmodified = false if expired
|
33
|
+
expired
|
34
|
+
end
|
35
|
+
File.write(cache_file, cache.to_json) unless cache.empty? || unmodified
|
36
|
+
|
37
|
+
cache.dig(id, 'result')
|
38
|
+
end
|
39
|
+
|
40
|
+
private def cache
|
41
|
+
@cache ||= Bolt::Util.read_optional_json_file(@cache_file, 'cache')
|
42
|
+
end
|
43
|
+
|
44
|
+
def write_cache(result)
|
45
|
+
cache.merge!({ id => { 'result' => result,
|
46
|
+
'mtime' => Time.now,
|
47
|
+
'ttl' => ttl } })
|
48
|
+
FileUtils.touch(cache_file)
|
49
|
+
File.write(cache_file, cache.to_json)
|
50
|
+
end
|
51
|
+
|
52
|
+
def validate
|
53
|
+
# The default cache `plugin-cache` will be validated by the config
|
54
|
+
# validator
|
55
|
+
return if reference['_cache'].nil?
|
56
|
+
r = reference['_cache']
|
57
|
+
unless r.is_a?(Hash)
|
58
|
+
raise Bolt::ValidationError,
|
59
|
+
"_cache must be a Hash, received #{r.class}: #{r.inspect}"
|
60
|
+
end
|
61
|
+
|
62
|
+
unless r.key?('ttl')
|
63
|
+
raise Bolt::ValidationError, "_cache must set 'ttl' key."
|
64
|
+
end
|
65
|
+
|
66
|
+
unless r['ttl'] >= 0
|
67
|
+
raise Bolt::ValidationError, "'ttl' key under '_cache' must be a minimum of 0."
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private def ttl
|
72
|
+
@ttl ||= reference.dig('_cache', 'ttl') || default_config['ttl']
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/bolt/plugin/module.rb
CHANGED
@@ -12,15 +12,15 @@ module Bolt
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
if mod
|
15
|
+
# mod should not be nil
|
16
|
+
def self.load(mod, opts)
|
17
|
+
if mod.plugin?
|
18
18
|
opts[:mod] = mod
|
19
19
|
plugin = Bolt::Plugin::Module.new(**opts)
|
20
20
|
plugin.setup
|
21
21
|
plugin
|
22
22
|
else
|
23
|
-
raise PluginError::Unknown, name
|
23
|
+
raise PluginError::Unknown, mod.name
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
data/lib/bolt/project.rb
CHANGED
@@ -2,24 +2,19 @@
|
|
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` 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` 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,
|
21
16
|
:deprecations, :downloads, :plans_path, :modulepath, :managed_moduledir,
|
22
|
-
:backup_dir
|
17
|
+
:backup_dir, :cache_file
|
23
18
|
|
24
19
|
def self.default_project(logs = [])
|
25
20
|
create_project(File.expand_path(File.join('~', '.puppetlabs', 'bolt')), 'user', logs)
|
@@ -32,23 +27,31 @@ module Bolt
|
|
32
27
|
# directory called Boltdir or a file called bolt.yaml (for a control repo
|
33
28
|
# type Project). Otherwise, repeat the check on each directory up the
|
34
29
|
# hierarchy, falling back to the default if we reach the root.
|
35
|
-
def self.find_boltdir(dir, logs = [])
|
30
|
+
def self.find_boltdir(dir, logs = [], deprecations = [])
|
36
31
|
dir = Pathname.new(dir)
|
37
32
|
|
38
33
|
if (dir + BOLTDIR_NAME).directory?
|
39
34
|
create_project(dir + BOLTDIR_NAME, 'embedded', logs)
|
40
|
-
elsif (dir + 'bolt.yaml').file?
|
35
|
+
elsif (dir + 'bolt.yaml').file?
|
36
|
+
command = Bolt::Util.powershell? ? 'Update-BoltProject' : 'bolt project migrate'
|
37
|
+
msg = "Configuration file #{dir + 'bolt.yaml'} is deprecated and will be "\
|
38
|
+
"removed in Bolt 3.0.\nUpdate your Bolt project to the latest Bolt practices "\
|
39
|
+
"using #{command}"
|
40
|
+
deprecations << { type: "Project level bolt.yaml",
|
41
|
+
msg: msg }
|
42
|
+
create_project(dir, 'local', logs, deprecations)
|
43
|
+
elsif (dir + CONFIG_NAME).file?
|
41
44
|
create_project(dir, 'local', logs)
|
42
45
|
elsif dir.root?
|
43
46
|
default_project(logs)
|
44
47
|
else
|
45
48
|
logs << { debug: "Did not detect Boltdir, bolt.yaml, or bolt-project.yaml at '#{dir}'. "\
|
46
49
|
"This directory won't be loaded as a project." }
|
47
|
-
find_boltdir(dir.parent, logs)
|
50
|
+
find_boltdir(dir.parent, logs, deprecations)
|
48
51
|
end
|
49
52
|
end
|
50
53
|
|
51
|
-
def self.create_project(path, type = 'option', logs = [])
|
54
|
+
def self.create_project(path, type = 'option', logs = [], deprecations = [])
|
52
55
|
fullpath = Pathname.new(path).expand_path
|
53
56
|
|
54
57
|
if type == 'user'
|
@@ -73,21 +76,36 @@ module Bolt
|
|
73
76
|
)
|
74
77
|
end
|
75
78
|
|
76
|
-
project_file = File.join(fullpath,
|
77
|
-
data
|
78
|
-
default
|
79
|
-
exist
|
79
|
+
project_file = File.join(fullpath, CONFIG_NAME)
|
80
|
+
data = Bolt::Util.read_optional_yaml_hash(File.expand_path(project_file), 'project')
|
81
|
+
default = type =~ /user|system/ ? 'default ' : ''
|
82
|
+
exist = File.exist?(File.expand_path(project_file))
|
83
|
+
|
80
84
|
logs << { info: "Loaded #{default}project from '#{fullpath}'" } if exist
|
81
|
-
new(data, path, type, logs)
|
82
|
-
end
|
83
85
|
|
84
|
-
|
85
|
-
|
86
|
+
# Validate the config against the schema. This will raise a single error
|
87
|
+
# with all validation errors.
|
88
|
+
schema = Bolt::Config::OPTIONS.slice(*Bolt::Config::BOLT_PROJECT_OPTIONS)
|
89
|
+
|
90
|
+
Bolt::Config::Validator.new.tap do |validator|
|
91
|
+
validator.validate(data, schema, project_file)
|
92
|
+
|
93
|
+
validator.warnings.each { |warning| logs << { warn: warning } }
|
94
|
+
|
95
|
+
validator.deprecations.each do |dep|
|
96
|
+
deprecations << { type: "#{CONFIG_NAME} #{dep[:option]}", msg: dep[:message] }
|
97
|
+
end
|
98
|
+
end
|
86
99
|
|
87
|
-
|
100
|
+
new(data, path, type, logs, deprecations)
|
101
|
+
end
|
102
|
+
|
103
|
+
def initialize(raw_data, path, type = 'option', logs = [], deprecations = [])
|
104
|
+
@path = Pathname.new(path).expand_path
|
105
|
+
@project_file = @path + CONFIG_NAME
|
106
|
+
@logs = logs
|
107
|
+
@deprecations = deprecations
|
88
108
|
|
89
|
-
@logs = logs
|
90
|
-
@deprecations = []
|
91
109
|
if (@path + 'bolt.yaml').file? && project_file?
|
92
110
|
msg = "Project-level configuration in bolt.yaml is deprecated if using bolt-project.yaml. "\
|
93
111
|
"Transport config should be set in inventory.yaml, all other config should be set in "\
|
@@ -105,6 +123,7 @@ module Bolt
|
|
105
123
|
@plans_path = @path + 'plans'
|
106
124
|
@managed_moduledir = @path + '.modules'
|
107
125
|
@backup_dir = @path + '.bolt-bak'
|
126
|
+
@cache_file = @path + '.plugin_cache.json'
|
108
127
|
|
109
128
|
tc = Bolt::Config::INVENTORY_OPTIONS.keys & raw_data.keys
|
110
129
|
if tc.any?
|
@@ -173,6 +192,10 @@ module Bolt
|
|
173
192
|
@data['plans']
|
174
193
|
end
|
175
194
|
|
195
|
+
def plugin_cache
|
196
|
+
@data['plugin-cache']
|
197
|
+
end
|
198
|
+
|
176
199
|
def modules
|
177
200
|
@modules ||= @data['modules']&.map do |mod|
|
178
201
|
if mod.is_a?(String)
|
@@ -198,23 +221,6 @@ module Bolt
|
|
198
221
|
message = "No project name is specified in bolt-project.yaml. Project-level content will not be available."
|
199
222
|
@logs << { warn: message }
|
200
223
|
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
224
|
end
|
219
225
|
|
220
226
|
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)
|
@@ -54,14 +55,51 @@ module Bolt
|
|
54
55
|
@outputter.print_action_step("Renaming bolt.yaml to bolt-project.yaml")
|
55
56
|
FileUtils.mv(config_file, project_file)
|
56
57
|
|
58
|
+
command = Bolt::Util.powershell? ? 'Get-Help about_bolt_project' : 'bolt guide project'
|
57
59
|
@outputter.print_action_step(
|
58
60
|
"Successfully migrated config. Please add a 'name' key to bolt-project.yaml "\
|
59
61
|
"to use project-level tasks and plans. Learn more about projects by running "\
|
60
|
-
"'
|
62
|
+
"'#{command}'."
|
61
63
|
)
|
62
64
|
|
63
65
|
true
|
64
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
|
65
103
|
end
|
66
104
|
end
|
67
105
|
end
|