bolt 3.3.0 → 3.7.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +5 -5
  3. data/bolt-modules/boltlib/lib/puppet/datatypes/containerresult.rb +24 -0
  4. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_command.rb +66 -0
  5. data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +20 -2
  6. data/bolt-modules/boltlib/lib/puppet/functions/run_container.rb +162 -0
  7. data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +19 -2
  8. data/bolt-modules/boltlib/types/planresult.pp +1 -0
  9. data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +20 -2
  10. data/bolt-modules/prompt/lib/puppet/functions/prompt/menu.rb +103 -0
  11. data/guides/targets.txt +31 -0
  12. data/lib/bolt/analytics.rb +4 -8
  13. data/lib/bolt/bolt_option_parser.rb +35 -17
  14. data/lib/bolt/cli.rb +109 -28
  15. data/lib/bolt/config.rb +11 -7
  16. data/lib/bolt/config/options.rb +41 -9
  17. data/lib/bolt/config/transport/lxd.rb +3 -1
  18. data/lib/bolt/config/transport/options.rb +7 -0
  19. data/lib/bolt/config/transport/podman.rb +33 -0
  20. data/lib/bolt/container_result.rb +105 -0
  21. data/lib/bolt/error.rb +15 -0
  22. data/lib/bolt/executor.rb +27 -15
  23. data/lib/bolt/inventory.rb +5 -4
  24. data/lib/bolt/inventory/inventory.rb +3 -2
  25. data/lib/bolt/inventory/options.rb +9 -0
  26. data/lib/bolt/inventory/target.rb +16 -0
  27. data/lib/bolt/node/output.rb +14 -4
  28. data/lib/bolt/outputter/human.rb +243 -84
  29. data/lib/bolt/outputter/json.rb +6 -4
  30. data/lib/bolt/outputter/logger.rb +17 -0
  31. data/lib/bolt/pal.rb +22 -2
  32. data/lib/bolt/pal/yaml_plan/step.rb +4 -2
  33. data/lib/bolt/pal/yaml_plan/step/command.rb +8 -0
  34. data/lib/bolt/pal/yaml_plan/step/script.rb +4 -0
  35. data/lib/bolt/pal/yaml_plan/transpiler.rb +2 -2
  36. data/lib/bolt/plan_creator.rb +2 -2
  37. data/lib/bolt/plugin.rb +13 -11
  38. data/lib/bolt/puppetdb/client.rb +54 -0
  39. data/lib/bolt/result.rb +5 -14
  40. data/lib/bolt/shell/bash.rb +33 -22
  41. data/lib/bolt/shell/powershell.rb +6 -8
  42. data/lib/bolt/transport/docker.rb +1 -1
  43. data/lib/bolt/transport/docker/connection.rb +21 -32
  44. data/lib/bolt/transport/lxd/connection.rb +5 -5
  45. data/lib/bolt/transport/orch.rb +13 -5
  46. data/lib/bolt/transport/podman.rb +19 -0
  47. data/lib/bolt/transport/podman/connection.rb +98 -0
  48. data/lib/bolt/util.rb +42 -0
  49. data/lib/bolt/version.rb +1 -1
  50. data/lib/bolt_server/transport_app.rb +3 -0
  51. data/lib/bolt_spec/plans/action_stubs/command_stub.rb +8 -1
  52. data/lib/bolt_spec/plans/action_stubs/script_stub.rb +8 -1
  53. data/lib/bolt_spec/plans/mock_executor.rb +91 -11
  54. data/modules/puppet_connect/plans/test_input_data.pp +22 -0
  55. metadata +11 -2
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bolt/error'
4
+
5
+ # Display a menu prompt and wait for a response. Continues to prompt
6
+ # until an option from the menu is selected.
7
+ #
8
+ # > **Note:** Not available in apply block
9
+ Puppet::Functions.create_function(:'prompt::menu') do
10
+ # Select from a list of options.
11
+ # @param prompt The prompt to display.
12
+ # @param menu A list of options to choose from.
13
+ # @param options A hash of additional options.
14
+ # @option options [String] default The default option to return if the user does not provide
15
+ # input or if standard in (stdin) is not a tty. Must be an option present in the menu.
16
+ # @return The selected option.
17
+ # @example Prompt the user to select from a list of options
18
+ # $selection = prompt::menu('Select a fruit', ['apple', 'banana', 'carrot'])
19
+ # @example Prompt the user to select from a list of options with a default value
20
+ # $selection = prompt::menu('Select environment', ['development', 'production'], 'default' => 'development')
21
+ dispatch :prompt_menu_array do
22
+ param 'String', :prompt
23
+ param 'Array[Variant[Target, Data]]', :menu
24
+ optional_param 'Hash[String[1], Variant[Target, Data]]', :options
25
+ return_type 'Variant[Target, Data]'
26
+ end
27
+
28
+ # Select from a list of options with custom inputs.
29
+ # @param prompt The prompt to display.
30
+ # @param menu A hash of options to choose from, where keys are the input used to select a value.
31
+ # @param options A hash of additional options.
32
+ # @option options [String] default The default option to return if the user does not provide
33
+ # input or if standard in (stdin) is not a tty. Must be an option present in the menu.
34
+ # @return The selected option.
35
+ # @example Prompt the user to select from a list of options with custom inputs
36
+ # $menu = { 'y' => 'yes', 'n' => 'no' }
37
+ # $selection = prompt::menu('Install Puppet?', $menu)
38
+ dispatch :prompt_menu do
39
+ param 'String', :prompt
40
+ param 'Hash[String[1], Variant[Target, Data]]', :menu
41
+ optional_param 'Hash[String[1], Variant[Target, Data]]', :options
42
+ return_type 'Variant[TargetSpec, Data]'
43
+ end
44
+
45
+ def prompt_menu_array(prompt, menu, options = {})
46
+ menu_hash = menu.map.with_index { |value, index| [(index + 1).to_s, value] }.to_h
47
+ prompt_menu(prompt, menu_hash, options)
48
+ end
49
+
50
+ def prompt_menu(prompt, menu, options = {})
51
+ unless Puppet[:tasks]
52
+ raise Puppet::ParseErrorWithIssue
53
+ .from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING,
54
+ action: 'prompt::menu')
55
+ end
56
+
57
+ options = options.transform_keys(&:to_sym)
58
+ executor = Puppet.lookup(:bolt_executor)
59
+
60
+ # Send analytics report
61
+ executor.report_function_call(self.class.name)
62
+
63
+ # Error if there are no options
64
+ if menu.empty?
65
+ raise Bolt::ValidationError, "Menu cannot be empty"
66
+ end
67
+
68
+ # Error if the default value is not on the menu
69
+ if options.key?(:default) && !menu.value?(options[:default])
70
+ raise Bolt::ValidationError, "Default value '#{options[:default]}' is not one of the provided menu options"
71
+ end
72
+
73
+ # The first prompt should include the menu
74
+ to_prompt = format_menu(menu) + prompt
75
+
76
+ # Request input from the user until they provide a valid option
77
+ loop do
78
+ selection = executor.prompt(to_prompt, options)
79
+
80
+ return menu[selection] if menu.key?(selection)
81
+ return selection if options.key?(:default) && options[:default] == selection
82
+
83
+ # Only reprint the prompt, not the menu
84
+ to_prompt = "Invalid option, try again. #{prompt}"
85
+ end
86
+ end
87
+
88
+ # Builds the menu string. Aligns all the values by padding input keys.
89
+ #
90
+ private def format_menu(menu)
91
+ # Find the longest input and add 2 for wrapping parenthesis
92
+ key_length = menu.keys.max_by(&:length).length + 2
93
+
94
+ menu_string = +''
95
+
96
+ menu.each do |key, value|
97
+ key = "(#{key})".ljust(key_length)
98
+ menu_string << "#{key} #{value}\n"
99
+ end
100
+
101
+ menu_string
102
+ end
103
+ end
@@ -0,0 +1,31 @@
1
+ TOPIC
2
+ targets
3
+
4
+ DESCRIPTION
5
+ A target is a device that Bolt connects to and runs actions on. Targets can
6
+ be physical, such as servers, or virtual, such as containers or virtual
7
+ machines.
8
+
9
+ Several of Bolt's commands connect to targets and run actions on them. When
10
+ you run these commands, Bolt requires a list of targets to run the action
11
+ on. For example, the `bolt script run` command and `Invoke-BoltScript`
12
+ PowerShell cmdlet require you to provide a list of targets to run your
13
+ script on. You can provide a list of targets to a command using one of the
14
+ following command-line options:
15
+
16
+ Shell commands
17
+ -t, --targets TARGETS
18
+ -q, --query QUERY
19
+ --rerun FILTER
20
+
21
+ PowerShell cmdlets
22
+ -T, -Targets TARGETS
23
+ -Q, -Query QUERY
24
+ -Rerun FILTER
25
+
26
+ Typically, targets and their configuration and data are listed in a
27
+ project's inventory file. For more information about inventory files,
28
+ see 'bolt guide inventory'.
29
+
30
+ DOCUMENTATION
31
+ https://pup.pt/bolt-commands
@@ -29,7 +29,7 @@ module Bolt
29
29
  yaml_plan_count: :cd13
30
30
  }.freeze
31
31
 
32
- def self.build_client
32
+ def self.build_client(enabled = true)
33
33
  logger = Bolt::Logger.logger(self)
34
34
  begin
35
35
  config_file = config_path
@@ -38,7 +38,7 @@ module Bolt
38
38
  config = { 'disabled' => true }
39
39
  end
40
40
 
41
- if config['disabled'] || ENV['BOLT_DISABLE_ANALYTICS']
41
+ if !enabled || config['disabled'] || ENV['BOLT_DISABLE_ANALYTICS']
42
42
  logger.debug "Analytics opt-out is set, analytics will be disabled"
43
43
  NoopClient.new
44
44
  else
@@ -80,12 +80,8 @@ module Bolt
80
80
  unless ENV['BOLT_DISABLE_ANALYTICS']
81
81
  msg = <<~ANALYTICS
82
82
  Bolt collects data about how you use it. You can opt out of providing this data.
83
-
84
- To disable analytics data collection, add this line to ~/.puppetlabs/etc/bolt/analytics.yaml :
85
- disabled: true
86
-
87
- Read more about what data Bolt collects and why here:
88
- https://puppet.com/docs/bolt/latest/bolt_installing.html#analytics-data-collection
83
+ To learn how to disable data collection, or see what data Bolt collects and why,
84
+ see http://pup.pt/bolt-analytics
89
85
  ANALYTICS
90
86
  Bolt::Logger.warn_once('analytics_opt_out', msg)
91
87
  end
@@ -190,7 +190,8 @@ module Bolt
190
190
  apply
191
191
 
192
192
  USAGE
193
- bolt apply [manifest.pp] [options]
193
+ bolt apply [manifest] {--targets TARGETS | --query QUERY | --rerun FILTER}
194
+ [options]
194
195
 
195
196
  DESCRIPTION
196
197
  Apply Puppet manifest code on the specified targets.
@@ -219,7 +220,8 @@ module Bolt
219
220
  run
220
221
 
221
222
  USAGE
222
- bolt command run <command> [options]
223
+ bolt command run <command> {--targets TARGETS | --query QUERY | --rerun FILTER}
224
+ [options]
223
225
 
224
226
  DESCRIPTION
225
227
  Run a command on the specified targets.
@@ -248,7 +250,8 @@ module Bolt
248
250
  download
249
251
 
250
252
  USAGE
251
- bolt file download <src> <dest> [options]
253
+ bolt file download <source> <destination> {--targets TARGETS | --query QUERY | --rerun FILTER}
254
+ [options]
252
255
 
253
256
  DESCRIPTION
254
257
  Download a file or directory from one or more targets.
@@ -267,7 +270,8 @@ module Bolt
267
270
  upload
268
271
 
269
272
  USAGE
270
- bolt file upload <src> <dest> [options]
273
+ bolt file upload <source> <destination> {--targets TARGETS | --query QUERY | --rerun FILTER}
274
+ [options]
271
275
 
272
276
  DESCRIPTION
273
277
  Upload a local file or directory.
@@ -343,7 +347,12 @@ module Bolt
343
347
  bolt inventory show [options]
344
348
 
345
349
  DESCRIPTION
346
- Show the list of targets an action would run on.
350
+ Show the list of targets an action would run on. This command will list
351
+ all targets in the project's inventory by default.
352
+
353
+ To filter the targets in the list, use the --targets, --query, or --rerun
354
+ options. To view detailed configuration and data for targets, use the
355
+ --detail option.
347
356
  HELP
348
357
 
349
358
  MODULE_HELP = <<~HELP
@@ -432,7 +441,7 @@ module Bolt
432
441
  plan
433
442
 
434
443
  USAGE
435
- bolt plan <action> [parameters] [options]
444
+ bolt plan <action> [options]
436
445
 
437
446
  DESCRIPTION
438
447
  Convert, create, show, and run Bolt plans.
@@ -449,16 +458,18 @@ module Bolt
449
458
  convert
450
459
 
451
460
  USAGE
452
- bolt plan convert <path> [options]
461
+ bolt plan convert <plan name> [options]
453
462
 
454
463
  DESCRIPTION
455
- Convert a YAML plan to a Puppet language plan and print the converted plan to stdout.
464
+ Convert a YAML plan to a Puppet language plan and print the converted
465
+ plan to stdout.
456
466
 
457
467
  Converting a YAML plan might result in a plan that is syntactically
458
468
  correct but has different behavior. Always verify a converted plan's
459
469
  functionality. Note that the converted plan is not written to a file.
460
470
 
461
471
  EXAMPLES
472
+ bolt plan convert myproject::myplan
462
473
  bolt plan convert path/to/plan/myplan.yaml
463
474
  HELP
464
475
 
@@ -467,7 +478,7 @@ module Bolt
467
478
  new
468
479
 
469
480
  USAGE
470
- bolt plan new <plan> [options]
481
+ bolt plan new <plan name> [options]
471
482
 
472
483
  DESCRIPTION
473
484
  Create a new plan in the current project.
@@ -481,7 +492,7 @@ module Bolt
481
492
  run
482
493
 
483
494
  USAGE
484
- bolt plan run <plan> [parameters] [options]
495
+ bolt plan run <plan name> [parameters] [options]
485
496
 
486
497
  DESCRIPTION
487
498
  Run a plan on the specified targets.
@@ -495,7 +506,7 @@ module Bolt
495
506
  show
496
507
 
497
508
  USAGE
498
- bolt plan show [plan] [options]
509
+ bolt plan show [plan name] [options]
499
510
 
500
511
  DESCRIPTION
501
512
  Show available plans and plan documentation.
@@ -557,7 +568,8 @@ module Bolt
557
568
  bolt project migrate [options]
558
569
 
559
570
  DESCRIPTION
560
- Migrate a Bolt project to use current best practices and the latest version of configuration files.
571
+ Migrate a Bolt project to use current best practices and the latest version of
572
+ configuration files.
561
573
  HELP
562
574
 
563
575
  SCRIPT_HELP = <<~HELP
@@ -579,7 +591,8 @@ module Bolt
579
591
  run
580
592
 
581
593
  USAGE
582
- bolt script run <script> [arguments] [options]
594
+ bolt script run <script> [arguments] {--targets TARGETS | --query QUERY | --rerun FILTER}
595
+ [options]
583
596
 
584
597
  DESCRIPTION
585
598
  Run a script on the specified targets.
@@ -661,7 +674,8 @@ module Bolt
661
674
  run
662
675
 
663
676
  USAGE
664
- bolt task run <task> [parameters] [options]
677
+ bolt task run <task name> [parameters] {--targets TARGETS | --query QUERY | --rerun FILTER}
678
+ [options]
665
679
 
666
680
  DESCRIPTION
667
681
  Run a task on the specified targets.
@@ -677,7 +691,7 @@ module Bolt
677
691
  show
678
692
 
679
693
  USAGE
680
- bolt task show [task] [options]
694
+ bolt task show [task name] [options]
681
695
 
682
696
  DESCRIPTION
683
697
  Show available tasks and task documentation.
@@ -710,7 +724,8 @@ module Bolt
710
724
  "SSH is the default protocol; can be #{TRANSPORTS.keys.join(', ')}",
711
725
  'For Windows targets, specify the winrm:// protocol if it has not be configured',
712
726
  'For SSH, port defaults to `22`',
713
- 'For WinRM, port defaults to `5985` or `5986` based on the --[no-]ssl setting') do |targets|
727
+ 'For WinRM, port defaults to `5985` or `5986` based on the --[no-]ssl setting',
728
+ "For more information, see 'bolt guide targets'.") do |targets|
714
729
  @options[:targets] ||= []
715
730
  @options[:targets] << Bolt::Util.get_arg_input(targets)
716
731
  end
@@ -888,7 +903,10 @@ module Bolt
888
903
  define('-v', '--[no-]verbose', 'Display verbose logging') do |value|
889
904
  @options[:verbose] = value
890
905
  end
891
- define('--stream', 'Stream output from scripts and commands to the console') do |_|
906
+ define('--stream',
907
+ 'Stream output from scripts and commands to the console.',
908
+ 'Run with --no-verbose to prevent Bolt from displaying output',
909
+ 'a second time after the action is completed.') do |_|
892
910
  @options[:stream] = true
893
911
  end
894
912
  define('--trace', 'Display error stack traces') do |_|
data/lib/bolt/cli.rb CHANGED
@@ -47,6 +47,8 @@ module Bolt
47
47
  'guide' => %w[]
48
48
  }.freeze
49
49
 
50
+ TARGETING_OPTIONS = %i[query rerun targets].freeze
51
+
50
52
  attr_reader :config, :options
51
53
 
52
54
  def initialize(argv)
@@ -96,6 +98,48 @@ module Bolt
96
98
  finalize_setup
97
99
  end
98
100
 
101
+ # Prints a welcome message when users first install Bolt and run `bolt`, `bolt help` or `bolt --help`
102
+ def welcome_message
103
+ bolt = <<~BOLT
104
+ `.::-`
105
+ `.-:///////-.`
106
+ `-:////:. `-:///:- /ooo. .ooo/
107
+ `.-:///::///:-` `-//: ymmm- :mmmy .---.
108
+ :///:-. `.:////. -//: ymmm- :mmmy +mmm+
109
+ ://. ///. -//: ymmm--/++/- `-/++/:` :mmmy-:smmms::-
110
+ ://. ://. .://: ymmmdmmmmmmdo` .smmmmmmmmh: :mmmysmmmmmmmms
111
+ ://. ://:///:-. ymmmh/--/hmmmy -mmmd/-.:hmmm+:mmmy.-smmms--.
112
+ ://:.` .-////:-` ymmm- ymmm:hmmm- `dmmm/mmmy +mmm+
113
+ `-:///:-..:///:-.` ymmm- ommm/dmmm` hmmm+mmmy +mmm+
114
+ `.-:////:-` ymmm+ /mmmm.ommms` /mmmh:mmmy +mmmo
115
+ `-.` ymmmmmhhmmmmd: ommmmhydmmmy`:mmmy -mmmmdhd
116
+ oyyy+shddhs/` .+shddhy+- -yyyo .ohddhs
117
+
118
+
119
+ BOLT
120
+ example_cmd = if Bolt::Util.windows?
121
+ "Invoke-BoltCommand -Command 'hostname' -Targets localhost"
122
+ else
123
+ "bolt command run 'hostname' --target localhost"
124
+ end
125
+ prev_cmd = String.new("bolt")
126
+ prev_cmd << " #{@argv[0]}" unless @argv.empty?
127
+
128
+ message = <<~MSG
129
+ 🎉 Welcome to Bolt #{VERSION}
130
+ 😌 We're here to help bring order to the chaos
131
+ 📖 Find our documentation at https://bolt.guide
132
+ 🙋 Ask a question in #bolt on https://slack.puppet.com/
133
+ 🔩 Contribute at https://github.com/puppetlabs/bolt/
134
+ 💡 Not sure where to start? Try "#{example_cmd}"
135
+
136
+ We only print this message once. Run "#{prev_cmd}" again for help text.
137
+ MSG
138
+
139
+ $stdout.print "\033[36m#{bolt}\033[0m"
140
+ $stdout.print message
141
+ end
142
+
99
143
  # Parses the command and validates options. All errors that are raised here
100
144
  # are not handled by the outputter, as it relies on config being loaded.
101
145
  def parse_command
@@ -107,6 +151,16 @@ module Bolt
107
151
  # help text
108
152
  options[:subcommand] = nil unless COMMANDS.include?(options[:subcommand])
109
153
 
154
+ if Bolt::Util.first_run?
155
+ FileUtils.mkdir_p(Bolt::Util.first_runs_free.dirname)
156
+ FileUtils.touch(Bolt::Util.first_runs_free)
157
+
158
+ if options[:subcommand].nil? && $stdout.isatty
159
+ welcome_message
160
+ raise Bolt::CLIExit
161
+ end
162
+ end
163
+
110
164
  # Update the parser for the subcommand (or lack thereof)
111
165
  parser.update
112
166
  puts parser.help
@@ -210,7 +264,7 @@ module Bolt
210
264
  end
211
265
 
212
266
  def update_targets(options)
213
- target_opts = options.keys.select { |opt| %i[query rerun targets].include?(opt) }
267
+ target_opts = options.keys.select { |opt| TARGETING_OPTIONS.include?(opt) }
214
268
  target_string = "'--targets', '--rerun', or '--query'"
215
269
  if target_opts.length > 1
216
270
  raise Bolt::CLIError, "Only one targeting option #{target_string} can be specified"
@@ -489,7 +543,11 @@ module Bolt
489
543
  end
490
544
  code = apply_manifest(options[:code], options[:targets], options[:object], options[:noop])
491
545
  else
492
- executor = Bolt::Executor.new(config.concurrency, analytics, options[:noop], config.modified_concurrency)
546
+ executor = Bolt::Executor.new(config.concurrency,
547
+ analytics,
548
+ options[:noop],
549
+ config.modified_concurrency,
550
+ config.future)
493
551
  targets = options[:targets]
494
552
 
495
553
  results = nil
@@ -578,8 +636,39 @@ module Bolt
578
636
  end
579
637
 
580
638
  def list_targets
581
- inventoryfile = config.inventoryfile || config.default_inventoryfile
639
+ if options.keys.any? { |key| TARGETING_OPTIONS.include?(key) }
640
+ target_flag = true
641
+ else
642
+ options[:targets] = 'all'
643
+ end
644
+
645
+ outputter.print_targets(
646
+ group_targets_by_source,
647
+ inventory.source,
648
+ config.default_inventoryfile,
649
+ target_flag
650
+ )
651
+ end
582
652
 
653
+ def show_targets
654
+ if options.keys.any? { |key| TARGETING_OPTIONS.include?(key) }
655
+ target_flag = true
656
+ else
657
+ options[:targets] = 'all'
658
+ end
659
+
660
+ outputter.print_target_info(
661
+ group_targets_by_source,
662
+ inventory.source,
663
+ config.default_inventoryfile,
664
+ target_flag
665
+ )
666
+ end
667
+
668
+ # Returns a hash of targets sorted by those that are found in the
669
+ # inventory and those that are provided on the command line.
670
+ #
671
+ private def group_targets_by_source
583
672
  # Retrieve the known group and target names. This needs to be done before
584
673
  # updating targets, as that will add adhoc targets to the inventory.
585
674
  known_names = inventory.target_names
@@ -590,22 +679,11 @@ module Bolt
590
679
  known_names.include?(target.name)
591
680
  end
592
681
 
593
- target_list = {
594
- inventory: inventory_targets,
595
- adhoc: adhoc_targets
596
- }
597
-
598
- outputter.print_targets(target_list, inventoryfile)
599
- end
600
-
601
- def show_targets
602
- update_targets(options)
603
- outputter.print_target_info(options[:targets])
682
+ { inventory: inventory_targets, adhoc: adhoc_targets }
604
683
  end
605
684
 
606
685
  def list_groups
607
- groups = inventory.group_names
608
- outputter.print_groups(groups)
686
+ outputter.print_groups(inventory.group_names.sort, inventory.source, config.default_inventoryfile)
609
687
  end
610
688
 
611
689
  def run_plan(plan_name, plan_arguments, nodes, options)
@@ -636,7 +714,11 @@ module Bolt
636
714
  plan_context = { plan_name: plan_name,
637
715
  params: plan_arguments }
638
716
 
639
- executor = Bolt::Executor.new(config.concurrency, analytics, options[:noop], config.modified_concurrency)
717
+ executor = Bolt::Executor.new(config.concurrency,
718
+ analytics,
719
+ options[:noop],
720
+ config.modified_concurrency,
721
+ config.future)
640
722
  if %w[human rainbow].include?(options.fetch(:format, 'human'))
641
723
  executor.subscribe(outputter)
642
724
  else
@@ -672,7 +754,11 @@ module Bolt
672
754
  Bolt::Logger.warn("empty_manifest", message)
673
755
  end
674
756
 
675
- executor = Bolt::Executor.new(config.concurrency, analytics, noop, config.modified_concurrency)
757
+ executor = Bolt::Executor.new(config.concurrency,
758
+ analytics,
759
+ noop,
760
+ config.modified_concurrency,
761
+ config.future)
676
762
  executor.subscribe(outputter) if options.fetch(:format, 'human') == 'human'
677
763
  executor.subscribe(log_outputter)
678
764
  # apply logging looks like plan logging, so tell the outputter we're in a
@@ -757,15 +843,10 @@ module Bolt
757
843
  #
758
844
  def assert_project_file(project)
759
845
  unless project.project_file?
760
- msg = if project.config_file.exist?
761
- command = Bolt::Util.powershell? ? 'Update-BoltProject' : 'bolt project migrate'
762
- "Detected Bolt configuration file #{project.config_file}, unable to install "\
763
- "modules. To update to a project configuration file, run '#{command}'."
764
- else
765
- command = Bolt::Util.powershell? ? 'New-BoltProject' : 'bolt project init'
766
- "Could not find project configuration file #{project.project_file}, unable "\
767
- "to install modules. To create a Bolt project, run '#{command}'."
768
- end
846
+ command = Bolt::Util.powershell? ? 'New-BoltProject' : 'bolt project init'
847
+
848
+ msg = "Could not find project configuration file #{project.project_file}, unable "\
849
+ "to install modules. To create a Bolt project, run '#{command}'."
769
850
 
770
851
  raise Bolt::Error.new(msg, 'bolt/missing-project-config-error')
771
852
  end
@@ -883,7 +964,7 @@ module Bolt
883
964
 
884
965
  def analytics
885
966
  @analytics ||= begin
886
- client = Bolt::Analytics.build_client
967
+ client = Bolt::Analytics.build_client(config.analytics)
887
968
  client.bundled_content = bundled_content
888
969
  client
889
970
  end