bolt 3.1.0 → 3.3.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/Puppetfile +8 -8
 - data/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +1 -1
 - data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +2 -2
 - data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +27 -5
 - data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +1 -1
 - data/bolt-modules/file/lib/puppet/functions/file/read.rb +3 -2
 - data/lib/bolt/apply_result.rb +1 -1
 - data/lib/bolt/bolt_option_parser.rb +6 -3
 - data/lib/bolt/cli.rb +37 -12
 - data/lib/bolt/config.rb +4 -0
 - data/lib/bolt/config/options.rb +21 -3
 - data/lib/bolt/config/transport/lxd.rb +21 -0
 - data/lib/bolt/config/transport/options.rb +1 -1
 - data/lib/bolt/executor.rb +10 -3
 - data/lib/bolt/logger.rb +8 -0
 - data/lib/bolt/module_installer.rb +2 -2
 - data/lib/bolt/module_installer/puppetfile.rb +2 -2
 - data/lib/bolt/module_installer/specs/forge_spec.rb +2 -2
 - data/lib/bolt/module_installer/specs/git_spec.rb +2 -2
 - data/lib/bolt/outputter/human.rb +47 -12
 - data/lib/bolt/pal.rb +2 -2
 - data/lib/bolt/pal/yaml_plan.rb +1 -2
 - data/lib/bolt/pal/yaml_plan/evaluator.rb +5 -141
 - data/lib/bolt/pal/yaml_plan/step.rb +91 -31
 - data/lib/bolt/pal/yaml_plan/step/command.rb +16 -16
 - data/lib/bolt/pal/yaml_plan/step/download.rb +15 -16
 - data/lib/bolt/pal/yaml_plan/step/eval.rb +11 -11
 - data/lib/bolt/pal/yaml_plan/step/message.rb +13 -4
 - data/lib/bolt/pal/yaml_plan/step/plan.rb +19 -15
 - data/lib/bolt/pal/yaml_plan/step/resources.rb +82 -21
 - data/lib/bolt/pal/yaml_plan/step/script.rb +32 -17
 - data/lib/bolt/pal/yaml_plan/step/task.rb +19 -16
 - data/lib/bolt/pal/yaml_plan/step/upload.rb +16 -17
 - data/lib/bolt/pal/yaml_plan/transpiler.rb +1 -1
 - data/lib/bolt/plan_creator.rb +1 -1
 - data/lib/bolt/project_manager.rb +1 -1
 - data/lib/bolt/project_manager/module_migrator.rb +1 -1
 - data/lib/bolt/shell.rb +16 -0
 - data/lib/bolt/shell/bash.rb +48 -21
 - data/lib/bolt/shell/bash/tmpdir.rb +2 -2
 - data/lib/bolt/shell/powershell.rb +24 -5
 - data/lib/bolt/task.rb +1 -1
 - data/lib/bolt/transport/lxd.rb +26 -0
 - data/lib/bolt/transport/lxd/connection.rb +99 -0
 - data/lib/bolt/transport/ssh/connection.rb +1 -1
 - data/lib/bolt/transport/winrm/connection.rb +1 -1
 - data/lib/bolt/version.rb +1 -1
 - data/lib/bolt_server/transport_app.rb +13 -1
 - data/lib/bolt_spec/plans/action_stubs.rb +1 -1
 - data/lib/bolt_spec/plans/mock_executor.rb +4 -0
 - metadata +5 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 7e32573bc97fea7eca64b7c915cb4b462e1325fb5d4dcbe95c48c72aae8c0e14
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: abb279c5a363092ca37ddf4eac9de665de9f79aa74c9e0af9697910b336b7b93
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 23bf7042750c180eb618eaafd8af34e014deb5c7ab0dadcce316e92c3aa66e62ae85e89e96f471cc54f17c81eba463f73b776e9aa4581219567ed15876722967
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: bcd1eb6192f5ac92959088edfbe7b333dcb9ed63f6da7a36a6274d72cbce32e77f4f01a8427edec78be3dd9caeab2472ec3691d846108367df407187606ba2ae
         
     | 
    
        data/Puppetfile
    CHANGED
    
    | 
         @@ -5,14 +5,14 @@ forge "http://forge.puppetlabs.com" 
     | 
|
| 
       5 
5 
     | 
    
         
             
            moduledir File.join(File.dirname(__FILE__), 'modules')
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            # Core modules used by 'apply'
         
     | 
| 
       8 
     | 
    
         
            -
            mod 'puppetlabs-service', ' 
     | 
| 
      
 8 
     | 
    
         
            +
            mod 'puppetlabs-service', '2.0.0'
         
     | 
| 
       9 
9 
     | 
    
         
             
            mod 'puppetlabs-puppet_agent', '4.4.0'
         
     | 
| 
       10 
10 
     | 
    
         
             
            mod 'puppetlabs-facts', '1.4.0'
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
            # Core types and providers for Puppet 6
         
     | 
| 
       13 
     | 
    
         
            -
            mod 'puppetlabs-augeas_core', '1.1. 
     | 
| 
      
 13 
     | 
    
         
            +
            mod 'puppetlabs-augeas_core', '1.1.2'
         
     | 
| 
       14 
14 
     | 
    
         
             
            mod 'puppetlabs-host_core', '1.0.3'
         
     | 
| 
       15 
     | 
    
         
            -
            mod 'puppetlabs-scheduled_task', ' 
     | 
| 
      
 15 
     | 
    
         
            +
            mod 'puppetlabs-scheduled_task', '3.0.0'
         
     | 
| 
       16 
16 
     | 
    
         
             
            mod 'puppetlabs-sshkeys_core', '2.2.0'
         
     | 
| 
       17 
17 
     | 
    
         
             
            mod 'puppetlabs-zfs_core', '1.2.0'
         
     | 
| 
       18 
18 
     | 
    
         
             
            mod 'puppetlabs-cron_core', '1.0.5'
         
     | 
| 
         @@ -22,20 +22,20 @@ mod 'puppetlabs-yumrepo_core', '1.0.7' 
     | 
|
| 
       22 
22 
     | 
    
         
             
            mod 'puppetlabs-zone_core', '1.0.3'
         
     | 
| 
       23 
23 
     | 
    
         | 
| 
       24 
24 
     | 
    
         
             
            # Useful additional modules
         
     | 
| 
       25 
     | 
    
         
            -
            mod 'puppetlabs-package', ' 
     | 
| 
      
 25 
     | 
    
         
            +
            mod 'puppetlabs-package', '2.0.0'
         
     | 
| 
       26 
26 
     | 
    
         
             
            mod 'puppetlabs-powershell_task_helper', '0.1.0'
         
     | 
| 
       27 
     | 
    
         
            -
            mod 'puppetlabs-puppet_conf', '0. 
     | 
| 
      
 27 
     | 
    
         
            +
            mod 'puppetlabs-puppet_conf', '1.0.0'
         
     | 
| 
       28 
28 
     | 
    
         
             
            mod 'puppetlabs-python_task_helper', '0.5.0'
         
     | 
| 
       29 
     | 
    
         
            -
            mod 'puppetlabs-reboot', ' 
     | 
| 
      
 29 
     | 
    
         
            +
            mod 'puppetlabs-reboot', '4.0.0'
         
     | 
| 
       30 
30 
     | 
    
         
             
            mod 'puppetlabs-ruby_task_helper', '0.6.0'
         
     | 
| 
       31 
31 
     | 
    
         
             
            mod 'puppetlabs-ruby_plugin_helper', '0.2.0'
         
     | 
| 
       32 
     | 
    
         
            -
            mod 'puppetlabs-stdlib', ' 
     | 
| 
      
 32 
     | 
    
         
            +
            mod 'puppetlabs-stdlib', '7.0.0'
         
     | 
| 
       33 
33 
     | 
    
         | 
| 
       34 
34 
     | 
    
         
             
            # Plugin modules
         
     | 
| 
       35 
35 
     | 
    
         
             
            mod 'puppetlabs-aws_inventory', '0.6.0'
         
     | 
| 
       36 
36 
     | 
    
         
             
            mod 'puppetlabs-azure_inventory', '0.5.0'
         
     | 
| 
       37 
37 
     | 
    
         
             
            mod 'puppetlabs-gcloud_inventory', '0.2.0'
         
     | 
| 
       38 
     | 
    
         
            -
            mod 'puppetlabs-http_request', '0.2. 
     | 
| 
      
 38 
     | 
    
         
            +
            mod 'puppetlabs-http_request', '0.2.2'
         
     | 
| 
       39 
39 
     | 
    
         
             
            mod 'puppetlabs-pkcs7', '0.1.1'
         
     | 
| 
       40 
40 
     | 
    
         
             
            mod 'puppetlabs-secure_env_vars', '0.2.0'
         
     | 
| 
       41 
41 
     | 
    
         
             
            mod 'puppetlabs-terraform', '0.6.1'
         
     | 
| 
         @@ -7,7 +7,7 @@ require 'bolt/error' 
     | 
|
| 
       7 
7 
     | 
    
         
             
            # > **Note:** Not available in apply block
         
     | 
| 
       8 
8 
     | 
    
         
             
            Puppet::Functions.create_function(:add_facts) do
         
     | 
| 
       9 
9 
     | 
    
         
             
              # @param target A target.
         
     | 
| 
       10 
     | 
    
         
            -
              # @param facts A hash of fact names to values that  
     | 
| 
      
 10 
     | 
    
         
            +
              # @param facts A hash of fact names to values that can include structured facts.
         
     | 
| 
       11 
11 
     | 
    
         
             
              # @return A `Target` object.
         
     | 
| 
       12 
12 
     | 
    
         
             
              # @example Adding facts to a target
         
     | 
| 
       13 
13 
     | 
    
         
             
              #   add_facts($target, { 'os' => { 'family' => 'windows', 'name' => 'windows' } })
         
     | 
| 
         @@ -256,7 +256,7 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction 
     | 
|
| 
       256 
256 
     | 
    
         
             
                if nodes_param
         
     | 
| 
       257 
257 
     | 
    
         
             
                  if params['nodes']
         
     | 
| 
       258 
258 
     | 
    
         
             
                    raise ArgumentError,
         
     | 
| 
       259 
     | 
    
         
            -
                          "A plan's 'nodes' parameter  
     | 
| 
      
 259 
     | 
    
         
            +
                          "A plan's 'nodes' parameter can be specified as the second positional argument to " \
         
     | 
| 
       260 
260 
     | 
    
         
             
                          "run_plan(), but in that case 'nodes' must not be specified in the named arguments " \
         
     | 
| 
       261 
261 
     | 
    
         
             
                          "hash."
         
     | 
| 
       262 
262 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -265,7 +265,7 @@ Puppet::Functions.create_function(:run_plan, Puppet::Functions::InternalFunction 
     | 
|
| 
       265 
265 
     | 
    
         
             
                elsif targets_param
         
     | 
| 
       266 
266 
     | 
    
         
             
                  if params['targets']
         
     | 
| 
       267 
267 
     | 
    
         
             
                    raise ArgumentError,
         
     | 
| 
       268 
     | 
    
         
            -
                          "A plan's 'targets' parameter  
     | 
| 
      
 268 
     | 
    
         
            +
                          "A plan's 'targets' parameter can be specified as the second positional argument to " \
         
     | 
| 
       269 
269 
     | 
    
         
             
                          "run_plan(), but in that case 'targets' must not be specified in the named arguments " \
         
     | 
| 
       270 
270 
     | 
    
         
             
                          "hash."
         
     | 
| 
       271 
271 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -6,19 +6,24 @@ 
     | 
|
| 
       6 
6 
     | 
    
         
             
            # > **Note:** Not available in apply block
         
     | 
| 
       7 
7 
     | 
    
         
             
            Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFunction) do
         
     | 
| 
       8 
8 
     | 
    
         
             
              # Run a script.
         
     | 
| 
       9 
     | 
    
         
            -
              # @param script Path to a script to run on target.  
     | 
| 
      
 9 
     | 
    
         
            +
              # @param script Path to a script to run on target. Can be an absolute path or a modulename/filename selector for a
         
     | 
| 
       10 
10 
     | 
    
         
             
              #               file in $MODULEROOT/files.
         
     | 
| 
       11 
11 
     | 
    
         
             
              # @param targets A pattern identifying zero or more targets. See {get_targets} for accepted patterns.
         
     | 
| 
       12 
12 
     | 
    
         
             
              # @param options A hash of additional options.
         
     | 
| 
       13 
13 
     | 
    
         
             
              # @option options [Array[String]] arguments An array of arguments to be passed to the script.
         
     | 
| 
      
 14 
     | 
    
         
            +
              #   Cannot be used with `pwsh_params`.
         
     | 
| 
      
 15 
     | 
    
         
            +
              # @option options [Hash] pwsh_params Map of named parameters to pass to a PowerShell script.
         
     | 
| 
      
 16 
     | 
    
         
            +
              #   Cannot be used with `arguments`.
         
     | 
| 
       14 
17 
     | 
    
         
             
              # @option options [Boolean] _catch_errors Whether to catch raised errors.
         
     | 
| 
       15 
18 
     | 
    
         
             
              # @option options [String] _run_as User to run as using privilege escalation.
         
     | 
| 
       16 
     | 
    
         
            -
              # @option options [Hash] _env_vars Map of environment variables to set
         
     | 
| 
      
 19 
     | 
    
         
            +
              # @option options [Hash] _env_vars Map of environment variables to set.
         
     | 
| 
       17 
20 
     | 
    
         
             
              # @return A list of results, one entry per target.
         
     | 
| 
       18 
21 
     | 
    
         
             
              # @example Run a local script on Linux targets as 'root'
         
     | 
| 
       19 
22 
     | 
    
         
             
              #   run_script('/var/tmp/myscript', $targets, '_run_as' => 'root')
         
     | 
| 
       20 
23 
     | 
    
         
             
              # @example Run a module-provided script with arguments
         
     | 
| 
       21 
24 
     | 
    
         
             
              #   run_script('iis/setup.ps1', $target, 'arguments' => ['/u', 'Administrator'])
         
     | 
| 
      
 25 
     | 
    
         
            +
              # @example Pass named parameters to a PowerShell script
         
     | 
| 
      
 26 
     | 
    
         
            +
              #   run_script('iis/setup.ps1', $target, 'pwsh_params' => { 'User' => 'Administrator' })
         
     | 
| 
       22 
27 
     | 
    
         
             
              dispatch :run_script do
         
     | 
| 
       23 
28 
     | 
    
         
             
                scope_param
         
     | 
| 
       24 
29 
     | 
    
         
             
                param 'String[1]', :script
         
     | 
| 
         @@ -28,15 +33,18 @@ Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFuncti 
     | 
|
| 
       28 
33 
     | 
    
         
             
              end
         
     | 
| 
       29 
34 
     | 
    
         | 
| 
       30 
35 
     | 
    
         
             
              # Run a script, logging the provided description.
         
     | 
| 
       31 
     | 
    
         
            -
              # @param script Path to a script to run on target.  
     | 
| 
      
 36 
     | 
    
         
            +
              # @param script Path to a script to run on target. Can be an absolute path or a modulename/filename selector for a
         
     | 
| 
       32 
37 
     | 
    
         
             
              #               file in $MODULEROOT/files.
         
     | 
| 
       33 
38 
     | 
    
         
             
              # @param targets A pattern identifying zero or more targets. See {get_targets} for accepted patterns.
         
     | 
| 
       34 
39 
     | 
    
         
             
              # @param description A description to be output when calling this function.
         
     | 
| 
       35 
40 
     | 
    
         
             
              # @param options A hash of additional options.
         
     | 
| 
       36 
41 
     | 
    
         
             
              # @option options [Array[String]] arguments An array of arguments to be passed to the script.
         
     | 
| 
      
 42 
     | 
    
         
            +
              #   Cannot be used with `pwsh_params`.
         
     | 
| 
      
 43 
     | 
    
         
            +
              # @option options [Hash] pwsh_params Map of named parameters to pass to a PowerShell script.
         
     | 
| 
      
 44 
     | 
    
         
            +
              #   Cannot be used with `arguments`.
         
     | 
| 
       37 
45 
     | 
    
         
             
              # @option options [Boolean] _catch_errors Whether to catch raised errors.
         
     | 
| 
       38 
46 
     | 
    
         
             
              # @option options [String] _run_as User to run as using privilege escalation.
         
     | 
| 
       39 
     | 
    
         
            -
              # @option options [Hash] _env_vars Map of environment variables to set
         
     | 
| 
      
 47 
     | 
    
         
            +
              # @option options [Hash] _env_vars Map of environment variables to set.
         
     | 
| 
       40 
48 
     | 
    
         
             
              # @return A list of results, one entry per target.
         
     | 
| 
       41 
49 
     | 
    
         
             
              # @example Run a script
         
     | 
| 
       42 
50 
     | 
    
         
             
              #   run_script('/var/tmp/myscript', $targets, 'Downloading my application')
         
     | 
| 
         @@ -59,9 +67,23 @@ Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFuncti 
     | 
|
| 
       59 
67 
     | 
    
         
             
                    .from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'run_script')
         
     | 
| 
       60 
68 
     | 
    
         
             
                end
         
     | 
| 
       61 
69 
     | 
    
         | 
| 
      
 70 
     | 
    
         
            +
                if options.key?('arguments') && options.key?('pwsh_params')
         
     | 
| 
      
 71 
     | 
    
         
            +
                  raise Bolt::ValidationError, "Cannot specify both 'arguments' and 'pwsh_params'"
         
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                if options.key?('pwsh_params') && !options['pwsh_params'].is_a?(Hash)
         
     | 
| 
      
 75 
     | 
    
         
            +
                  raise Bolt::ValidationError, "Option 'pwsh_params' must be a hash"
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                if options.key?('arguments') && !options['arguments'].is_a?(Array)
         
     | 
| 
      
 79 
     | 
    
         
            +
                  raise Bolt::ValidationError, "Option 'arguments' must be an array"
         
     | 
| 
      
 80 
     | 
    
         
            +
                end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
       62 
82 
     | 
    
         
             
                arguments = options['arguments'] || []
         
     | 
| 
      
 83 
     | 
    
         
            +
                pwsh_params = options['pwsh_params']
         
     | 
| 
       63 
84 
     | 
    
         
             
                options = options.select { |opt| opt.start_with?('_') }.transform_keys { |k| k.sub(/^_/, '').to_sym }
         
     | 
| 
       64 
85 
     | 
    
         
             
                options[:description] = description if description
         
     | 
| 
      
 86 
     | 
    
         
            +
                options[:pwsh_params] = pwsh_params if pwsh_params
         
     | 
| 
       65 
87 
     | 
    
         | 
| 
       66 
88 
     | 
    
         
             
                executor = Puppet.lookup(:bolt_executor)
         
     | 
| 
       67 
89 
     | 
    
         
             
                inventory = Puppet.lookup(:bolt_inventory)
         
     | 
| 
         @@ -80,7 +102,7 @@ Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFuncti 
     | 
|
| 
       80 
102 
     | 
    
         
             
                    Puppet::Pops::Issues::NOT_A_FILE, file: script
         
     | 
| 
       81 
103 
     | 
    
         
             
                  )
         
     | 
| 
       82 
104 
     | 
    
         
             
                end
         
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
      
 105 
     | 
    
         
            +
                executor.report_file_source(self.class.name, script)
         
     | 
| 
       84 
106 
     | 
    
         
             
                # Ensure that given targets are all Target instances)
         
     | 
| 
       85 
107 
     | 
    
         
             
                targets = inventory.get_targets(targets)
         
     | 
| 
       86 
108 
     | 
    
         | 
| 
         @@ -76,7 +76,7 @@ Puppet::Functions.create_function(:upload_file, Puppet::Functions::InternalFunct 
     | 
|
| 
       76 
76 
     | 
    
         
             
                    Puppet::Pops::Issues::NO_SUCH_FILE_OR_DIRECTORY, file: source
         
     | 
| 
       77 
77 
     | 
    
         
             
                  )
         
     | 
| 
       78 
78 
     | 
    
         
             
                end
         
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
      
 79 
     | 
    
         
            +
                executor.report_file_source(self.class.name, source)
         
     | 
| 
       80 
80 
     | 
    
         
             
                # Ensure that that given targets are all Target instances
         
     | 
| 
       81 
81 
     | 
    
         
             
                targets = inventory.get_targets(targets)
         
     | 
| 
       82 
82 
     | 
    
         
             
                if targets.empty?
         
     | 
| 
         @@ -17,7 +17,8 @@ Puppet::Functions.create_function(:'file::read', Puppet::Functions::InternalFunc 
     | 
|
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
              def read(scope, filename)
         
     | 
| 
       19 
19 
     | 
    
         
             
                # Send Analytics Report
         
     | 
| 
       20 
     | 
    
         
            -
                Puppet.lookup(:bolt_executor) {} 
     | 
| 
      
 20 
     | 
    
         
            +
                executor = Puppet.lookup(:bolt_executor) {}
         
     | 
| 
      
 21 
     | 
    
         
            +
                executor&.report_function_call(self.class.name)
         
     | 
| 
       21 
22 
     | 
    
         | 
| 
       22 
23 
     | 
    
         
             
                found = Puppet::Parser::Files.find_file(filename, scope.compiler.environment)
         
     | 
| 
       23 
24 
     | 
    
         
             
                unless found && Puppet::FileSystem.exist?(found)
         
     | 
| 
         @@ -25,7 +26,7 @@ Puppet::Functions.create_function(:'file::read', Puppet::Functions::InternalFunc 
     | 
|
| 
       25 
26 
     | 
    
         
             
                    Puppet::Pops::Issues::NO_SUCH_FILE_OR_DIRECTORY, file: filename
         
     | 
| 
       26 
27 
     | 
    
         
             
                  )
         
     | 
| 
       27 
28 
     | 
    
         
             
                end
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
      
 29 
     | 
    
         
            +
                executor&.report_file_source(self.class.name, filename)
         
     | 
| 
       29 
30 
     | 
    
         
             
                File.read(found)
         
     | 
| 
       30 
31 
     | 
    
         
             
              end
         
     | 
| 
       31 
32 
     | 
    
         
             
            end
         
     | 
    
        data/lib/bolt/apply_result.rb
    CHANGED
    
    | 
         @@ -54,7 +54,7 @@ module Bolt 
     | 
|
| 
       54 
54 
     | 
    
         
             
                  unless missing_keys.empty?
         
     | 
| 
       55 
55 
     | 
    
         
             
                    if result['_output']
         
     | 
| 
       56 
56 
     | 
    
         
             
                      # rubocop:disable Layout/LineLength
         
     | 
| 
       57 
     | 
    
         
            -
                      msg = "Report result contains an '_output' key. Catalog application  
     | 
| 
      
 57 
     | 
    
         
            +
                      msg = "Report result contains an '_output' key. Catalog application might have printed extraneous output to stdout: #{result['_output']}"
         
     | 
| 
       58 
58 
     | 
    
         
             
                      # rubocop:enable Layout/LineLength
         
     | 
| 
       59 
59 
     | 
    
         
             
                    else
         
     | 
| 
       60 
60 
     | 
    
         
             
                      msg = "Report did not contain all expected keys missing: #{missing_keys.join(', ')}"
         
     | 
| 
         @@ -13,7 +13,7 @@ module Bolt 
     | 
|
| 
       13 
13 
     | 
    
         
             
                            run_context: %w[concurrency inventoryfile save-rerun cleanup],
         
     | 
| 
       14 
14 
     | 
    
         
             
                            global_config_setters: PROJECT_PATHS + %w[modulepath],
         
     | 
| 
       15 
15 
     | 
    
         
             
                            transports: %w[transport connect-timeout tty native-ssh ssh-command copy-command],
         
     | 
| 
       16 
     | 
    
         
            -
                            display: %w[format color verbose trace],
         
     | 
| 
      
 16 
     | 
    
         
            +
                            display: %w[format color verbose trace stream],
         
     | 
| 
       17 
17 
     | 
    
         
             
                            global: %w[help version log-level clear-cache] }.freeze
         
     | 
| 
       18 
18 
     | 
    
         | 
| 
       19 
19 
     | 
    
         
             
                ACTION_OPTS = OPTIONS.values.flatten.freeze
         
     | 
| 
         @@ -454,7 +454,7 @@ module Bolt 
     | 
|
| 
       454 
454 
     | 
    
         
             
                  DESCRIPTION
         
     | 
| 
       455 
455 
     | 
    
         
             
                      Convert a YAML plan to a Puppet language plan and print the converted plan to stdout.
         
     | 
| 
       456 
456 
     | 
    
         | 
| 
       457 
     | 
    
         
            -
                      Converting a YAML plan  
     | 
| 
      
 457 
     | 
    
         
            +
                      Converting a YAML plan might result in a plan that is syntactically
         
     | 
| 
       458 
458 
     | 
    
         
             
                      correct but has different behavior. Always verify a converted plan's
         
     | 
| 
       459 
459 
     | 
    
         
             
                      functionality. Note that the converted plan is not written to a file.
         
     | 
| 
       460 
460 
     | 
    
         | 
| 
         @@ -707,7 +707,7 @@ module Bolt 
     | 
|
| 
       707 
707 
     | 
    
         
             
                         "Or read a target list from an input file '@<file>' or stdin '-'.",
         
     | 
| 
       708 
708 
     | 
    
         
             
                         'Example: --targets localhost,target_group,ssh://nix.com:23,winrm://windows.puppet.com',
         
     | 
| 
       709 
709 
     | 
    
         
             
                         'URI format is [protocol://]host[:port]',
         
     | 
| 
       710 
     | 
    
         
            -
                         "SSH is the default protocol;  
     | 
| 
      
 710 
     | 
    
         
            +
                         "SSH is the default protocol; can be #{TRANSPORTS.keys.join(', ')}",
         
     | 
| 
       711 
711 
     | 
    
         
             
                         'For Windows targets, specify the winrm:// protocol if it has not be configured',
         
     | 
| 
       712 
712 
     | 
    
         
             
                         'For SSH, port defaults to `22`',
         
     | 
| 
       713 
713 
     | 
    
         
             
                         'For WinRM, port defaults to `5985` or `5986` based on the --[no-]ssl setting') do |targets|
         
     | 
| 
         @@ -888,6 +888,9 @@ module Bolt 
     | 
|
| 
       888 
888 
     | 
    
         
             
                  define('-v', '--[no-]verbose', 'Display verbose logging') do |value|
         
     | 
| 
       889 
889 
     | 
    
         
             
                    @options[:verbose] = value
         
     | 
| 
       890 
890 
     | 
    
         
             
                  end
         
     | 
| 
      
 891 
     | 
    
         
            +
                  define('--stream', 'Stream output from scripts and commands to the console') do |_|
         
     | 
| 
      
 892 
     | 
    
         
            +
                    @options[:stream] = true
         
     | 
| 
      
 893 
     | 
    
         
            +
                  end
         
     | 
| 
       891 
894 
     | 
    
         
             
                  define('--trace', 'Display error stack traces') do |_|
         
     | 
| 
       892 
895 
     | 
    
         
             
                    @options[:trace] = true
         
     | 
| 
       893 
896 
     | 
    
         
             
                  end
         
     | 
    
        data/lib/bolt/cli.rb
    CHANGED
    
    | 
         @@ -175,6 +175,7 @@ module Bolt 
     | 
|
| 
       175 
175 
     | 
    
         
             
                # Completes the setup process by configuring Bolt and log messages
         
     | 
| 
       176 
176 
     | 
    
         
             
                def finalize_setup
         
     | 
| 
       177 
177 
     | 
    
         
             
                  Bolt::Logger.configure(config.log, config.color, config.disable_warnings)
         
     | 
| 
      
 178 
     | 
    
         
            +
                  Bolt::Logger.stream = config.stream
         
     | 
| 
       178 
179 
     | 
    
         
             
                  Bolt::Logger.analytics = analytics
         
     | 
| 
       179 
180 
     | 
    
         
             
                  Bolt::Logger.flush_queue
         
     | 
| 
       180 
181 
     | 
    
         | 
| 
         @@ -212,7 +213,7 @@ module Bolt 
     | 
|
| 
       212 
213 
     | 
    
         
             
                  target_opts = options.keys.select { |opt| %i[query rerun targets].include?(opt) }
         
     | 
| 
       213 
214 
     | 
    
         
             
                  target_string = "'--targets', '--rerun', or '--query'"
         
     | 
| 
       214 
215 
     | 
    
         
             
                  if target_opts.length > 1
         
     | 
| 
       215 
     | 
    
         
            -
                    raise Bolt::CLIError, "Only one targeting option #{target_string}  
     | 
| 
      
 216 
     | 
    
         
            +
                    raise Bolt::CLIError, "Only one targeting option #{target_string} can be specified"
         
     | 
| 
       216 
217 
     | 
    
         
             
                  elsif target_opts.empty? && options[:subcommand] != 'plan'
         
     | 
| 
       217 
218 
     | 
    
         
             
                    raise Bolt::CLIError, "Command requires a targeting option: #{target_string}"
         
     | 
| 
       218 
219 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -249,11 +250,14 @@ module Bolt 
     | 
|
| 
       249 
250 
     | 
    
         
             
                    end
         
     | 
| 
       250 
251 
     | 
    
         
             
                  end
         
     | 
| 
       251 
252 
     | 
    
         | 
| 
       252 
     | 
    
         
            -
                  if %w[task plan].include?(options[:subcommand]) && options[:action] == 'run'
         
     | 
| 
      
 253 
     | 
    
         
            +
                  if %w[task plan script].include?(options[:subcommand]) && options[:action] == 'run'
         
     | 
| 
       253 
254 
     | 
    
         
             
                    if options[:object].nil?
         
     | 
| 
       254 
255 
     | 
    
         
             
                      raise Bolt::CLIError, "Must specify a #{options[:subcommand]} to run"
         
     | 
| 
       255 
256 
     | 
    
         
             
                    end
         
     | 
| 
       256 
     | 
    
         
            -
             
     | 
| 
      
 257 
     | 
    
         
            +
                  end
         
     | 
| 
      
 258 
     | 
    
         
            +
             
     | 
| 
      
 259 
     | 
    
         
            +
                  # This may mean that we parsed a parameter as the object
         
     | 
| 
      
 260 
     | 
    
         
            +
                  if %w[task plan].include?(options[:subcommand]) && options[:action] == 'run'
         
     | 
| 
       257 
261 
     | 
    
         
             
                    unless options[:object] =~ /\A([a-z][a-z0-9_]*)?(::[a-z][a-z0-9_]*)*\Z/
         
     | 
| 
       258 
262 
     | 
    
         
             
                      raise Bolt::CLIError,
         
     | 
| 
       259 
263 
     | 
    
         
             
                            "Invalid #{options[:subcommand]} '#{options[:object]}'"
         
     | 
| 
         @@ -301,13 +305,13 @@ module Bolt 
     | 
|
| 
       301 
305 
     | 
    
         
             
                  if options[:noop] &&
         
     | 
| 
       302 
306 
     | 
    
         
             
                     !(options[:subcommand] == 'task' && options[:action] == 'run') && options[:subcommand] != 'apply'
         
     | 
| 
       303 
307 
     | 
    
         
             
                    raise Bolt::CLIError,
         
     | 
| 
       304 
     | 
    
         
            -
                          "Option '--noop'  
     | 
| 
      
 308 
     | 
    
         
            +
                          "Option '--noop' can only be specified when running a task or applying manifest code"
         
     | 
| 
       305 
309 
     | 
    
         
             
                  end
         
     | 
| 
       306 
310 
     | 
    
         | 
| 
       307 
311 
     | 
    
         
             
                  if options[:env_vars]
         
     | 
| 
       308 
312 
     | 
    
         
             
                    unless %w[command script].include?(options[:subcommand]) && options[:action] == 'run'
         
     | 
| 
       309 
313 
     | 
    
         
             
                      raise Bolt::CLIError,
         
     | 
| 
       310 
     | 
    
         
            -
                            "Option '--env-var'  
     | 
| 
      
 314 
     | 
    
         
            +
                            "Option '--env-var' can only be specified when running a command or script"
         
     | 
| 
       311 
315 
     | 
    
         
             
                    end
         
     | 
| 
       312 
316 
     | 
    
         
             
                  end
         
     | 
| 
       313 
317 
     | 
    
         
             
                end
         
     | 
| 
         @@ -354,7 +358,7 @@ module Bolt 
     | 
|
| 
       354 
358 
     | 
    
         
             
                  if inventory_source && conflicting_options.any?
         
     | 
| 
       355 
359 
     | 
    
         
             
                    Bolt::Logger.warn(
         
     | 
| 
       356 
360 
     | 
    
         
             
                      "cli_overrides",
         
     | 
| 
       357 
     | 
    
         
            -
                      "CLI arguments #{conflicting_options.to_a}  
     | 
| 
      
 361 
     | 
    
         
            +
                      "CLI arguments #{conflicting_options.to_a} might be overridden by Inventory: #{inventory_source}"
         
     | 
| 
       358 
362 
     | 
    
         
             
                    )
         
     | 
| 
       359 
363 
     | 
    
         
             
                  end
         
     | 
| 
       360 
364 
     | 
    
         
             
                end
         
     | 
| 
         @@ -432,7 +436,7 @@ module Bolt 
     | 
|
| 
       432 
436 
     | 
    
         
             
                    return 0
         
     | 
| 
       433 
437 
     | 
    
         
             
                  end
         
     | 
| 
       434 
438 
     | 
    
         | 
| 
       435 
     | 
    
         
            -
                  message = 'There  
     | 
| 
      
 439 
     | 
    
         
            +
                  message = 'There might be processes left executing on some nodes.'
         
     | 
| 
       436 
440 
     | 
    
         | 
| 
       437 
441 
     | 
    
         
             
                  if %w[task plan].include?(options[:subcommand]) && options[:task_options] && !options[:params_parsed] && pal
         
     | 
| 
       438 
442 
     | 
    
         
             
                    options[:task_options] = pal.parse_params(options[:subcommand], options[:object], options[:task_options])
         
     | 
| 
         @@ -501,9 +505,8 @@ module Bolt 
     | 
|
| 
       501 
505 
     | 
    
         
             
                        when 'command'
         
     | 
| 
       502 
506 
     | 
    
         
             
                          executor.run_command(targets, options[:object], executor_opts)
         
     | 
| 
       503 
507 
     | 
    
         
             
                        when 'script'
         
     | 
| 
       504 
     | 
    
         
            -
                           
     | 
| 
       505 
     | 
    
         
            -
                           
     | 
| 
       506 
     | 
    
         
            -
                          executor.run_script(targets, script, options[:leftovers], executor_opts)
         
     | 
| 
      
 508 
     | 
    
         
            +
                          script_path = find_file(options[:object])
         
     | 
| 
      
 509 
     | 
    
         
            +
                          executor.run_script(targets, script_path, options[:leftovers], executor_opts)
         
     | 
| 
       507 
510 
     | 
    
         
             
                        when 'task'
         
     | 
| 
       508 
511 
     | 
    
         
             
                          pal.run_task(options[:object],
         
     | 
| 
       509 
512 
     | 
    
         
             
                                       targets,
         
     | 
| 
         @@ -610,7 +613,7 @@ module Bolt 
     | 
|
| 
       610 
613 
     | 
    
         
             
                    if plan_arguments['nodes'] || plan_arguments['targets']
         
     | 
| 
       611 
614 
     | 
    
         
             
                      key = plan_arguments.include?('nodes') ? 'nodes' : 'targets'
         
     | 
| 
       612 
615 
     | 
    
         
             
                      raise Bolt::CLIError,
         
     | 
| 
       613 
     | 
    
         
            -
                            "A plan's '#{key}' parameter  
     | 
| 
      
 616 
     | 
    
         
            +
                            "A plan's '#{key}' parameter can be specified using the --#{key} option, but in that " \
         
     | 
| 
       614 
617 
     | 
    
         
             
                            "case it must not be specified as a separate #{key}=<value> parameter nor included " \
         
     | 
| 
       615 
618 
     | 
    
         
             
                            "in the JSON data passed in the --params option"
         
     | 
| 
       616 
619 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -840,6 +843,28 @@ module Bolt 
     | 
|
| 
       840 
843 
     | 
    
         
             
                  Bolt::Util.validate_file(type, path, allow_dir)
         
     | 
| 
       841 
844 
     | 
    
         
             
                end
         
     | 
| 
       842 
845 
     | 
    
         | 
| 
      
 846 
     | 
    
         
            +
                # Returns the path to a file. If the path is an absolute or relative to
         
     | 
| 
      
 847 
     | 
    
         
            +
                # a file, and the file exists, returns the path as-is. Otherwise, checks if
         
     | 
| 
      
 848 
     | 
    
         
            +
                # the path is a Puppet file path and looks for the file in a module's files
         
     | 
| 
      
 849 
     | 
    
         
            +
                # directory.
         
     | 
| 
      
 850 
     | 
    
         
            +
                #
         
     | 
| 
      
 851 
     | 
    
         
            +
                def find_file(path)
         
     | 
| 
      
 852 
     | 
    
         
            +
                  unless File.exist?(path) || Pathname.new(path).absolute?
         
     | 
| 
      
 853 
     | 
    
         
            +
                    modulepath = Bolt::Config::Modulepath.new(config.modulepath)
         
     | 
| 
      
 854 
     | 
    
         
            +
                    modules    = Bolt::Module.discover(modulepath.full_modulepath, config.project)
         
     | 
| 
      
 855 
     | 
    
         
            +
                    mod, file = path.split(File::SEPARATOR, 2)
         
     | 
| 
      
 856 
     | 
    
         
            +
             
     | 
| 
      
 857 
     | 
    
         
            +
                    if modules[mod]
         
     | 
| 
      
 858 
     | 
    
         
            +
                      @logger.debug("Did not find file at #{File.expand_path(path)}, checking in module '#{mod}'")
         
     | 
| 
      
 859 
     | 
    
         
            +
                      path = File.join(modules[mod].path, 'files', file)
         
     | 
| 
      
 860 
     | 
    
         
            +
                    end
         
     | 
| 
      
 861 
     | 
    
         
            +
                  end
         
     | 
| 
      
 862 
     | 
    
         
            +
             
     | 
| 
      
 863 
     | 
    
         
            +
                  Bolt::Util.validate_file('script', path)
         
     | 
| 
      
 864 
     | 
    
         
            +
             
     | 
| 
      
 865 
     | 
    
         
            +
                  path
         
     | 
| 
      
 866 
     | 
    
         
            +
                end
         
     | 
| 
      
 867 
     | 
    
         
            +
             
     | 
| 
       843 
868 
     | 
    
         
             
                def rerun
         
     | 
| 
       844 
869 
     | 
    
         
             
                  @rerun ||= Bolt::Rerun.new(config.rerunfile, config.save_rerun)
         
     | 
| 
       845 
870 
     | 
    
         
             
                end
         
     | 
| 
         @@ -868,7 +893,7 @@ module Bolt 
     | 
|
| 
       868 
893 
     | 
    
         
             
                  # If the bundled content directory is empty, Bolt is likely installed as a gem.
         
     | 
| 
       869 
894 
     | 
    
         
             
                  if ENV['BOLT_GEM'].nil? && incomplete_install?
         
     | 
| 
       870 
895 
     | 
    
         
             
                    msg = <<~MSG.chomp
         
     | 
| 
       871 
     | 
    
         
            -
                      Bolt  
     | 
| 
      
 896 
     | 
    
         
            +
                      Bolt might be installed as a gem. To use Bolt reliably and with all of its
         
     | 
| 
       872 
897 
     | 
    
         
             
                      dependencies, uninstall the 'bolt' gem and install Bolt as a package:
         
     | 
| 
       873 
898 
     | 
    
         
             
                      https://puppet.com/docs/bolt/latest/bolt_installing.html
         
     | 
| 
       874 
899 
     | 
    
         | 
    
        data/lib/bolt/config.rb
    CHANGED
    
    
    
        data/lib/bolt/config/options.rb
    CHANGED
    
    | 
         @@ -4,6 +4,7 @@ require 'bolt/config/transport/ssh' 
     | 
|
| 
       4 
4 
     | 
    
         
             
            require 'bolt/config/transport/winrm'
         
     | 
| 
       5 
5 
     | 
    
         
             
            require 'bolt/config/transport/orch'
         
     | 
| 
       6 
6 
     | 
    
         
             
            require 'bolt/config/transport/local'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'bolt/config/transport/lxd'
         
     | 
| 
       7 
8 
     | 
    
         
             
            require 'bolt/config/transport/docker'
         
     | 
| 
       8 
9 
     | 
    
         
             
            require 'bolt/config/transport/remote'
         
     | 
| 
       9 
10 
     | 
    
         | 
| 
         @@ -17,6 +18,7 @@ module Bolt 
     | 
|
| 
       17 
18 
     | 
    
         
             
                    'winrm'  => Bolt::Config::Transport::WinRM,
         
     | 
| 
       18 
19 
     | 
    
         
             
                    'pcp'    => Bolt::Config::Transport::Orch,
         
     | 
| 
       19 
20 
     | 
    
         
             
                    'local'  => Bolt::Config::Transport::Local,
         
     | 
| 
      
 21 
     | 
    
         
            +
                    'lxd'    => Bolt::Config::Transport::LXD,
         
     | 
| 
       20 
22 
     | 
    
         
             
                    'docker' => Bolt::Config::Transport::Docker,
         
     | 
| 
       21 
23 
     | 
    
         
             
                    'remote' => Bolt::Config::Transport::Remote
         
     | 
| 
       22 
24 
     | 
    
         
             
                  }.freeze
         
     | 
| 
         @@ -423,7 +425,14 @@ module Bolt 
     | 
|
| 
       423 
425 
     | 
    
         
             
                      _example: false,
         
     | 
| 
       424 
426 
     | 
    
         
             
                      _default: true
         
     | 
| 
       425 
427 
     | 
    
         
             
                    },
         
     | 
| 
       426 
     | 
    
         
            -
             
     | 
| 
      
 428 
     | 
    
         
            +
                    "stream" => {
         
     | 
| 
      
 429 
     | 
    
         
            +
                      description: "Whether to stream output from scripts and commands to the console. "\
         
     | 
| 
      
 430 
     | 
    
         
            +
                                   "**This option is experimental**.",
         
     | 
| 
      
 431 
     | 
    
         
            +
                      type: [TrueClass, FalseClass],
         
     | 
| 
      
 432 
     | 
    
         
            +
                      _plugin: false,
         
     | 
| 
      
 433 
     | 
    
         
            +
                      _default: false,
         
     | 
| 
      
 434 
     | 
    
         
            +
                      _example: true
         
     | 
| 
      
 435 
     | 
    
         
            +
                    },
         
     | 
| 
       427 
436 
     | 
    
         
             
                    "tasks" => {
         
     | 
| 
       428 
437 
     | 
    
         
             
                      description: "A list of task names and glob patterns to filter the project's tasks by. This option is used "\
         
     | 
| 
       429 
438 
     | 
    
         
             
                                   "to limit the visibility of tasks for users of the project. For example, project authors "\
         
     | 
| 
         @@ -440,8 +449,8 @@ module Bolt 
     | 
|
| 
       440 
449 
     | 
    
         
             
                    },
         
     | 
| 
       441 
450 
     | 
    
         
             
                    "trusted-external-command" => {
         
     | 
| 
       442 
451 
     | 
    
         
             
                      description: "The path to an executable on the Bolt controller that can produce external trusted facts. "\
         
     | 
| 
       443 
     | 
    
         
            -
                                   "**External trusted facts are experimental in both Puppet and Bolt and this API  
     | 
| 
       444 
     | 
    
         
            -
                                   "be removed.**",
         
     | 
| 
      
 452 
     | 
    
         
            +
                                   "**External trusted facts are experimental in both Puppet and Bolt and this API might "\
         
     | 
| 
      
 453 
     | 
    
         
            +
                                   "change or be removed.**",
         
     | 
| 
       445 
454 
     | 
    
         
             
                      type: String,
         
     | 
| 
       446 
455 
     | 
    
         
             
                      _plugin: false,
         
     | 
| 
       447 
456 
     | 
    
         
             
                      _example: "/etc/puppetlabs/facts/trusted_external.sh"
         
     | 
| 
         @@ -475,6 +484,13 @@ module Bolt 
     | 
|
| 
       475 
484 
     | 
    
         
             
                      _plugin: true,
         
     | 
| 
       476 
485 
     | 
    
         
             
                      _example: { "cleanup" => false, "tmpdir" => "/tmp/bolt" }
         
     | 
| 
       477 
486 
     | 
    
         
             
                    },
         
     | 
| 
      
 487 
     | 
    
         
            +
                    "lxd" => {
         
     | 
| 
      
 488 
     | 
    
         
            +
                      description: "A map of configuration options for the LXD transport. The LXD transport is "\
         
     | 
| 
      
 489 
     | 
    
         
            +
                                   "experimental and might include breaking changes between minor versions.",
         
     | 
| 
      
 490 
     | 
    
         
            +
                      type: Hash,
         
     | 
| 
      
 491 
     | 
    
         
            +
                      _plugin: true,
         
     | 
| 
      
 492 
     | 
    
         
            +
                      _example: { cleanup: false }
         
     | 
| 
      
 493 
     | 
    
         
            +
                    },
         
     | 
| 
       478 
494 
     | 
    
         
             
                    "pcp" => {
         
     | 
| 
       479 
495 
     | 
    
         
             
                      description: "A map of configuration options for the pcp transport.",
         
     | 
| 
       480 
496 
     | 
    
         
             
                      type: Hash,
         
     | 
| 
         @@ -530,6 +546,7 @@ module Bolt 
     | 
|
| 
       530 
546 
     | 
    
         
             
                    puppetdb
         
     | 
| 
       531 
547 
     | 
    
         
             
                    save-rerun
         
     | 
| 
       532 
548 
     | 
    
         
             
                    spinner
         
     | 
| 
      
 549 
     | 
    
         
            +
                    stream
         
     | 
| 
       533 
550 
     | 
    
         
             
                  ].freeze
         
     | 
| 
       534 
551 
     | 
    
         | 
| 
       535 
552 
     | 
    
         
             
                  # Options that are available in a bolt-project.yaml file
         
     | 
| 
         @@ -553,6 +570,7 @@ module Bolt 
     | 
|
| 
       553 
570 
     | 
    
         
             
                    puppetdb
         
     | 
| 
       554 
571 
     | 
    
         
             
                    save-rerun
         
     | 
| 
       555 
572 
     | 
    
         
             
                    spinner
         
     | 
| 
      
 573 
     | 
    
         
            +
                    stream
         
     | 
| 
       556 
574 
     | 
    
         
             
                    tasks
         
     | 
| 
       557 
575 
     | 
    
         
             
                    trusted-external-command
         
     | 
| 
       558 
576 
     | 
    
         
             
                  ].freeze
         
     |