bolt 2.35.0 → 2.40.2

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +1 -1
  3. data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +1 -0
  4. data/lib/bolt/analytics.rb +27 -8
  5. data/lib/bolt/apply_result.rb +3 -3
  6. data/lib/bolt/bolt_option_parser.rb +45 -18
  7. data/lib/bolt/cli.rb +92 -110
  8. data/lib/bolt/config.rb +184 -80
  9. data/lib/bolt/config/options.rb +144 -83
  10. data/lib/bolt/config/transport/base.rb +10 -19
  11. data/lib/bolt/config/transport/local.rb +1 -7
  12. data/lib/bolt/config/transport/options.rb +11 -68
  13. data/lib/bolt/config/transport/ssh.rb +8 -19
  14. data/lib/bolt/executor.rb +5 -17
  15. data/lib/bolt/inventory.rb +25 -0
  16. data/lib/bolt/inventory/group.rb +0 -8
  17. data/lib/bolt/inventory/options.rb +130 -0
  18. data/lib/bolt/inventory/target.rb +10 -11
  19. data/lib/bolt/module_installer.rb +21 -13
  20. data/lib/bolt/module_installer/resolver.rb +1 -1
  21. data/lib/bolt/outputter.rb +19 -5
  22. data/lib/bolt/outputter/human.rb +20 -1
  23. data/lib/bolt/outputter/json.rb +1 -1
  24. data/lib/bolt/outputter/logger.rb +1 -1
  25. data/lib/bolt/outputter/rainbow.rb +13 -2
  26. data/lib/bolt/plugin.rb +41 -12
  27. data/lib/bolt/plugin/cache.rb +76 -0
  28. data/lib/bolt/plugin/module.rb +4 -4
  29. data/lib/bolt/plugin/puppetdb.rb +1 -1
  30. data/lib/bolt/project.rb +59 -40
  31. data/lib/bolt/project_manager.rb +201 -0
  32. data/lib/bolt/{project_migrator/config.rb → project_manager/config_migrator.rb} +49 -4
  33. data/lib/bolt/{project_migrator/inventory.rb → project_manager/inventory_migrator.rb} +3 -3
  34. data/lib/bolt/{project_migrator/base.rb → project_manager/migrator.rb} +2 -2
  35. data/lib/bolt/{project_migrator/modules.rb → project_manager/module_migrator.rb} +5 -3
  36. data/lib/bolt/puppetdb/client.rb +8 -0
  37. data/lib/bolt/puppetdb/config.rb +1 -2
  38. data/lib/bolt/rerun.rb +1 -5
  39. data/lib/bolt/shell/bash.rb +8 -2
  40. data/lib/bolt/shell/powershell.rb +21 -3
  41. data/lib/bolt/target.rb +4 -0
  42. data/lib/bolt/task/run.rb +1 -1
  43. data/lib/bolt/transport/local.rb +13 -0
  44. data/lib/bolt/transport/ssh/exec_connection.rb +6 -2
  45. data/lib/bolt/util.rb +36 -7
  46. data/lib/bolt/validator.rb +227 -0
  47. data/lib/bolt/version.rb +1 -1
  48. data/lib/bolt_server/base_config.rb +3 -1
  49. data/lib/bolt_server/config.rb +3 -1
  50. data/lib/bolt_server/plugin.rb +13 -0
  51. data/lib/bolt_server/plugin/puppet_connect_data.rb +37 -0
  52. data/lib/bolt_server/schemas/connect-data.json +22 -0
  53. data/lib/bolt_server/schemas/partials/task.json +3 -3
  54. data/lib/bolt_server/transport_app.rb +68 -40
  55. data/libexec/apply_catalog.rb +1 -1
  56. data/libexec/custom_facts.rb +1 -1
  57. data/libexec/query_resources.rb +1 -1
  58. metadata +23 -17
  59. data/lib/bolt/project_migrator.rb +0 -80
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d05af3f780d500b91be547a73123d24c2da041a8ef60ba14114921358b120800
4
- data.tar.gz: e8534835e69d1e5e57a353ff89a7d2667cf6d0894e8a07c1e5812282ed85b2cd
3
+ metadata.gz: d1b59f916303bbd38bb82a011ecff7a2e5086094586cea84d4cd78fb052d2171
4
+ data.tar.gz: 425288bb47b49aa017d71ee0b2bb1e48de475980f70e14be11f369acadfd0582
5
5
  SHA512:
6
- metadata.gz: 97b3faac5a1e423dcebf8e4fa92f55bbc36bd1c9735fc38332db40a2bb0db0e1ddc8e1e815aa29f31f9eb3601972a8d6e07b39d0c5dc6cd2762ea87a91ddec92
7
- data.tar.gz: 15963b1bb77ee04a1db4f54996964b32e599e4a0cc422dc77892151b221c1a17df9e6a1c74f160a30e9146402d48819b07b3b9d2ee9c96d7e763bba97389ccc8
6
+ metadata.gz: dc56fc52b8e52553902316fb26204a89a90901a9cf56e13d9ff8a1f2d4aea96d1054d578bda7598ba38384baf424a751230038bd8c6c593b113854a176cafeb7
7
+ data.tar.gz: 07a33c2ea3d3fdf5f69e9844d7c45dbb88cfedfabd8ce9264408876ee7496568033d372128eba510431bbb749c4223a8ba5420941936f2efd304ded398c90ad0
data/Puppetfile CHANGED
@@ -34,7 +34,7 @@ mod 'puppetlabs-stdlib', '6.5.0'
34
34
  mod 'puppetlabs-aws_inventory', '0.5.2'
35
35
  mod 'puppetlabs-azure_inventory', '0.4.1'
36
36
  mod 'puppetlabs-gcloud_inventory', '0.1.3'
37
- mod 'puppetlabs-http_request', '0.2.0'
37
+ mod 'puppetlabs-http_request', '0.2.1'
38
38
  mod 'puppetlabs-pkcs7', '0.1.1'
39
39
  mod 'puppetlabs-secure_env_vars', '0.1.0'
40
40
  mod 'puppetlabs-terraform', '0.5.0'
@@ -12,6 +12,7 @@ Puppet::DataTypes.create_type('ApplyResult') do
12
12
  message => Callable[[], Optional[String]],
13
13
  action => Callable[[], String],
14
14
  to_data => Callable[[], Hash],
15
+ value => Callable[[], Hash]
15
16
  }
16
17
  PUPPET
17
18
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'bolt/util'
4
4
  require 'bolt/version'
5
+ require 'find'
5
6
  require 'json'
6
7
  require 'logging'
7
8
  require 'securerandom'
@@ -23,14 +24,16 @@ module Bolt
23
24
  plan_steps: :cd8,
24
25
  return_type: :cd9,
25
26
  inventory_version: :cd10,
26
- boltdir_type: :cd11
27
+ boltdir_type: :cd11,
28
+ puppet_plan_count: :cd12,
29
+ yaml_plan_count: :cd13
27
30
  }.freeze
28
31
 
29
32
  def self.build_client
30
33
  logger = Bolt::Logger.logger(self)
31
34
  begin
32
- config_file = config_path(logger)
33
- config = load_config(config_file, logger)
35
+ config_file = config_path
36
+ config = load_config(config_file)
34
37
  rescue ArgumentError
35
38
  config = { 'disabled' => true }
36
39
  end
@@ -51,7 +54,7 @@ module Bolt
51
54
  NoopClient.new
52
55
  end
53
56
 
54
- def self.config_path(logger)
57
+ def self.config_path
55
58
  path = File.expand_path(File.join('~', '.puppetlabs', 'etc', 'bolt', 'analytics.yaml'))
56
59
  old_path = File.expand_path(File.join('~', '.puppetlabs', 'bolt', 'analytics.yaml'))
57
60
 
@@ -59,7 +62,7 @@ module Bolt
59
62
  if File.exist?(old_path)
60
63
  message = "Detected analytics configuration files at '#{old_path}' and '#{path}'. Loading "\
61
64
  "analytics configuration from '#{path}'."
62
- logger.warn(message)
65
+ Bolt::Logger.warn_once('duplicate_analytics', message)
63
66
  end
64
67
 
65
68
  path
@@ -70,12 +73,12 @@ module Bolt
70
73
  end
71
74
  end
72
75
 
73
- def self.load_config(filename, logger)
76
+ def self.load_config(filename)
74
77
  if File.exist?(filename)
75
78
  Bolt::Util.read_optional_yaml_hash(filename, 'analytics')
76
79
  else
77
80
  unless ENV['BOLT_DISABLE_ANALYTICS']
78
- logger.warn <<~ANALYTICS
81
+ Bolt::Logger.warn_once('analytics_opt_out', <<~ANALYTICS)
79
82
  Bolt collects data about how you use it. You can opt out of providing this data.
80
83
 
81
84
  To disable analytics data collection, add this line to ~/.puppetlabs/etc/bolt/analytics.yaml :
@@ -134,11 +137,23 @@ module Bolt
134
137
  end
135
138
 
136
139
  def report_bundled_content(mode, name)
137
- if bundled_content[mode.split(' ').first]&.include?(name)
140
+ if bundled_content[mode.split.first]&.include?(name)
138
141
  event('Bundled Content', mode, label: name)
139
142
  end
140
143
  end
141
144
 
145
+ def plan_counts(plans_path)
146
+ pp_count, yaml_count = if File.exist?(plans_path)
147
+ %w[pp yaml].map do |extension|
148
+ Find.find(plans_path.to_s).grep(/.*\.#{extension}/).length
149
+ end
150
+ else
151
+ [0, 0]
152
+ end
153
+
154
+ { puppet_plan_count: pp_count, yaml_plan_count: yaml_count }
155
+ end
156
+
142
157
  def event(category, action, label: nil, value: nil, **kwargs)
143
158
  custom_dimensions = Bolt::Util.walk_keys(kwargs) do |k|
144
159
  CUSTOM_DIMENSIONS[k] || raise("Unknown analytics key '#{k}'")
@@ -224,6 +239,10 @@ module Bolt
224
239
 
225
240
  def report_bundled_content(mode, name); end
226
241
 
242
+ def plan_counts(_)
243
+ {}
244
+ end
245
+
227
246
  def event(category, action, **_kwargs)
228
247
  @logger.trace "Skipping submission of '#{category} #{action}' event because analytics is disabled"
229
248
  end
@@ -96,9 +96,9 @@ module Bolt
96
96
  @target = target
97
97
  @value = {}
98
98
  @action = 'apply'
99
- value['report'] = report if report
100
- value['_error'] = error if error
101
- value['_output'] = metrics_message if metrics_message
99
+ @value['report'] = report if report
100
+ @value['_error'] = error if error
101
+ @value['_output'] = metrics_message if metrics_message
102
102
  end
103
103
 
104
104
  def event_metrics
@@ -6,14 +6,15 @@ require 'optparse'
6
6
 
7
7
  module Bolt
8
8
  class BoltOptionParser < OptionParser
9
+ PROJECT_PATHS = %w[project configfile boltdir].freeze
9
10
  OPTIONS = { inventory: %w[targets query rerun description],
10
11
  authentication: %w[user password password-prompt private-key host-key-check ssl ssl-verify],
11
12
  escalation: %w[run-as sudo-password sudo-password-prompt sudo-executable],
12
13
  run_context: %w[concurrency inventoryfile save-rerun cleanup],
13
- global_config_setters: %w[modulepath project configfile],
14
+ global_config_setters: PROJECT_PATHS + %w[modulepath],
14
15
  transports: %w[transport connect-timeout tty native-ssh ssh-command copy-command],
15
16
  display: %w[format color verbose trace],
16
- global: %w[help version debug log-level] }.freeze
17
+ global: %w[help version debug log-level clear-cache] }.freeze
17
18
 
18
19
  ACTION_OPTS = OPTIONS.values.flatten.freeze
19
20
 
@@ -46,7 +47,8 @@ module Bolt
46
47
  when 'inventory'
47
48
  case action
48
49
  when 'show'
49
- { flags: OPTIONS[:inventory] + OPTIONS[:global] + %w[format inventoryfile boltdir configfile detail],
50
+ { flags: OPTIONS[:inventory] + OPTIONS[:global] +
51
+ PROJECT_PATHS + %w[format inventoryfile detail],
50
52
  banner: INVENTORY_SHOW_HELP }
51
53
  else
52
54
  { flags: OPTIONS[:global],
@@ -55,7 +57,7 @@ module Bolt
55
57
  when 'group'
56
58
  case action
57
59
  when 'show'
58
- { flags: OPTIONS[:global] + %w[format inventoryfile boltdir configfile],
60
+ { flags: OPTIONS[:global] + PROJECT_PATHS + %w[format inventoryfile],
59
61
  banner: GROUP_SHOW_HELP }
60
62
  else
61
63
  { flags: OPTIONS[:global],
@@ -67,13 +69,13 @@ module Bolt
67
69
  when 'module'
68
70
  case action
69
71
  when 'add'
70
- { flags: OPTIONS[:global] + %w[configfile project],
72
+ { flags: OPTIONS[:global] + PROJECT_PATHS,
71
73
  banner: MODULE_ADD_HELP }
72
74
  when 'generate-types'
73
75
  { flags: OPTIONS[:global] + OPTIONS[:global_config_setters],
74
76
  banner: MODULE_GENERATETYPES_HELP }
75
77
  when 'install'
76
- { flags: OPTIONS[:global] + %w[configfile force project resolve],
78
+ { flags: OPTIONS[:global] + PROJECT_PATHS + %w[force resolve],
77
79
  banner: MODULE_INSTALL_HELP }
78
80
  when 'show'
79
81
  { flags: OPTIONS[:global] + OPTIONS[:global_config_setters],
@@ -88,7 +90,7 @@ module Bolt
88
90
  { flags: OPTIONS[:global] + OPTIONS[:global_config_setters],
89
91
  banner: PLAN_CONVERT_HELP }
90
92
  when 'new'
91
- { flags: OPTIONS[:global] + %w[configfile project pp],
93
+ { flags: OPTIONS[:global] + PROJECT_PATHS + %w[pp],
92
94
  banner: PLAN_NEW_HELP }
93
95
  when 'run'
94
96
  { flags: ACTION_OPTS + %w[params compile-concurrency tmpdir hiera-config],
@@ -106,7 +108,7 @@ module Bolt
106
108
  { flags: OPTIONS[:global] + %w[modules],
107
109
  banner: PROJECT_INIT_HELP }
108
110
  when 'migrate'
109
- { flags: OPTIONS[:global] + %w[inventoryfile project configfile],
111
+ { flags: OPTIONS[:global] + PROJECT_PATHS + %w[inventoryfile],
110
112
  banner: PROJECT_MIGRATE_HELP }
111
113
  else
112
114
  { flags: OPTIONS[:global],
@@ -793,7 +795,10 @@ module Bolt
793
795
  @options[:noop] = true
794
796
  end
795
797
  define('--description DESCRIPTION',
796
- 'Description to use for the job') do |description|
798
+ 'Deprecated. Description to use for the job') do |description|
799
+ msg = "Command line option '--description' is deprecated, and will be "\
800
+ "removed in Bolt 3.0."
801
+ @deprecations << { type: 'Using --description', msg: msg }
797
802
  @options[:description] = description
798
803
  end
799
804
  define('--params PARAMETERS',
@@ -873,13 +878,25 @@ module Bolt
873
878
  File.expand_path(moduledir)
874
879
  end
875
880
  end
876
- define('--project PATH', '--boltdir PATH',
877
- 'Specify what project to load config from (default: autodiscovered from current working dir)') do |path|
881
+ define('--boltdir PATH',
882
+ 'Deprecated. Specify what project to load config from (default:',
883
+ 'autodiscovered from current working dir)') do |path|
884
+ msg = "Command line option '--boltdir' is deprecated, use '--project' instead."
885
+ @deprecations << { type: 'Using --boltdir', msg: msg }
878
886
  @options[:boltdir] = path
879
887
  end
888
+ define('--project PATH',
889
+ 'Path to load the Bolt project from (default: autodiscovered from current dir)') do |path|
890
+ @options[:project] = path
891
+ end
880
892
  define('--configfile PATH',
881
- 'Specify where to load config from (default: ~/.puppetlabs/bolt/bolt.yaml).',
882
- 'Directory containing bolt.yaml will be used as the project directory.') do |path|
893
+ 'Deprecated. Specify where to load config from (default:',
894
+ '~/.puppetlabs/bolt/bolt.yaml). Directory containing bolt.yaml will be',
895
+ 'used as the project directory.') do |path|
896
+ msg = "Command line option '--configfile' is deprecated, and " \
897
+ "will be removed in Bolt 3.0. Use '--project' and provide the "\
898
+ "directory path instead."
899
+ @deprecations << { type: 'Using --configfile', msg: msg }
883
900
  @options[:configfile] = path
884
901
  end
885
902
  define('--hiera-config PATH',
@@ -891,12 +908,18 @@ module Bolt
891
908
  if ENV.include?(Bolt::Inventory::ENVIRONMENT_VAR)
892
909
  raise Bolt::CLIError, "Cannot pass inventory file when #{Bolt::Inventory::ENVIRONMENT_VAR} is set"
893
910
  end
894
- @options[:inventoryfile] = Pathname.new(File.expand_path(path))
911
+ @options[:inventoryfile] = File.expand_path(path)
895
912
  end
896
913
  define('--puppetfile PATH',
897
- 'Specify a Puppetfile to use when installing modules. (default: ~/.puppetlabs/bolt/Puppetfile)',
914
+ 'Deprecated. Specify a Puppetfile to use when installing modules.',
915
+ ' (default: ~/.puppetlabs/bolt/Puppetfile)',
898
916
  'Modules are installed in the current project.') do |path|
899
- @options[:puppetfile_path] = Pathname.new(File.expand_path(path))
917
+ command = Bolt::Util.powershell? ? 'Update-BoltProject' : 'bolt project migrate'
918
+ msg = "Command line option '--puppetfile' is deprecated, and will be removed "\
919
+ "in Bolt 3.0. You can migrate to using the new module management "\
920
+ "workflow using '#{command}'."
921
+ @deprecations << { type: 'Using --puppetfile', msg: msg }
922
+ @options[:puppetfile_path] = File.expand_path(path)
900
923
  end
901
924
  define('--[no-]save-rerun', 'Whether to update the rerun file after this command.') do |save|
902
925
  @options[:'save-rerun'] = save
@@ -946,8 +969,8 @@ module Bolt
946
969
  end
947
970
 
948
971
  separator "\nPLAN OPTIONS"
949
- define('--pp', 'Create a new Puppet language plan.') do |pp|
950
- @options[:puppet] = pp
972
+ define('--pp', 'Create a new Puppet language plan.') do |_|
973
+ @options[:puppet] = true
951
974
  end
952
975
 
953
976
  separator "\nDISPLAY OPTIONS"
@@ -1002,6 +1025,10 @@ module Bolt
1002
1025
  "trace, debug, info, warn, error, fatal, any.") do |level|
1003
1026
  @options[:log] = { 'console' => { 'level' => level } }
1004
1027
  end
1028
+ define('--clear-cache',
1029
+ "Clear plugin cache before executing") do |_|
1030
+ @options[:clear_cache] = true
1031
+ end
1005
1032
  define('--plugin PLUGIN', 'Select the plugin to use') do |plug|
1006
1033
  @options[:plugin] = plug
1007
1034
  end
@@ -21,7 +21,7 @@ require 'bolt/outputter'
21
21
  require 'bolt/pal'
22
22
  require 'bolt/plan_creator'
23
23
  require 'bolt/plugin'
24
- require 'bolt/project_migrator'
24
+ require 'bolt/project_manager'
25
25
  require 'bolt/puppetdb'
26
26
  require 'bolt/rerun'
27
27
  require 'bolt/secret'
@@ -30,6 +30,7 @@ require 'bolt/version'
30
30
 
31
31
  module Bolt
32
32
  class CLIExit < StandardError; end
33
+
33
34
  class CLI
34
35
  COMMANDS = {
35
36
  'command' => %w[run],
@@ -164,8 +165,9 @@ module Bolt
164
165
  elsif options[:configfile]
165
166
  Bolt::Config.from_file(options[:configfile], options)
166
167
  else
167
- project = if options[:boltdir]
168
- dir = Pathname.new(options[:boltdir])
168
+ cli_flag = options[:project] || options[:boltdir]
169
+ project = if cli_flag
170
+ dir = Pathname.new(cli_flag)
169
171
  if (dir + Bolt::Project::BOLTDIR_NAME).directory?
170
172
  Bolt::Project.create_project(dir + Bolt::Project::BOLTDIR_NAME)
171
173
  else
@@ -195,7 +197,12 @@ module Bolt
195
197
  @parser_deprecations.each { |dep| Bolt::Logger.deprecation_warning(dep[:type], dep[:msg]) }
196
198
  config.deprecations.each { |dep| Bolt::Logger.deprecation_warning(dep[:type], dep[:msg]) }
197
199
 
200
+ if options[:clear_cache] && File.exist?(config.project.cache_file)
201
+ FileUtils.rm(config.project.cache_file)
202
+ end
203
+
198
204
  warn_inventory_overrides_cli(options)
205
+ validate_ps_version
199
206
 
200
207
  options
201
208
  rescue Bolt::Error => e
@@ -203,6 +210,20 @@ module Bolt
203
210
  raise e
204
211
  end
205
212
 
213
+ private def validate_ps_version
214
+ if Bolt::Util.powershell?
215
+ command = "powershell.exe -NoProfile -NonInteractive -NoLogo -ExecutionPolicy "\
216
+ "Bypass -Command $PSVersionTable.PSVersion.Major"
217
+ stdout, _stderr, _status = Open3.capture3(command)
218
+
219
+ return unless !stdout.empty? && stdout.to_i < 3
220
+
221
+ msg = "Detected PowerShell 2 on controller. PowerShell 2 is deprecated and "\
222
+ "support will be removed in Bolt 3.0."
223
+ Bolt::Logger.deprecation_warning("PowerShell 2 controller", msg)
224
+ end
225
+ end
226
+
206
227
  def update_targets(options)
207
228
  target_opts = options.keys.select { |opt| %i[query rerun targets].include?(opt) }
208
229
  target_string = "'--targets', '--rerun', or '--query'"
@@ -293,7 +314,7 @@ module Bolt
293
314
  "Unknown argument(s) #{options[:leftovers].join(', ')}"
294
315
  end
295
316
 
296
- if options[:boltdir] && options[:configfile]
317
+ if options.slice(:boltdir, :configfile, :project).length > 1
297
318
  raise Bolt::CLIError, "Only one of '--boltdir', '--project', or '--configfile' may be specified"
298
319
  end
299
320
 
@@ -340,15 +361,10 @@ module Bolt
340
361
  def warn_inventory_overrides_cli(opts)
341
362
  inventory_source = if ENV[Bolt::Inventory::ENVIRONMENT_VAR]
342
363
  Bolt::Inventory::ENVIRONMENT_VAR
343
- elsif config.inventoryfile && Bolt::Util.file_stat(config.inventoryfile)
364
+ elsif config.inventoryfile
344
365
  config.inventoryfile
345
- else
346
- begin
347
- Bolt::Util.file_stat(config.default_inventoryfile)
348
- config.default_inventoryfile
349
- rescue Errno::ENOENT
350
- nil
351
- end
366
+ elsif File.exist?(config.default_inventoryfile)
367
+ config.default_inventoryfile
352
368
  end
353
369
 
354
370
  inventory_cli_opts = %i[authentication escalation transports].each_with_object([]) do |key, acc|
@@ -392,7 +408,7 @@ module Bolt
392
408
  output_format: config.format,
393
409
  # For continuity
394
410
  boltdir_type: config.project.type
395
- }
411
+ }.merge!(analytics.plan_counts(config.project.plans_path))
396
412
 
397
413
  # Only include target and inventory info for commands that take a targets
398
414
  # list. This avoids loading inventory for commands that don't need it.
@@ -456,15 +472,14 @@ module Bolt
456
472
  when 'project'
457
473
  case options[:action]
458
474
  when 'init'
459
- code = initialize_project
475
+ code = Bolt::ProjectManager.new(config, outputter, pal)
476
+ .create(Dir.pwd, options[:object], options[:modules])
460
477
  when 'migrate'
461
- code = Bolt::ProjectMigrator.new(config, outputter).migrate
478
+ code = Bolt::ProjectManager.new(config, outputter, pal).migrate
462
479
  end
463
480
  when 'plan'
464
481
  case options[:action]
465
482
  when 'new'
466
- command = Bolt::Util.powershell? ? 'New-BoltPlan' : 'bolt plan new'
467
- @logger.warn("Command '#{command}' is experimental and subject to changes.")
468
483
  plan_name = options[:object]
469
484
 
470
485
  # If this passes validation, it will return the path to the plan to create
@@ -479,9 +494,9 @@ module Bolt
479
494
  when 'module'
480
495
  case options[:action]
481
496
  when 'add'
482
- code = add_project_module(options[:object], config.project)
497
+ code = add_project_module(options[:object], config.project, config.module_install)
483
498
  when 'install'
484
- code = install_project_modules(config.project, options[:force], options[:resolve])
499
+ code = install_project_modules(config.project, config.module_install, options[:force], options[:resolve])
485
500
  when 'generate-types'
486
501
  code = generate_types
487
502
  end
@@ -526,12 +541,15 @@ module Bolt
526
541
  validate_file('script', script)
527
542
  executor.run_script(targets, script, options[:leftovers], executor_opts)
528
543
  when 'task'
529
- pal.run_task(options[:object],
530
- targets,
531
- options[:task_options],
532
- executor,
533
- inventory,
534
- options[:description])
544
+ r = outputter.spin do
545
+ pal.run_task(options[:object],
546
+ targets,
547
+ options[:task_options],
548
+ executor,
549
+ inventory,
550
+ options[:description])
551
+ end
552
+ r
535
553
  when 'file'
536
554
  src = options[:object]
537
555
  dest = options[:leftovers].first
@@ -666,7 +684,9 @@ module Bolt
666
684
 
667
685
  executor.subscribe(log_outputter)
668
686
  executor.start_plan(plan_context)
669
- result = pal.run_plan(plan_name, plan_arguments, executor, inventory, puppetdb_client)
687
+ result = outputter.spin do
688
+ pal.run_plan(plan_name, plan_arguments, executor, inventory, puppetdb_client)
689
+ end
670
690
 
671
691
  # If a non-bolt exception bubbles up the plan won't get finished
672
692
  executor.finish_plan(result)
@@ -729,79 +749,9 @@ module Bolt
729
749
  0
730
750
  end
731
751
 
732
- # Initializes a specified directory as a Bolt project and installs any modules
733
- # specified by the user, along with their dependencies
734
- def initialize_project
735
- # Dir.pwd will return backslashes on Windows, but Pathname always uses
736
- # forward slashes to concatenate paths. This results in paths like
737
- # C:\User\Administrator/modules, which fail module install. This ensure
738
- # forward slashes in the cwd path.
739
- dir = File.expand_path(Dir.pwd)
740
- name = options[:object] || File.basename(dir)
741
- if name !~ Bolt::Module::MODULE_NAME_REGEX
742
- if options[:object]
743
- raise Bolt::ValidationError, "The provided project name '#{name}' is invalid; "\
744
- "project name must begin with a lowercase letter and can include lowercase "\
745
- "letters, numbers, and underscores."
746
- else
747
- command = Bolt::Util.powershell? ? 'New-BoltProject -Name <NAME>' : 'bolt project init <NAME>'
748
- raise Bolt::ValidationError, "The current directory name '#{name}' is an invalid "\
749
- "project name. Please specify a name using '#{command}'."
750
- end
751
- end
752
-
753
- project = Pathname.new(dir)
754
- old_config = project + 'bolt.yaml'
755
- config = project + 'bolt-project.yaml'
756
- puppetfile = project + 'Puppetfile'
757
- moduledir = project + 'modules'
758
-
759
- # Warn the user if the project directory already exists. We don't error
760
- # here since users might not have installed any modules yet. If both
761
- # bolt.yaml and bolt-project.yaml exist, this will just warn about
762
- # bolt-project.yaml and subsequent Bolt actions will warn about both files
763
- # existing.
764
- if config.exist?
765
- @logger.warn "Found existing project directory at #{project}. Skipping file creation."
766
- elsif old_config.exist?
767
- @logger.warn "Found existing #{old_config.basename} at #{project}. "\
768
- "#{old_config.basename} is deprecated, please rename to #{config.basename}."
769
- end
770
-
771
- # If modules were specified, first check if there is already a Puppetfile
772
- # at the project directory, erroring if there is. If there is no
773
- # Puppetfile, install the specified modules. The module installer will
774
- # resolve dependencies, generate a Puppetfile, and install the modules.
775
- if options[:modules]
776
- if puppetfile.exist?
777
- raise Bolt::CLIError,
778
- "Found existing Puppetfile at #{puppetfile}, unable to initialize "\
779
- "project with modules."
780
- end
781
-
782
- installer = Bolt::ModuleInstaller.new(outputter, pal)
783
- installer.install(options[:modules], puppetfile, moduledir)
784
- end
785
-
786
- # If either bolt.yaml or bolt-project.yaml exist, the user has already
787
- # been warned and we can just finish project creation. Otherwise, create a
788
- # bolt-project.yaml with the project name in it.
789
- unless config.exist? || old_config.exist?
790
- begin
791
- content = { 'name' => name }
792
- File.write(config.to_path, content.to_yaml)
793
- outputter.print_message "Successfully created Bolt project at #{project}"
794
- rescue StandardError => e
795
- raise Bolt::FileError.new("Could not create bolt-project.yaml at #{project}: #{e.message}", nil)
796
- end
797
- end
798
-
799
- 0
800
- end
801
-
802
752
  # Installs modules declared in the project configuration file.
803
753
  #
804
- def install_project_modules(project, force, resolve)
754
+ def install_project_modules(project, config, force, resolve)
805
755
  assert_project_file(project)
806
756
  assert_puppetfile_or_module_command(project.modules)
807
757
 
@@ -811,30 +761,55 @@ module Bolt
811
761
  return 0
812
762
  end
813
763
 
764
+ if resolve != false && config.any?
765
+ @logger.warn(
766
+ "Detected configuration for 'module-install'. This configuration is currently "\
767
+ "only supported when installing modules, not when resolving module dependencies. "\
768
+ "For more information, see https://pup.pt/bolt-module-install"
769
+ )
770
+ end
771
+
772
+ modules = project.modules || []
814
773
  installer = Bolt::ModuleInstaller.new(outputter, pal)
815
774
 
816
- ok = installer.install(project.modules,
817
- project.puppetfile,
818
- project.managed_moduledir,
819
- force: force,
820
- resolve: resolve)
775
+ ok = outputter.spin do
776
+ installer.install(modules,
777
+ project.puppetfile,
778
+ project.managed_moduledir,
779
+ config,
780
+ force: force,
781
+ resolve: resolve)
782
+ end
783
+
821
784
  ok ? 0 : 1
822
785
  end
823
786
 
824
787
  # Adds a single module to the project.
825
788
  #
826
- def add_project_module(name, project)
789
+ def add_project_module(name, project, config)
827
790
  assert_project_file(project)
828
791
  assert_puppetfile_or_module_command(project.modules)
829
792
 
793
+ if config.any?
794
+ @logger.warn(
795
+ "Detected configuration for 'module-install'. This configuration is currently "\
796
+ "only supported when installing modules, not when resolving module dependencies. "\
797
+ "For more information, see https://pup.pt/bolt-module-install"
798
+ )
799
+ end
800
+
830
801
  modules = project.modules || []
831
802
  installer = Bolt::ModuleInstaller.new(outputter, pal)
832
803
 
833
- ok = installer.add(name,
834
- modules,
835
- project.puppetfile,
836
- project.managed_moduledir,
837
- project.project_file)
804
+ ok = outputter.spin do
805
+ installer.add(name,
806
+ modules,
807
+ project.puppetfile,
808
+ project.managed_moduledir,
809
+ project.project_file,
810
+ config)
811
+ end
812
+
838
813
  ok ? 0 : 1
839
814
  end
840
815
 
@@ -863,7 +838,10 @@ module Bolt
863
838
 
864
839
  outputter.print_message("Installing modules from Puppetfile")
865
840
  installer = Bolt::ModuleInstaller.new(outputter, pal)
866
- ok = installer.install_puppetfile(puppetfile, moduledir, puppetfile_config)
841
+ ok = outputter.spin do
842
+ installer.install_puppetfile(puppetfile, moduledir, puppetfile_config)
843
+ end
844
+
867
845
  ok ? 0 : 1
868
846
  end
869
847
 
@@ -969,7 +947,11 @@ module Bolt
969
947
  end
970
948
 
971
949
  def outputter
972
- @outputter ||= Bolt::Outputter.for_format(config.format, config.color, options[:verbose], config.trace)
950
+ @outputter ||= Bolt::Outputter.for_format(config.format,
951
+ config.color,
952
+ options[:verbose],
953
+ config.trace,
954
+ config.spinner)
973
955
  end
974
956
 
975
957
  def log_outputter