bolt 2.14.0 → 2.19.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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +1 -1
  3. data/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +1 -0
  4. data/bolt-modules/boltlib/lib/puppet/functions/add_to_group.rb +1 -0
  5. data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +20 -9
  6. data/bolt-modules/boltlib/lib/puppet/functions/catch_errors.rb +1 -0
  7. data/bolt-modules/boltlib/lib/puppet/functions/facts.rb +1 -0
  8. data/bolt-modules/boltlib/lib/puppet/functions/fail_plan.rb +1 -0
  9. data/bolt-modules/boltlib/lib/puppet/functions/get_resources.rb +1 -0
  10. data/bolt-modules/boltlib/lib/puppet/functions/get_target.rb +1 -0
  11. data/bolt-modules/boltlib/lib/puppet/functions/get_targets.rb +1 -0
  12. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_fact.rb +1 -0
  13. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +1 -0
  14. data/bolt-modules/boltlib/lib/puppet/functions/remove_from_group.rb +1 -0
  15. data/bolt-modules/boltlib/lib/puppet/functions/resolve_references.rb +1 -0
  16. data/bolt-modules/boltlib/lib/puppet/functions/resource.rb +1 -0
  17. data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +3 -0
  18. data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +2 -1
  19. data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +7 -4
  20. data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +2 -1
  21. data/bolt-modules/boltlib/lib/puppet/functions/set_config.rb +1 -0
  22. data/bolt-modules/boltlib/lib/puppet/functions/set_feature.rb +1 -0
  23. data/bolt-modules/boltlib/lib/puppet/functions/set_resources.rb +1 -0
  24. data/bolt-modules/boltlib/lib/puppet/functions/set_var.rb +1 -0
  25. data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +1 -0
  26. data/bolt-modules/boltlib/lib/puppet/functions/vars.rb +1 -0
  27. data/bolt-modules/boltlib/lib/puppet/functions/wait_until_available.rb +1 -0
  28. data/bolt-modules/boltlib/lib/puppet/functions/without_default_logging.rb +1 -0
  29. data/bolt-modules/boltlib/lib/puppet/functions/write_file.rb +1 -0
  30. data/bolt-modules/ctrl/lib/puppet/functions/ctrl/do_until.rb +2 -0
  31. data/bolt-modules/ctrl/lib/puppet/functions/ctrl/sleep.rb +2 -0
  32. data/bolt-modules/file/lib/puppet/functions/file/exists.rb +2 -1
  33. data/bolt-modules/file/lib/puppet/functions/file/join.rb +2 -0
  34. data/bolt-modules/file/lib/puppet/functions/file/read.rb +3 -1
  35. data/bolt-modules/file/lib/puppet/functions/file/readable.rb +3 -1
  36. data/bolt-modules/file/lib/puppet/functions/file/write.rb +2 -0
  37. data/bolt-modules/out/lib/puppet/functions/out/message.rb +2 -0
  38. data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +1 -0
  39. data/bolt-modules/system/lib/puppet/functions/system/env.rb +2 -0
  40. data/lib/bolt/applicator.rb +34 -20
  41. data/lib/bolt/apply_result.rb +1 -1
  42. data/lib/bolt/bolt_option_parser.rb +30 -18
  43. data/lib/bolt/cli.rb +78 -56
  44. data/lib/bolt/config.rb +158 -128
  45. data/lib/bolt/config/options.rb +474 -0
  46. data/lib/bolt/config/transport/base.rb +16 -16
  47. data/lib/bolt/config/transport/docker.rb +9 -23
  48. data/lib/bolt/config/transport/local.rb +6 -44
  49. data/lib/bolt/config/transport/options.rb +460 -0
  50. data/lib/bolt/config/transport/orch.rb +9 -18
  51. data/lib/bolt/config/transport/remote.rb +3 -6
  52. data/lib/bolt/config/transport/ssh.rb +74 -154
  53. data/lib/bolt/config/transport/winrm.rb +18 -47
  54. data/lib/bolt/inventory/group.rb +1 -1
  55. data/lib/bolt/inventory/inventory.rb +0 -14
  56. data/lib/bolt/inventory/target.rb +18 -5
  57. data/lib/bolt/logger.rb +24 -1
  58. data/lib/bolt/outputter.rb +3 -0
  59. data/lib/bolt/outputter/rainbow.rb +90 -0
  60. data/lib/bolt/pal.rb +23 -9
  61. data/lib/bolt/pal/yaml_plan/evaluator.rb +1 -1
  62. data/lib/bolt/plugin/module.rb +2 -4
  63. data/lib/bolt/project.rb +41 -52
  64. data/lib/bolt/shell/bash.rb +30 -42
  65. data/lib/bolt/shell/powershell.rb +13 -8
  66. data/lib/bolt/shell/powershell/snippets.rb +15 -6
  67. data/lib/bolt/transport/docker.rb +9 -5
  68. data/lib/bolt/transport/orch.rb +8 -0
  69. data/lib/bolt/transport/ssh.rb +7 -1
  70. data/lib/bolt/transport/ssh/exec_connection.rb +1 -1
  71. data/lib/bolt/version.rb +1 -1
  72. metadata +18 -15
@@ -15,7 +15,9 @@ Puppet::Functions.create_function(:'file::write') do
15
15
  end
16
16
 
17
17
  def write(filename, content)
18
+ # Send Analytics Report
18
19
  Puppet.lookup(:bolt_executor) {}&.report_function_call(self.class.name)
20
+
19
21
  File.write(filename, content)
20
22
  nil
21
23
  end
@@ -23,7 +23,9 @@ Puppet::Functions.create_function(:'out::message') do
23
23
  end
24
24
 
25
25
  executor = Puppet.lookup(:bolt_executor)
26
+ # Send Analytics Report
26
27
  executor.report_function_call(self.class.name)
28
+
27
29
  executor.publish_event(type: :message, message: message)
28
30
 
29
31
  nil
@@ -30,6 +30,7 @@ Puppet::Functions.create_function(:prompt) do
30
30
  options = options.transform_keys(&:to_sym)
31
31
 
32
32
  executor = Puppet.lookup(:bolt_executor)
33
+ # Send analytics report
33
34
  executor.report_function_call(self.class.name)
34
35
 
35
36
  response = executor.prompt(prompt, options)
@@ -12,7 +12,9 @@ Puppet::Functions.create_function(:'system::env') do
12
12
  end
13
13
 
14
14
  def env(name)
15
+ # Send analytics report
15
16
  Puppet.lookup(:bolt_executor) {}&.report_function_call(self.class.name)
17
+
16
18
  ENV[name]
17
19
  end
18
20
  end
@@ -18,7 +18,6 @@ module Bolt
18
18
  pdb_client, hiera_config, max_compiles, apply_settings)
19
19
  # lazy-load expensive gem code
20
20
  require 'concurrent'
21
-
22
21
  @inventory = inventory
23
22
  @executor = executor
24
23
  @modulepath = modulepath || []
@@ -30,17 +29,6 @@ module Bolt
30
29
 
31
30
  @pool = Concurrent::ThreadPoolExecutor.new(max_threads: max_compiles)
32
31
  @logger = Logging.logger[self]
33
- @plugin_tarball = Concurrent::Delay.new do
34
- build_plugin_tarball do |mod|
35
- search_dirs = []
36
- search_dirs << mod.plugins if mod.plugins?
37
- search_dirs << mod.pluginfacts if mod.pluginfacts?
38
- search_dirs << mod.files if mod.files?
39
- type_files = "#{mod.path}/types"
40
- search_dirs << type_files if File.exist?(type_files)
41
- search_dirs
42
- end
43
- end
44
32
  end
45
33
 
46
34
  private def libexec
@@ -106,6 +94,16 @@ module Bolt
106
94
  out, err, stat = Open3.capture3('ruby', bolt_catalog_exe, 'compile', stdin_data: catalog_input.to_json)
107
95
  ENV['PATH'] = old_path
108
96
 
97
+ # If bolt_catalog does not return valid JSON, we should print stderr to
98
+ # see what happened
99
+ print_logs = stat.success?
100
+ result = begin
101
+ JSON.parse(out)
102
+ rescue JSON::ParserError
103
+ print_logs = true
104
+ { 'message' => "Something's gone terribly wrong! STDERR is logged." }
105
+ end
106
+
109
107
  # Any messages logged by Puppet will be on stderr as JSON hashes, so we
110
108
  # parse those and store them here. Any message on stderr that is not
111
109
  # properly JSON formatted is assumed to be an error message. If
@@ -119,17 +117,15 @@ module Bolt
119
117
  { 'level' => 'err', 'message' => line }
120
118
  end
121
119
 
122
- result = JSON.parse(out)
123
- if stat.success?
120
+ if print_logs
124
121
  logs.each do |log|
125
122
  bolt_level = Bolt::Util::PuppetLogLevel::MAPPING[log['level'].to_sym]
126
123
  message = log['message'].chomp
127
124
  @logger.send(bolt_level, "#{target.name}: #{message}")
128
125
  end
129
- result
130
- else
131
- raise ApplyError.new(target.name, result['message'])
132
126
  end
127
+ raise ApplyError.new(target.name, result['message']) unless stat.success?
128
+ result
133
129
  end
134
130
 
135
131
  def validate_hiera_config(hiera_config)
@@ -180,7 +176,6 @@ module Bolt
180
176
 
181
177
  def apply_ast(raw_ast, targets, options, plan_vars = {})
182
178
  ast = Puppet::Pops::Serialization::ToDataConverter.convert(raw_ast, rich_data: true, symbol_to_string: true)
183
-
184
179
  # Serialize as pcore for *Result* objects
185
180
  plan_vars = Puppet::Pops::Serialization::ToDataConverter.convert(plan_vars,
186
181
  rich_data: true,
@@ -188,19 +183,37 @@ module Bolt
188
183
  type_by_reference: true,
189
184
  local_reference: true)
190
185
 
186
+ bolt_project = @project if @project&.name
191
187
  scope = {
192
188
  code_ast: ast,
193
189
  modulepath: @modulepath,
194
- project: @project.to_h,
190
+ project: bolt_project.to_h,
195
191
  pdb_config: @pdb_client.config.to_hash,
196
192
  hiera_config: @hiera_config,
197
193
  plan_vars: plan_vars,
198
194
  # This data isn't available on the target config hash
199
195
  config: @inventory.transport_data_get
200
196
  }
201
-
202
197
  description = options[:description] || 'apply catalog'
203
198
 
199
+ required_modules = options[:required_modules].nil? ? nil : Array(options[:required_modules])
200
+ if required_modules&.any?
201
+ @logger.debug("Syncing only required modules: #{required_modules.join(',')}.")
202
+ end
203
+
204
+ @plugin_tarball = Concurrent::Delay.new do
205
+ build_plugin_tarball do |mod|
206
+ next unless required_modules.nil? || required_modules.include?(mod.name)
207
+ search_dirs = []
208
+ search_dirs << mod.plugins if mod.plugins?
209
+ search_dirs << mod.pluginfacts if mod.pluginfacts?
210
+ search_dirs << mod.files if mod.files?
211
+ type_files = "#{mod.path}/types"
212
+ search_dirs << type_files if File.exist?(type_files)
213
+ search_dirs
214
+ end
215
+ end
216
+
204
217
  r = @executor.log_action(description, targets) do
205
218
  futures = targets.map do |target|
206
219
  Concurrent::Future.execute(executor: @pool) do
@@ -227,6 +240,7 @@ module Bolt
227
240
  result
228
241
  end
229
242
  else
243
+
230
244
  arguments = {
231
245
  'catalog' => Puppet::Pops::Types::PSensitiveType::Sensitive.new(catalog),
232
246
  'plugins' => Puppet::Pops::Types::PSensitiveType::Sensitive.new(plugins),
@@ -20,7 +20,7 @@ module Bolt
20
20
  error_hash['msg'] =~ /The term 'ruby.exe' is not recognized as the name of a cmdlet/)
21
21
  # Windows does not have Ruby present
22
22
  {
23
- 'msg' => "Puppet is not installed on the target in $env:ProgramFiles, please install it to enable 'apply'",
23
+ 'msg' => "Puppet was not found on the target or in $env:ProgramFiles, please install it to enable 'apply'",
24
24
  'kind' => 'bolt/apply-error'
25
25
  }
26
26
  elsif exit_code == 1 && error_hash['msg'] =~ /cannot load such file -- puppet \(LoadError\)/
@@ -10,10 +10,10 @@ module Bolt
10
10
  authentication: %w[user password password-prompt private-key host-key-check ssl ssl-verify],
11
11
  escalation: %w[run-as sudo-password sudo-password-prompt sudo-executable],
12
12
  run_context: %w[concurrency inventoryfile save-rerun cleanup],
13
- global_config_setters: %w[modulepath boltdir configfile],
14
- transports: %w[transport connect-timeout tty ssh-command copy-command],
13
+ global_config_setters: %w[modulepath project configfile],
14
+ transports: %w[transport connect-timeout tty native-ssh ssh-command copy-command],
15
15
  display: %w[format color verbose trace],
16
- global: %w[help version debug] }.freeze
16
+ global: %w[help version debug log-level] }.freeze
17
17
 
18
18
  ACTION_OPTS = OPTIONS.values.flatten.freeze
19
19
 
@@ -422,7 +422,7 @@ module Bolt
422
422
 
423
423
  ACTIONS
424
424
  generate-types Generate type references to register in plans
425
- install Install modules from a Puppetfile into a Boltdir
425
+ install Install modules from a Puppetfile into a project
426
426
  show-modules List modules available to the Bolt project
427
427
  HELP
428
428
 
@@ -445,7 +445,7 @@ module Bolt
445
445
  bolt puppetfile install [options]
446
446
 
447
447
  DESCRIPTION
448
- Install modules from a Puppetfile into a Boltdir
448
+ Install modules from a Puppetfile into a project
449
449
  HELP
450
450
 
451
451
  PUPPETFILE_SHOWMODULES_HELP = <<~HELP
@@ -594,13 +594,13 @@ module Bolt
594
594
  bolt task show canary
595
595
  HELP
596
596
 
597
- attr_reader :warnings
597
+ attr_reader :deprecations
598
598
 
599
599
  def initialize(options)
600
600
  super()
601
601
 
602
602
  @options = options
603
- @warnings = []
603
+ @deprecations = []
604
604
 
605
605
  separator "\nINVENTORY OPTIONS"
606
606
  define('-t', '--targets TARGETS',
@@ -709,29 +709,29 @@ module Bolt
709
709
  File.expand_path(moduledir)
710
710
  end
711
711
  end
712
- define('--boltdir FILEPATH',
713
- 'Specify what Boltdir to load config from (default: autodiscovered from current working dir)') do |path|
712
+ define('--project PATH', '--boltdir PATH',
713
+ 'Specify what project to load config from (default: autodiscovered from current working dir)') do |path|
714
714
  @options[:boltdir] = path
715
715
  end
716
- define('--configfile FILEPATH',
716
+ define('--configfile PATH',
717
717
  'Specify where to load config from (default: ~/.puppetlabs/bolt/bolt.yaml).',
718
- 'Directory containing bolt.yaml will be used as the Boltdir.') do |path|
718
+ 'Directory containing bolt.yaml will be used as the project directory.') do |path|
719
719
  @options[:configfile] = path
720
720
  end
721
- define('--hiera-config FILEPATH',
721
+ define('--hiera-config PATH',
722
722
  'Specify where to load Hiera config from (default: ~/.puppetlabs/bolt/hiera.yaml)') do |path|
723
723
  @options[:'hiera-config'] = File.expand_path(path)
724
724
  end
725
- define('-i', '--inventoryfile FILEPATH',
725
+ define('-i', '--inventoryfile PATH',
726
726
  'Specify where to load inventory from (default: ~/.puppetlabs/bolt/inventory.yaml)') do |path|
727
727
  if ENV.include?(Bolt::Inventory::ENVIRONMENT_VAR)
728
728
  raise Bolt::CLIError, "Cannot pass inventory file when #{Bolt::Inventory::ENVIRONMENT_VAR} is set"
729
729
  end
730
730
  @options[:inventoryfile] = Pathname.new(File.expand_path(path))
731
731
  end
732
- define('--puppetfile FILEPATH',
732
+ define('--puppetfile PATH',
733
733
  'Specify a Puppetfile to use when installing modules. (default: ~/.puppetlabs/bolt/Puppetfile)',
734
- 'Modules are installed in the current Boltdir.') do |path|
734
+ 'Modules are installed in the current project.') do |path|
735
735
  @options[:puppetfile_path] = Pathname.new(File.expand_path(path))
736
736
  end
737
737
  define('--[no-]save-rerun', 'Whether to update the rerun file after this command.') do |save|
@@ -743,11 +743,15 @@ module Bolt
743
743
  "Specify a default transport: #{TRANSPORTS.keys.join(', ')}") do |t|
744
744
  @options[:transport] = t
745
745
  end
746
- define('--ssh-command EXEC', "Executable to use instead of the net-ssh ruby library. ",
746
+ define('--[no-]native-ssh', 'Whether to shell out to native SSH or use the net-ssh Ruby library.',
747
+ 'This option is experimental') do |bool|
748
+ @options[:'native-ssh'] = bool
749
+ end
750
+ define('--ssh-command EXEC', "Executable to use instead of the net-ssh Ruby library. ",
747
751
  "This option is experimental.") do |exec|
748
752
  @options[:'ssh-command'] = exec
749
753
  end
750
- define('--copy-command EXEC', "Command to copy files to remote hosts if using external SSH. ",
754
+ define('--copy-command EXEC', "Command to copy files to remote hosts if using native SSH. ",
751
755
  "This option is experimental.") do |exec|
752
756
  @options[:'copy-command'] = exec
753
757
  end
@@ -803,8 +807,16 @@ module Bolt
803
807
  end
804
808
  define('--debug', 'Display debug logging') do |_|
805
809
  @options[:debug] = true
810
+ # We don't actually set '--log-level debug' here, but once the options are evaluated by
811
+ # the config class the end result is the same.
812
+ msg = "Command line option '--debug' is deprecated, set '--log-level debug' instead."
813
+ @deprecations << { type: 'Using --debug instead of --log-level debug', msg: msg }
814
+ end
815
+ define('--log-level LEVEL',
816
+ "Set the log level for the console. Available options are",
817
+ "debug, info, notice, warn, error, fatal, any.") do |level|
818
+ @options[:log] = { 'console' => { 'level' => level } }
806
819
  end
807
-
808
820
  define('--plugin PLUGIN', 'Select the plugin to use') do |plug|
809
821
  @options[:plugin] = plug
810
822
  end
@@ -46,7 +46,6 @@ module Bolt
46
46
  Bolt::Logger.initialize_logging
47
47
  @logger = Logging.logger[self]
48
48
  @argv = argv
49
- @config = Bolt::Config.default
50
49
  @options = {}
51
50
  end
52
51
 
@@ -77,63 +76,83 @@ module Bolt
77
76
  private :help?
78
77
 
79
78
  def parse
80
- parser = BoltOptionParser.new(options)
81
- # This part aims to handle both `bolt <mode> --help` and `bolt help <mode>`.
82
- remaining = handle_parser_errors { parser.permute(@argv) } unless @argv.empty?
83
- if @argv.empty? || help?(remaining)
84
- # Update the parser for the subcommand (or lack thereof)
85
- parser.update
86
- puts parser.help
87
- raise Bolt::CLIExit
88
- end
89
-
90
- options[:object] = remaining.shift
91
-
92
- # Only parse task_options for task or plan
93
- if %w[task plan].include?(options[:subcommand])
94
- task_options, remaining = remaining.partition { |s| s =~ /.+=/ }
95
- if options[:task_options]
96
- unless task_options.empty?
97
- raise Bolt::CLIError,
98
- "Parameters must be specified through either the --params " \
99
- "option or param=value pairs, not both"
79
+ begin
80
+ parser = BoltOptionParser.new(options)
81
+ # This part aims to handle both `bolt <mode> --help` and `bolt help <mode>`.
82
+ remaining = handle_parser_errors { parser.permute(@argv) } unless @argv.empty?
83
+ if @argv.empty? || help?(remaining)
84
+ # Update the parser for the subcommand (or lack thereof)
85
+ parser.update
86
+ puts parser.help
87
+ raise Bolt::CLIExit
88
+ end
89
+
90
+ options[:object] = remaining.shift
91
+
92
+ # Only parse task_options for task or plan
93
+ if %w[task plan].include?(options[:subcommand])
94
+ task_options, remaining = remaining.partition { |s| s =~ /.+=/ }
95
+ if options[:task_options]
96
+ unless task_options.empty?
97
+ raise Bolt::CLIError,
98
+ "Parameters must be specified through either the --params " \
99
+ "option or param=value pairs, not both"
100
+ end
101
+ options[:params_parsed] = true
102
+ elsif task_options.any?
103
+ options[:params_parsed] = false
104
+ options[:task_options] = Hash[task_options.map { |a| a.split('=', 2) }]
105
+ else
106
+ options[:params_parsed] = true
107
+ options[:task_options] = {}
100
108
  end
101
- options[:params_parsed] = true
102
- elsif task_options.any?
103
- options[:params_parsed] = false
104
- options[:task_options] = Hash[task_options.map { |a| a.split('=', 2) }]
109
+ end
110
+ options[:leftovers] = remaining
111
+
112
+ validate(options)
113
+
114
+ @config = if ENV['BOLT_PROJECT']
115
+ project = Bolt::Project.create_project(ENV['BOLT_PROJECT'], 'environment')
116
+ Bolt::Config.from_project(project, options)
117
+ elsif options[:configfile]
118
+ Bolt::Config.from_file(options[:configfile], options)
119
+ else
120
+ project = if options[:boltdir]
121
+ dir = Pathname.new(options[:boltdir])
122
+ if (dir + Bolt::Project::BOLTDIR_NAME).directory?
123
+ Bolt::Project.create_project(dir + Bolt::Project::BOLTDIR_NAME)
124
+ else
125
+ Bolt::Project.create_project(dir)
126
+ end
127
+ else
128
+ Bolt::Project.find_boltdir(Dir.pwd)
129
+ end
130
+ Bolt::Config.from_project(project, options)
131
+ end
132
+
133
+ Bolt::Logger.configure(config.log, config.color)
134
+ Bolt::Logger.analytics = analytics
135
+ rescue Bolt::Error => e
136
+ if $stdout.isatty
137
+ # Print the error message in red, mimicking outputter.fatal_error
138
+ $stdout.puts("\033[31m#{e.message}\033[0m")
105
139
  else
106
- options[:params_parsed] = true
107
- options[:task_options] = {}
140
+ $stdout.puts(e.message)
108
141
  end
142
+ raise e
109
143
  end
110
- options[:leftovers] = remaining
111
-
112
- validate(options)
113
-
114
- @config = if options[:configfile]
115
- Bolt::Config.from_file(options[:configfile], options)
116
- else
117
- project = if options[:boltdir]
118
- Bolt::Project.create_project(options[:boltdir])
119
- else
120
- Bolt::Project.find_boltdir(Dir.pwd)
121
- end
122
- Bolt::Config.from_project(project, options)
123
- end
124
-
125
- Bolt::Logger.configure(config.log, config.color)
126
144
 
127
145
  # Logger must be configured before checking path case and project file, otherwise warnings will not display
128
- @config.check_path_case('modulepath', @config.modulepath)
129
- @config.project.check_deprecated_file
146
+ config.check_path_case('modulepath', config.modulepath)
147
+ config.project.check_deprecated_file
130
148
 
131
149
  # Log the file paths for loaded config files
132
150
  config_loaded
133
151
 
134
152
  # Display warnings created during parser and config initialization
135
- parser.warnings.each { |warning| @logger.warn(warning[:msg]) }
136
153
  config.warnings.each { |warning| @logger.warn(warning[:msg]) }
154
+ parser.deprecations.each { |dep| Bolt::Logger.deprecation_warning(dep[:type], dep[:msg]) }
155
+ config.deprecations.each { |dep| Bolt::Logger.deprecation_warning(dep[:type], dep[:msg]) }
137
156
 
138
157
  # After validation, initialize inventory and targets. Errors here are better to catch early.
139
158
  # After this step
@@ -219,7 +238,7 @@ module Bolt
219
238
  end
220
239
 
221
240
  if options[:boltdir] && options[:configfile]
222
- raise Bolt::CLIError, "Only one of '--boltdir' or '--configfile' may be specified"
241
+ raise Bolt::CLIError, "Only one of '--boltdir', '--project', or '--configfile' may be specified"
223
242
  end
224
243
 
225
244
  if options[:noop] &&
@@ -245,6 +264,10 @@ module Bolt
245
264
  !options[:object]
246
265
  raise Bolt::CLIError, "Must specify a value to #{options[:action]}"
247
266
  end
267
+
268
+ if options.key?(:debug) && options.key?(:log)
269
+ raise Bolt::CLIError, "Only one of '--debug' or '--log-level' may be specified"
270
+ end
248
271
  end
249
272
 
250
273
  def handle_parser_errors
@@ -272,12 +295,12 @@ module Bolt
272
295
  def warn_inventory_overrides_cli(opts)
273
296
  inventory_source = if ENV[Bolt::Inventory::ENVIRONMENT_VAR]
274
297
  Bolt::Inventory::ENVIRONMENT_VAR
275
- elsif @config.inventoryfile && Bolt::Util.file_stat(@config.inventoryfile)
276
- @config.inventoryfile
298
+ elsif config.inventoryfile && Bolt::Util.file_stat(config.inventoryfile)
299
+ config.inventoryfile
277
300
  else
278
301
  begin
279
- Bolt::Util.file_stat(@config.default_inventoryfile)
280
- @config.default_inventoryfile
302
+ Bolt::Util.file_stat(config.default_inventoryfile)
303
+ config.default_inventoryfile
281
304
  rescue Errno::ENOENT
282
305
  nil
283
306
  end
@@ -381,7 +404,7 @@ module Bolt
381
404
  if options[:action] == 'generate-types'
382
405
  code = generate_types
383
406
  elsif options[:action] == 'install'
384
- code = install_puppetfile(@config.puppetfile_config, @config.puppetfile, @config.modulepath)
407
+ code = install_puppetfile(config.puppetfile_config, config.puppetfile, config.modulepath)
385
408
  end
386
409
  when 'secret'
387
410
  code = Bolt::Secret.execute(plugins, outputter, options)
@@ -513,7 +536,7 @@ module Bolt
513
536
  plan_context[:description] = options[:description] if options[:description]
514
537
 
515
538
  executor = Bolt::Executor.new(config.concurrency, analytics, options[:noop], config.modified_concurrency)
516
- if options.fetch(:format, 'human') == 'human'
539
+ if %w[human rainbow].include?(options.fetch(:format, 'human'))
517
540
  executor.subscribe(outputter)
518
541
  else
519
542
  # Only subscribe to out::message events for JSON outputter
@@ -771,14 +794,13 @@ module Bolt
771
794
  end
772
795
 
773
796
  def pal
774
- project = config.project.project_file? ? config.project : nil
775
797
  @pal ||= Bolt::PAL.new(config.modulepath,
776
798
  config.hiera_config,
777
799
  config.project.resource_types,
778
800
  config.compile_concurrency,
779
801
  config.trusted_external,
780
802
  config.apply_settings,
781
- project)
803
+ config.project)
782
804
  end
783
805
 
784
806
  def convert_plan(plan)
@@ -794,7 +816,7 @@ module Bolt
794
816
  end
795
817
 
796
818
  def rerun
797
- @rerun ||= Bolt::Rerun.new(@config.rerunfile, @config.save_rerun)
819
+ @rerun ||= Bolt::Rerun.new(config.rerunfile, config.save_rerun)
798
820
  end
799
821
 
800
822
  def outputter