bolt 2.42.0 → 3.3.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.

Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +21 -19
  3. data/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +1 -1
  4. data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +25 -0
  5. data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +6 -8
  6. data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +2 -2
  7. data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +27 -5
  8. data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +1 -1
  9. data/bolt-modules/boltlib/lib/puppet/functions/wait_until_available.rb +7 -3
  10. data/bolt-modules/file/lib/puppet/functions/file/read.rb +3 -2
  11. data/lib/bolt/analytics.rb +3 -2
  12. data/lib/bolt/applicator.rb +11 -1
  13. data/lib/bolt/apply_result.rb +1 -1
  14. data/lib/bolt/bolt_option_parser.rb +9 -116
  15. data/lib/bolt/catalog.rb +10 -29
  16. data/lib/bolt/cli.rb +90 -154
  17. data/lib/bolt/config.rb +66 -239
  18. data/lib/bolt/config/options.rb +79 -102
  19. data/lib/bolt/config/transport/local.rb +1 -0
  20. data/lib/bolt/config/transport/lxd.rb +21 -0
  21. data/lib/bolt/config/transport/options.rb +9 -2
  22. data/lib/bolt/config/transport/orch.rb +1 -0
  23. data/lib/bolt/executor.rb +23 -6
  24. data/lib/bolt/inventory.rb +1 -1
  25. data/lib/bolt/inventory/group.rb +7 -4
  26. data/lib/bolt/logger.rb +123 -11
  27. data/lib/bolt/module_installer.rb +6 -4
  28. data/lib/bolt/module_installer/puppetfile.rb +2 -2
  29. data/lib/bolt/module_installer/resolver.rb +59 -14
  30. data/lib/bolt/module_installer/specs/forge_spec.rb +10 -4
  31. data/lib/bolt/module_installer/specs/git_spec.rb +19 -4
  32. data/lib/bolt/outputter/human.rb +56 -17
  33. data/lib/bolt/outputter/json.rb +16 -16
  34. data/lib/bolt/outputter/rainbow.rb +3 -3
  35. data/lib/bolt/pal.rb +95 -15
  36. data/lib/bolt/pal/yaml_plan.rb +9 -4
  37. data/lib/bolt/pal/yaml_plan/evaluator.rb +5 -153
  38. data/lib/bolt/pal/yaml_plan/step.rb +91 -52
  39. data/lib/bolt/pal/yaml_plan/step/command.rb +16 -16
  40. data/lib/bolt/pal/yaml_plan/step/download.rb +15 -16
  41. data/lib/bolt/pal/yaml_plan/step/eval.rb +11 -11
  42. data/lib/bolt/pal/yaml_plan/step/message.rb +13 -4
  43. data/lib/bolt/pal/yaml_plan/step/plan.rb +19 -15
  44. data/lib/bolt/pal/yaml_plan/step/resources.rb +82 -21
  45. data/lib/bolt/pal/yaml_plan/step/script.rb +32 -17
  46. data/lib/bolt/pal/yaml_plan/step/task.rb +19 -16
  47. data/lib/bolt/pal/yaml_plan/step/upload.rb +16 -17
  48. data/lib/bolt/pal/yaml_plan/transpiler.rb +2 -1
  49. data/lib/bolt/plan_creator.rb +1 -1
  50. data/lib/bolt/plugin.rb +2 -2
  51. data/lib/bolt/plugin/cache.rb +7 -7
  52. data/lib/bolt/plugin/module.rb +0 -23
  53. data/lib/bolt/plugin/puppet_connect_data.rb +77 -0
  54. data/lib/bolt/plugin/puppetdb.rb +1 -1
  55. data/lib/bolt/project.rb +54 -81
  56. data/lib/bolt/project_manager.rb +5 -4
  57. data/lib/bolt/project_manager/module_migrator.rb +7 -6
  58. data/lib/bolt/rerun.rb +1 -1
  59. data/lib/bolt/result.rb +6 -1
  60. data/lib/bolt/shell.rb +16 -0
  61. data/lib/bolt/shell/bash.rb +57 -25
  62. data/lib/bolt/shell/bash/tmpdir.rb +6 -3
  63. data/lib/bolt/shell/powershell.rb +33 -10
  64. data/lib/bolt/shell/powershell/snippets.rb +37 -150
  65. data/lib/bolt/task.rb +2 -2
  66. data/lib/bolt/transport/base.rb +0 -9
  67. data/lib/bolt/transport/docker.rb +1 -125
  68. data/lib/bolt/transport/docker/connection.rb +86 -161
  69. data/lib/bolt/transport/local.rb +1 -9
  70. data/lib/bolt/transport/lxd.rb +26 -0
  71. data/lib/bolt/transport/lxd/connection.rb +99 -0
  72. data/lib/bolt/transport/orch/connection.rb +1 -1
  73. data/lib/bolt/transport/ssh.rb +1 -2
  74. data/lib/bolt/transport/ssh/connection.rb +2 -2
  75. data/lib/bolt/transport/winrm/connection.rb +1 -1
  76. data/lib/bolt/validator.rb +2 -2
  77. data/lib/bolt/version.rb +1 -1
  78. data/lib/bolt_server/config.rb +1 -1
  79. data/lib/bolt_server/transport_app.rb +61 -32
  80. data/lib/bolt_spec/bolt_context.rb +9 -4
  81. data/lib/bolt_spec/plans.rb +1 -109
  82. data/lib/bolt_spec/plans/action_stubs.rb +1 -1
  83. data/lib/bolt_spec/plans/mock_executor.rb +4 -0
  84. data/libexec/bolt_catalog +1 -1
  85. data/modules/aggregate/plans/count.pp +21 -0
  86. data/modules/aggregate/plans/targets.pp +21 -0
  87. data/modules/puppet_connect/plans/test_input_data.pp +67 -0
  88. data/modules/puppetdb_fact/plans/init.pp +10 -0
  89. metadata +13 -9
  90. data/modules/aggregate/plans/nodes.pp +0 -36
@@ -6,35 +6,50 @@ module Bolt
6
6
  class Step
7
7
  class Script < Step
8
8
  def self.allowed_keys
9
- super + Set['script', 'parameters', 'arguments']
9
+ super + Set['arguments', 'pwsh_params']
10
+ end
11
+
12
+ def self.option_keys
13
+ Set['catch_errors', 'env_vars', 'run_as']
10
14
  end
11
15
 
12
16
  def self.required_keys
13
- Set['targets']
17
+ Set['script', 'targets']
14
18
  end
15
19
 
16
- def initialize(step_body)
20
+ def self.validate_step_keys(body, number)
17
21
  super
18
- @script = step_body['script']
19
- @parameters = step_body.fetch('parameters', {})
20
- @arguments = step_body.fetch('arguments', [])
22
+
23
+ if body.key?('arguments') && !body['arguments'].nil? && !body['arguments'].is_a?(Array)
24
+ raise StepError.new('arguments key must be an array', body['name'], number)
25
+ end
26
+
27
+ if body.key?('pwsh_params') && !body['pwsh_params'].nil? && !body['pwsh_params'].is_a?(Hash)
28
+ raise StepError.new('pwsh_params key must be a hash', body['name'], number)
29
+ end
21
30
  end
22
31
 
23
- def transpile
24
- code = String.new(" ")
25
- code << "$#{@name} = " if @name
32
+ # Returns an array of arguments to pass to the step's function call
33
+ #
34
+ private def format_args(body)
35
+ args = body['arguments'] || []
36
+ pwsh_params = body['pwsh_params'] || {}
26
37
 
27
- options = @parameters.dup
28
- options['arguments'] = @arguments unless @arguments.empty?
38
+ opts = format_options(body)
39
+ opts = opts.merge('arguments' => args) if args.any?
40
+ opts = opts.merge('pwsh_params' => pwsh_params) if pwsh_params.any?
29
41
 
30
- fn = 'run_script'
31
- args = [@script, @targets]
32
- args << @description if @description
33
- args << options unless options.empty?
42
+ args = [body['script'], body['targets']]
43
+ args << body['description'] if body['description']
44
+ args << opts if opts.any?
34
45
 
35
- code << function_call(fn, args)
46
+ args
47
+ end
36
48
 
37
- code << "\n"
49
+ # Returns the function corresponding to the step
50
+ #
51
+ private def function
52
+ 'run_script'
38
53
  end
39
54
  end
40
55
  end
@@ -6,31 +6,34 @@ module Bolt
6
6
  class Step
7
7
  class Task < Step
8
8
  def self.allowed_keys
9
- super + Set['task', 'parameters']
9
+ super + Set['parameters']
10
10
  end
11
11
 
12
- def self.required_keys
13
- Set['targets']
12
+ def self.option_keys
13
+ Set['catch_errors', 'noop', 'run_as']
14
14
  end
15
15
 
16
- def initialize(step_body)
17
- super
18
- @task = step_body['task']
19
- @parameters = step_body.fetch('parameters', {})
16
+ def self.required_keys
17
+ Set['targets', 'task']
20
18
  end
21
19
 
22
- def transpile
23
- code = String.new(" ")
24
- code << "$#{@name} = " if @name
20
+ # Returns an array of arguments to pass to the step's function call
21
+ #
22
+ private def format_args(body)
23
+ opts = format_options(body)
24
+ params = (body['parameters'] || {}).merge(opts)
25
25
 
26
- fn = 'run_task'
27
- args = [@task, @targets]
28
- args << @description if @description
29
- args << @parameters unless @parameters.empty?
26
+ args = [body['task'], body['targets']]
27
+ args << body['description'] if body['description']
28
+ args << params if params.any?
30
29
 
31
- code << function_call(fn, args)
30
+ args
31
+ end
32
32
 
33
- code << "\n"
33
+ # Returns the function corresponding to the step
34
+ #
35
+ private def function
36
+ 'run_task'
34
37
  end
35
38
  end
36
39
  end
@@ -5,31 +5,30 @@ module Bolt
5
5
  class YamlPlan
6
6
  class Step
7
7
  class Upload < Step
8
- def self.allowed_keys
9
- super + Set['source', 'destination', 'upload']
8
+ def self.option_keys
9
+ Set['catch_errors', 'run_as']
10
10
  end
11
11
 
12
12
  def self.required_keys
13
- Set['upload', 'destination', 'targets']
13
+ Set['destination', 'targets', 'upload']
14
14
  end
15
15
 
16
- def initialize(step_body)
17
- super
18
- @source = step_body['upload'] || step_body['source']
19
- @destination = step_body['destination']
20
- end
21
-
22
- def transpile
23
- code = String.new(" ")
24
- code << "$#{@name} = " if @name
16
+ # Returns an array of arguments to pass to the step's function call
17
+ #
18
+ private def format_args(body)
19
+ opts = format_options(body)
25
20
 
26
- fn = 'upload_file'
27
- args = [@source, @destination, @targets]
28
- args << @description if @description
21
+ args = [body['upload'], body['destination'], body['targets']]
22
+ args << body['description'] if body['description']
23
+ args << opts if opts.any?
29
24
 
30
- code << function_call(fn, args)
25
+ args
26
+ end
31
27
 
32
- code << "\n"
28
+ # Returns the function corresponding to the step
29
+ #
30
+ private def function
31
+ 'upload_file'
33
32
  end
34
33
  end
35
34
  end
@@ -29,7 +29,8 @@ module Bolt
29
29
 
30
30
  plan_string = String.new('')
31
31
  plan_string << "# #{plan_object.description}\n" if plan_object.description
32
- plan_string << "# WARNING: This is an autogenerated plan. It may not behave as expected.\n"
32
+ plan_string << "# WARNING: This is an autogenerated plan. It might not behave as expected.\n"
33
+ plan_string << "# @private #{plan_object.private}\n" unless plan_object.private.nil?
33
34
  plan_string << "#{param_descriptions}\n" unless param_descriptions.empty?
34
35
 
35
36
  plan_string << "plan #{plan_object.name}("
@@ -22,7 +22,7 @@ module Bolt
22
22
  Invalid plan name '#{plan_name}'. Plan names are composed of one or more name segments
23
23
  separated by double colons '::'.
24
24
 
25
- Each name segment must begin with a lowercase letter, and may only include lowercase
25
+ Each name segment must begin with a lowercase letter, and can only include lowercase
26
26
  letters, digits, and underscores.
27
27
 
28
28
  Examples of valid plan names:
data/lib/bolt/plugin.rb CHANGED
@@ -139,7 +139,7 @@ module Bolt
139
139
  plugins
140
140
  end
141
141
 
142
- RUBY_PLUGINS = %w[task prompt env_var puppetdb].freeze
142
+ RUBY_PLUGINS = %w[task prompt env_var puppetdb puppet_connect_data].freeze
143
143
  BUILTIN_PLUGINS = %w[task terraform pkcs7 prompt vault aws_inventory puppetdb azure_inventory
144
144
  yaml env_var gcloud_inventory].freeze
145
145
  DEFAULT_PLUGIN_HOOKS = { 'puppet_library' => { 'plugin' => 'puppet_agent', 'stop_service' => true } }.freeze
@@ -297,7 +297,7 @@ module Bolt
297
297
  def resolve_single_reference(reference)
298
298
  plugin_cache = if cache?(reference)
299
299
  cache = Bolt::Plugin::Cache.new(reference,
300
- @config.project.cache_file,
300
+ @config.project.plugin_cache_file,
301
301
  @config.plugin_cache)
302
302
  entry = cache.read_and_clean_cache
303
303
  return entry unless entry.nil?
@@ -7,11 +7,11 @@ require 'bolt/util'
7
7
  module Bolt
8
8
  class Plugin
9
9
  class Cache
10
- attr_reader :reference, :cache_file, :default_config, :id
10
+ attr_reader :reference, :plugin_cache_file, :default_config, :id
11
11
 
12
- def initialize(reference, cache_file, default_config)
12
+ def initialize(reference, plugin_cache_file, default_config)
13
13
  @reference = reference
14
- @cache_file = cache_file
14
+ @plugin_cache_file = plugin_cache_file
15
15
  @default_config = default_config
16
16
  end
17
17
 
@@ -32,21 +32,21 @@ module Bolt
32
32
  unmodified = false if expired
33
33
  expired
34
34
  end
35
- File.write(cache_file, cache.to_json) unless cache.empty? || unmodified
35
+ File.write(plugin_cache_file, cache.to_json) unless cache.empty? || unmodified
36
36
 
37
37
  cache.dig(id, 'result')
38
38
  end
39
39
 
40
40
  private def cache
41
- @cache ||= Bolt::Util.read_optional_json_file(@cache_file, 'cache')
41
+ @cache ||= Bolt::Util.read_optional_json_file(@plugin_cache_file, 'cache')
42
42
  end
43
43
 
44
44
  def write_cache(result)
45
45
  cache.merge!({ id => { 'result' => result,
46
46
  'mtime' => Time.now,
47
47
  'ttl' => ttl } })
48
- FileUtils.touch(cache_file)
49
- File.write(cache_file, cache.to_json)
48
+ FileUtils.touch(plugin_cache_file)
49
+ File.write(plugin_cache_file, cache.to_json)
50
50
  end
51
51
 
52
52
  def validate
@@ -30,10 +30,6 @@ module Bolt
30
30
  @module = mod
31
31
  @config = config
32
32
  @context = context
33
-
34
- if @module.name == 'pkcs7'
35
- @config = handle_deprecated_pkcs7_keys(@config)
36
- end
37
33
  end
38
34
 
39
35
  # This method interacts with the module on disk so it's separate from initialize
@@ -160,10 +156,6 @@ module Bolt
160
156
  # out now.
161
157
  meta, params = opts.partition { |key, _val| key.start_with?('_') }.map(&:to_h)
162
158
 
163
- if task.module_name == 'pkcs7'
164
- params = handle_deprecated_pkcs7_keys(params)
165
- end
166
-
167
159
  # Reject parameters from config that are not accepted by the task and
168
160
  # merge in parameter defaults
169
161
  params = if task.parameters
@@ -181,21 +173,6 @@ module Bolt
181
173
  [params, meta]
182
174
  end
183
175
 
184
- # Raises a deprecation warning if the pkcs7 plugin is using deprecated keys and
185
- # modifies the keys so they are the correct format
186
- def handle_deprecated_pkcs7_keys(params)
187
- if params.key?('private-key') || params.key?('public-key')
188
- message = "pkcs7 keys 'private-key' and 'public-key' have been deprecated and will be "\
189
- "removed in a future version of Bolt; use 'private_key' and 'public_key' instead."
190
- Bolt::Logger.deprecation_warning('PKCS7 keys using hyphens, not underscores', message)
191
- end
192
-
193
- params['private_key'] = params.delete('private-key') if params.key?('private-key')
194
- params['public_key'] = params.delete('public-key') if params.key?('public-key')
195
-
196
- params
197
- end
198
-
199
176
  def extract_task_parameter_schema
200
177
  # Get the intersection of expected types (using Set)
201
178
  type_set = @hook_map.each_with_object({}) do |(_hook, task), acc|
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bolt
4
+ class Plugin
5
+ class PuppetConnectData
6
+ INPUT_DATA_VAR = 'PUPPET_CONNECT_INPUT_DATA'
7
+
8
+ def initialize(context:, **_opts)
9
+ if ENV.key?(INPUT_DATA_VAR)
10
+ # The user provided input data that they will copy-paste into the Puppet Connect UI
11
+ # for inventory syncing. This environment variable will likely be set when invoking a
12
+ # general "test Puppet Connect input data" command. That command tests that parsing
13
+ # the inventory with the given input data results in connectable targets. Part of
14
+ # that requires validating that the input data contains all of the referenced keys,
15
+ # which is what this plugin will do in validate_resolve_reference.
16
+ @input_data_path = ENV[INPUT_DATA_VAR]
17
+ data_path = @input_data_path
18
+ else
19
+ # The user is using this plugin during a regular Bolt invocation, so fetch the (minimal)
20
+ # required data from the default location. This data should typically be non-autoloadable
21
+ # secrets like WinRM passwords.
22
+ #
23
+ # Note that any unspecified keys will be resolved to nil.
24
+ data_path = File.join(context.boltdir, 'puppet_connect_data.yaml')
25
+ end
26
+
27
+ @data = Bolt::Util.read_optional_yaml_hash(
28
+ data_path,
29
+ File.basename(data_path)
30
+ )
31
+
32
+ if @input_data_path
33
+ # Validate that the data does not contain any plugin-reference
34
+ # values
35
+ @data.each do |key, toplevel_value|
36
+ # Use walk_vals to check for nested plugin references
37
+ Bolt::Util.walk_vals(toplevel_value) do |current_value|
38
+ if current_value.is_a?(Hash) && current_value.key?('_plugin')
39
+ raise invalid_input_data_err("the #{key} key's value contains a plugin reference")
40
+ end
41
+ current_value
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ def name
48
+ 'puppet_connect_data'
49
+ end
50
+
51
+ def hooks
52
+ %i[resolve_reference validate_resolve_reference]
53
+ end
54
+
55
+ def resolve_reference(opts)
56
+ key = opts['key']
57
+ @data[key]
58
+ end
59
+
60
+ def validate_resolve_reference(opts)
61
+ unless opts['key']
62
+ raise Bolt::ValidationError,
63
+ "puppet_connect_data plugin requires that 'key' be specified"
64
+ end
65
+ if @input_data_path && !@data.key?(opts['key'])
66
+ # Input data for Puppet Connect was provided and opts['key'] does not have a
67
+ # value specified. Raise an error for this case.
68
+ raise invalid_input_data_err("a value for the #{opts['key']} key is not specified")
69
+ end
70
+ end
71
+
72
+ def invalid_input_data_err(msg)
73
+ Bolt::ValidationError.new("invalid input data #{@input_data_path}: #{msg}")
74
+ end
75
+ end
76
+ end
77
+ end
@@ -31,7 +31,7 @@ module Bolt
31
31
  end
32
32
 
33
33
  def warn_missing_fact(certname, fact)
34
- @logger.warn("Could not find fact #{fact} for node #{certname}")
34
+ Bolt::Logger.warn("puppetdb_missing_fact", "Could not find fact #{fact} for node #{certname}")
35
35
  end
36
36
 
37
37
  def fact_path(raw_fact)
data/lib/bolt/project.rb CHANGED
@@ -11,47 +11,40 @@ module Bolt
11
11
  BOLTDIR_NAME = 'Boltdir'
12
12
  CONFIG_NAME = 'bolt-project.yaml'
13
13
 
14
- attr_reader :path, :data, :config_file, :inventory_file, :hiera_config,
15
- :puppetfile, :rerunfile, :type, :resource_types, :logs, :project_file,
16
- :deprecations, :downloads, :plans_path, :modulepath, :managed_moduledir,
17
- :backup_dir, :cache_file
14
+ attr_reader :path, :data, :inventory_file, :hiera_config,
15
+ :puppetfile, :rerunfile, :type, :resource_types, :project_file,
16
+ :downloads, :plans_path, :modulepath, :managed_moduledir,
17
+ :backup_dir, :plugin_cache_file, :plan_cache_file
18
18
 
19
- def self.default_project(logs = [])
20
- create_project(File.expand_path(File.join('~', '.puppetlabs', 'bolt')), 'user', logs)
19
+ def self.default_project
20
+ create_project(File.expand_path(File.join('~', '.puppetlabs', 'bolt')), 'user')
21
21
  # If homedir isn't defined use the system config path
22
22
  rescue ArgumentError
23
- create_project(Bolt::Config.system_path, 'system', logs)
23
+ create_project(Bolt::Config.system_path, 'system')
24
24
  end
25
25
 
26
26
  # Search recursively up the directory hierarchy for the Project. Look for a
27
- # directory called Boltdir or a file called bolt.yaml (for a control repo
28
- # type Project). Otherwise, repeat the check on each directory up the
27
+ # directory called Boltdir or a file called bolt-project.yaml (for a control
28
+ # repo type Project). Otherwise, repeat the check on each directory up the
29
29
  # hierarchy, falling back to the default if we reach the root.
30
- def self.find_boltdir(dir, logs = [], deprecations = [])
30
+ def self.find_boltdir(dir)
31
31
  dir = Pathname.new(dir)
32
32
 
33
33
  if (dir + BOLTDIR_NAME).directory?
34
- create_project(dir + BOLTDIR_NAME, 'embedded', logs)
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)
34
+ create_project(dir + BOLTDIR_NAME, 'embedded')
43
35
  elsif (dir + CONFIG_NAME).file?
44
- create_project(dir, 'local', logs)
36
+ create_project(dir, 'local')
45
37
  elsif dir.root?
46
- default_project(logs)
38
+ default_project
47
39
  else
48
- logs << { debug: "Did not detect Boltdir, bolt.yaml, or bolt-project.yaml at '#{dir}'. "\
49
- "This directory won't be loaded as a project." }
50
- find_boltdir(dir.parent, logs, deprecations)
40
+ Bolt::Logger.debug(
41
+ "Did not detect Boltdir or bolt-project.yaml at '#{dir}'. This directory won't be loaded as a project."
42
+ )
43
+ find_boltdir(dir.parent)
51
44
  end
52
45
  end
53
46
 
54
- def self.create_project(path, type = 'option', logs = [], deprecations = [])
47
+ def self.create_project(path, type = 'option')
55
48
  fullpath = Pathname.new(path).expand_path
56
49
 
57
50
  if type == 'user'
@@ -59,8 +52,11 @@ module Bolt
59
52
  # This is already expanded if the type is user
60
53
  FileUtils.mkdir_p(path)
61
54
  rescue StandardError
62
- logs << { warn: "Could not create default project at #{path}. Continuing without a writeable project. "\
63
- "Log and rerun files will not be written." }
55
+ Bolt::Logger.warn(
56
+ "non_writeable_project",
57
+ "Could not create default project at #{path}. Continuing without a writeable project. "\
58
+ "Log and rerun files will not be written."
59
+ )
64
60
  end
65
61
  end
66
62
 
@@ -79,21 +75,18 @@ module Bolt
79
75
  project_file = File.join(fullpath, CONFIG_NAME)
80
76
  data = Bolt::Util.read_optional_yaml_hash(File.expand_path(project_file), 'project')
81
77
  default = type =~ /user|system/ ? 'default ' : ''
82
- exist = File.exist?(File.expand_path(project_file))
83
78
 
84
- logs << { info: "Loaded #{default}project from '#{fullpath}'" } if exist
79
+ if File.exist?(File.expand_path(project_file))
80
+ Bolt::Logger.info("Loaded #{default}project from '#{fullpath}'")
81
+ end
85
82
 
86
83
  Bolt::Validator.new.tap do |validator|
87
84
  validator.validate(data, schema, project_file)
88
-
89
- validator.warnings.each { |warning| logs << { warn: warning } }
90
-
91
- validator.deprecations.each do |dep|
92
- deprecations << { type: "#{CONFIG_NAME} #{dep[:option]}", msg: dep[:message] }
93
- end
85
+ validator.warnings.each { |warning| Bolt::Logger.warn(warning[:id], warning[:msg]) }
86
+ validator.deprecations.each { |dep| Bolt::Logger.deprecate(dep[:id], dep[:msg]) }
94
87
  end
95
88
 
96
- new(data, path, type, logs, deprecations)
89
+ new(data, path, type)
97
90
  end
98
91
 
99
92
  # Builds the schema for bolt-project.yaml used by the validator.
@@ -101,63 +94,37 @@ module Bolt
101
94
  def self.schema
102
95
  {
103
96
  type: Hash,
104
- properties: Bolt::Config::BOLT_PROJECT_OPTIONS.map { |opt| [opt, _ref: opt] }.to_h,
97
+ properties: Bolt::Config::PROJECT_OPTIONS.map { |opt| [opt, _ref: opt] }.to_h,
105
98
  definitions: Bolt::Config::OPTIONS
106
99
  }
107
100
  end
108
101
 
109
- def initialize(raw_data, path, type = 'option', logs = [], deprecations = [])
110
- @path = Pathname.new(path).expand_path
111
- @project_file = @path + CONFIG_NAME
112
- @logs = logs
113
- @deprecations = deprecations
114
-
115
- if (@path + 'bolt.yaml').file? && project_file?
116
- msg = "Project-level configuration in bolt.yaml is deprecated if using bolt-project.yaml. "\
117
- "Transport config should be set in inventory.yaml, all other config should be set in "\
118
- "bolt-project.yaml."
119
- @deprecations << { type: 'Using bolt.yaml for project configuration', msg: msg }
120
- end
121
-
102
+ def initialize(data, path, type = 'option')
103
+ @type = type
104
+ @path = Pathname.new(path).expand_path
105
+ @project_file = @path + CONFIG_NAME
122
106
  @inventory_file = @path + 'inventory.yaml'
123
107
  @hiera_config = @path + 'hiera.yaml'
124
108
  @puppetfile = @path + 'Puppetfile'
125
109
  @rerunfile = @path + '.rerun.json'
126
110
  @resource_types = @path + '.resource_types'
127
- @type = type
128
111
  @downloads = @path + 'downloads'
129
112
  @plans_path = @path + 'plans'
130
113
  @managed_moduledir = @path + '.modules'
131
114
  @backup_dir = @path + '.bolt-bak'
132
- @cache_file = @path + '.plugin_cache.json'
133
-
134
- tc = Bolt::Config::INVENTORY_OPTIONS.keys & raw_data.keys
135
- if tc.any?
136
- msg = "Transport configuration isn't supported in bolt-project.yaml. Ignoring keys #{tc}"
137
- @logs << { warn: msg }
115
+ @plugin_cache_file = @path + '.plugin_cache.json'
116
+ @plan_cache_file = @path + '.plan_cache.json'
117
+ @modulepath = [(@path + 'modules').to_s]
118
+
119
+ if (tc = Bolt::Config::INVENTORY_OPTIONS.keys & data.keys).any?
120
+ Bolt::Logger.warn(
121
+ "project_transport_config",
122
+ "Transport configuration isn't supported in bolt-project.yaml. Ignoring keys #{tc}."
123
+ )
138
124
  end
139
125
 
140
- @data = raw_data.reject { |k, _| Bolt::Config::INVENTORY_OPTIONS.include?(k) }
141
-
142
- # If the 'modules' key is present in the project configuration file,
143
- # use the new, shorter modulepath.
144
- @modulepath = if @data.key?('modules')
145
- [(@path + 'modules').to_s]
146
- else
147
- [(@path + 'modules').to_s, (@path + 'site-modules').to_s, (@path + 'site').to_s]
148
- end
149
-
150
- # Once bolt.yaml deprecation is removed, this attribute should be removed
151
- # and replaced with .project_file in lib/bolt/config.rb
152
- @config_file = if (Bolt::Config::BOLT_OPTIONS & @data.keys).any?
153
- if (@path + 'bolt.yaml').file?
154
- msg = "bolt-project.yaml contains valid config keys, bolt.yaml will be ignored"
155
- @logs << { warn: msg }
156
- end
157
- @project_file
158
- else
159
- @path + 'bolt.yaml'
160
- end
126
+ @data = data.slice(*Bolt::Config::PROJECT_OPTIONS)
127
+
161
128
  validate if project_file?
162
129
  end
163
130
 
@@ -206,8 +173,13 @@ module Bolt
206
173
  @data['module-install']
207
174
  end
208
175
 
176
+ def disable_warnings
177
+ @data['disable-warnings'] || []
178
+ end
179
+
209
180
  def modules
210
- @modules ||= @data['modules']&.map do |mod|
181
+ mod_data = @data['modules'] || []
182
+ @modules ||= mod_data.map do |mod|
211
183
  if mod.is_a?(String)
212
184
  { 'name' => mod }
213
185
  else
@@ -232,14 +204,15 @@ module Bolt
232
204
  File.directory?(@path + 'tasks') ||
233
205
  File.directory?(@path + 'files'))
234
206
  message = "No project name is specified in bolt-project.yaml. Project-level content will not be available."
235
- @logs << { warn: message }
207
+
208
+ Bolt::Logger.warn("missing_project_name", message)
236
209
  end
237
210
  end
238
211
 
239
212
  def check_deprecated_file
240
213
  if (@path + 'project.yaml').file?
241
214
  msg = "Project configuration file 'project.yaml' is deprecated; use 'bolt-project.yaml' instead."
242
- Bolt::Logger.deprecation_warning('Using project.yaml instead of bolt-project.yaml', msg)
215
+ Bolt::Logger.warn("project_yaml", msg)
243
216
  end
244
217
  end
245
218
  end