bolt 2.28.0 → 2.33.1
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 +15 -14
- data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/facts.rb +6 -0
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +2 -2
- data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/write_file.rb +2 -2
- data/bolt-modules/out/lib/puppet/functions/out/message.rb +44 -1
- data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +3 -0
- data/guides/logging.txt +18 -0
- data/guides/module.txt +19 -0
- data/guides/modulepath.txt +25 -0
- data/lib/bolt/bolt_option_parser.rb +50 -28
- data/lib/bolt/catalog.rb +1 -1
- data/lib/bolt/cli.rb +159 -112
- data/lib/bolt/config.rb +13 -1
- data/lib/bolt/config/modulepath.rb +30 -0
- data/lib/bolt/config/options.rb +38 -9
- data/lib/bolt/config/transport/options.rb +2 -2
- data/lib/bolt/error.rb +4 -0
- data/lib/bolt/executor.rb +13 -13
- data/lib/bolt/inventory.rb +10 -9
- data/lib/bolt/logger.rb +26 -19
- data/lib/bolt/module_installer.rb +198 -0
- data/lib/bolt/{puppetfile → module_installer}/installer.rb +3 -2
- data/lib/bolt/module_installer/puppetfile.rb +117 -0
- data/lib/bolt/module_installer/puppetfile/forge_module.rb +54 -0
- data/lib/bolt/module_installer/puppetfile/git_module.rb +37 -0
- data/lib/bolt/module_installer/puppetfile/module.rb +26 -0
- data/lib/bolt/module_installer/resolver.rb +76 -0
- data/lib/bolt/module_installer/specs.rb +93 -0
- data/lib/bolt/module_installer/specs/forge_spec.rb +84 -0
- data/lib/bolt/module_installer/specs/git_spec.rb +178 -0
- data/lib/bolt/outputter.rb +2 -45
- data/lib/bolt/outputter/human.rb +78 -18
- data/lib/bolt/outputter/json.rb +22 -7
- data/lib/bolt/outputter/logger.rb +2 -2
- data/lib/bolt/pal.rb +55 -45
- data/lib/bolt/pal/yaml_plan.rb +4 -2
- data/lib/bolt/pal/yaml_plan/evaluator.rb +23 -1
- data/lib/bolt/pal/yaml_plan/loader.rb +14 -9
- data/lib/bolt/plugin.rb +1 -1
- data/lib/bolt/plugin/module.rb +1 -1
- data/lib/bolt/project.rb +32 -22
- data/lib/bolt/project_migrator.rb +80 -0
- data/lib/bolt/project_migrator/base.rb +39 -0
- data/lib/bolt/project_migrator/config.rb +67 -0
- data/lib/bolt/project_migrator/inventory.rb +67 -0
- data/lib/bolt/project_migrator/modules.rb +200 -0
- data/lib/bolt/result.rb +23 -11
- data/lib/bolt/shell/bash.rb +15 -9
- data/lib/bolt/shell/powershell.rb +11 -6
- data/lib/bolt/transport/base.rb +18 -18
- data/lib/bolt/transport/docker.rb +23 -6
- data/lib/bolt/transport/orch.rb +23 -14
- data/lib/bolt/transport/remote.rb +2 -2
- data/lib/bolt/transport/simple.rb +6 -6
- data/lib/bolt/transport/ssh/connection.rb +1 -1
- data/lib/bolt/util.rb +41 -0
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/acl.rb +2 -2
- data/lib/bolt_server/base_config.rb +3 -3
- data/lib/bolt_server/schemas/partials/task.json +17 -2
- data/lib/bolt_server/transport_app.rb +93 -13
- data/lib/bolt_spec/bolt_context.rb +4 -2
- data/lib/bolt_spec/plans.rb +1 -1
- data/lib/bolt_spec/plans/action_stubs/command_stub.rb +1 -1
- data/lib/bolt_spec/plans/action_stubs/script_stub.rb +1 -1
- data/lib/bolt_spec/plans/mock_executor.rb +6 -6
- data/lib/bolt_spec/run.rb +1 -1
- metadata +31 -12
- data/lib/bolt/project_migrate.rb +0 -138
- data/lib/bolt/puppetfile.rb +0 -160
- data/lib/bolt/puppetfile/module.rb +0 -66
- data/lib/bolt_server/pe/pal.rb +0 -67
- data/modules/secure_env_vars/plans/init.pp +0 -20
@@ -13,9 +13,9 @@ module Bolt
|
|
13
13
|
def handle_event(event)
|
14
14
|
case event[:type]
|
15
15
|
when :step_start
|
16
|
-
log_step_start(event)
|
16
|
+
log_step_start(**event)
|
17
17
|
when :step_finish
|
18
|
-
log_step_finish(event)
|
18
|
+
log_step_finish(**event)
|
19
19
|
when :plan_start
|
20
20
|
log_plan_start(event)
|
21
21
|
when :plan_finish
|
data/lib/bolt/pal.rb
CHANGED
@@ -5,40 +5,36 @@ require 'bolt/executor'
|
|
5
5
|
require 'bolt/error'
|
6
6
|
require 'bolt/plan_result'
|
7
7
|
require 'bolt/util'
|
8
|
+
require 'bolt/config/modulepath'
|
8
9
|
require 'etc'
|
9
10
|
|
10
11
|
module Bolt
|
11
12
|
class PAL
|
12
|
-
BOLTLIB_PATH = File.expand_path('../../bolt-modules', __dir__)
|
13
|
-
MODULES_PATH = File.expand_path('../../modules', __dir__)
|
14
|
-
|
15
13
|
# PALError is used to convert errors from executing puppet code into
|
16
14
|
# Bolt::Errors
|
17
15
|
class PALError < Bolt::Error
|
18
16
|
def self.from_preformatted_error(err)
|
19
|
-
if err.cause
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
error = if err.cause.is_a? Bolt::Error
|
18
|
+
err.cause
|
19
|
+
else
|
20
|
+
from_error(err)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Provide the location of an error if it came from a plan
|
24
|
+
details = {}
|
25
|
+
details[:file] = err.file if defined?(err.file)
|
26
|
+
details[:line] = err.line if defined?(err.line)
|
27
|
+
details[:column] = err.pos if defined?(err.pos)
|
28
|
+
|
29
|
+
error.add_filelineno(details)
|
30
|
+
error
|
24
31
|
end
|
25
32
|
|
26
33
|
# Generate a Bolt::Pal::PALError for non-bolt errors
|
27
34
|
def self.from_error(err)
|
28
35
|
# Use the original error message if available
|
29
36
|
message = err.cause ? err.cause.message : err.message
|
30
|
-
|
31
|
-
# Provide the location of an error if it came from a plan
|
32
|
-
details = if defined?(err.file) && err.file
|
33
|
-
{ file: err.file,
|
34
|
-
line: err.line,
|
35
|
-
column: err.pos }.compact
|
36
|
-
else
|
37
|
-
{}
|
38
|
-
end
|
39
|
-
|
40
|
-
e = new(message, details)
|
41
|
-
|
37
|
+
e = new(message)
|
42
38
|
e.set_backtrace(err.backtrace)
|
43
39
|
e
|
44
40
|
end
|
@@ -48,16 +44,16 @@ module Bolt
|
|
48
44
|
end
|
49
45
|
end
|
50
46
|
|
51
|
-
attr_reader :modulepath, :user_modulepath
|
52
|
-
|
53
47
|
def initialize(modulepath, hiera_config, resource_types, max_compiles = Etc.nprocessors,
|
54
48
|
trusted_external = nil, apply_settings = {}, project = nil)
|
49
|
+
unless modulepath.is_a?(Bolt::Config::Modulepath)
|
50
|
+
msg = "Type error in PAL: modulepath must be a Bolt::Config::Modulepath"
|
51
|
+
raise Bolt::Error.new(msg, "bolt/execution-error")
|
52
|
+
end
|
55
53
|
# Nothing works without initialized this global state. Reinitializing
|
56
54
|
# is safe and in practice only happens in tests
|
57
55
|
self.class.load_puppet
|
58
|
-
|
59
|
-
@user_modulepath = modulepath
|
60
|
-
@modulepath = [BOLTLIB_PATH, *modulepath, MODULES_PATH]
|
56
|
+
@modulepath = modulepath
|
61
57
|
@hiera_config = hiera_config
|
62
58
|
@trusted_external = trusted_external
|
63
59
|
@apply_settings = apply_settings
|
@@ -66,13 +62,21 @@ module Bolt
|
|
66
62
|
@project = project
|
67
63
|
|
68
64
|
@logger = Bolt::Logger.logger(self)
|
69
|
-
|
70
|
-
@logger.debug("Loading modules from #{
|
65
|
+
unless user_modulepath.empty?
|
66
|
+
@logger.debug("Loading modules from #{full_modulepath.join(File::PATH_SEPARATOR)}")
|
71
67
|
end
|
72
68
|
|
73
69
|
@loaded = false
|
74
70
|
end
|
75
71
|
|
72
|
+
def full_modulepath
|
73
|
+
@modulepath.full_modulepath
|
74
|
+
end
|
75
|
+
|
76
|
+
def user_modulepath
|
77
|
+
@modulepath.user_modulepath
|
78
|
+
end
|
79
|
+
|
76
80
|
# Puppet logging is global so this is class method to avoid confusion
|
77
81
|
def self.configure_logging
|
78
82
|
Puppet::Util::Log.destinations.clear
|
@@ -160,7 +164,7 @@ module Bolt
|
|
160
164
|
def in_bolt_compiler
|
161
165
|
# TODO: If we always call this inside a bolt_executor we can remove this here
|
162
166
|
setup
|
163
|
-
r = Puppet::Pal.in_tmp_environment('bolt', modulepath:
|
167
|
+
r = Puppet::Pal.in_tmp_environment('bolt', modulepath: full_modulepath, facts: {}) do |pal|
|
164
168
|
# Only load the project if it a) exists, b) has a name it can be loaded with
|
165
169
|
Puppet.override(bolt_project: @project,
|
166
170
|
yaml_plan_instantiator: Bolt::PAL::YamlPlan::Loader) do
|
@@ -215,11 +219,11 @@ module Bolt
|
|
215
219
|
apply_executor: applicator || Applicator.new(
|
216
220
|
inventory,
|
217
221
|
executor,
|
218
|
-
|
222
|
+
full_modulepath,
|
219
223
|
# Skip syncing built-in plugins, since we vendor some Puppet 6
|
220
224
|
# versions of "core" types, which are already present on the agent,
|
221
225
|
# but may cause issues on Puppet 5 agents.
|
222
|
-
|
226
|
+
user_modulepath,
|
223
227
|
@project,
|
224
228
|
pdb_client,
|
225
229
|
@hiera_config,
|
@@ -253,19 +257,24 @@ module Bolt
|
|
253
257
|
|
254
258
|
# TODO: PUP-8553 should replace this
|
255
259
|
def with_puppet_settings
|
256
|
-
Dir.mktmpdir('bolt')
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
Puppet.settings.send(:clear_everything_for_tests)
|
262
|
-
Puppet.initialize_settings(cli)
|
263
|
-
Puppet::GettextConfig.create_default_text_domain
|
264
|
-
Puppet[:trusted_external_command] = @trusted_external
|
265
|
-
Puppet.settings[:hiera_config] = @hiera_config
|
266
|
-
self.class.configure_logging
|
267
|
-
yield
|
260
|
+
dir = Dir.mktmpdir('bolt')
|
261
|
+
|
262
|
+
cli = []
|
263
|
+
Puppet::Settings::REQUIRED_APP_SETTINGS.each do |setting|
|
264
|
+
cli << "--#{setting}" << dir
|
268
265
|
end
|
266
|
+
Puppet.settings.send(:clear_everything_for_tests)
|
267
|
+
Puppet.initialize_settings(cli)
|
268
|
+
Puppet::GettextConfig.create_default_text_domain
|
269
|
+
Puppet[:trusted_external_command] = @trusted_external
|
270
|
+
Puppet.settings[:hiera_config] = @hiera_config
|
271
|
+
self.class.configure_logging
|
272
|
+
yield
|
273
|
+
ensure
|
274
|
+
# Delete the tmpdir if it still exists. This check is needed to
|
275
|
+
# prevent Bolt from erroring if the tmpdir is somehow deleted
|
276
|
+
# before reaching this point.
|
277
|
+
FileUtils.remove_entry_secure(dir) if File.exist?(dir)
|
269
278
|
end
|
270
279
|
|
271
280
|
# Parses a snippet of Puppet manifest code and returns the AST represented
|
@@ -441,13 +450,14 @@ module Bolt
|
|
441
450
|
# Returns a mapping of all modules available to the Bolt compiler
|
442
451
|
#
|
443
452
|
# @return [Hash{String => Array<Hash{Symbol => String,nil}>}]
|
444
|
-
# A hash that associates each directory on the
|
453
|
+
# A hash that associates each directory on the modulepath with an array
|
445
454
|
# containing a hash of information for each module in that directory.
|
446
455
|
# The information hash provides the name, version, and a string
|
447
456
|
# indicating whether the module belongs to an internal module group.
|
448
457
|
def list_modules
|
449
|
-
internal_module_groups = { BOLTLIB_PATH => 'Plan Language Modules',
|
450
|
-
MODULES_PATH => 'Packaged Modules'
|
458
|
+
internal_module_groups = { Bolt::Config::Modulepath::BOLTLIB_PATH => 'Plan Language Modules',
|
459
|
+
Bolt::Config::Modulepath::MODULES_PATH => 'Packaged Modules',
|
460
|
+
@project.managed_moduledir.to_s => 'Project Dependencies' }
|
451
461
|
|
452
462
|
in_bolt_compiler do
|
453
463
|
# NOTE: Can replace map+to_h with transform_values when Ruby 2.4
|
data/lib/bolt/pal/yaml_plan.rb
CHANGED
@@ -98,10 +98,12 @@ module Bolt
|
|
98
98
|
# subclasses this parent class in order to implement its own evaluation
|
99
99
|
# logic.
|
100
100
|
class EvaluableString
|
101
|
-
attr_reader :value
|
101
|
+
attr_reader :file, :line, :value
|
102
102
|
|
103
|
-
def initialize(value)
|
103
|
+
def initialize(value, file = nil, line = nil)
|
104
104
|
@value = value
|
105
|
+
@file = file
|
106
|
+
@line = line
|
105
107
|
end
|
106
108
|
|
107
109
|
def ==(other)
|
@@ -191,7 +191,11 @@ module Bolt
|
|
191
191
|
o[key] = evaluate_code_blocks(scope, v)
|
192
192
|
end
|
193
193
|
when EvaluableString
|
194
|
-
|
194
|
+
begin
|
195
|
+
value.evaluate(scope, @evaluator)
|
196
|
+
rescue StandardError => e
|
197
|
+
raise format_evaluate_error(e, value)
|
198
|
+
end
|
195
199
|
else
|
196
200
|
value
|
197
201
|
end
|
@@ -203,6 +207,24 @@ module Bolt
|
|
203
207
|
def evaluate(value, _scope)
|
204
208
|
value
|
205
209
|
end
|
210
|
+
|
211
|
+
def format_evaluate_error(error, value)
|
212
|
+
# The Puppet::PreformattedError includes the line number of the
|
213
|
+
# evaluable string that caused the error, while the value includes the
|
214
|
+
# line number of the YAML plan that the string began on. To get the
|
215
|
+
# actual line number of the error, add these two numbers together.
|
216
|
+
line = error.line + value.line
|
217
|
+
|
218
|
+
# If the evaluable string is not a scalar literal, correct for it
|
219
|
+
# being on the same line as the step key.
|
220
|
+
line -= 1 if value.is_a?(BareString)
|
221
|
+
|
222
|
+
Bolt::PlanFailure.new(
|
223
|
+
error.basic_message,
|
224
|
+
'bolt/evaluation-error',
|
225
|
+
{ file: value.file, line: line }
|
226
|
+
)
|
227
|
+
end
|
206
228
|
end
|
207
229
|
end
|
208
230
|
end
|
@@ -9,10 +9,15 @@ module Bolt
|
|
9
9
|
class YamlPlan
|
10
10
|
class Loader
|
11
11
|
class PuppetVisitor < Psych::Visitors::NoAliasRuby
|
12
|
-
def
|
12
|
+
def initialize(scanner, class_loader, file)
|
13
|
+
super(scanner, class_loader)
|
14
|
+
@file = file
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.create_visitor(source_ref)
|
13
18
|
class_loader = Psych::ClassLoader::Restricted.new([], [])
|
14
19
|
scanner = Psych::ScalarScanner.new(class_loader)
|
15
|
-
new(scanner, class_loader)
|
20
|
+
new(scanner, class_loader, source_ref)
|
16
21
|
end
|
17
22
|
|
18
23
|
def deserialize(node)
|
@@ -23,18 +28,18 @@ module Bolt
|
|
23
28
|
# @ss is a ScalarScanner, from the base ToRuby visitor class
|
24
29
|
node.value
|
25
30
|
when Psych::Nodes::Scalar::DOUBLE_QUOTED
|
26
|
-
DoubleQuotedString.new(node.value)
|
27
|
-
# | style string
|
28
|
-
when Psych::Nodes::Scalar::LITERAL
|
29
|
-
CodeLiteral.new(node.value)
|
30
|
-
#
|
31
|
+
DoubleQuotedString.new(node.value, @file, node.start_line + 1)
|
32
|
+
# | style string
|
33
|
+
when Psych::Nodes::Scalar::LITERAL
|
34
|
+
CodeLiteral.new(node.value, @file, node.start_line + 1)
|
35
|
+
# > style string
|
31
36
|
else
|
32
37
|
@ss.tokenize(node.value)
|
33
38
|
end
|
34
39
|
else
|
35
40
|
value = @ss.tokenize(node.value)
|
36
41
|
if value.is_a?(String)
|
37
|
-
BareString.new(value)
|
42
|
+
BareString.new(value, @file, node.start_line + 1)
|
38
43
|
else
|
39
44
|
value
|
40
45
|
end
|
@@ -50,7 +55,7 @@ module Bolt
|
|
50
55
|
else
|
51
56
|
Psych.parse(yaml_string, source_ref)
|
52
57
|
end
|
53
|
-
PuppetVisitor.create_visitor.accept(parse_tree)
|
58
|
+
PuppetVisitor.create_visitor(source_ref).accept(parse_tree)
|
54
59
|
end
|
55
60
|
|
56
61
|
def self.from_string(name, yaml_string, source_ref)
|
data/lib/bolt/plugin.rb
CHANGED
data/lib/bolt/plugin/module.rb
CHANGED
data/lib/bolt/project.rb
CHANGED
@@ -16,9 +16,10 @@ module Bolt
|
|
16
16
|
"These tasks are included in `bolt task show` output"
|
17
17
|
}.freeze
|
18
18
|
|
19
|
-
attr_reader :path, :data, :config_file, :inventory_file, :
|
19
|
+
attr_reader :path, :data, :config_file, :inventory_file, :hiera_config,
|
20
20
|
:puppetfile, :rerunfile, :type, :resource_types, :logs, :project_file,
|
21
|
-
:deprecations, :downloads, :plans_path
|
21
|
+
:deprecations, :downloads, :plans_path, :modulepath, :managed_moduledir,
|
22
|
+
:backup_dir
|
22
23
|
|
23
24
|
def self.default_project(logs = [])
|
24
25
|
create_project(File.expand_path(File.join('~', '.puppetlabs', 'bolt')), 'user', logs)
|
@@ -94,15 +95,16 @@ module Bolt
|
|
94
95
|
@deprecations << { type: 'Using bolt.yaml for project configuration', msg: msg }
|
95
96
|
end
|
96
97
|
|
97
|
-
@inventory_file
|
98
|
-
@
|
99
|
-
@
|
100
|
-
@
|
101
|
-
@
|
102
|
-
@
|
103
|
-
@
|
104
|
-
@
|
105
|
-
@
|
98
|
+
@inventory_file = @path + 'inventory.yaml'
|
99
|
+
@hiera_config = @path + 'hiera.yaml'
|
100
|
+
@puppetfile = @path + 'Puppetfile'
|
101
|
+
@rerunfile = @path + '.rerun.json'
|
102
|
+
@resource_types = @path + '.resource_types'
|
103
|
+
@type = type
|
104
|
+
@downloads = @path + 'downloads'
|
105
|
+
@plans_path = @path + 'plans'
|
106
|
+
@managed_moduledir = @path + '.modules'
|
107
|
+
@backup_dir = @path + '.bolt-bak'
|
106
108
|
|
107
109
|
tc = Bolt::Config::INVENTORY_OPTIONS.keys & raw_data.keys
|
108
110
|
if tc.any?
|
@@ -112,6 +114,14 @@ module Bolt
|
|
112
114
|
|
113
115
|
@data = raw_data.reject { |k, _| Bolt::Config::INVENTORY_OPTIONS.include?(k) }
|
114
116
|
|
117
|
+
# If the 'modules' key is present in the project configuration file,
|
118
|
+
# use the new, shorter modulepath.
|
119
|
+
@modulepath = if @data.key?('modules')
|
120
|
+
[(@path + 'modules').to_s]
|
121
|
+
else
|
122
|
+
[(@path + 'modules').to_s, (@path + 'site-modules').to_s, (@path + 'site').to_s]
|
123
|
+
end
|
124
|
+
|
115
125
|
# Once bolt.yaml deprecation is removed, this attribute should be removed
|
116
126
|
# and replaced with .project_file in lib/bolt/config.rb
|
117
127
|
@config_file = if (Bolt::Config::BOLT_OPTIONS & @data.keys).any?
|
@@ -164,7 +174,13 @@ module Bolt
|
|
164
174
|
end
|
165
175
|
|
166
176
|
def modules
|
167
|
-
@data['modules']
|
177
|
+
@modules ||= @data['modules']&.map do |mod|
|
178
|
+
if mod.is_a?(String)
|
179
|
+
{ 'name' => mod }
|
180
|
+
else
|
181
|
+
mod
|
182
|
+
end
|
183
|
+
end
|
168
184
|
end
|
169
185
|
|
170
186
|
def validate
|
@@ -174,7 +190,7 @@ module Bolt
|
|
174
190
|
Invalid project name '#{name}' in bolt-project.yaml; project name must begin with a lowercase letter
|
175
191
|
and can include lowercase letters, numbers, and underscores.
|
176
192
|
ERROR_STRING
|
177
|
-
elsif Dir.children(Bolt::
|
193
|
+
elsif Dir.children(Bolt::Config::Modulepath::BOLTLIB_PATH).include?(name)
|
178
194
|
raise Bolt::ValidationError, "The project '#{name}' will not be loaded. The project name conflicts "\
|
179
195
|
"with a built-in Bolt module of the same name."
|
180
196
|
end
|
@@ -194,15 +210,9 @@ module Bolt
|
|
194
210
|
raise Bolt::ValidationError, "'modules' in bolt-project.yaml must be an array"
|
195
211
|
end
|
196
212
|
|
197
|
-
@data['modules'].each do |
|
198
|
-
next if
|
199
|
-
raise Bolt::ValidationError, "Module
|
200
|
-
end
|
201
|
-
|
202
|
-
unknown_keys = data['modules'].flat_map(&:keys).uniq - ['name']
|
203
|
-
if unknown_keys.any?
|
204
|
-
@logs << { warn: "Module declarations in bolt-project.yaml only support a name key. Ignoring "\
|
205
|
-
"unsupported keys: #{unknown_keys.join(', ')}." }
|
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"
|
206
216
|
end
|
207
217
|
end
|
208
218
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/project_migrator/config'
|
4
|
+
require 'bolt/project_migrator/inventory'
|
5
|
+
require 'bolt/project_migrator/modules'
|
6
|
+
|
7
|
+
module Bolt
|
8
|
+
class ProjectMigrator
|
9
|
+
def initialize(config, outputter)
|
10
|
+
@config = config
|
11
|
+
@outputter = outputter
|
12
|
+
end
|
13
|
+
|
14
|
+
def migrate
|
15
|
+
unless $stdin.tty?
|
16
|
+
raise Bolt::Error.new(
|
17
|
+
"stdin is not a tty, unable to migrate project",
|
18
|
+
'bolt/stdin-not-a-tty-error'
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
@outputter.print_message("Migrating project #{@config.project.path}\n\n")
|
23
|
+
|
24
|
+
@outputter.print_action_step(
|
25
|
+
"Migrating a Bolt project may make irreversible changes to the project's "\
|
26
|
+
"configuration and inventory files. Before continuing, make sure the "\
|
27
|
+
"project has a backup or uses a version control system."
|
28
|
+
)
|
29
|
+
|
30
|
+
return 0 unless Bolt::Util.prompt_yes_no("Continue with project migration?", @outputter)
|
31
|
+
|
32
|
+
@outputter.print_message('')
|
33
|
+
|
34
|
+
ok = migrate_inventory && migrate_config && migrate_modules
|
35
|
+
|
36
|
+
if ok
|
37
|
+
@outputter.print_message("Project successfully migrated")
|
38
|
+
else
|
39
|
+
@outputter.print_error("Project could not be migrated completely")
|
40
|
+
end
|
41
|
+
|
42
|
+
ok ? 0 : 1
|
43
|
+
end
|
44
|
+
|
45
|
+
# Migrates the project-level configuration file to the latest version.
|
46
|
+
#
|
47
|
+
private def migrate_config
|
48
|
+
migrator = Bolt::ProjectMigrator::Config.new(@outputter)
|
49
|
+
|
50
|
+
migrator.migrate(
|
51
|
+
@config.project.config_file,
|
52
|
+
@config.project.project_file,
|
53
|
+
@config.inventoryfile || @config.project.inventory_file,
|
54
|
+
@config.project.backup_dir
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Migrates the inventory file to the latest version.
|
59
|
+
#
|
60
|
+
private def migrate_inventory
|
61
|
+
migrator = Bolt::ProjectMigrator::Inventory.new(@outputter)
|
62
|
+
|
63
|
+
migrator.migrate(
|
64
|
+
@config.inventoryfile || @config.project.inventory_file,
|
65
|
+
@config.project.backup_dir
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Migrates the project's modules to use current best practices.
|
70
|
+
#
|
71
|
+
private def migrate_modules
|
72
|
+
migrator = Bolt::ProjectMigrator::Modules.new(@outputter)
|
73
|
+
|
74
|
+
migrator.migrate(
|
75
|
+
@config.project,
|
76
|
+
@config.modulepath
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|