bolt 2.32.0 → 2.36.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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +6 -6
  3. data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +1 -0
  4. data/bolt-modules/boltlib/lib/puppet/functions/catch_errors.rb +1 -3
  5. data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +17 -6
  6. data/bolt-modules/boltlib/lib/puppet/functions/facts.rb +6 -0
  7. data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +56 -0
  8. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +2 -2
  9. data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +24 -6
  10. data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +27 -8
  11. data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +21 -1
  12. data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +18 -1
  13. data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +24 -6
  14. data/guides/logging.txt +18 -0
  15. data/lib/bolt/analytics.rb +27 -8
  16. data/lib/bolt/apply_result.rb +3 -3
  17. data/lib/bolt/bolt_option_parser.rb +43 -15
  18. data/lib/bolt/cli.rb +79 -227
  19. data/lib/bolt/config.rb +131 -52
  20. data/lib/bolt/config/options.rb +46 -8
  21. data/lib/bolt/config/transport/base.rb +10 -19
  22. data/lib/bolt/config/transport/local.rb +0 -7
  23. data/lib/bolt/config/transport/options.rb +1 -1
  24. data/lib/bolt/config/transport/ssh.rb +8 -14
  25. data/lib/bolt/config/validator.rb +231 -0
  26. data/lib/bolt/error.rb +37 -3
  27. data/lib/bolt/executor.rb +103 -17
  28. data/lib/bolt/inventory/group.rb +2 -1
  29. data/lib/bolt/module_installer.rb +2 -1
  30. data/lib/bolt/module_installer/specs/forge_spec.rb +5 -4
  31. data/lib/bolt/module_installer/specs/git_spec.rb +4 -3
  32. data/lib/bolt/outputter/human.rb +21 -9
  33. data/lib/bolt/outputter/rainbow.rb +1 -1
  34. data/lib/bolt/pal.rb +48 -30
  35. data/lib/bolt/pal/yaml_plan.rb +11 -2
  36. data/lib/bolt/pal/yaml_plan/evaluator.rb +23 -1
  37. data/lib/bolt/pal/yaml_plan/loader.rb +14 -9
  38. data/lib/bolt/plan_creator.rb +160 -0
  39. data/lib/bolt/plugin.rb +1 -8
  40. data/lib/bolt/project.rb +30 -36
  41. data/lib/bolt/project_manager.rb +199 -0
  42. data/lib/bolt/{project_migrator/config.rb → project_manager/config_migrator.rb} +43 -5
  43. data/lib/bolt/{project_migrator/inventory.rb → project_manager/inventory_migrator.rb} +5 -5
  44. data/lib/bolt/{project_migrator/base.rb → project_manager/migrator.rb} +2 -2
  45. data/lib/bolt/{project_migrator/modules.rb → project_manager/module_migrator.rb} +3 -3
  46. data/lib/bolt/puppetdb/client.rb +3 -2
  47. data/lib/bolt/puppetdb/config.rb +9 -8
  48. data/lib/bolt/result.rb +23 -11
  49. data/lib/bolt/shell/bash.rb +12 -7
  50. data/lib/bolt/shell/powershell.rb +12 -7
  51. data/lib/bolt/task/run.rb +1 -1
  52. data/lib/bolt/transport/base.rb +18 -18
  53. data/lib/bolt/transport/docker.rb +23 -6
  54. data/lib/bolt/transport/orch.rb +23 -19
  55. data/lib/bolt/transport/orch/connection.rb +10 -3
  56. data/lib/bolt/transport/remote.rb +3 -3
  57. data/lib/bolt/transport/simple.rb +6 -6
  58. data/lib/bolt/transport/ssh/exec_connection.rb +6 -2
  59. data/lib/bolt/util.rb +19 -7
  60. data/lib/bolt/version.rb +1 -1
  61. data/lib/bolt/yarn.rb +23 -0
  62. data/lib/bolt_server/base_config.rb +3 -1
  63. data/lib/bolt_server/config.rb +3 -1
  64. data/lib/bolt_server/file_cache.rb +2 -0
  65. data/lib/bolt_server/schemas/partials/task.json +2 -2
  66. data/lib/bolt_server/transport_app.rb +42 -11
  67. data/lib/bolt_spec/plans/action_stubs/command_stub.rb +1 -1
  68. data/lib/bolt_spec/plans/action_stubs/script_stub.rb +1 -1
  69. data/lib/bolt_spec/plans/mock_executor.rb +9 -6
  70. data/libexec/apply_catalog.rb +1 -1
  71. data/libexec/custom_facts.rb +1 -1
  72. data/libexec/query_resources.rb +1 -1
  73. metadata +12 -14
  74. data/lib/bolt/project_migrator.rb +0 -80
  75. data/modules/secure_env_vars/plans/init.pp +0 -20
@@ -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,11 +6,12 @@ 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
17
  global: %w[help version debug log-level] }.freeze
@@ -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],
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
@@ -945,6 +968,11 @@ module Bolt
945
968
  @options[:resolve] = resolve
946
969
  end
947
970
 
971
+ separator "\nPLAN OPTIONS"
972
+ define('--pp', 'Create a new Puppet language plan.') do |pp|
973
+ @options[:puppet] = pp
974
+ end
975
+
948
976
  separator "\nDISPLAY OPTIONS"
949
977
  define('--filter FILTER', 'Filter tasks and plans by a matching substring') do |filter|
950
978
  unless /^[a-z0-9_:]+$/.match(filter)
@@ -15,20 +15,22 @@ require 'bolt/config'
15
15
  require 'bolt/error'
16
16
  require 'bolt/executor'
17
17
  require 'bolt/inventory'
18
- require 'bolt/rerun'
19
18
  require 'bolt/logger'
19
+ require 'bolt/module_installer'
20
20
  require 'bolt/outputter'
21
- require 'bolt/puppetdb'
22
- require 'bolt/plugin'
23
- require 'bolt/project_migrator'
24
21
  require 'bolt/pal'
22
+ require 'bolt/plan_creator'
23
+ require 'bolt/plugin'
24
+ require 'bolt/project_manager'
25
+ require 'bolt/puppetdb'
26
+ require 'bolt/rerun'
27
+ require 'bolt/secret'
25
28
  require 'bolt/target'
26
29
  require 'bolt/version'
27
- require 'bolt/secret'
28
- require 'bolt/module_installer'
29
30
 
30
31
  module Bolt
31
32
  class CLIExit < StandardError; end
33
+
32
34
  class CLI
33
35
  COMMANDS = {
34
36
  'command' => %w[run],
@@ -163,8 +165,9 @@ module Bolt
163
165
  elsif options[:configfile]
164
166
  Bolt::Config.from_file(options[:configfile], options)
165
167
  else
166
- project = if options[:boltdir]
167
- dir = Pathname.new(options[:boltdir])
168
+ cli_flag = options[:project] || options[:boltdir]
169
+ project = if cli_flag
170
+ dir = Pathname.new(cli_flag)
168
171
  if (dir + Bolt::Project::BOLTDIR_NAME).directory?
169
172
  Bolt::Project.create_project(dir + Bolt::Project::BOLTDIR_NAME)
170
173
  else
@@ -196,10 +199,6 @@ module Bolt
196
199
 
197
200
  warn_inventory_overrides_cli(options)
198
201
 
199
- # Assert whether the puppetfile/module commands are available depending
200
- # on whether 'modules' is configured.
201
- assert_puppetfile_or_module_command(config.project.modules)
202
-
203
202
  options
204
203
  rescue Bolt::Error => e
205
204
  outputter.fatal_error(e)
@@ -228,9 +227,9 @@ module Bolt
228
227
 
229
228
  def validate(options)
230
229
  unless COMMANDS.include?(options[:subcommand])
230
+ command = Bolt::Util.powershell? ? 'Get-Command -Module PuppetBolt' : 'bolt help'
231
231
  raise Bolt::CLIError,
232
- "Expected subcommand '#{options[:subcommand]}' to be one of " \
233
- "#{COMMANDS.keys.join(', ')}"
232
+ "'#{options[:subcommand]}' is not a Bolt command. See '#{command}'."
234
233
  end
235
234
 
236
235
  actions = COMMANDS[options[:subcommand]]
@@ -285,8 +284,9 @@ module Bolt
285
284
  end
286
285
 
287
286
  if options[:subcommand] == 'module' && options[:action] == 'install' && options[:object]
287
+ command = Bolt::Util.powershell? ? 'Add-BoltModule -Module' : 'bolt module add'
288
288
  raise Bolt::CLIError, "Invalid argument '#{options[:object]}'. To add a new module to "\
289
- "the project, run 'bolt module add #{options[:object]}'."
289
+ "the project, run '#{command} #{options[:object]}'."
290
290
  end
291
291
 
292
292
  if options[:subcommand] != 'file' && options[:subcommand] != 'script' &&
@@ -295,7 +295,7 @@ module Bolt
295
295
  "Unknown argument(s) #{options[:leftovers].join(', ')}"
296
296
  end
297
297
 
298
- if options[:boltdir] && options[:configfile]
298
+ if options.slice(:boltdir, :configfile, :project).length > 1
299
299
  raise Bolt::CLIError, "Only one of '--boltdir', '--project', or '--configfile' may be specified"
300
300
  end
301
301
 
@@ -342,15 +342,10 @@ module Bolt
342
342
  def warn_inventory_overrides_cli(opts)
343
343
  inventory_source = if ENV[Bolt::Inventory::ENVIRONMENT_VAR]
344
344
  Bolt::Inventory::ENVIRONMENT_VAR
345
- elsif config.inventoryfile && Bolt::Util.file_stat(config.inventoryfile)
345
+ elsif config.inventoryfile
346
346
  config.inventoryfile
347
- else
348
- begin
349
- Bolt::Util.file_stat(config.default_inventoryfile)
350
- config.default_inventoryfile
351
- rescue Errno::ENOENT
352
- nil
353
- end
347
+ elsif File.exist?(config.default_inventoryfile)
348
+ config.default_inventoryfile
354
349
  end
355
350
 
356
351
  inventory_cli_opts = %i[authentication escalation transports].each_with_object([]) do |key, acc|
@@ -394,7 +389,7 @@ module Bolt
394
389
  output_format: config.format,
395
390
  # For continuity
396
391
  boltdir_type: config.project.type
397
- }
392
+ }.merge!(analytics.plan_counts(config.project.plans_path))
398
393
 
399
394
  # Only include target and inventory info for commands that take a targets
400
395
  # list. This avoids loading inventory for commands that don't need it.
@@ -458,14 +453,22 @@ module Bolt
458
453
  when 'project'
459
454
  case options[:action]
460
455
  when 'init'
461
- code = initialize_project
456
+ code = Bolt::ProjectManager.new(config, outputter, pal)
457
+ .create(Dir.pwd, options[:object], options[:modules])
462
458
  when 'migrate'
463
- code = Bolt::ProjectMigrator.new(config, outputter).migrate
459
+ code = Bolt::ProjectManager.new(config, outputter, pal).migrate
464
460
  end
465
461
  when 'plan'
466
462
  case options[:action]
467
463
  when 'new'
468
- code = new_plan(options[:object])
464
+ plan_name = options[:object]
465
+
466
+ # If this passes validation, it will return the path to the plan to create
467
+ Bolt::PlanCreator.validate_input(config.project, plan_name)
468
+ code = Bolt::PlanCreator.create_plan(config.project.plans_path,
469
+ plan_name,
470
+ outputter,
471
+ options[:puppet])
469
472
  when 'run'
470
473
  code = run_plan(options[:object], options[:task_options], options[:target_args], options)
471
474
  end
@@ -568,10 +571,15 @@ module Bolt
568
571
  outputter.print_task_info(pal.get_task(task_name))
569
572
  end
570
573
 
574
+ # Filters a list of content by matching substring.
575
+ #
576
+ private def filter_content(content, filter)
577
+ return content unless content && filter
578
+ content.select { |name,| name.include?(filter) }
579
+ end
580
+
571
581
  def list_tasks
572
- tasks = pal.list_tasks
573
- tasks.select! { |task| task.first.include?(options[:filter]) } if options[:filter]
574
- tasks.select! { |task| config.project.tasks.include?(task.first) } unless config.project.tasks.nil?
582
+ tasks = filter_content(pal.list_tasks(filter_content: true), options[:filter])
575
583
  outputter.print_tasks(tasks, pal.user_modulepath)
576
584
  end
577
585
 
@@ -580,9 +588,7 @@ module Bolt
580
588
  end
581
589
 
582
590
  def list_plans
583
- plans = pal.list_plans
584
- plans.select! { |plan| plan.first.include?(options[:filter]) } if options[:filter]
585
- plans.select! { |plan| config.project.plans.include?(plan.first) } unless config.project.plans.nil?
591
+ plans = filter_content(pal.list_plans(filter_content: true), options[:filter])
586
592
  outputter.print_plans(plans, pal.user_modulepath)
587
593
  end
588
594
 
@@ -617,118 +623,6 @@ module Bolt
617
623
  outputter.print_groups(groups)
618
624
  end
619
625
 
620
- def new_plan(plan_name)
621
- @logger.warn("Command 'bolt plan new' is experimental and subject to changes.")
622
-
623
- if config.project.name.nil?
624
- raise Bolt::Error.new(
625
- "Project directory '#{config.project.path}' is not a named project. Unable to create "\
626
- "a project-level plan. To name a project, set the 'name' key in the 'bolt-project.yaml' "\
627
- "configuration file.",
628
- "bolt/unnamed-project-error"
629
- )
630
- end
631
-
632
- if plan_name !~ Bolt::Module::CONTENT_NAME_REGEX
633
- message = <<~MESSAGE.chomp
634
- Invalid plan name '#{plan_name}'. Plan names are composed of one or more name segments
635
- separated by double colons '::'.
636
-
637
- Each name segment must begin with a lowercase letter, and may only include lowercase
638
- letters, digits, and underscores.
639
-
640
- Examples of valid plan names:
641
- - #{config.project.name}
642
- - #{config.project.name}::my_plan
643
- MESSAGE
644
-
645
- raise Bolt::ValidationError, message
646
- end
647
-
648
- prefix, *name_segments, basename = plan_name.split('::')
649
-
650
- # If the plan name is just the project name, then create an 'init' plan.
651
- # Otherwise, use the last name segment for the plan's filename.
652
- basename ||= 'init'
653
-
654
- unless prefix == config.project.name
655
- message = "First segment of plan name '#{plan_name}' must match project name '#{config.project.name}'. "\
656
- "Did you mean '#{config.project.name}::#{plan_name}'?"
657
-
658
- raise Bolt::ValidationError, message
659
- end
660
-
661
- dir_path = config.project.plans_path.join(*name_segments)
662
-
663
- %w[pp yaml].each do |ext|
664
- next unless (path = config.project.plans_path + "#{basename}.#{ext}").exist?
665
- raise Bolt::Error.new(
666
- "A plan with the name '#{plan_name}' already exists at '#{path}', nothing to do.",
667
- 'bolt/existing-plan-error'
668
- )
669
- end
670
-
671
- begin
672
- FileUtils.mkdir_p(dir_path)
673
- rescue Errno::EEXIST => e
674
- raise Bolt::Error.new(
675
- "#{e.message}; unable to create plan directory '#{dir_path}'",
676
- 'bolt/existing-file-error'
677
- )
678
- end
679
-
680
- plan_path = dir_path + "#{basename}.yaml"
681
-
682
- plan_template = <<~PLAN
683
- # This is the structure of a simple plan. To learn more about writing
684
- # YAML plans, see the documentation: http://pup.pt/bolt-yaml-plans
685
-
686
- # The description sets the description of the plan that will appear
687
- # in 'bolt plan show' output.
688
- description: A plan created with bolt plan new
689
-
690
- # The parameters key defines the parameters that can be passed to
691
- # the plan.
692
- parameters:
693
- targets:
694
- type: TargetSpec
695
- description: A list of targets to run actions on
696
- default: localhost
697
-
698
- # The steps key defines the actions the plan will take in order.
699
- steps:
700
- - message: Hello from #{plan_name}
701
- - name: command_step
702
- command: whoami
703
- targets: $targets
704
-
705
- # The return key sets the return value of the plan.
706
- return: $command_step
707
- PLAN
708
-
709
- begin
710
- File.write(plan_path, plan_template)
711
- rescue Errno::EACCES => e
712
- raise Bolt::FileError.new(
713
- "#{e.message}; unable to create plan",
714
- plan_path
715
- )
716
- end
717
-
718
- output = <<~OUTPUT
719
- Created plan '#{plan_name}' at '#{plan_path}'
720
-
721
- Show this plan with:
722
- bolt plan show #{plan_name}
723
- Run this plan with:
724
- bolt plan run #{plan_name}
725
- OUTPUT
726
-
727
- outputter.print_message(output)
728
-
729
- 0
730
- end
731
-
732
626
  def run_plan(plan_name, plan_arguments, nodes, options)
733
627
  unless nodes.empty?
734
628
  if plan_arguments['nodes'] || plan_arguments['targets']
@@ -820,88 +714,22 @@ module Bolt
820
714
  end
821
715
 
822
716
  def list_modules
717
+ assert_puppetfile_or_module_command(config.project.modules)
823
718
  outputter.print_module_list(pal.list_modules)
824
719
  end
825
720
 
826
721
  def generate_types
722
+ assert_puppetfile_or_module_command(config.project.modules)
827
723
  # generate_types will surface a nice error with helpful message if it fails
828
724
  pal.generate_types
829
725
  0
830
726
  end
831
727
 
832
- # Initializes a specified directory as a Bolt project and installs any modules
833
- # specified by the user, along with their dependencies
834
- def initialize_project
835
- # Dir.pwd will return backslashes on Windows, but Pathname always uses
836
- # forward slashes to concatenate paths. This results in paths like
837
- # C:\User\Administrator/modules, which fail module install. This ensure
838
- # forward slashes in the cwd path.
839
- dir = File.expand_path(Dir.pwd)
840
- name = options[:object] || File.basename(dir)
841
- if name !~ Bolt::Module::MODULE_NAME_REGEX
842
- if options[:object]
843
- raise Bolt::ValidationError, "The provided project name '#{name}' is invalid; "\
844
- "project name must begin with a lowercase letter and can include lowercase "\
845
- "letters, numbers, and underscores."
846
- else
847
- raise Bolt::ValidationError, "The current directory name '#{name}' is an invalid "\
848
- "project name. Please specify a name using 'bolt project init <name>'."
849
- end
850
- end
851
-
852
- project = Pathname.new(dir)
853
- old_config = project + 'bolt.yaml'
854
- config = project + 'bolt-project.yaml'
855
- puppetfile = project + 'Puppetfile'
856
- moduledir = project + 'modules'
857
-
858
- # Warn the user if the project directory already exists. We don't error
859
- # here since users might not have installed any modules yet. If both
860
- # bolt.yaml and bolt-project.yaml exist, this will just warn about
861
- # bolt-project.yaml and subsequent Bolt actions will warn about both files
862
- # existing.
863
- if config.exist?
864
- @logger.warn "Found existing project directory at #{project}. Skipping file creation."
865
- elsif old_config.exist?
866
- @logger.warn "Found existing #{old_config.basename} at #{project}. "\
867
- "#{old_config.basename} is deprecated, please rename to #{config.basename}."
868
- end
869
-
870
- # If modules were specified, first check if there is already a Puppetfile
871
- # at the project directory, erroring if there is. If there is no
872
- # Puppetfile, install the specified modules. The module installer will
873
- # resolve dependencies, generate a Puppetfile, and install the modules.
874
- if options[:modules]
875
- if puppetfile.exist?
876
- raise Bolt::CLIError,
877
- "Found existing Puppetfile at #{puppetfile}, unable to initialize "\
878
- "project with modules."
879
- end
880
-
881
- installer = Bolt::ModuleInstaller.new(outputter, pal)
882
- installer.install(options[:modules], puppetfile, moduledir)
883
- end
884
-
885
- # If either bolt.yaml or bolt-project.yaml exist, the user has already
886
- # been warned and we can just finish project creation. Otherwise, create a
887
- # bolt-project.yaml with the project name in it.
888
- unless config.exist? || old_config.exist?
889
- begin
890
- content = { 'name' => name }
891
- File.write(config.to_path, content.to_yaml)
892
- outputter.print_message "Successfully created Bolt project at #{project}"
893
- rescue StandardError => e
894
- raise Bolt::FileError.new("Could not create bolt-project.yaml at #{project}: #{e.message}", nil)
895
- end
896
- end
897
-
898
- 0
899
- end
900
-
901
728
  # Installs modules declared in the project configuration file.
902
729
  #
903
730
  def install_project_modules(project, force, resolve)
904
731
  assert_project_file(project)
732
+ assert_puppetfile_or_module_command(project.modules)
905
733
 
906
734
  unless project.modules
907
735
  outputter.print_message "Project configuration file #{project.project_file} does not "\
@@ -923,6 +751,7 @@ module Bolt
923
751
  #
924
752
  def add_project_module(name, project)
925
753
  assert_project_file(project)
754
+ assert_puppetfile_or_module_command(project.modules)
926
755
 
927
756
  modules = project.modules || []
928
757
  installer = Bolt::ModuleInstaller.new(outputter, pal)
@@ -940,11 +769,13 @@ module Bolt
940
769
  def assert_project_file(project)
941
770
  unless project.project_file?
942
771
  msg = if project.config_file.exist?
772
+ command = Bolt::Util.powershell? ? 'Update-BoltProject' : 'bolt project migrate'
943
773
  "Detected Bolt configuration file #{project.config_file}, unable to install "\
944
- "modules. To update to a project configuration file, run 'bolt project migrate'."
774
+ "modules. To update to a project configuration file, run '#{command}'."
945
775
  else
776
+ command = Bolt::Util.powershell? ? 'New-BoltProject' : 'bolt project init'
946
777
  "Could not find project configuration file #{project.project_file}, unable "\
947
- "to install modules. To create a Bolt project, run 'bolt project init'."
778
+ "to install modules. To create a Bolt project, run '#{command}'."
948
779
  end
949
780
 
950
781
  raise Bolt::Error.new(msg, 'bolt/missing-project-config-error')
@@ -953,10 +784,12 @@ module Bolt
953
784
 
954
785
  # Loads a Puppetfile and installs its modules.
955
786
  #
956
- def install_puppetfile(config, puppetfile, moduledir)
787
+ def install_puppetfile(puppetfile_config, puppetfile, moduledir)
788
+ assert_puppetfile_or_module_command(config.project.modules)
789
+
957
790
  outputter.print_message("Installing modules from Puppetfile")
958
791
  installer = Bolt::ModuleInstaller.new(outputter, pal)
959
- ok = installer.install_puppetfile(puppetfile, moduledir, config)
792
+ ok = installer.install_puppetfile(puppetfile, moduledir, puppetfile_config)
960
793
  ok ? 0 : 1
961
794
  end
962
795
 
@@ -964,17 +797,36 @@ module Bolt
964
797
  # modules being configured.
965
798
  #
966
799
  def assert_puppetfile_or_module_command(modules)
800
+ if Bolt::Util.powershell?
801
+ case options[:action]
802
+ when 'generate-types'
803
+ old_command = 'Register-BoltPuppetfileTypes'
804
+ new_command = 'Register-BoltModuleTypes'
805
+ when 'install'
806
+ old_command = 'Install-BoltPuppetfile'
807
+ new_command = 'Install-BoltModule'
808
+ when 'show', 'show-modules'
809
+ old_command = 'Get-BoltPuppetfileModules'
810
+ new_command = 'Get-BoltModule'
811
+ end
812
+ else
813
+ old_command = "bolt puppetfile #{options[:action]}"
814
+ new_command = if options[:action] == 'show-modules'
815
+ 'bolt module show'
816
+ else
817
+ "bolt module #{options[:action]}"
818
+ end
819
+ end
820
+
967
821
  if modules && options[:subcommand] == 'puppetfile'
968
822
  raise Bolt::CLIError,
969
- "Unable to use command 'bolt puppetfile #{options[:action]}' when "\
970
- "'modules' is configured in bolt-project.yaml. Use the 'module' command "\
971
- "instead. For a list of available actions for the 'module' command, run "\
972
- "'bolt module --help'."
823
+ "Unable to use command '#{old_command}' when 'modules' is configured in "\
824
+ "bolt-project.yaml. Use '#{new_command}' instead."
973
825
  elsif modules.nil? && options[:subcommand] == 'module'
974
- raise Bolt::CLIError,
975
- "Unable to use command 'bolt module #{options[:action]}'. To use "\
976
- "this command, update your project configuration to manage module "\
977
- "dependencies."
826
+ msg = "Unable to use command '#{new_command}' when 'modules' is not configured in "\
827
+ "bolt-project.yaml. "
828
+ msg += "Use '#{old_command}' instead." if options[:action] != 'add'
829
+ raise Bolt::CLIError, msg
978
830
  end
979
831
  end
980
832