bolt 3.9.2 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/guides/debugging.txt +28 -0
- data/lib/bolt/bolt_option_parser.rb +49 -2
- data/lib/bolt/cli.rb +38 -9
- data/lib/bolt/outputter/human.rb +32 -0
- data/lib/bolt/outputter/json.rb +9 -0
- data/lib/bolt/pal.rb +98 -14
- data/lib/bolt/plugin.rb +38 -0
- data/lib/bolt/plugin/env_var.rb +8 -1
- data/lib/bolt/plugin/module.rb +1 -1
- data/lib/bolt/plugin/prompt.rb +8 -1
- data/lib/bolt/plugin/puppet_connect_data.rb +8 -1
- data/lib/bolt/plugin/puppetdb.rb +7 -1
- data/lib/bolt/plugin/task.rb +9 -1
- data/lib/bolt/project.rb +2 -1
- data/lib/bolt/task.rb +7 -0
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_spec/plans/mock_executor.rb +1 -1
- data/resources/bolt_bash_completion.sh +214 -0
- metadata +4 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: fa1075046a81e0596ff3f0483dc7b7a5913a073dd6e998f66c70687049531e74
         | 
| 4 | 
            +
              data.tar.gz: 9cdb2d3503e1bd2d84fa7c0fc846e3f4d2293780f648d9d07d549fd50d2b1a51
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 4b2f636ec7f5f038b69cd5c4f82e9fd93e59521035e15fa678cef67501a4e00287e29f40ce1672d2f5db0fa4972cbc26d9763f62480612e30ebcfae404d12a1f
         | 
| 7 | 
            +
              data.tar.gz: f87b3966ea10cf5a5fe46937e9a47b73d4553924bff00ee578f6c659a70fe82864e2cc78b76a685dfb9e3d4a4e5a3fb7bea136730bf6b5160454e665f4f02ea8
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            TOPIC
         | 
| 2 | 
            +
                debugging
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            DESCRIPTION
         | 
| 5 | 
            +
                When Bolt isn't behaving as expected, there are a few helpful commands and
         | 
| 6 | 
            +
                logs that can help identify common issues. The first place to look is in
         | 
| 7 | 
            +
                `<PROJECT>/bolt-debug.log`, which contains debug-level logs from the last Bolt
         | 
| 8 | 
            +
                run. This log file includes where the Bolt project was loaded from, the
         | 
| 9 | 
            +
                location of any configuration or inventory files that were loaded, and the
         | 
| 10 | 
            +
                modulepath that modules were loaded from.
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                If you're having issues with loading targets or target configuration, you
         | 
| 13 | 
            +
                can see the list of resolved Bolt target names by running `bolt inventory
         | 
| 14 | 
            +
                show` on *nix systems or `Get-BoltInventory` in PowerShell. To see the
         | 
| 15 | 
            +
                resolved configuration for each target, run the command with the `--detail` or
         | 
| 16 | 
            +
                `-Detail` options.
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                Lastly, if you're having trouble loading Bolt content you can use `bolt
         | 
| 19 | 
            +
                module show` on *nix systems or `Get-BoltModule` in PowerShell to see the list
         | 
| 20 | 
            +
                of loaded modules, including where they were loaded from. You can also use
         | 
| 21 | 
            +
                `bolt task show` or `Get-BoltTask` to list loaded tasks, and `bolt plan show`
         | 
| 22 | 
            +
                or `Get-BoltPlan` to list loaded plans.
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                Visit the linked documentation for more in-depth troubleshooting help for
         | 
| 25 | 
            +
                specific issues.
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            DOCUMENTATION
         | 
| 28 | 
            +
                https://pup.pt/bolt-troubleshooting
         | 
| @@ -67,7 +67,7 @@ module Bolt | |
| 67 67 | 
             
                    { flags: OPTIONS[:global] + %w[format],
         | 
| 68 68 | 
             
                      banner: GUIDE_HELP }
         | 
| 69 69 | 
             
                  when 'lookup'
         | 
| 70 | 
            -
                    { flags: ACTION_OPTS + %w[hiera-config],
         | 
| 70 | 
            +
                    { flags: ACTION_OPTS + %w[hiera-config plan-hierarchy],
         | 
| 71 71 | 
             
                      banner: LOOKUP_HELP }
         | 
| 72 72 | 
             
                  when 'module'
         | 
| 73 73 | 
             
                    case action
         | 
| @@ -105,6 +105,15 @@ module Bolt | |
| 105 105 | 
             
                      { flags: OPTIONS[:global],
         | 
| 106 106 | 
             
                        banner: PLAN_HELP }
         | 
| 107 107 | 
             
                    end
         | 
| 108 | 
            +
                  when 'plugin'
         | 
| 109 | 
            +
                    case action
         | 
| 110 | 
            +
                    when 'show'
         | 
| 111 | 
            +
                      { flags: OPTIONS[:global] + %w[color format modulepath project],
         | 
| 112 | 
            +
                        banner: PLUGIN_SHOW_HELP }
         | 
| 113 | 
            +
                    else
         | 
| 114 | 
            +
                      { flags: OPTIONS[:global],
         | 
| 115 | 
            +
                        banner: PLUGIN_HELP }
         | 
| 116 | 
            +
                    end
         | 
| 108 117 | 
             
                  when 'project'
         | 
| 109 118 | 
             
                    case action
         | 
| 110 119 | 
             
                    when 'init'
         | 
| @@ -192,6 +201,7 @@ module Bolt | |
| 192 201 | 
             
                      module            Manage Bolt project modules
         | 
| 193 202 | 
             
                      lookup            Look up a value with Hiera
         | 
| 194 203 | 
             
                      plan              Convert, create, show, and run Bolt plans
         | 
| 204 | 
            +
                      plugin            Show available plugins
         | 
| 195 205 | 
             
                      project           Create and migrate Bolt projects
         | 
| 196 206 | 
             
                      script            Upload a local script and run it remotely
         | 
| 197 207 | 
             
                      secret            Create encryption keys and encrypt and decrypt values
         | 
| @@ -407,7 +417,7 @@ module Bolt | |
| 407 417 | 
             
                      lookup
         | 
| 408 418 |  | 
| 409 419 | 
             
                  #{colorize(:cyan, 'Usage')}
         | 
| 410 | 
            -
                      bolt lookup <key> {--targets TARGETS | --query QUERY | --rerun FILTER}
         | 
| 420 | 
            +
                      bolt lookup <key> {--targets TARGETS | --query QUERY | --rerun FILTER | --plan-hierarchy}
         | 
| 411 421 | 
             
                        [options]
         | 
| 412 422 |  | 
| 413 423 | 
             
                  #{colorize(:cyan, 'Description')}
         | 
| @@ -418,6 +428,7 @@ module Bolt | |
| 418 428 |  | 
| 419 429 | 
             
                  #{colorize(:cyan, 'Examples')}
         | 
| 420 430 | 
             
                      bolt lookup password --targets servers
         | 
| 431 | 
            +
                      bolt lookup password --plan-hierarchy variable=value
         | 
| 421 432 | 
             
                HELP
         | 
| 422 433 |  | 
| 423 434 | 
             
                MODULE_HELP = <<~HELP
         | 
| @@ -608,6 +619,37 @@ module Bolt | |
| 608 619 | 
             
                        bolt plan show aggregate::count
         | 
| 609 620 | 
             
                HELP
         | 
| 610 621 |  | 
| 622 | 
            +
                PLUGIN_HELP = <<~HELP
         | 
| 623 | 
            +
                  #{colorize(:cyan, 'Name')}
         | 
| 624 | 
            +
                      plugin
         | 
| 625 | 
            +
             | 
| 626 | 
            +
                  #{colorize(:cyan, 'Usage')}
         | 
| 627 | 
            +
                      bolt plugin <action> [options]
         | 
| 628 | 
            +
             | 
| 629 | 
            +
                  #{colorize(:cyan, 'Description')}
         | 
| 630 | 
            +
                      Show available plugins.
         | 
| 631 | 
            +
             | 
| 632 | 
            +
                  #{colorize(:cyan, 'Documentation')}
         | 
| 633 | 
            +
                      Learn more about Bolt plugins at https://pup.pt/bolt-plugins.
         | 
| 634 | 
            +
             | 
| 635 | 
            +
                  #{colorize(:cyan, 'Actions')}
         | 
| 636 | 
            +
                      show          Show available plugins
         | 
| 637 | 
            +
                HELP
         | 
| 638 | 
            +
             | 
| 639 | 
            +
                PLUGIN_SHOW_HELP = <<~HELP
         | 
| 640 | 
            +
                  #{colorize(:cyan, 'Name')}
         | 
| 641 | 
            +
                      show
         | 
| 642 | 
            +
             | 
| 643 | 
            +
                  #{colorize(:cyan, 'Usage')}
         | 
| 644 | 
            +
                      bolt plugin show [options]
         | 
| 645 | 
            +
             | 
| 646 | 
            +
                  #{colorize(:cyan, 'Description')}
         | 
| 647 | 
            +
                      Show available plugins.
         | 
| 648 | 
            +
             | 
| 649 | 
            +
                  #{colorize(:cyan, 'Documentation')}
         | 
| 650 | 
            +
                      Learn more about Bolt plugins at https://pup.pt/bolt-plugins.
         | 
| 651 | 
            +
                HELP
         | 
| 652 | 
            +
             | 
| 611 653 | 
             
                PROJECT_HELP = <<~HELP
         | 
| 612 654 | 
             
                  #{colorize(:cyan, 'Name')}
         | 
| 613 655 | 
             
                      project
         | 
| @@ -988,6 +1030,11 @@ module Bolt | |
| 988 1030 | 
             
                    @options[:resolve] = resolve
         | 
| 989 1031 | 
             
                  end
         | 
| 990 1032 |  | 
| 1033 | 
            +
                  separator "\n#{self.class.colorize(:cyan, 'Lookup options')}"
         | 
| 1034 | 
            +
                  define('--plan-hierarchy', 'Look up a value with Hiera in the context of a specific plan.') do |_|
         | 
| 1035 | 
            +
                    @options[:plan_hierarchy] = true
         | 
| 1036 | 
            +
                  end
         | 
| 1037 | 
            +
             | 
| 991 1038 | 
             
                  separator "\n#{self.class.colorize(:cyan, 'Plan options')}"
         | 
| 992 1039 | 
             
                  define('--pp', 'Create a new Puppet language plan.') do |_|
         | 
| 993 1040 | 
             
                    @options[:puppet] = true
         | 
    
        data/lib/bolt/cli.rb
    CHANGED
    
    | @@ -42,6 +42,7 @@ module Bolt | |
| 42 42 | 
             
                  'lookup'    => %w[],
         | 
| 43 43 | 
             
                  'module'    => %w[add generate-types install show],
         | 
| 44 44 | 
             
                  'plan'      => %w[show run convert new],
         | 
| 45 | 
            +
                  'plugin'    => %w[show],
         | 
| 45 46 | 
             
                  'project'   => %w[init migrate],
         | 
| 46 47 | 
             
                  'script'    => %w[run],
         | 
| 47 48 | 
             
                  'secret'    => %w[encrypt decrypt createkeys],
         | 
| @@ -354,12 +355,18 @@ module Bolt | |
| 354 355 | 
             
                                          "the project, run '#{command} #{options[:object]}'."
         | 
| 355 356 | 
             
                  end
         | 
| 356 357 |  | 
| 357 | 
            -
                  if  | 
| 358 | 
            +
                  if !%w[file script lookup].include?(options[:subcommand]) &&
         | 
| 358 359 | 
             
                     !options[:leftovers].empty?
         | 
| 359 360 | 
             
                    raise Bolt::CLIError,
         | 
| 360 361 | 
             
                          "Unknown argument(s) #{options[:leftovers].join(', ')}"
         | 
| 361 362 | 
             
                  end
         | 
| 362 363 |  | 
| 364 | 
            +
                  target_opts = options.keys.select { |opt| TARGETING_OPTIONS.include?(opt) }
         | 
| 365 | 
            +
                  if options[:subcommand] == 'lookup' &&
         | 
| 366 | 
            +
                     target_opts.any? && options[:plan_hierarchy]
         | 
| 367 | 
            +
                    raise Bolt::CLIError, "The 'lookup' command accepts either targeting option OR --plan-hierarchy."
         | 
| 368 | 
            +
                  end
         | 
| 369 | 
            +
             | 
| 363 370 | 
             
                  if options[:noop] &&
         | 
| 364 371 | 
             
                     !(options[:subcommand] == 'task' && options[:action] == 'run') && options[:subcommand] != 'apply'
         | 
| 365 372 | 
             
                    raise Bolt::CLIError,
         | 
| @@ -432,10 +439,11 @@ module Bolt | |
| 432 439 | 
             
                  end
         | 
| 433 440 |  | 
| 434 441 | 
             
                  # Initialize inventory and targets. Errors here are better to catch early.
         | 
| 435 | 
            -
                  # options[:target_args] will contain a string/array version of the  | 
| 442 | 
            +
                  # options[:target_args] will contain a string/array version of the targeting options this is passed to plans
         | 
| 436 443 | 
             
                  # options[:targets] will contain a resolved set of Target objects
         | 
| 437 444 | 
             
                  unless %w[guide module project secret].include?(options[:subcommand]) ||
         | 
| 438 | 
            -
                         %w[convert new show].include?(options[:action])
         | 
| 445 | 
            +
                         %w[convert new show].include?(options[:action]) ||
         | 
| 446 | 
            +
                         options[:plan_hierarchy]
         | 
| 439 447 | 
             
                    update_targets(options)
         | 
| 440 448 | 
             
                  end
         | 
| 441 449 |  | 
| @@ -487,6 +495,8 @@ module Bolt | |
| 487 495 | 
             
                      list_groups
         | 
| 488 496 | 
             
                    when 'module'
         | 
| 489 497 | 
             
                      list_modules
         | 
| 498 | 
            +
                    when 'plugin'
         | 
| 499 | 
            +
                      list_plugins
         | 
| 490 500 | 
             
                    end
         | 
| 491 501 | 
             
                    return 0
         | 
| 492 502 | 
             
                  when 'convert'
         | 
| @@ -516,7 +526,13 @@ module Bolt | |
| 516 526 | 
             
                      code = Bolt::ProjectManager.new(config, outputter, pal).migrate
         | 
| 517 527 | 
             
                    end
         | 
| 518 528 | 
             
                  when 'lookup'
         | 
| 519 | 
            -
                     | 
| 529 | 
            +
                    plan_vars = Hash[options[:leftovers].map { |a| a.split('=', 2) }]
         | 
| 530 | 
            +
                    # Validate functions verifies one of these was passed
         | 
| 531 | 
            +
                    if options[:targets]
         | 
| 532 | 
            +
                      code = lookup(options[:object], options[:targets], plan_vars: plan_vars)
         | 
| 533 | 
            +
                    elsif options[:plan_hierarchy]
         | 
| 534 | 
            +
                      code = plan_lookup(options[:object], plan_vars: plan_vars)
         | 
| 535 | 
            +
                    end
         | 
| 520 536 | 
             
                  when 'plan'
         | 
| 521 537 | 
             
                    case options[:action]
         | 
| 522 538 | 
             
                    when 'new'
         | 
| @@ -630,7 +646,7 @@ module Bolt | |
| 630 646 | 
             
                end
         | 
| 631 647 |  | 
| 632 648 | 
             
                def list_tasks
         | 
| 633 | 
            -
                  tasks = filter_content(pal. | 
| 649 | 
            +
                  tasks = filter_content(pal.list_tasks_with_cache(filter_content: true), options[:filter])
         | 
| 634 650 | 
             
                  outputter.print_tasks(tasks, pal.user_modulepath)
         | 
| 635 651 | 
             
                end
         | 
| 636 652 |  | 
| @@ -694,10 +710,19 @@ module Bolt | |
| 694 710 | 
             
                  outputter.print_groups(inventory.group_names.sort, inventory.source, config.default_inventoryfile)
         | 
| 695 711 | 
             
                end
         | 
| 696 712 |  | 
| 713 | 
            +
                # Looks up a value with Hiera as if in a plan outside an apply block, using
         | 
| 714 | 
            +
                # provided variable values for interpolations
         | 
| 715 | 
            +
                #
         | 
| 716 | 
            +
                def plan_lookup(key, plan_vars: {})
         | 
| 717 | 
            +
                  result = pal.plan_hierarchy_lookup(key, plan_vars: plan_vars)
         | 
| 718 | 
            +
                  outputter.print_plan_lookup(result)
         | 
| 719 | 
            +
                  0
         | 
| 720 | 
            +
                end
         | 
| 721 | 
            +
             | 
| 697 722 | 
             
                # Looks up a value with Hiera, using targets as the contexts to perform the
         | 
| 698 | 
            -
                # look ups in.
         | 
| 723 | 
            +
                # look ups in. This should return the same value as a lookup in an apply block.
         | 
| 699 724 | 
             
                #
         | 
| 700 | 
            -
                def lookup(key, targets)
         | 
| 725 | 
            +
                def lookup(key, targets, plan_vars: {})
         | 
| 701 726 | 
             
                  executor = Bolt::Executor.new(
         | 
| 702 727 | 
             
                    config.concurrency,
         | 
| 703 728 | 
             
                    analytics,
         | 
| @@ -706,7 +731,7 @@ module Bolt | |
| 706 731 | 
             
                    config.future
         | 
| 707 732 | 
             
                  )
         | 
| 708 733 |  | 
| 709 | 
            -
                  executor.subscribe(outputter) if  | 
| 734 | 
            +
                  executor.subscribe(outputter) if config.format == 'human'
         | 
| 710 735 | 
             
                  executor.subscribe(log_outputter)
         | 
| 711 736 | 
             
                  executor.publish_event(type: :plan_start, plan: nil)
         | 
| 712 737 |  | 
| @@ -716,7 +741,7 @@ module Bolt | |
| 716 741 | 
             
                      targets,
         | 
| 717 742 | 
             
                      inventory,
         | 
| 718 743 | 
             
                      executor,
         | 
| 719 | 
            -
                       | 
| 744 | 
            +
                      plan_vars: plan_vars
         | 
| 720 745 | 
             
                    )
         | 
| 721 746 | 
             
                  end
         | 
| 722 747 |  | 
| @@ -827,6 +852,10 @@ module Bolt | |
| 827 852 | 
             
                  outputter.print_module_list(pal.list_modules)
         | 
| 828 853 | 
             
                end
         | 
| 829 854 |  | 
| 855 | 
            +
                def list_plugins
         | 
| 856 | 
            +
                  outputter.print_plugin_list(plugins.list_plugins, pal.user_modulepath)
         | 
| 857 | 
            +
                end
         | 
| 858 | 
            +
             | 
| 830 859 | 
             
                def generate_types
         | 
| 831 860 | 
             
                  # generate_types will surface a nice error with helpful message if it fails
         | 
| 832 861 | 
             
                  pal.generate_types(cache: true)
         | 
    
        data/lib/bolt/outputter/human.rb
    CHANGED
    
    | @@ -460,6 +460,10 @@ module Bolt | |
| 460 460 | 
             
                    @stream.puts(guide)
         | 
| 461 461 | 
             
                  end
         | 
| 462 462 |  | 
| 463 | 
            +
                  def print_plan_lookup(value)
         | 
| 464 | 
            +
                    @stream.puts(value)
         | 
| 465 | 
            +
                  end
         | 
| 466 | 
            +
             | 
| 463 467 | 
             
                  def print_module_list(module_list)
         | 
| 464 468 | 
             
                    module_list.each do |path, modules|
         | 
| 465 469 | 
             
                      if (mod = modules.find { |m| m[:internal_module_group] })
         | 
| @@ -488,6 +492,34 @@ module Bolt | |
| 488 492 | 
             
                    end
         | 
| 489 493 | 
             
                  end
         | 
| 490 494 |  | 
| 495 | 
            +
                  def print_plugin_list(plugin_list, modulepath)
         | 
| 496 | 
            +
                    info   = +''
         | 
| 497 | 
            +
                    length = plugin_list.values.map(&:keys).flatten.map(&:length).max + 4
         | 
| 498 | 
            +
             | 
| 499 | 
            +
                    plugin_list.each do |hook, plugins|
         | 
| 500 | 
            +
                      next if plugins.empty?
         | 
| 501 | 
            +
                      next if hook == :validate_resolve_reference
         | 
| 502 | 
            +
             | 
| 503 | 
            +
                      info << colorize(:cyan, "#{hook}\n")
         | 
| 504 | 
            +
             | 
| 505 | 
            +
                      plugins.each do |name, description|
         | 
| 506 | 
            +
                        info << indent(2, name.ljust(length))
         | 
| 507 | 
            +
                        info << truncate(description, 80 - length) if description
         | 
| 508 | 
            +
                        info << "\n"
         | 
| 509 | 
            +
                      end
         | 
| 510 | 
            +
             | 
| 511 | 
            +
                      info << "\n"
         | 
| 512 | 
            +
                    end
         | 
| 513 | 
            +
             | 
| 514 | 
            +
                    info << colorize(:cyan, "Modulepath\n")
         | 
| 515 | 
            +
                    info << indent(2, "#{modulepath.join(File::PATH_SEPARATOR)}\n\n")
         | 
| 516 | 
            +
             | 
| 517 | 
            +
                    info << colorize(:cyan, "Additional information\n")
         | 
| 518 | 
            +
                    info << indent(2, "For more information about using plugins see https://pup.pt/bolt-plugins")
         | 
| 519 | 
            +
             | 
| 520 | 
            +
                    @stream.puts info.chomp
         | 
| 521 | 
            +
                  end
         | 
| 522 | 
            +
             | 
| 491 523 | 
             
                  def print_targets(target_list, inventory_source, default_inventory, target_flag)
         | 
| 492 524 | 
             
                    adhoc = colorize(:yellow, "(Not found in inventory file)")
         | 
| 493 525 |  | 
    
        data/lib/bolt/outputter/json.rb
    CHANGED
    
    | @@ -60,6 +60,11 @@ module Bolt | |
| 60 60 | 
             
                    print_table('tasks' => tasks, 'modulepath' => modulepath)
         | 
| 61 61 | 
             
                  end
         | 
| 62 62 |  | 
| 63 | 
            +
                  def print_plugin_list(plugins, modulepath)
         | 
| 64 | 
            +
                    plugins.delete(:validate_resolve_reference)
         | 
| 65 | 
            +
                    print_table('plugins' => plugins, 'modulepath' => modulepath)
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 63 68 | 
             
                  def print_plan_info(plan)
         | 
| 64 69 | 
             
                    path = plan.delete('module')
         | 
| 65 70 | 
             
                    plan['module_dir'] = if path.start_with?(Bolt::Config::Modulepath::MODULES_PATH)
         | 
| @@ -98,6 +103,10 @@ module Bolt | |
| 98 103 | 
             
                    }.to_json)
         | 
| 99 104 | 
             
                  end
         | 
| 100 105 |  | 
| 106 | 
            +
                  def print_plan_lookup(value)
         | 
| 107 | 
            +
                    @stream.puts(value.to_json)
         | 
| 108 | 
            +
                  end
         | 
| 109 | 
            +
             | 
| 101 110 | 
             
                  def print_puppetfile_result(success, puppetfile, moduledir)
         | 
| 102 111 | 
             
                    @stream.puts({ success: success,
         | 
| 103 112 | 
             
                                   puppetfile: puppetfile,
         | 
    
        data/lib/bolt/pal.rb
    CHANGED
    
    | @@ -163,9 +163,10 @@ module Bolt | |
| 163 163 | 
             
                # Runs a block in a PAL script compiler configured for Bolt.  Catches
         | 
| 164 164 | 
             
                # exceptions thrown by the block and re-raises them ensuring they are
         | 
| 165 165 | 
             
                # Bolt::Errors since the script compiler block will squash all exceptions.
         | 
| 166 | 
            -
                def in_bolt_compiler
         | 
| 166 | 
            +
                def in_bolt_compiler(compiler_params: {})
         | 
| 167 167 | 
             
                  # TODO: If we always call this inside a bolt_executor we can remove this here
         | 
| 168 168 | 
             
                  setup
         | 
| 169 | 
            +
                  compiler_params = compiler_params.merge(set_local_facts: false)
         | 
| 169 170 | 
             
                  r = Puppet::Pal.in_tmp_environment('bolt', modulepath: full_modulepath, facts: {}) do |pal|
         | 
| 170 171 | 
             
                    # Only load the project if it a) exists, b) has a name it can be loaded with
         | 
| 171 172 | 
             
                    Puppet.override(bolt_project: @project,
         | 
| @@ -174,7 +175,7 @@ module Bolt | |
| 174 175 | 
             
                      # of modules, it must happen *after* we have overridden
         | 
| 175 176 | 
             
                      # bolt_project or the project will be ignored
         | 
| 176 177 | 
             
                      detect_project_conflict(@project, Puppet.lookup(:environments).get('bolt'))
         | 
| 177 | 
            -
                      pal.with_script_compiler( | 
| 178 | 
            +
                      pal.with_script_compiler(**compiler_params) do |compiler|
         | 
| 178 179 | 
             
                        alias_types(compiler)
         | 
| 179 180 | 
             
                        register_resource_types(Puppet.lookup(:loaders)) if @resource_types
         | 
| 180 181 | 
             
                        begin
         | 
| @@ -299,6 +300,49 @@ module Bolt | |
| 299 300 | 
             
                  end
         | 
| 300 301 | 
             
                end
         | 
| 301 302 |  | 
| 303 | 
            +
                def list_tasks_with_cache(filter_content: false)
         | 
| 304 | 
            +
                  # Don't filter content yet, so that if users update their task filters
         | 
| 305 | 
            +
                  # we don't need to refresh the cache
         | 
| 306 | 
            +
                  task_names = list_tasks(filter_content: false).map(&:first)
         | 
| 307 | 
            +
                  task_cache = if @project
         | 
| 308 | 
            +
                                 Bolt::Util.read_optional_json_file(@project.task_cache_file, 'Task cache file')
         | 
| 309 | 
            +
                               else
         | 
| 310 | 
            +
                                 {}
         | 
| 311 | 
            +
                               end
         | 
| 312 | 
            +
                  updated = false
         | 
| 313 | 
            +
             | 
| 314 | 
            +
                  task_list = task_names.each_with_object([]) do |task_name, list|
         | 
| 315 | 
            +
                    data = task_cache[task_name] || get_task_info(task_name, with_mtime: true)
         | 
| 316 | 
            +
             | 
| 317 | 
            +
                    # Make sure all the keys are strings - if we get data from
         | 
| 318 | 
            +
                    # get_task_info they will be symbols
         | 
| 319 | 
            +
                    data = Bolt::Util.walk_keys(data, &:to_s)
         | 
| 320 | 
            +
             | 
| 321 | 
            +
                    # If any files in the task were updated, refresh the cache
         | 
| 322 | 
            +
                    if data['files']&.any?
         | 
| 323 | 
            +
                      # For all the files that are part of the task
         | 
| 324 | 
            +
                      data['files'].each do |f|
         | 
| 325 | 
            +
                        # If any file has been updated since we last cached, update the
         | 
| 326 | 
            +
                        # cache
         | 
| 327 | 
            +
                        next if File.mtime(f['path']).to_s == f['mtime']
         | 
| 328 | 
            +
                        data = get_task_info(task_name, with_mtime: true)
         | 
| 329 | 
            +
                        data = Bolt::Util.walk_keys(data, &:to_s)
         | 
| 330 | 
            +
                        # Tell Bolt to write to the cache file once we're done
         | 
| 331 | 
            +
                        updated = true
         | 
| 332 | 
            +
                        # Update the cache data
         | 
| 333 | 
            +
                        task_cache[task_name] = data
         | 
| 334 | 
            +
                      end
         | 
| 335 | 
            +
                    end
         | 
| 336 | 
            +
                    metadata = data['metadata'] || {}
         | 
| 337 | 
            +
                    # Don't add tasks to the list to return if they are private
         | 
| 338 | 
            +
                    list << [task_name, metadata['description']] unless metadata['private']
         | 
| 339 | 
            +
                  end
         | 
| 340 | 
            +
             | 
| 341 | 
            +
                  # Write the cache if any entries were updated
         | 
| 342 | 
            +
                  File.write(@project.task_cache_file, task_cache.to_json) if updated
         | 
| 343 | 
            +
                  filter_content ? filter_content(task_list, @project&.tasks) : task_list
         | 
| 344 | 
            +
                end
         | 
| 345 | 
            +
             | 
| 302 346 | 
             
                def list_tasks(filter_content: false)
         | 
| 303 347 | 
             
                  in_bolt_compiler do |compiler|
         | 
| 304 348 | 
             
                    tasks = compiler.list_tasks.map(&:name).sort.each_with_object([]) do |task_name, data|
         | 
| @@ -350,14 +394,20 @@ module Bolt | |
| 350 394 | 
             
                  end
         | 
| 351 395 | 
             
                end
         | 
| 352 396 |  | 
| 353 | 
            -
                def get_task(task_name)
         | 
| 397 | 
            +
                def get_task(task_name, with_mtime: false)
         | 
| 354 398 | 
             
                  task = task_signature(task_name)
         | 
| 355 399 |  | 
| 356 400 | 
             
                  if task.nil?
         | 
| 357 401 | 
             
                    raise Bolt::Error.unknown_task(task_name)
         | 
| 358 402 | 
             
                  end
         | 
| 359 403 |  | 
| 360 | 
            -
                  Bolt::Task.from_task_signature(task)
         | 
| 404 | 
            +
                  task = Bolt::Task.from_task_signature(task)
         | 
| 405 | 
            +
                  task.add_mtimes if with_mtime
         | 
| 406 | 
            +
                  task
         | 
| 407 | 
            +
                end
         | 
| 408 | 
            +
             | 
| 409 | 
            +
                def get_task_info(task_name, with_mtime: false)
         | 
| 410 | 
            +
                  get_task(task_name, with_mtime: with_mtime).to_h
         | 
| 361 411 | 
             
                end
         | 
| 362 412 |  | 
| 363 413 | 
             
                def list_plans_with_cache(filter_content: false)
         | 
| @@ -372,20 +422,20 @@ module Bolt | |
| 372 422 | 
             
                  updated = false
         | 
| 373 423 |  | 
| 374 424 | 
             
                  plan_list = plan_names.each_with_object([]) do |plan_name, list|
         | 
| 375 | 
            -
                     | 
| 425 | 
            +
                    data = plan_cache[plan_name] || get_plan_info(plan_name, with_mtime: true)
         | 
| 376 426 |  | 
| 377 427 | 
             
                    # If the plan is a 'local' plan (in the project itself, or the
         | 
| 378 428 | 
             
                    # modules/ directory) then verify it hasn't been updated since we
         | 
| 379 429 | 
             
                    # cached it. If it has been updated, refresh the cache and use the
         | 
| 380 430 | 
             
                    # new data.
         | 
| 381 | 
            -
                    if  | 
| 382 | 
            -
                        | 
| 383 | 
            -
                       | 
| 431 | 
            +
                    if data['file'] &&
         | 
| 432 | 
            +
                       File.mtime(data.dig('file', 'path')).to_s != data.dig('file', 'mtime')
         | 
| 433 | 
            +
                      data = get_plan_info(plan_name, with_mtime: true)
         | 
| 384 434 | 
             
                      updated = true
         | 
| 385 | 
            -
                      plan_cache[plan_name] =  | 
| 435 | 
            +
                      plan_cache[plan_name] = data
         | 
| 386 436 | 
             
                    end
         | 
| 387 437 |  | 
| 388 | 
            -
                    list << [plan_name,  | 
| 438 | 
            +
                    list << [plan_name, data['description']] unless data['private']
         | 
| 389 439 | 
             
                  end
         | 
| 390 440 |  | 
| 391 441 | 
             
                  File.write(@project.plan_cache_file, plan_cache.to_json) if updated
         | 
| @@ -585,6 +635,7 @@ module Bolt | |
| 585 635 | 
             
                    inputs = generator.find_inputs(:pcore)
         | 
| 586 636 | 
             
                    FileUtils.mkdir_p(@resource_types)
         | 
| 587 637 | 
             
                    cache_plan_info if @project && cache
         | 
| 638 | 
            +
                    cache_task_info if @project && cache
         | 
| 588 639 | 
             
                    generator.generate(inputs, @resource_types, true)
         | 
| 589 640 | 
             
                  end
         | 
| 590 641 | 
             
                end
         | 
| @@ -600,6 +651,17 @@ module Bolt | |
| 600 651 | 
             
                  File.write(@project.plan_cache_file, plans_info.to_json)
         | 
| 601 652 | 
             
                end
         | 
| 602 653 |  | 
| 654 | 
            +
                def cache_task_info
         | 
| 655 | 
            +
                  # task_name is an array here
         | 
| 656 | 
            +
                  tasks_info = list_tasks(filter_content: false).map do |task_name,|
         | 
| 657 | 
            +
                    data = get_task_info(task_name, with_mtime: true)
         | 
| 658 | 
            +
                    { task_name => data }
         | 
| 659 | 
            +
                  end.reduce({}, :merge)
         | 
| 660 | 
            +
             | 
| 661 | 
            +
                  FileUtils.touch(@project.task_cache_file)
         | 
| 662 | 
            +
                  File.write(@project.task_cache_file, tasks_info.to_json)
         | 
| 663 | 
            +
                end
         | 
| 664 | 
            +
             | 
| 603 665 | 
             
                def run_task(task_name, targets, params, executor, inventory, description = nil)
         | 
| 604 666 | 
             
                  in_task_compiler(executor, inventory) do |compiler|
         | 
| 605 667 | 
             
                    params = params.merge('_bolt_api_call' => true, '_catch_errors' => true)
         | 
| @@ -632,7 +694,21 @@ module Bolt | |
| 632 694 | 
             
                  Bolt::PlanResult.new(e, 'failure')
         | 
| 633 695 | 
             
                end
         | 
| 634 696 |  | 
| 635 | 
            -
                def  | 
| 697 | 
            +
                def plan_hierarchy_lookup(key, plan_vars: {})
         | 
| 698 | 
            +
                  # Do a lookup with a script compiler, which uses the 'plan_hierarchy' key in
         | 
| 699 | 
            +
                  # Hiera config.
         | 
| 700 | 
            +
                  with_puppet_settings do
         | 
| 701 | 
            +
                    # We want all of the setup and teardown that `in_bolt_compiler` does,
         | 
| 702 | 
            +
                    # but also want to pass keys to the script compiler.
         | 
| 703 | 
            +
                    in_bolt_compiler(compiler_params: { variables: plan_vars }) do |compiler|
         | 
| 704 | 
            +
                      compiler.call_function('lookup', key)
         | 
| 705 | 
            +
                    end
         | 
| 706 | 
            +
                  rescue Puppet::Error => e
         | 
| 707 | 
            +
                    raise PALError.from_error(e)
         | 
| 708 | 
            +
                  end
         | 
| 709 | 
            +
                end
         | 
| 710 | 
            +
             | 
| 711 | 
            +
                def lookup(key, targets, inventory, executor, plan_vars: {})
         | 
| 636 712 | 
             
                  # Install the puppet-agent package and collect facts. Facts are
         | 
| 637 713 | 
             
                  # automatically added to the targets.
         | 
| 638 714 | 
             
                  in_plan_compiler(executor, inventory, nil) do |compiler|
         | 
| @@ -654,21 +730,29 @@ module Bolt | |
| 654 730 |  | 
| 655 731 | 
             
                    trusted = Puppet::Context::TrustedInformation.local(node).to_h
         | 
| 656 732 |  | 
| 733 | 
            +
                    # Separate environment configuration from interpolation data the same
         | 
| 734 | 
            +
                    # way we do when compiling Puppet catalogs.
         | 
| 657 735 | 
             
                    env_conf = {
         | 
| 658 736 | 
             
                      modulepath: @modulepath.full_modulepath,
         | 
| 659 | 
            -
                      facts:      target.facts | 
| 660 | 
            -
             | 
| 737 | 
            +
                      facts:      target.facts
         | 
| 738 | 
            +
                    }
         | 
| 739 | 
            +
             | 
| 740 | 
            +
                    interpolations = {
         | 
| 741 | 
            +
                      variables:        plan_vars,
         | 
| 742 | 
            +
                      target_variables: target.vars
         | 
| 661 743 | 
             
                    }
         | 
| 662 744 |  | 
| 663 745 | 
             
                    with_puppet_settings do
         | 
| 664 746 | 
             
                      Puppet::Pal.in_tmp_environment(target.name, **env_conf) do |pal|
         | 
| 665 747 | 
             
                        Puppet.override(overrides) do
         | 
| 666 748 | 
             
                          Puppet.lookup(:pal_current_node).trusted_data = trusted
         | 
| 667 | 
            -
                          pal.with_catalog_compiler do |compiler|
         | 
| 749 | 
            +
                          pal.with_catalog_compiler(**interpolations) do |compiler|
         | 
| 668 750 | 
             
                            Bolt::Result.for_lookup(target, key, compiler.call_function('lookup', key))
         | 
| 669 751 | 
             
                          rescue StandardError => e
         | 
| 670 752 | 
             
                            Bolt::Result.from_exception(target, e)
         | 
| 671 753 | 
             
                          end
         | 
| 754 | 
            +
                        rescue Puppet::Error => e
         | 
| 755 | 
            +
                          raise PALError.from_error(e)
         | 
| 672 756 | 
             
                        end
         | 
| 673 757 | 
             
                      end
         | 
| 674 758 | 
             
                    end
         | 
    
        data/lib/bolt/plugin.rb
    CHANGED
    
    | @@ -250,6 +250,44 @@ module Bolt | |
| 250 250 | 
             
                  end
         | 
| 251 251 | 
             
                end
         | 
| 252 252 |  | 
| 253 | 
            +
                # Loads all plugins and returns a map of plugin names to hooks.
         | 
| 254 | 
            +
                #
         | 
| 255 | 
            +
                def list_plugins
         | 
| 256 | 
            +
                  load_all_plugins
         | 
| 257 | 
            +
             | 
| 258 | 
            +
                  hooks = KNOWN_HOOKS.map { |hook| [hook, {}] }.to_h
         | 
| 259 | 
            +
             | 
| 260 | 
            +
                  @plugins.sort.each do |name, plugin|
         | 
| 261 | 
            +
                    # Don't show the Puppet Connect plugin for now.
         | 
| 262 | 
            +
                    next if name == 'puppet_connect_data'
         | 
| 263 | 
            +
             | 
| 264 | 
            +
                    case plugin
         | 
| 265 | 
            +
                    when Bolt::Plugin::Module
         | 
| 266 | 
            +
                      plugin.hook_map.each do |hook, spec|
         | 
| 267 | 
            +
                        next unless hooks.include?(hook)
         | 
| 268 | 
            +
                        hooks[hook][name] = spec['task'].description
         | 
| 269 | 
            +
                      end
         | 
| 270 | 
            +
                    else
         | 
| 271 | 
            +
                      plugin.hook_descriptions.each do |hook, description|
         | 
| 272 | 
            +
                        hooks[hook][name] = description
         | 
| 273 | 
            +
                      end
         | 
| 274 | 
            +
                    end
         | 
| 275 | 
            +
                  end
         | 
| 276 | 
            +
             | 
| 277 | 
            +
                  hooks
         | 
| 278 | 
            +
                end
         | 
| 279 | 
            +
             | 
| 280 | 
            +
                # Loads all plugins available to the project.
         | 
| 281 | 
            +
                #
         | 
| 282 | 
            +
                private def load_all_plugins
         | 
| 283 | 
            +
                  modules.each do |name, mod|
         | 
| 284 | 
            +
                    next unless mod.plugin?
         | 
| 285 | 
            +
                    by_name(name)
         | 
| 286 | 
            +
                  end
         | 
| 287 | 
            +
             | 
| 288 | 
            +
                  RUBY_PLUGINS.each { |name| by_name(name) }
         | 
| 289 | 
            +
                end
         | 
| 290 | 
            +
             | 
| 253 291 | 
             
                def puppetdb_client
         | 
| 254 292 | 
             
                  by_name('puppetdb').puppetdb_client
         | 
| 255 293 | 
             
                end
         | 
    
        data/lib/bolt/plugin/env_var.rb
    CHANGED
    
    | @@ -10,7 +10,14 @@ module Bolt | |
| 10 10 | 
             
                  end
         | 
| 11 11 |  | 
| 12 12 | 
             
                  def hooks
         | 
| 13 | 
            -
                     | 
| 13 | 
            +
                    hook_descriptions.keys
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def hook_descriptions
         | 
| 17 | 
            +
                    {
         | 
| 18 | 
            +
                      resolve_reference: 'Read values stored in environment variables.',
         | 
| 19 | 
            +
                      validate_resolve_reference: nil
         | 
| 20 | 
            +
                    }
         | 
| 14 21 | 
             
                  end
         | 
| 15 22 |  | 
| 16 23 | 
             
                  def validate_resolve_reference(opts)
         | 
    
        data/lib/bolt/plugin/module.rb
    CHANGED
    
    
    
        data/lib/bolt/plugin/prompt.rb
    CHANGED
    
    | @@ -10,7 +10,14 @@ module Bolt | |
| 10 10 | 
             
                  end
         | 
| 11 11 |  | 
| 12 12 | 
             
                  def hooks
         | 
| 13 | 
            -
                     | 
| 13 | 
            +
                    hook_descriptions.keys
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def hook_descriptions
         | 
| 17 | 
            +
                    {
         | 
| 18 | 
            +
                      resolve_reference: 'Prompt the user for a sensitive value.',
         | 
| 19 | 
            +
                      validate_resolve_reference: nil
         | 
| 20 | 
            +
                    }
         | 
| 14 21 | 
             
                  end
         | 
| 15 22 |  | 
| 16 23 | 
             
                  def validate_resolve_reference(opts)
         | 
| @@ -49,7 +49,14 @@ module Bolt | |
| 49 49 | 
             
                  end
         | 
| 50 50 |  | 
| 51 51 | 
             
                  def hooks
         | 
| 52 | 
            -
                     | 
| 52 | 
            +
                    hook_descriptions.keys
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  def hook_descriptions
         | 
| 56 | 
            +
                    {
         | 
| 57 | 
            +
                      resolve_reference: nil,
         | 
| 58 | 
            +
                      validate_resolve_reference: nil
         | 
| 59 | 
            +
                    }
         | 
| 53 60 | 
             
                  end
         | 
| 54 61 |  | 
| 55 62 | 
             
                  def resolve_reference(opts)
         | 
    
        data/lib/bolt/plugin/puppetdb.rb
    CHANGED
    
    
    
        data/lib/bolt/plugin/task.rb
    CHANGED
    
    | @@ -4,7 +4,15 @@ module Bolt | |
| 4 4 | 
             
              class Plugin
         | 
| 5 5 | 
             
                class Task
         | 
| 6 6 | 
             
                  def hooks
         | 
| 7 | 
            -
                     | 
| 7 | 
            +
                    hook_descriptions.keys
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def hook_descriptions
         | 
| 11 | 
            +
                    {
         | 
| 12 | 
            +
                      puppet_library: 'Run a task to install the Puppet agent package.',
         | 
| 13 | 
            +
                      resolve_reference: 'Run a task as a plugin.',
         | 
| 14 | 
            +
                      validate_resolve_reference: nil
         | 
| 15 | 
            +
                    }
         | 
| 8 16 | 
             
                  end
         | 
| 9 17 |  | 
| 10 18 | 
             
                  def name
         | 
    
        data/lib/bolt/project.rb
    CHANGED
    
    | @@ -14,7 +14,7 @@ module Bolt | |
| 14 14 | 
             
                attr_reader :path, :data, :inventory_file, :hiera_config,
         | 
| 15 15 | 
             
                            :puppetfile, :rerunfile, :type, :resource_types, :project_file,
         | 
| 16 16 | 
             
                            :downloads, :plans_path, :modulepath, :managed_moduledir,
         | 
| 17 | 
            -
                            :backup_dir, :plugin_cache_file, :plan_cache_file
         | 
| 17 | 
            +
                            :backup_dir, :plugin_cache_file, :plan_cache_file, :task_cache_file
         | 
| 18 18 |  | 
| 19 19 | 
             
                def self.default_project
         | 
| 20 20 | 
             
                  create_project(File.expand_path(File.join('~', '.puppetlabs', 'bolt')), 'user')
         | 
| @@ -114,6 +114,7 @@ module Bolt | |
| 114 114 | 
             
                  @backup_dir        = @path + '.bolt-bak'
         | 
| 115 115 | 
             
                  @plugin_cache_file = @path + '.plugin_cache.json'
         | 
| 116 116 | 
             
                  @plan_cache_file   = @path + '.plan_cache.json'
         | 
| 117 | 
            +
                  @task_cache_file   = @path + '.task_cache.json'
         | 
| 117 118 | 
             
                  @modulepath        = [(@path + 'modules').to_s]
         | 
| 118 119 |  | 
| 119 120 | 
             
                  if (tc = Bolt::Config::INVENTORY_OPTIONS.keys & data.keys).any?
         | 
    
        data/lib/bolt/task.rb
    CHANGED
    
    | @@ -17,6 +17,7 @@ module Bolt | |
| 17 17 | 
             
                                   remote supports_noop].freeze
         | 
| 18 18 |  | 
| 19 19 | 
             
                attr_reader :name, :files, :metadata, :remote
         | 
| 20 | 
            +
                attr_accessor :mtime
         | 
| 20 21 |  | 
| 21 22 | 
             
                # name [String] name of the task
         | 
| 22 23 | 
             
                # files [Array<Hash>] where each entry includes `name` and `path`
         | 
| @@ -77,6 +78,12 @@ module Bolt | |
| 77 78 | 
             
                  file_map[file_name]['path']
         | 
| 78 79 | 
             
                end
         | 
| 79 80 |  | 
| 81 | 
            +
                def add_mtimes
         | 
| 82 | 
            +
                  @files.each do |f|
         | 
| 83 | 
            +
                    f['mtime'] = File.mtime(f['path']) if File.exist?(f['path'])
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
             | 
| 80 87 | 
             
                def implementations
         | 
| 81 88 | 
             
                  metadata['implementations']
         | 
| 82 89 | 
             
                end
         | 
    
        data/lib/bolt/version.rb
    CHANGED
    
    
| @@ -0,0 +1,214 @@ | |
| 1 | 
            +
            #####################################################################
         | 
| 2 | 
            +
            ###
         | 
| 3 | 
            +
            ### Bash autocompletion for bolt
         | 
| 4 | 
            +
            ### include this file in your .bash_profile or .bashrc to use completion
         | 
| 5 | 
            +
            ### "source bolt_bash_completion.sh"
         | 
| 6 | 
            +
            ###
         | 
| 7 | 
            +
            ### Marc Schoechlin ms-github@256bit.org
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            get_json_keys() {
         | 
| 10 | 
            +
            /opt/puppetlabs/bolt/bin/ruby <<-EOF
         | 
| 11 | 
            +
              require 'json'
         | 
| 12 | 
            +
              data = JSON.parse(File.read("${1}"))
         | 
| 13 | 
            +
              puts data.keys.uniq.sort.join(' ')
         | 
| 14 | 
            +
            EOF
         | 
| 15 | 
            +
            }
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            _bolt_complete() {
         | 
| 18 | 
            +
              local prev
         | 
| 19 | 
            +
              local cur
         | 
| 20 | 
            +
              # Get the current word and previous word without colons
         | 
| 21 | 
            +
              _get_comp_words_by_ref -n : cur
         | 
| 22 | 
            +
              _get_comp_words_by_ref -n : prev
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              local next=""
         | 
| 25 | 
            +
              local subcommand=${COMP_WORDS[1]}
         | 
| 26 | 
            +
              [[ ${#COMP_WORDS[@]} -gt 2 ]] && local action=${COMP_WORDS[2]}
         | 
| 27 | 
            +
              local context_opts="-m --modulepath --project"
         | 
| 28 | 
            +
              local global_opts="--clear-cache -h --help --log-level --version"
         | 
| 29 | 
            +
              local inventory_opts="-q --query --rerun -t --targets"
         | 
| 30 | 
            +
              local authentication_opts="-u --user -p --password --password-prompt --private-key --host-key-check --no-host-key-check --ssl --no-ssl --ssl-verify --no-ssl-verify"
         | 
| 31 | 
            +
              local escalation_opts="--run-as --sudo-password --sudo-password-prompt --sudo-executable"
         | 
| 32 | 
            +
              local run_context_opts="-c --concurrency -i --inventoryfile --save-rerun --no-save-rerun --cleanup --no-cleanup"
         | 
| 33 | 
            +
              local transport_opts="--transport --connect-timeout --tty --no-tty --native-ssh --no-native-ssh --ssh-command --copy-command"
         | 
| 34 | 
            +
              local display_opts="--format --color --no-color -v --verbose --no-verbose --trace --stream"
         | 
| 35 | 
            +
              local action_opts="${inventory_opts} ${context_opts} ${authentication_opts} ${escalation_opts} ${run_context_opts} ${transport_opts} ${display_opts}"
         | 
| 36 | 
            +
              local apply_opts="--compile-concurrency --hiera-config"
         | 
| 37 | 
            +
              local file_opts=" -m --modulepath --project --private-key -i --inventoryfile --hiera-config "
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              # If there's only one word and it's "bolt", tab complete the subcommand
         | 
| 40 | 
            +
              if [ $COMP_CWORD -eq 1 ]; then
         | 
| 41 | 
            +
                next="apply command file group guide inventory lookup module plan plugin project script secret task"
         | 
| 42 | 
            +
              fi
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              # Tab complete files for options that accept files. The spaces are important!
         | 
| 45 | 
            +
              # They make it so `bolt inventory` isn't confused with `--inventoryfile`.
         | 
| 46 | 
            +
              if [[ $file_opts =~ " ${prev} " ]]; then
         | 
| 47 | 
            +
                next=$(compgen -f -d "" -- $cur)
         | 
| 48 | 
            +
              # Handle tab completing enumerable CLI options
         | 
| 49 | 
            +
              elif [ "$prev" == "--log-level" ]; then
         | 
| 50 | 
            +
                next="trace debug info warn error fatal any"
         | 
| 51 | 
            +
              elif [ "$prev" == "--transport" ]; then
         | 
| 52 | 
            +
                next="docker local lxd pcp podman remote ssh winrm"
         | 
| 53 | 
            +
              elif [ "$prev" == "--format" ]; then
         | 
| 54 | 
            +
                next="human json rainbow"
         | 
| 55 | 
            +
              else
         | 
| 56 | 
            +
                # Once we have subcommands, tab complete actions
         | 
| 57 | 
            +
                case $subcommand in
         | 
| 58 | 
            +
                  apply)
         | 
| 59 | 
            +
                    next="${action_opts} ${apply_opts} -e --execute"
         | 
| 60 | 
            +
                    ;;
         | 
| 61 | 
            +
                  command)
         | 
| 62 | 
            +
                    if [ $COMP_CWORD -eq 2 ]; then
         | 
| 63 | 
            +
                      next="run"
         | 
| 64 | 
            +
                    elif [ $action = "run" ]; then
         | 
| 65 | 
            +
                      next="${action_opts} --env-var"
         | 
| 66 | 
            +
                    fi
         | 
| 67 | 
            +
                    ;;
         | 
| 68 | 
            +
                  file)
         | 
| 69 | 
            +
                    if [ $COMP_CWORD -eq 2 ]; then
         | 
| 70 | 
            +
                      next="download upload"
         | 
| 71 | 
            +
                    else
         | 
| 72 | 
            +
                      case $action in
         | 
| 73 | 
            +
                        download) next="${action_opts} --tmpdir";;
         | 
| 74 | 
            +
                        upload) next=$action_opts;;
         | 
| 75 | 
            +
                      esac
         | 
| 76 | 
            +
                    fi
         | 
| 77 | 
            +
                    ;;
         | 
| 78 | 
            +
                  group)
         | 
| 79 | 
            +
                    if [ $COMP_CWORD -eq 2 ]; then
         | 
| 80 | 
            +
                      next="show"
         | 
| 81 | 
            +
                    elif [ $action == 'show' ]; then
         | 
| 82 | 
            +
                      next="--project --format --inventoryfile"
         | 
| 83 | 
            +
                    fi
         | 
| 84 | 
            +
                    ;;
         | 
| 85 | 
            +
                  guide)
         | 
| 86 | 
            +
                    next="--format"
         | 
| 87 | 
            +
                    ;;
         | 
| 88 | 
            +
                  inventory)
         | 
| 89 | 
            +
                    if [ $COMP_CWORD -eq 2 ]; then
         | 
| 90 | 
            +
                      next="show"
         | 
| 91 | 
            +
                    elif [ $action == 'show' ]; then
         | 
| 92 | 
            +
                      next="${inventory_opts} --project --format --inventoryfile --detail"
         | 
| 93 | 
            +
                    fi
         | 
| 94 | 
            +
                    ;;
         | 
| 95 | 
            +
                  lookup)
         | 
| 96 | 
            +
                    next="${action_opts} --hiera-config --plan-hierarchy"
         | 
| 97 | 
            +
                    ;;
         | 
| 98 | 
            +
                  module)
         | 
| 99 | 
            +
                    if [ $COMP_CWORD -eq 2 ]; then
         | 
| 100 | 
            +
                      next="add generate-types install show"
         | 
| 101 | 
            +
                    else
         | 
| 102 | 
            +
                      case $action in
         | 
| 103 | 
            +
                        add | install) next="--project";;
         | 
| 104 | 
            +
                        generate-types) next="${context_opts}";;
         | 
| 105 | 
            +
                        show) next="${context_opts} --filter --format";;
         | 
| 106 | 
            +
                      esac
         | 
| 107 | 
            +
                    fi
         | 
| 108 | 
            +
                    ;;
         | 
| 109 | 
            +
                  plan)
         | 
| 110 | 
            +
                    if [ $COMP_CWORD -eq 2 ]; then
         | 
| 111 | 
            +
                      next="convert new run show"
         | 
| 112 | 
            +
                    elif [[ ($COMP_CWORD -eq 3 || \
         | 
| 113 | 
            +
                      ( $COMP_CWORD -eq 4 && "$cur" == *"::" ) || \
         | 
| 114 | 
            +
                      ( $COMP_CWORD -eq 5 && "$cur" == *"::"* )) &&
         | 
| 115 | 
            +
                      $action != "new" ]]; then
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                      if [ -f "${PWD}/.plan_cache.json" ]; then
         | 
| 118 | 
            +
                        # Use Puppet's ruby instead of jq since we know it will be there.
         | 
| 119 | 
            +
                        next=$(get_json_keys "${PWD}/.plan_cache.json")
         | 
| 120 | 
            +
                      elif [ -f "${HOME}/.puppetlabs/bolt/.plan_cache.json" ]; then
         | 
| 121 | 
            +
                        next=$(get_json_keys "${HOME}/.puppetlabs/bolt/.plan_cache.json")
         | 
| 122 | 
            +
                      else
         | 
| 123 | 
            +
                        case $action in
         | 
| 124 | 
            +
                          convert) next="${context_opts}";;
         | 
| 125 | 
            +
                          new) next="--project --pp";;
         | 
| 126 | 
            +
                          run) next="${action_opts} ${apply_opts} --params --tmpdir";;
         | 
| 127 | 
            +
                          show) next="${context_opts} --filter --format";;
         | 
| 128 | 
            +
                        esac
         | 
| 129 | 
            +
                      fi
         | 
| 130 | 
            +
                    else
         | 
| 131 | 
            +
                      case $action in
         | 
| 132 | 
            +
                        convert) next="${context_opts}";;
         | 
| 133 | 
            +
                        new) next="--project --pp";;
         | 
| 134 | 
            +
                        run) next="${action_opts} ${apply_opts} --params --tmpdir";;
         | 
| 135 | 
            +
                        show) next="${context_opts} --filter --format";;
         | 
| 136 | 
            +
                      esac
         | 
| 137 | 
            +
                    fi
         | 
| 138 | 
            +
                    ;;
         | 
| 139 | 
            +
                  plugin)
         | 
| 140 | 
            +
                    if [ $COMP_CWORD -eq 2 ]; then
         | 
| 141 | 
            +
                      next="show"
         | 
| 142 | 
            +
                    else
         | 
| 143 | 
            +
                      next="${context_opts} --format --color --no-color"
         | 
| 144 | 
            +
                    fi
         | 
| 145 | 
            +
                    ;;
         | 
| 146 | 
            +
                  project)
         | 
| 147 | 
            +
                    if [ $COMP_CWORD -eq 2 ]; then
         | 
| 148 | 
            +
                      next="init migrate"
         | 
| 149 | 
            +
                    else
         | 
| 150 | 
            +
                      case $action in
         | 
| 151 | 
            +
                        init) next="--modules";;
         | 
| 152 | 
            +
                        migrate) next="--project --inventoryfile";;
         | 
| 153 | 
            +
                      esac
         | 
| 154 | 
            +
                    fi
         | 
| 155 | 
            +
                    ;;
         | 
| 156 | 
            +
                  script)
         | 
| 157 | 
            +
                    if [ $COMP_CWORD -eq 2 ]; then
         | 
| 158 | 
            +
                      next="run"
         | 
| 159 | 
            +
                    elif [[ $COMP_CWORD -eq 3 && $action == 'run' ]]; then
         | 
| 160 | 
            +
                      # List files and directories
         | 
| 161 | 
            +
                      next=$(compgen -f -d "" -- $cur)
         | 
| 162 | 
            +
                    elif [ $action == 'run' ]; then
         | 
| 163 | 
            +
                      next="${action_opts} --env-var --tmpdir"
         | 
| 164 | 
            +
                    fi
         | 
| 165 | 
            +
                    ;;
         | 
| 166 | 
            +
                  secret)
         | 
| 167 | 
            +
                    if [ $COMP_CWORD -eq 2 ]; then
         | 
| 168 | 
            +
                      next="createkeys encrypt decrypt"
         | 
| 169 | 
            +
                    else
         | 
| 170 | 
            +
                      case $action in
         | 
| 171 | 
            +
                        createkeys) next="${context_opts} --plugin --force";;
         | 
| 172 | 
            +
                        encrypt | decrypt) next="${context_opts} --plugin";;
         | 
| 173 | 
            +
                      esac
         | 
| 174 | 
            +
                    fi
         | 
| 175 | 
            +
                    ;;
         | 
| 176 | 
            +
                  task)
         | 
| 177 | 
            +
                    if [ $COMP_CWORD -eq 2 ]; then
         | 
| 178 | 
            +
                      next="run show"
         | 
| 179 | 
            +
                    elif [[ $COMP_CWORD -eq 3 || \
         | 
| 180 | 
            +
                      ( $COMP_CWORD -eq 4 && "$cur" == *"::" ) || \
         | 
| 181 | 
            +
                      ( $COMP_CWORD -eq 5 && "$cur" == *"::"* ) ]]; then
         | 
| 182 | 
            +
                      if [ -f "${PWD}/.task_cache.json" ]; then
         | 
| 183 | 
            +
                        # Use Puppet's ruby instead of jq since we know it will be there.
         | 
| 184 | 
            +
                        next=$(get_json_keys "${PWD}/.task_cache.json")
         | 
| 185 | 
            +
                      elif [ -f "${HOME}/.puppetlabs/bolt/.task_cache.json" ]; then
         | 
| 186 | 
            +
                        next=$(get_json_keys "${HOME}/.puppetlabs/bolt/.task_cache.json")
         | 
| 187 | 
            +
                      else
         | 
| 188 | 
            +
                        case $action in
         | 
| 189 | 
            +
                          run) next="${action_opts} --env-var --tmpdir";;
         | 
| 190 | 
            +
                          show) next="${context_opts} --filter --format";;
         | 
| 191 | 
            +
                        esac
         | 
| 192 | 
            +
                      fi
         | 
| 193 | 
            +
                    else
         | 
| 194 | 
            +
                      case $action in
         | 
| 195 | 
            +
                        run) next="${action_opts} --env-var --tmpdir";;
         | 
| 196 | 
            +
                        show) next="${context_opts} --filter --format";;
         | 
| 197 | 
            +
                      esac
         | 
| 198 | 
            +
                    fi
         | 
| 199 | 
            +
                    ;;
         | 
| 200 | 
            +
                esac
         | 
| 201 | 
            +
              fi
         | 
| 202 | 
            +
             | 
| 203 | 
            +
              # If any of the next options are flags, we've reached the end of the
         | 
| 204 | 
            +
              # building-a-Bolt-command part and can re-enable file and directory name
         | 
| 205 | 
            +
              # completion and include Bolt's global flags.
         | 
| 206 | 
            +
              if [[ "$next" =~ "--" ]]; then
         | 
| 207 | 
            +
                next+=" ${global_opts}"
         | 
| 208 | 
            +
              fi
         | 
| 209 | 
            +
             | 
| 210 | 
            +
              COMPREPLY=($(compgen -W "$next" -- $cur))
         | 
| 211 | 
            +
              __ltrim_colon_completions $cur
         | 
| 212 | 
            +
            }
         | 
| 213 | 
            +
             | 
| 214 | 
            +
            complete -F _bolt_complete bolt
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: bolt
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 3. | 
| 4 | 
            +
              version: 3.10.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Puppet
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2021-06- | 
| 11 | 
            +
            date: 2021-06-14 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: addressable
         | 
| @@ -453,6 +453,7 @@ files: | |
| 453 453 | 
             
            - bolt-modules/prompt/lib/puppet/functions/prompt/menu.rb
         | 
| 454 454 | 
             
            - bolt-modules/system/lib/puppet/functions/system/env.rb
         | 
| 455 455 | 
             
            - exe/bolt
         | 
| 456 | 
            +
            - guides/debugging.txt
         | 
| 456 457 | 
             
            - guides/guide.txt
         | 
| 457 458 | 
             
            - guides/inventory.txt
         | 
| 458 459 | 
             
            - guides/links.txt
         | 
| @@ -636,6 +637,7 @@ files: | |
| 636 637 | 
             
            - modules/canary/plans/init.pp
         | 
| 637 638 | 
             
            - modules/puppet_connect/plans/test_input_data.pp
         | 
| 638 639 | 
             
            - modules/puppetdb_fact/plans/init.pp
         | 
| 640 | 
            +
            - resources/bolt_bash_completion.sh
         | 
| 639 641 | 
             
            homepage: https://github.com/puppetlabs/bolt
         | 
| 640 642 | 
             
            licenses:
         | 
| 641 643 | 
             
            - Apache-2.0
         |