bolt 2.25.0 → 2.30.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 +4 -3
- data/bolt-modules/boltlib/lib/puppet/datatypes/result.rb +2 -1
- data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +1 -1
- data/bolt-modules/dir/lib/puppet/functions/dir/children.rb +1 -1
- data/lib/bolt/analytics.rb +7 -3
- data/lib/bolt/applicator.rb +21 -21
- data/lib/bolt/bolt_option_parser.rb +116 -26
- data/lib/bolt/catalog.rb +5 -3
- data/lib/bolt/cli.rb +194 -185
- data/lib/bolt/config.rb +61 -26
- data/lib/bolt/config/options.rb +35 -2
- data/lib/bolt/executor.rb +2 -2
- data/lib/bolt/inventory.rb +8 -1
- data/lib/bolt/inventory/group.rb +1 -1
- data/lib/bolt/inventory/inventory.rb +1 -1
- data/lib/bolt/inventory/target.rb +1 -1
- data/lib/bolt/logger.rb +35 -21
- data/lib/bolt/module_installer.rb +172 -0
- data/lib/bolt/outputter.rb +4 -0
- data/lib/bolt/outputter/human.rb +53 -11
- data/lib/bolt/outputter/json.rb +7 -1
- data/lib/bolt/outputter/logger.rb +3 -3
- data/lib/bolt/pal.rb +29 -20
- data/lib/bolt/pal/yaml_plan/evaluator.rb +1 -1
- data/lib/bolt/plugin/module.rb +1 -1
- data/lib/bolt/plugin/puppetdb.rb +1 -1
- data/lib/bolt/project.rb +89 -28
- 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 +198 -0
- data/lib/bolt/puppetdb/client.rb +1 -1
- data/lib/bolt/puppetdb/config.rb +1 -1
- data/lib/bolt/puppetfile.rb +142 -0
- data/lib/bolt/puppetfile/installer.rb +43 -0
- data/lib/bolt/puppetfile/module.rb +90 -0
- data/lib/bolt/r10k_log_proxy.rb +1 -1
- data/lib/bolt/rerun.rb +2 -2
- data/lib/bolt/result.rb +23 -0
- data/lib/bolt/shell.rb +1 -1
- data/lib/bolt/shell/bash.rb +1 -1
- data/lib/bolt/task.rb +1 -1
- data/lib/bolt/transport/base.rb +5 -5
- data/lib/bolt/transport/docker/connection.rb +1 -1
- data/lib/bolt/transport/local/connection.rb +1 -1
- data/lib/bolt/transport/ssh.rb +1 -1
- data/lib/bolt/transport/ssh/connection.rb +1 -1
- data/lib/bolt/transport/ssh/exec_connection.rb +1 -1
- data/lib/bolt/transport/winrm.rb +1 -1
- data/lib/bolt/transport/winrm/connection.rb +1 -1
- data/lib/bolt/util.rb +52 -11
- 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/config.rb +1 -1
- data/lib/bolt_server/file_cache.rb +12 -12
- data/lib/bolt_server/transport_app.rb +125 -26
- data/lib/bolt_spec/bolt_context.rb +4 -4
- data/lib/bolt_spec/plans/mock_executor.rb +1 -1
- metadata +15 -13
- data/lib/bolt/project_migrate.rb +0 -138
data/lib/bolt/outputter.rb
CHANGED
@@ -35,6 +35,10 @@ module Bolt
|
|
35
35
|
raise NotImplementedError, "print_message() must be implemented by the outputter class"
|
36
36
|
end
|
37
37
|
|
38
|
+
def print_error
|
39
|
+
raise NotImplementedError, "print_error() must be implemented by the outputter class"
|
40
|
+
end
|
41
|
+
|
38
42
|
def stringify(message)
|
39
43
|
formatted = format_message(message)
|
40
44
|
if formatted.is_a?(Hash) || formatted.is_a?(Array)
|
data/lib/bolt/outputter/human.rb
CHANGED
@@ -5,9 +5,12 @@ require 'bolt/pal'
|
|
5
5
|
module Bolt
|
6
6
|
class Outputter
|
7
7
|
class Human < Bolt::Outputter
|
8
|
-
COLORS = {
|
9
|
-
|
10
|
-
|
8
|
+
COLORS = {
|
9
|
+
red: "31",
|
10
|
+
green: "32",
|
11
|
+
yellow: "33",
|
12
|
+
cyan: "36"
|
13
|
+
}.freeze
|
11
14
|
|
12
15
|
def print_head; end
|
13
16
|
|
@@ -31,6 +34,10 @@ module Bolt
|
|
31
34
|
string.sub(/\s\z/, '')
|
32
35
|
end
|
33
36
|
|
37
|
+
def wrap(string, width = 80)
|
38
|
+
string.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n")
|
39
|
+
end
|
40
|
+
|
34
41
|
def handle_event(event)
|
35
42
|
case event[:type]
|
36
43
|
when :enable_default_output
|
@@ -48,9 +55,9 @@ module Bolt
|
|
48
55
|
when :node_result
|
49
56
|
print_result(event[:result]) if @verbose
|
50
57
|
when :step_start
|
51
|
-
print_step_start(event) if plan_logging?
|
58
|
+
print_step_start(**event) if plan_logging?
|
52
59
|
when :step_finish
|
53
|
-
print_step_finish(event) if plan_logging?
|
60
|
+
print_step_finish(**event) if plan_logging?
|
54
61
|
when :plan_start
|
55
62
|
print_plan_start(event)
|
56
63
|
when :plan_finish
|
@@ -188,7 +195,7 @@ module Bolt
|
|
188
195
|
@stream.puts total_msg
|
189
196
|
end
|
190
197
|
|
191
|
-
def print_table(results)
|
198
|
+
def print_table(results, padding_left = 0, padding_right = 3)
|
192
199
|
# lazy-load expensive gem code
|
193
200
|
require 'terminal-table'
|
194
201
|
|
@@ -198,8 +205,8 @@ module Bolt
|
|
198
205
|
border_x: '',
|
199
206
|
border_y: '',
|
200
207
|
border_i: '',
|
201
|
-
padding_left:
|
202
|
-
padding_right:
|
208
|
+
padding_left: padding_left,
|
209
|
+
padding_right: padding_right,
|
203
210
|
border_top: false,
|
204
211
|
border_bottom: false
|
205
212
|
}
|
@@ -299,9 +306,9 @@ module Bolt
|
|
299
306
|
def print_module_list(module_list)
|
300
307
|
module_list.each do |path, modules|
|
301
308
|
if (mod = modules.find { |m| m[:internal_module_group] })
|
302
|
-
@stream.puts(mod[:internal_module_group])
|
309
|
+
@stream.puts(colorize(:cyan, mod[:internal_module_group]))
|
303
310
|
else
|
304
|
-
@stream.puts(path)
|
311
|
+
@stream.puts(colorize(:cyan, path))
|
305
312
|
end
|
306
313
|
|
307
314
|
if modules.empty?
|
@@ -317,7 +324,7 @@ module Bolt
|
|
317
324
|
[m[:name], version]
|
318
325
|
end
|
319
326
|
|
320
|
-
print_table(module_info)
|
327
|
+
print_table(module_info, 2, 1)
|
321
328
|
end
|
322
329
|
|
323
330
|
@stream.write("\n")
|
@@ -394,6 +401,41 @@ module Bolt
|
|
394
401
|
@stream.puts(message)
|
395
402
|
end
|
396
403
|
|
404
|
+
def print_error(message)
|
405
|
+
@stream.puts(colorize(:red, message))
|
406
|
+
end
|
407
|
+
|
408
|
+
def print_prompt(prompt)
|
409
|
+
@stream.print(colorize(:cyan, indent(4, prompt)))
|
410
|
+
end
|
411
|
+
|
412
|
+
def print_prompt_error(message)
|
413
|
+
@stream.puts(colorize(:red, indent(4, message)))
|
414
|
+
end
|
415
|
+
|
416
|
+
def print_migrate_step(step)
|
417
|
+
first, *remaining = wrap(step, 76).lines
|
418
|
+
|
419
|
+
first = indent(2, "→ #{first}")
|
420
|
+
remaining = remaining.map { |line| indent(4, line) }
|
421
|
+
step = [first, *remaining, "\n"].join
|
422
|
+
|
423
|
+
@stream.puts(step)
|
424
|
+
end
|
425
|
+
|
426
|
+
def print_migrate_error(error)
|
427
|
+
# Running everything through 'wrap' messes with newlines. Separating
|
428
|
+
# into lines and wrapping each individually ensures separate errors are
|
429
|
+
# distinguishable.
|
430
|
+
first, *remaining = error.lines
|
431
|
+
first = colorize(:red, indent(2, "→ #{wrap(first, 76)}"))
|
432
|
+
wrapped = remaining.map { |l| wrap(l) }
|
433
|
+
to_print = wrapped.map { |line| colorize(:red, indent(4, line)) }
|
434
|
+
step = [first, *to_print, "\n"].join
|
435
|
+
|
436
|
+
@stream.puts(step)
|
437
|
+
end
|
438
|
+
|
397
439
|
def duration_to_string(duration)
|
398
440
|
hrs = (duration / 3600).floor
|
399
441
|
mins = ((duration % 3600) / 60).floor
|
data/lib/bolt/outputter/json.rb
CHANGED
@@ -97,7 +97,7 @@ module Bolt
|
|
97
97
|
def print_puppetfile_result(success, puppetfile, moduledir)
|
98
98
|
@stream.puts({ "success": success,
|
99
99
|
"puppetfile": puppetfile,
|
100
|
-
"moduledir": moduledir }.to_json)
|
100
|
+
"moduledir": moduledir.to_s }.to_json)
|
101
101
|
end
|
102
102
|
|
103
103
|
def print_targets(targets)
|
@@ -135,6 +135,12 @@ module Bolt
|
|
135
135
|
def print_message(message)
|
136
136
|
$stderr.puts(message)
|
137
137
|
end
|
138
|
+
alias print_error print_message
|
139
|
+
|
140
|
+
def print_migrate_step(step)
|
141
|
+
$stderr.puts(step)
|
142
|
+
end
|
143
|
+
alias print_migrate_error print_migrate_step
|
138
144
|
end
|
139
145
|
end
|
140
146
|
end
|
@@ -7,15 +7,15 @@ module Bolt
|
|
7
7
|
class Logger < Bolt::Outputter
|
8
8
|
def initialize(verbose, trace)
|
9
9
|
super(false, verbose, trace)
|
10
|
-
@logger =
|
10
|
+
@logger = Bolt::Logger.logger(self)
|
11
11
|
end
|
12
12
|
|
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
@@ -29,15 +29,12 @@ module Bolt
|
|
29
29
|
message = err.cause ? err.cause.message : err.message
|
30
30
|
|
31
31
|
# Provide the location of an error if it came from a plan
|
32
|
-
details =
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
else
|
37
|
-
{}
|
38
|
-
end
|
32
|
+
details = {}
|
33
|
+
details[:file] = err.file if defined?(err.file)
|
34
|
+
details[:line] = err.line if defined?(err.line)
|
35
|
+
details[:column] = err.pos if defined?(err.pos)
|
39
36
|
|
40
|
-
e = new(message, details)
|
37
|
+
e = new(message, details.compact)
|
41
38
|
|
42
39
|
e.set_backtrace(err.backtrace)
|
43
40
|
e
|
@@ -65,7 +62,7 @@ module Bolt
|
|
65
62
|
@resource_types = resource_types
|
66
63
|
@project = project
|
67
64
|
|
68
|
-
@logger =
|
65
|
+
@logger = Bolt::Logger.logger(self)
|
69
66
|
if modulepath && !modulepath.empty?
|
70
67
|
@logger.debug("Loading modules from #{@modulepath.join(File::PATH_SEPARATOR)}")
|
71
68
|
end
|
@@ -76,7 +73,7 @@ module Bolt
|
|
76
73
|
# Puppet logging is global so this is class method to avoid confusion
|
77
74
|
def self.configure_logging
|
78
75
|
Puppet::Util::Log.destinations.clear
|
79
|
-
Puppet::Util::Log.newdestination(
|
76
|
+
Puppet::Util::Log.newdestination(Bolt::Logger.logger('Puppet'))
|
80
77
|
# Defer all log level decisions to the Logging library by telling Puppet
|
81
78
|
# to log everything
|
82
79
|
Puppet.settings[:log_level] = 'debug'
|
@@ -141,6 +138,19 @@ module Bolt
|
|
141
138
|
end
|
142
139
|
end
|
143
140
|
|
141
|
+
def detect_project_conflict(project, environment)
|
142
|
+
return unless project && project.load_as_module?
|
143
|
+
# The environment modulepath has stripped out non-existent directories,
|
144
|
+
# so we don't need to check for them
|
145
|
+
modules = environment.modulepath.flat_map do |path|
|
146
|
+
Dir.children(path).select { |name| Puppet::Module.is_module_directory?(name, path) }
|
147
|
+
end
|
148
|
+
if modules.include?(project.name)
|
149
|
+
Bolt::Logger.warn_once("project shadows module",
|
150
|
+
"The project '#{project.name}' shadows an existing module of the same name")
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
144
154
|
# Runs a block in a PAL script compiler configured for Bolt. Catches
|
145
155
|
# exceptions thrown by the block and re-raises them ensuring they are
|
146
156
|
# Bolt::Errors since the script compiler block will squash all exceptions.
|
@@ -149,15 +159,13 @@ module Bolt
|
|
149
159
|
setup
|
150
160
|
r = Puppet::Pal.in_tmp_environment('bolt', modulepath: @modulepath, facts: {}) do |pal|
|
151
161
|
# Only load the project if it a) exists, b) has a name it can be loaded with
|
152
|
-
bolt_project
|
153
|
-
# Puppet currently won't receive the project unless it is a named project. Since
|
154
|
-
# the download_file plan function needs access to the project path, add it to the
|
155
|
-
# context.
|
156
|
-
bolt_project_data = @project
|
157
|
-
Puppet.override(bolt_project: bolt_project,
|
158
|
-
bolt_project_data: bolt_project_data,
|
162
|
+
Puppet.override(bolt_project: @project,
|
159
163
|
yaml_plan_instantiator: Bolt::PAL::YamlPlan::Loader) do
|
160
|
-
|
164
|
+
# Because this has the side effect of loading and caching the list
|
165
|
+
# of modules, it must happen *after* we have overridden
|
166
|
+
# bolt_project or the project will be ignored
|
167
|
+
detect_project_conflict(@project, Puppet.lookup(:environments).get('bolt'))
|
168
|
+
pal.with_script_compiler(set_local_facts: false) do |compiler|
|
161
169
|
alias_types(compiler)
|
162
170
|
register_resource_types(Puppet.lookup(:loaders)) if @resource_types
|
163
171
|
begin
|
@@ -430,13 +438,14 @@ module Bolt
|
|
430
438
|
# Returns a mapping of all modules available to the Bolt compiler
|
431
439
|
#
|
432
440
|
# @return [Hash{String => Array<Hash{Symbol => String,nil}>}]
|
433
|
-
# A hash that associates each directory on the
|
441
|
+
# A hash that associates each directory on the modulepath with an array
|
434
442
|
# containing a hash of information for each module in that directory.
|
435
443
|
# The information hash provides the name, version, and a string
|
436
444
|
# indicating whether the module belongs to an internal module group.
|
437
445
|
def list_modules
|
438
446
|
internal_module_groups = { BOLTLIB_PATH => 'Plan Language Modules',
|
439
|
-
MODULES_PATH => 'Packaged Modules'
|
447
|
+
MODULES_PATH => 'Packaged Modules',
|
448
|
+
@project.managed_moduledir.to_s => 'Project Dependencies' }
|
440
449
|
|
441
450
|
in_bolt_compiler do
|
442
451
|
# NOTE: Can replace map+to_h with transform_values when Ruby 2.4
|
@@ -7,7 +7,7 @@ module Bolt
|
|
7
7
|
class YamlPlan
|
8
8
|
class Evaluator
|
9
9
|
def initialize(analytics = Bolt::Analytics::NoopClient.new)
|
10
|
-
@logger =
|
10
|
+
@logger = Bolt::Logger.logger(self)
|
11
11
|
@analytics = analytics
|
12
12
|
@evaluator = Puppet::Pops::Parser::EvaluatingParser.new
|
13
13
|
end
|
data/lib/bolt/plugin/module.rb
CHANGED
data/lib/bolt/plugin/puppetdb.rb
CHANGED
@@ -19,7 +19,7 @@ module Bolt
|
|
19
19
|
def initialize(config:, context:)
|
20
20
|
pdb_config = Bolt::PuppetDB::Config.load_config(config, context.boltdir)
|
21
21
|
@puppetdb_client = Bolt::PuppetDB::Client.new(pdb_config)
|
22
|
-
@logger =
|
22
|
+
@logger = Bolt::Logger.logger(self)
|
23
23
|
end
|
24
24
|
|
25
25
|
def name
|
data/lib/bolt/project.rb
CHANGED
@@ -16,38 +16,55 @@ 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, :
|
20
|
-
:puppetfile, :rerunfile, :type, :resource_types, :
|
21
|
-
:deprecations, :downloads, :plans_path
|
19
|
+
attr_reader :path, :data, :config_file, :inventory_file, :hiera_config,
|
20
|
+
:puppetfile, :rerunfile, :type, :resource_types, :logs, :project_file,
|
21
|
+
:deprecations, :downloads, :plans_path, :modulepath, :managed_moduledir,
|
22
|
+
:backup_dir
|
22
23
|
|
23
|
-
def self.default_project
|
24
|
-
create_project(File.expand_path(File.join('~', '.puppetlabs', 'bolt')), 'user')
|
24
|
+
def self.default_project(logs = [])
|
25
|
+
create_project(File.expand_path(File.join('~', '.puppetlabs', 'bolt')), 'user', logs)
|
25
26
|
# If homedir isn't defined use the system config path
|
26
27
|
rescue ArgumentError
|
27
|
-
create_project(Bolt::Config.system_path, 'system')
|
28
|
+
create_project(Bolt::Config.system_path, 'system', logs)
|
28
29
|
end
|
29
30
|
|
30
31
|
# Search recursively up the directory hierarchy for the Project. Look for a
|
31
32
|
# directory called Boltdir or a file called bolt.yaml (for a control repo
|
32
33
|
# type Project). Otherwise, repeat the check on each directory up the
|
33
34
|
# hierarchy, falling back to the default if we reach the root.
|
34
|
-
def self.find_boltdir(dir)
|
35
|
+
def self.find_boltdir(dir, logs = [])
|
35
36
|
dir = Pathname.new(dir)
|
36
37
|
|
37
38
|
if (dir + BOLTDIR_NAME).directory?
|
38
|
-
create_project(dir + BOLTDIR_NAME, 'embedded')
|
39
|
+
create_project(dir + BOLTDIR_NAME, 'embedded', logs)
|
39
40
|
elsif (dir + 'bolt.yaml').file? || (dir + 'bolt-project.yaml').file?
|
40
|
-
create_project(dir, 'local')
|
41
|
+
create_project(dir, 'local', logs)
|
41
42
|
elsif dir.root?
|
42
|
-
default_project
|
43
|
+
default_project(logs)
|
43
44
|
else
|
44
|
-
|
45
|
+
logs << { debug: "Did not detect Boltdir, bolt.yaml, or bolt-project.yaml at '#{dir}'. "\
|
46
|
+
"This directory won't be loaded as a project." }
|
47
|
+
find_boltdir(dir.parent, logs)
|
45
48
|
end
|
46
49
|
end
|
47
50
|
|
48
|
-
def self.create_project(path, type = 'option')
|
51
|
+
def self.create_project(path, type = 'option', logs = [])
|
49
52
|
fullpath = Pathname.new(path).expand_path
|
50
53
|
|
54
|
+
if type == 'user'
|
55
|
+
begin
|
56
|
+
# This is already expanded if the type is user
|
57
|
+
FileUtils.mkdir_p(path)
|
58
|
+
rescue StandardError
|
59
|
+
logs << { warn: "Could not create default project at #{path}. Continuing without a writeable project. "\
|
60
|
+
"Log and rerun files will not be written." }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
if type == 'option' && !File.directory?(path)
|
65
|
+
raise Bolt::Error.new("Could not find project at #{path}", "bolt/project-error")
|
66
|
+
end
|
67
|
+
|
51
68
|
if !Bolt::Util.windows? && type != 'environment' && fullpath.world_writable?
|
52
69
|
raise Bolt::Error.new(
|
53
70
|
"Project directory '#{fullpath}' is world-writable which poses a security risk. Set "\
|
@@ -58,15 +75,18 @@ module Bolt
|
|
58
75
|
|
59
76
|
project_file = File.join(fullpath, 'bolt-project.yaml')
|
60
77
|
data = Bolt::Util.read_optional_yaml_hash(File.expand_path(project_file), 'project')
|
61
|
-
|
78
|
+
default = type =~ /user|system/ ? 'default ' : ''
|
79
|
+
exist = File.exist?(File.expand_path(project_file))
|
80
|
+
logs << { info: "Loaded #{default}project from '#{fullpath}'" } if exist
|
81
|
+
new(data, path, type, logs)
|
62
82
|
end
|
63
83
|
|
64
|
-
def initialize(raw_data, path, type = 'option')
|
84
|
+
def initialize(raw_data, path, type = 'option', logs = [])
|
65
85
|
@path = Pathname.new(path).expand_path
|
66
86
|
|
67
87
|
@project_file = @path + 'bolt-project.yaml'
|
68
88
|
|
69
|
-
@
|
89
|
+
@logs = logs
|
70
90
|
@deprecations = []
|
71
91
|
if (@path + 'bolt.yaml').file? && project_file?
|
72
92
|
msg = "Project-level configuration in bolt.yaml is deprecated if using bolt-project.yaml. "\
|
@@ -75,30 +95,39 @@ module Bolt
|
|
75
95
|
@deprecations << { type: 'Using bolt.yaml for project configuration', msg: msg }
|
76
96
|
end
|
77
97
|
|
78
|
-
@inventory_file
|
79
|
-
@
|
80
|
-
@
|
81
|
-
@
|
82
|
-
@
|
83
|
-
@
|
84
|
-
@
|
85
|
-
@
|
86
|
-
@
|
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'
|
87
108
|
|
88
109
|
tc = Bolt::Config::INVENTORY_OPTIONS.keys & raw_data.keys
|
89
110
|
if tc.any?
|
90
111
|
msg = "Transport configuration isn't supported in bolt-project.yaml. Ignoring keys #{tc}"
|
91
|
-
@
|
112
|
+
@logs << { warn: msg }
|
92
113
|
end
|
93
114
|
|
94
115
|
@data = raw_data.reject { |k, _| Bolt::Config::INVENTORY_OPTIONS.include?(k) }
|
95
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
|
+
|
96
125
|
# Once bolt.yaml deprecation is removed, this attribute should be removed
|
97
126
|
# and replaced with .project_file in lib/bolt/config.rb
|
98
127
|
@config_file = if (Bolt::Config::BOLT_OPTIONS & @data.keys).any?
|
99
128
|
if (@path + 'bolt.yaml').file?
|
100
129
|
msg = "bolt-project.yaml contains valid config keys, bolt.yaml will be ignored"
|
101
|
-
@
|
130
|
+
@logs << { warn: msg }
|
102
131
|
end
|
103
132
|
@project_file
|
104
133
|
else
|
@@ -114,7 +143,9 @@ module Bolt
|
|
114
143
|
# This API is used to prepend the project as a module to Puppet's internal
|
115
144
|
# module_references list. CHANGE AT YOUR OWN RISK
|
116
145
|
def to_h
|
117
|
-
{ path: @path.to_s,
|
146
|
+
{ path: @path.to_s,
|
147
|
+
name: name,
|
148
|
+
load_as_module?: load_as_module? }
|
118
149
|
end
|
119
150
|
|
120
151
|
def eql?(other)
|
@@ -126,6 +157,10 @@ module Bolt
|
|
126
157
|
@project_file.file?
|
127
158
|
end
|
128
159
|
|
160
|
+
def load_as_module?
|
161
|
+
!name.nil?
|
162
|
+
end
|
163
|
+
|
129
164
|
def name
|
130
165
|
@data['name']
|
131
166
|
end
|
@@ -138,6 +173,16 @@ module Bolt
|
|
138
173
|
@data['plans']
|
139
174
|
end
|
140
175
|
|
176
|
+
def 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
|
184
|
+
end
|
185
|
+
|
141
186
|
def validate
|
142
187
|
if name
|
143
188
|
if name !~ Bolt::Module::MODULE_NAME_REGEX
|
@@ -151,7 +196,7 @@ module Bolt
|
|
151
196
|
end
|
152
197
|
else
|
153
198
|
message = "No project name is specified in bolt-project.yaml. Project-level content will not be available."
|
154
|
-
@
|
199
|
+
@logs << { warn: message }
|
155
200
|
end
|
156
201
|
|
157
202
|
%w[tasks plans].each do |conf|
|
@@ -159,6 +204,22 @@ module Bolt
|
|
159
204
|
raise Bolt::ValidationError, "'#{conf}' in bolt-project.yaml must be an array"
|
160
205
|
end
|
161
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 |mod|
|
214
|
+
next if (mod.is_a?(Hash) && mod.key?('name')) || mod.is_a?(String)
|
215
|
+
raise Bolt::ValidationError, "Module declaration #{mod.inspect} must be a hash with a name key"
|
216
|
+
end
|
217
|
+
|
218
|
+
unknown_keys = modules.flat_map(&:keys).uniq - %w[name version_requirement]
|
219
|
+
if unknown_keys.any?
|
220
|
+
@logs << { warn: "Ignoring unknown keys in module declarations: #{unknown_keys.join(', ')}." }
|
221
|
+
end
|
222
|
+
end
|
162
223
|
end
|
163
224
|
|
164
225
|
def check_deprecated_file
|