bolt 3.3.0 → 3.4.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 +3 -3
 - data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +20 -2
 - data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +19 -2
 - data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +20 -2
 - data/bolt-modules/prompt/lib/puppet/functions/prompt/menu.rb +103 -0
 - data/lib/bolt/cli.rb +52 -0
 - data/lib/bolt/config/transport/lxd.rb +3 -1
 - data/lib/bolt/config/transport/options.rb +7 -0
 - data/lib/bolt/executor.rb +10 -2
 - data/lib/bolt/node/output.rb +14 -4
 - data/lib/bolt/outputter/human.rb +4 -11
 - data/lib/bolt/pal.rb +22 -2
 - data/lib/bolt/pal/yaml_plan/step/command.rb +8 -0
 - data/lib/bolt/pal/yaml_plan/step/script.rb +4 -0
 - data/lib/bolt/pal/yaml_plan/transpiler.rb +2 -2
 - data/lib/bolt/result.rb +4 -10
 - data/lib/bolt/shell/bash.rb +10 -12
 - data/lib/bolt/shell/powershell.rb +6 -8
 - data/lib/bolt/transport/lxd/connection.rb +5 -5
 - data/lib/bolt/transport/orch.rb +13 -5
 - data/lib/bolt/util.rb +8 -0
 - data/lib/bolt/version.rb +1 -1
 - data/lib/bolt_spec/plans/action_stubs/command_stub.rb +8 -1
 - data/lib/bolt_spec/plans/action_stubs/script_stub.rb +8 -1
 - metadata +3 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 2e66e28078af9324bb7d5668ee5079535d829913a2dcb4bce65daa4d471d4524
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: a821d82c490030be200c0d4ab5dc4a56a1abf1aa862d69d1e4c6a4595e47952d
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 120dd18c9478c105387f2ad3634276cbaae05fe3638cc01d378aa9cbb1c423bf737991b7278ab4f96eb0a7cca39cd3d259cbba3d1734cea6ac071ba0695da901
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 61171ff383d06883e6f6ffa0cafc423a80d41ea0f2d45c3c0e4b76c7037a4626ad7a4b8b625e3a013e077b9e96cdafaab06cad6d5a490dae392af3fbb410d0fe
         
     | 
    
        data/Puppetfile
    CHANGED
    
    | 
         @@ -6,7 +6,7 @@ moduledir File.join(File.dirname(__FILE__), 'modules') 
     | 
|
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            # Core modules used by 'apply'
         
     | 
| 
       8 
8 
     | 
    
         
             
            mod 'puppetlabs-service', '2.0.0'
         
     | 
| 
       9 
     | 
    
         
            -
            mod 'puppetlabs-puppet_agent', '4. 
     | 
| 
      
 9 
     | 
    
         
            +
            mod 'puppetlabs-puppet_agent', '4.5.0'
         
     | 
| 
       10 
10 
     | 
    
         
             
            mod 'puppetlabs-facts', '1.4.0'
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
            # Core types and providers for Puppet 6
         
     | 
| 
         @@ -24,9 +24,9 @@ mod 'puppetlabs-zone_core', '1.0.3' 
     | 
|
| 
       24 
24 
     | 
    
         
             
            # Useful additional modules
         
     | 
| 
       25 
25 
     | 
    
         
             
            mod 'puppetlabs-package', '2.0.0'
         
     | 
| 
       26 
26 
     | 
    
         
             
            mod 'puppetlabs-powershell_task_helper', '0.1.0'
         
     | 
| 
       27 
     | 
    
         
            -
            mod 'puppetlabs-puppet_conf', '1. 
     | 
| 
      
 27 
     | 
    
         
            +
            mod 'puppetlabs-puppet_conf', '1.1.0'
         
     | 
| 
       28 
28 
     | 
    
         
             
            mod 'puppetlabs-python_task_helper', '0.5.0'
         
     | 
| 
       29 
     | 
    
         
            -
            mod 'puppetlabs-reboot', '4.0. 
     | 
| 
      
 29 
     | 
    
         
            +
            mod 'puppetlabs-reboot', '4.0.2'
         
     | 
| 
       30 
30 
     | 
    
         
             
            mod 'puppetlabs-ruby_task_helper', '0.6.0'
         
     | 
| 
       31 
31 
     | 
    
         
             
            mod 'puppetlabs-ruby_plugin_helper', '0.2.0'
         
     | 
| 
       32 
32 
     | 
    
         
             
            mod 'puppetlabs-stdlib', '7.0.0'
         
     | 
| 
         @@ -1,6 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require 'bolt/error'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'json'
         
     | 
| 
       4 
5 
     | 
    
         | 
| 
       5 
6 
     | 
    
         
             
            # Runs a command on the given set of targets and returns the result from each command execution.
         
     | 
| 
       6 
7 
     | 
    
         
             
            # This function does nothing if the list of targets is empty.
         
     | 
| 
         @@ -13,7 +14,7 @@ Puppet::Functions.create_function(:run_command) do 
     | 
|
| 
       13 
14 
     | 
    
         
             
              # @param options A hash of additional options.
         
     | 
| 
       14 
15 
     | 
    
         
             
              # @option options [Boolean] _catch_errors Whether to catch raised errors.
         
     | 
| 
       15 
16 
     | 
    
         
             
              # @option options [String] _run_as User to run as using privilege escalation.
         
     | 
| 
       16 
     | 
    
         
            -
              # @option options [Hash] _env_vars Map of environment variables to set
         
     | 
| 
      
 17 
     | 
    
         
            +
              # @option options [Hash[String, Any]] _env_vars Map of environment variables to set
         
     | 
| 
       17 
18 
     | 
    
         
             
              # @return A list of results, one entry per target.
         
     | 
| 
       18 
19 
     | 
    
         
             
              # @example Run a command on targets
         
     | 
| 
       19 
20 
     | 
    
         
             
              #   run_command('hostname', $targets, '_catch_errors' => true)
         
     | 
| 
         @@ -31,7 +32,7 @@ Puppet::Functions.create_function(:run_command) do 
     | 
|
| 
       31 
32 
     | 
    
         
             
              # @param options A hash of additional options.
         
     | 
| 
       32 
33 
     | 
    
         
             
              # @option options [Boolean] _catch_errors Whether to catch raised errors.
         
     | 
| 
       33 
34 
     | 
    
         
             
              # @option options [String] _run_as User to run as using privilege escalation.
         
     | 
| 
       34 
     | 
    
         
            -
              # @option options [Hash] _env_vars Map of environment variables to set
         
     | 
| 
      
 35 
     | 
    
         
            +
              # @option options [Hash[String, Any]] _env_vars Map of environment variables to set
         
     | 
| 
       35 
36 
     | 
    
         
             
              # @return A list of results, one entry per target.
         
     | 
| 
       36 
37 
     | 
    
         
             
              # @example Run a command on targets
         
     | 
| 
       37 
38 
     | 
    
         
             
              #   run_command('hostname', $targets, 'Get hostname')
         
     | 
| 
         @@ -56,6 +57,23 @@ Puppet::Functions.create_function(:run_command) do 
     | 
|
| 
       56 
57 
     | 
    
         
             
                options = options.transform_keys { |k| k.sub(/^_/, '').to_sym }
         
     | 
| 
       57 
58 
     | 
    
         
             
                options[:description] = description if description
         
     | 
| 
       58 
59 
     | 
    
         | 
| 
      
 60 
     | 
    
         
            +
                # Ensure env_vars is a hash and that each hash value is transformed to JSON
         
     | 
| 
      
 61 
     | 
    
         
            +
                # so we don't accidentally pass Ruby-style data to the target.
         
     | 
| 
      
 62 
     | 
    
         
            +
                if options[:env_vars]
         
     | 
| 
      
 63 
     | 
    
         
            +
                  unless options[:env_vars].is_a?(Hash)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    raise Bolt::ValidationError, "Option 'env_vars' must be a hash"
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  if (bad_keys = options[:env_vars].keys.reject { |k| k.is_a?(String) }).any?
         
     | 
| 
      
 68 
     | 
    
         
            +
                    raise Bolt::ValidationError,
         
     | 
| 
      
 69 
     | 
    
         
            +
                          "Keys for option 'env_vars' must be strings: #{bad_keys.map(&:inspect).join(', ')}"
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                  options[:env_vars] = options[:env_vars].transform_values do |val|
         
     | 
| 
      
 73 
     | 
    
         
            +
                    [Array, Hash].include?(val.class) ? val.to_json : val
         
     | 
| 
      
 74 
     | 
    
         
            +
                  end
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
       59 
77 
     | 
    
         
             
                executor = Puppet.lookup(:bolt_executor)
         
     | 
| 
       60 
78 
     | 
    
         
             
                inventory = Puppet.lookup(:bolt_inventory)
         
     | 
| 
       61 
79 
     | 
    
         | 
| 
         @@ -16,7 +16,7 @@ Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFuncti 
     | 
|
| 
       16 
16 
     | 
    
         
             
              #   Cannot be used with `arguments`.
         
     | 
| 
       17 
17 
     | 
    
         
             
              # @option options [Boolean] _catch_errors Whether to catch raised errors.
         
     | 
| 
       18 
18 
     | 
    
         
             
              # @option options [String] _run_as User to run as using privilege escalation.
         
     | 
| 
       19 
     | 
    
         
            -
              # @option options [Hash] _env_vars Map of environment variables to set.
         
     | 
| 
      
 19 
     | 
    
         
            +
              # @option options [Hash[String, Any]] _env_vars Map of environment variables to set.
         
     | 
| 
       20 
20 
     | 
    
         
             
              # @return A list of results, one entry per target.
         
     | 
| 
       21 
21 
     | 
    
         
             
              # @example Run a local script on Linux targets as 'root'
         
     | 
| 
       22 
22 
     | 
    
         
             
              #   run_script('/var/tmp/myscript', $targets, '_run_as' => 'root')
         
     | 
| 
         @@ -44,7 +44,7 @@ Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFuncti 
     | 
|
| 
       44 
44 
     | 
    
         
             
              #   Cannot be used with `arguments`.
         
     | 
| 
       45 
45 
     | 
    
         
             
              # @option options [Boolean] _catch_errors Whether to catch raised errors.
         
     | 
| 
       46 
46 
     | 
    
         
             
              # @option options [String] _run_as User to run as using privilege escalation.
         
     | 
| 
       47 
     | 
    
         
            -
              # @option options [Hash] _env_vars Map of environment variables to set.
         
     | 
| 
      
 47 
     | 
    
         
            +
              # @option options [Hash[String, Any]] _env_vars Map of environment variables to set.
         
     | 
| 
       48 
48 
     | 
    
         
             
              # @return A list of results, one entry per target.
         
     | 
| 
       49 
49 
     | 
    
         
             
              # @example Run a script
         
     | 
| 
       50 
50 
     | 
    
         
             
              #   run_script('/var/tmp/myscript', $targets, 'Downloading my application')
         
     | 
| 
         @@ -85,6 +85,23 @@ Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFuncti 
     | 
|
| 
       85 
85 
     | 
    
         
             
                options[:description] = description if description
         
     | 
| 
       86 
86 
     | 
    
         
             
                options[:pwsh_params] = pwsh_params if pwsh_params
         
     | 
| 
       87 
87 
     | 
    
         | 
| 
      
 88 
     | 
    
         
            +
                # Ensure env_vars is a hash and that each hash value is transformed to JSON
         
     | 
| 
      
 89 
     | 
    
         
            +
                # so we don't accidentally pass Ruby-style data to the target.
         
     | 
| 
      
 90 
     | 
    
         
            +
                if options[:env_vars]
         
     | 
| 
      
 91 
     | 
    
         
            +
                  unless options[:env_vars].is_a?(Hash)
         
     | 
| 
      
 92 
     | 
    
         
            +
                    raise Bolt::ValidationError, "Option 'env_vars' must be a hash"
         
     | 
| 
      
 93 
     | 
    
         
            +
                  end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                  if (bad_keys = options[:env_vars].keys.reject { |k| k.is_a?(String) }).any?
         
     | 
| 
      
 96 
     | 
    
         
            +
                    raise Bolt::ValidationError,
         
     | 
| 
      
 97 
     | 
    
         
            +
                          "Keys for option 'env_vars' must be strings: #{bad_keys.map(&:inspect).join(', ')}"
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  options[:env_vars] = options[:env_vars].transform_values do |val|
         
     | 
| 
      
 101 
     | 
    
         
            +
                    [Array, Hash].include?(val.class) ? val.to_json : val
         
     | 
| 
      
 102 
     | 
    
         
            +
                  end
         
     | 
| 
      
 103 
     | 
    
         
            +
                end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
       88 
105 
     | 
    
         
             
                executor = Puppet.lookup(:bolt_executor)
         
     | 
| 
       89 
106 
     | 
    
         
             
                inventory = Puppet.lookup(:bolt_inventory)
         
     | 
| 
       90 
107 
     | 
    
         | 
| 
         @@ -11,12 +11,24 @@ Puppet::Functions.create_function(:prompt) do 
     | 
|
| 
       11 
11 
     | 
    
         
             
              # @option options [Boolean] sensitive Disable echo back and mark the response as sensitive.
         
     | 
| 
       12 
12 
     | 
    
         
             
              #   The returned value will be wrapped by the `Sensitive` data type. To access the raw
         
     | 
| 
       13 
13 
     | 
    
         
             
              #   value, use the `unwrap` function (i.e. `$sensitive_value.unwrap`).
         
     | 
| 
      
 14 
     | 
    
         
            +
              # @option options [String] default The default value to return if the user does not provide
         
     | 
| 
      
 15 
     | 
    
         
            +
              #   input or if stdin is not a tty.
         
     | 
| 
       14 
16 
     | 
    
         
             
              # @return The response to the prompt.
         
     | 
| 
       15 
17 
     | 
    
         
             
              # @example Prompt the user if plan execution should continue
         
     | 
| 
       16 
18 
     | 
    
         
             
              #   $response = prompt('Continue executing plan? [Y\N]')
         
     | 
| 
       17 
19 
     | 
    
         
             
              # @example Prompt the user for sensitive information
         
     | 
| 
       18 
20 
     | 
    
         
             
              #   $password = prompt('Enter your password', 'sensitive' => true)
         
     | 
| 
       19 
21 
     | 
    
         
             
              #   out::message("Password is: ${password.unwrap}")
         
     | 
| 
      
 22 
     | 
    
         
            +
              # @example Prompt the user and provide a default value
         
     | 
| 
      
 23 
     | 
    
         
            +
              #   $user = prompt('Enter your login username', 'default' => 'root')
         
     | 
| 
      
 24 
     | 
    
         
            +
              # @example Prompt the user for sensitive information, returning a sensitive default if one is not provided
         
     | 
| 
      
 25 
     | 
    
         
            +
              #   $token = prompt('Enter token', 'default' => lookup('default_token'), 'sensitive' => true)
         
     | 
| 
      
 26 
     | 
    
         
            +
              #   out::message("Token is: ${token.unwrap}")
         
     | 
| 
      
 27 
     | 
    
         
            +
              # @example Prompt the user and fail with a custom message if no input was provided
         
     | 
| 
      
 28 
     | 
    
         
            +
              #   $response = prompt('Enter your name', 'default' => '')
         
     | 
| 
      
 29 
     | 
    
         
            +
              #   if $response.empty {
         
     | 
| 
      
 30 
     | 
    
         
            +
              #     fail_plan('Must provide your name')
         
     | 
| 
      
 31 
     | 
    
         
            +
              #   }
         
     | 
| 
       20 
32 
     | 
    
         
             
              dispatch :prompt do
         
     | 
| 
       21 
33 
     | 
    
         
             
                param 'String', :prompt
         
     | 
| 
       22 
34 
     | 
    
         
             
                optional_param 'Hash[String[1], Any]', :options
         
     | 
| 
         @@ -30,14 +42,20 @@ Puppet::Functions.create_function(:prompt) do 
     | 
|
| 
       30 
42 
     | 
    
         
             
                                          action: 'prompt')
         
     | 
| 
       31 
43 
     | 
    
         
             
                end
         
     | 
| 
       32 
44 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
                options 
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
      
 45 
     | 
    
         
            +
                options  = options.transform_keys(&:to_sym)
         
     | 
| 
       35 
46 
     | 
    
         
             
                executor = Puppet.lookup(:bolt_executor)
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
       36 
48 
     | 
    
         
             
                # Send analytics report
         
     | 
| 
       37 
49 
     | 
    
         
             
                executor.report_function_call(self.class.name)
         
     | 
| 
       38 
50 
     | 
    
         | 
| 
      
 51 
     | 
    
         
            +
                # Require default to be a string value
         
     | 
| 
      
 52 
     | 
    
         
            +
                if options.key?(:default) && !options[:default].is_a?(String)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  raise Bolt::ValidationError, "Option 'default' must be a string"
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
       39 
56 
     | 
    
         
             
                response = executor.prompt(prompt, options)
         
     | 
| 
       40 
57 
     | 
    
         | 
| 
      
 58 
     | 
    
         
            +
                # If sensitive, wrap it
         
     | 
| 
       41 
59 
     | 
    
         
             
                if options[:sensitive]
         
     | 
| 
       42 
60 
     | 
    
         
             
                  Puppet::Pops::Types::PSensitiveType::Sensitive.new(response)
         
     | 
| 
       43 
61 
     | 
    
         
             
                else
         
     | 
| 
         @@ -0,0 +1,103 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'bolt/error'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            # Display a menu prompt and wait for a response. Continues to prompt
         
     | 
| 
      
 6 
     | 
    
         
            +
            # until an option from the menu is selected.
         
     | 
| 
      
 7 
     | 
    
         
            +
            #
         
     | 
| 
      
 8 
     | 
    
         
            +
            # > **Note:** Not available in apply block
         
     | 
| 
      
 9 
     | 
    
         
            +
            Puppet::Functions.create_function(:'prompt::menu') do
         
     | 
| 
      
 10 
     | 
    
         
            +
              # Select from a list of options.
         
     | 
| 
      
 11 
     | 
    
         
            +
              # @param prompt The prompt to display.
         
     | 
| 
      
 12 
     | 
    
         
            +
              # @param menu A list of options to choose from.
         
     | 
| 
      
 13 
     | 
    
         
            +
              # @param options A hash of additional options.
         
     | 
| 
      
 14 
     | 
    
         
            +
              # @option options [String] default The default option to return if the user does not provide
         
     | 
| 
      
 15 
     | 
    
         
            +
              #   input or if standard in (stdin) is not a tty. Must be an option present in the menu.
         
     | 
| 
      
 16 
     | 
    
         
            +
              # @return The selected option.
         
     | 
| 
      
 17 
     | 
    
         
            +
              # @example Prompt the user to select from a list of options
         
     | 
| 
      
 18 
     | 
    
         
            +
              #   $selection = prompt::menu('Select a fruit', ['apple', 'banana', 'carrot'])
         
     | 
| 
      
 19 
     | 
    
         
            +
              # @example Prompt the user to select from a list of options with a default value
         
     | 
| 
      
 20 
     | 
    
         
            +
              #   $selection = prompt::menu('Select environment', ['development', 'production'], 'default' => 'development')
         
     | 
| 
      
 21 
     | 
    
         
            +
              dispatch :prompt_menu_array do
         
     | 
| 
      
 22 
     | 
    
         
            +
                param 'String', :prompt
         
     | 
| 
      
 23 
     | 
    
         
            +
                param 'Array[Variant[Target, Data]]', :menu
         
     | 
| 
      
 24 
     | 
    
         
            +
                optional_param 'Hash[String[1], Variant[Target, Data]]', :options
         
     | 
| 
      
 25 
     | 
    
         
            +
                return_type 'Variant[Target, Data]'
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              # Select from a list of options with custom inputs.
         
     | 
| 
      
 29 
     | 
    
         
            +
              # @param prompt The prompt to display.
         
     | 
| 
      
 30 
     | 
    
         
            +
              # @param menu A hash of options to choose from, where keys are the input used to select a value.
         
     | 
| 
      
 31 
     | 
    
         
            +
              # @param options A hash of additional options.
         
     | 
| 
      
 32 
     | 
    
         
            +
              # @option options [String] default The default option to return if the user does not provide
         
     | 
| 
      
 33 
     | 
    
         
            +
              #   input or if standard in (stdin) is not a tty. Must be an option present in the menu.
         
     | 
| 
      
 34 
     | 
    
         
            +
              # @return The selected option.
         
     | 
| 
      
 35 
     | 
    
         
            +
              # @example Prompt the user to select from a list of options with custom inputs
         
     | 
| 
      
 36 
     | 
    
         
            +
              #   $menu = { 'y' => 'yes', 'n' => 'no' }
         
     | 
| 
      
 37 
     | 
    
         
            +
              #   $selection = prompt::menu('Install Puppet?', $menu)
         
     | 
| 
      
 38 
     | 
    
         
            +
              dispatch :prompt_menu do
         
     | 
| 
      
 39 
     | 
    
         
            +
                param 'String', :prompt
         
     | 
| 
      
 40 
     | 
    
         
            +
                param 'Hash[String[1], Variant[Target, Data]]', :menu
         
     | 
| 
      
 41 
     | 
    
         
            +
                optional_param 'Hash[String[1], Variant[Target, Data]]', :options
         
     | 
| 
      
 42 
     | 
    
         
            +
                return_type 'Variant[TargetSpec, Data]'
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              def prompt_menu_array(prompt, menu, options = {})
         
     | 
| 
      
 46 
     | 
    
         
            +
                menu_hash = menu.map.with_index { |value, index| [(index + 1).to_s, value] }.to_h
         
     | 
| 
      
 47 
     | 
    
         
            +
                prompt_menu(prompt, menu_hash, options)
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              def prompt_menu(prompt, menu, options = {})
         
     | 
| 
      
 51 
     | 
    
         
            +
                unless Puppet[:tasks]
         
     | 
| 
      
 52 
     | 
    
         
            +
                  raise Puppet::ParseErrorWithIssue
         
     | 
| 
      
 53 
     | 
    
         
            +
                    .from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING,
         
     | 
| 
      
 54 
     | 
    
         
            +
                                          action: 'prompt::menu')
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                options  = options.transform_keys(&:to_sym)
         
     | 
| 
      
 58 
     | 
    
         
            +
                executor = Puppet.lookup(:bolt_executor)
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                # Send analytics report
         
     | 
| 
      
 61 
     | 
    
         
            +
                executor.report_function_call(self.class.name)
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                # Error if there are no options
         
     | 
| 
      
 64 
     | 
    
         
            +
                if menu.empty?
         
     | 
| 
      
 65 
     | 
    
         
            +
                  raise Bolt::ValidationError, "Menu cannot be empty"
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                # Error if the default value is not on the menu
         
     | 
| 
      
 69 
     | 
    
         
            +
                if options.key?(:default) && !menu.value?(options[:default])
         
     | 
| 
      
 70 
     | 
    
         
            +
                  raise Bolt::ValidationError, "Default value '#{options[:default]}' is not one of the provided menu options"
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                # The first prompt should include the menu
         
     | 
| 
      
 74 
     | 
    
         
            +
                to_prompt = format_menu(menu) + prompt
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                # Request input from the user until they provide a valid option
         
     | 
| 
      
 77 
     | 
    
         
            +
                loop do
         
     | 
| 
      
 78 
     | 
    
         
            +
                  selection = executor.prompt(to_prompt, options)
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                  return menu[selection] if menu.key?(selection)
         
     | 
| 
      
 81 
     | 
    
         
            +
                  return selection       if options.key?(:default) && options[:default] == selection
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                  # Only reprint the prompt, not the menu
         
     | 
| 
      
 84 
     | 
    
         
            +
                  to_prompt = "Invalid option, try again. #{prompt}"
         
     | 
| 
      
 85 
     | 
    
         
            +
                end
         
     | 
| 
      
 86 
     | 
    
         
            +
              end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
              # Builds the menu string. Aligns all the values by padding input keys.
         
     | 
| 
      
 89 
     | 
    
         
            +
              #
         
     | 
| 
      
 90 
     | 
    
         
            +
              private def format_menu(menu)
         
     | 
| 
      
 91 
     | 
    
         
            +
                # Find the longest input and add 2 for wrapping parenthesis
         
     | 
| 
      
 92 
     | 
    
         
            +
                key_length = menu.keys.max_by(&:length).length + 2
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                menu_string = +''
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                menu.each do |key, value|
         
     | 
| 
      
 97 
     | 
    
         
            +
                  key = "(#{key})".ljust(key_length)
         
     | 
| 
      
 98 
     | 
    
         
            +
                  menu_string << "#{key} #{value}\n"
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                menu_string
         
     | 
| 
      
 102 
     | 
    
         
            +
              end
         
     | 
| 
      
 103 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/bolt/cli.rb
    CHANGED
    
    | 
         @@ -96,6 +96,48 @@ module Bolt 
     | 
|
| 
       96 
96 
     | 
    
         
             
                  finalize_setup
         
     | 
| 
       97 
97 
     | 
    
         
             
                end
         
     | 
| 
       98 
98 
     | 
    
         | 
| 
      
 99 
     | 
    
         
            +
                # Prints a welcome message when users first install Bolt and run `bolt`, `bolt help` or `bolt --help`
         
     | 
| 
      
 100 
     | 
    
         
            +
                def welcome_message
         
     | 
| 
      
 101 
     | 
    
         
            +
                  bolt = <<~BOLT
         
     | 
| 
      
 102 
     | 
    
         
            +
                               `.::-`
         
     | 
| 
      
 103 
     | 
    
         
            +
                          `.-:///////-.`
         
     | 
| 
      
 104 
     | 
    
         
            +
                       `-:////:.  `-:///:-  /ooo.                        .ooo/
         
     | 
| 
      
 105 
     | 
    
         
            +
                   `.-:///::///:-`   `-//:  ymmm-                        :mmmy  .---.
         
     | 
| 
      
 106 
     | 
    
         
            +
                  :///:-.   `.:////.  -//:  ymmm-                        :mmmy  +mmm+
         
     | 
| 
      
 107 
     | 
    
         
            +
                  ://.          ///.  -//:  ymmm--/++/-       `-/++/:`   :mmmy-:smmms::-
         
     | 
| 
      
 108 
     | 
    
         
            +
                  ://.          ://. .://:  ymmmdmmmmmmdo`  .smmmmmmmmh: :mmmysmmmmmmmms
         
     | 
| 
      
 109 
     | 
    
         
            +
                  ://.          ://:///:-.  ymmmh/--/hmmmy -mmmd/-.:hmmm+:mmmy.-smmms--.
         
     | 
| 
      
 110 
     | 
    
         
            +
                  ://:.`      .-////:-`     ymmm-     ymmm:hmmm-    `dmmm/mmmy  +mmm+
         
     | 
| 
      
 111 
     | 
    
         
            +
                  `-:///:-..:///:-.`        ymmm-     ommm/dmmm`     hmmm+mmmy  +mmm+
         
     | 
| 
      
 112 
     | 
    
         
            +
                     `.-:////:-`            ymmm+    /mmmm.ommms`   /mmmh:mmmy  +mmmo
         
     | 
| 
      
 113 
     | 
    
         
            +
                         `-.`               ymmmmmhhmmmmd:  ommmmhydmmmy`:mmmy  -mmmmdhd
         
     | 
| 
      
 114 
     | 
    
         
            +
                                            oyyy+shddhs/`    .+shddhy+-  -yyyo   .ohddhs
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                  BOLT
         
     | 
| 
      
 118 
     | 
    
         
            +
                  example_cmd = if Bolt::Util.windows?
         
     | 
| 
      
 119 
     | 
    
         
            +
                                  "Invoke-BoltCommand -Command 'hostname' -Targets localhost"
         
     | 
| 
      
 120 
     | 
    
         
            +
                                else
         
     | 
| 
      
 121 
     | 
    
         
            +
                                  "bolt command run 'hostname' --target localhost"
         
     | 
| 
      
 122 
     | 
    
         
            +
                                end
         
     | 
| 
      
 123 
     | 
    
         
            +
                  prev_cmd = String.new("bolt")
         
     | 
| 
      
 124 
     | 
    
         
            +
                  prev_cmd << " #{@argv[0]}" unless @argv.empty?
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                  message = <<~MSG
         
     | 
| 
      
 127 
     | 
    
         
            +
                  🎉 Welcome to Bolt #{VERSION}
         
     | 
| 
      
 128 
     | 
    
         
            +
                  😌 We're here to help bring order to the chaos
         
     | 
| 
      
 129 
     | 
    
         
            +
                  📖 Find our documentation at https://bolt.guide
         
     | 
| 
      
 130 
     | 
    
         
            +
                  🙋 Ask a question in #bolt on https://slack.puppet.com/
         
     | 
| 
      
 131 
     | 
    
         
            +
                  🔩 Contribute at https://github.com/puppetlabs/bolt/
         
     | 
| 
      
 132 
     | 
    
         
            +
                  💡 Not sure where to start? Try "#{example_cmd}"
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                  We only print this message once. Run "#{prev_cmd}" again for help text.
         
     | 
| 
      
 135 
     | 
    
         
            +
                  MSG
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                  $stdout.print "\033[36m#{bolt}\033[0m"
         
     | 
| 
      
 138 
     | 
    
         
            +
                  $stdout.print message
         
     | 
| 
      
 139 
     | 
    
         
            +
                end
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
       99 
141 
     | 
    
         
             
                # Parses the command and validates options. All errors that are raised here
         
     | 
| 
       100 
142 
     | 
    
         
             
                # are not handled by the outputter, as it relies on config being loaded.
         
     | 
| 
       101 
143 
     | 
    
         
             
                def parse_command
         
     | 
| 
         @@ -107,6 +149,16 @@ module Bolt 
     | 
|
| 
       107 
149 
     | 
    
         
             
                    # help text
         
     | 
| 
       108 
150 
     | 
    
         
             
                    options[:subcommand] = nil unless COMMANDS.include?(options[:subcommand])
         
     | 
| 
       109 
151 
     | 
    
         | 
| 
      
 152 
     | 
    
         
            +
                    if Bolt::Util.first_run?
         
     | 
| 
      
 153 
     | 
    
         
            +
                      FileUtils.mkdir_p(Bolt::Util.first_runs_free.dirname)
         
     | 
| 
      
 154 
     | 
    
         
            +
                      FileUtils.touch(Bolt::Util.first_runs_free)
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
                      if options[:subcommand].nil? && $stdout.isatty
         
     | 
| 
      
 157 
     | 
    
         
            +
                        welcome_message
         
     | 
| 
      
 158 
     | 
    
         
            +
                        raise Bolt::CLIExit
         
     | 
| 
      
 159 
     | 
    
         
            +
                      end
         
     | 
| 
      
 160 
     | 
    
         
            +
                    end
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
       110 
162 
     | 
    
         
             
                    # Update the parser for the subcommand (or lack thereof)
         
     | 
| 
       111 
163 
     | 
    
         
             
                    parser.update
         
     | 
| 
       112 
164 
     | 
    
         
             
                    puts parser.help
         
     | 
| 
         @@ -266,6 +266,13 @@ module Bolt 
     | 
|
| 
       266 
266 
     | 
    
         
             
                        _plugin: true,
         
     | 
| 
       267 
267 
     | 
    
         
             
                        _example: "BOLT.PRODUCTION"
         
     | 
| 
       268 
268 
     | 
    
         
             
                      },
         
     | 
| 
      
 269 
     | 
    
         
            +
                      "remote" => {
         
     | 
| 
      
 270 
     | 
    
         
            +
                        type: String,
         
     | 
| 
      
 271 
     | 
    
         
            +
                        description: "The LXD remote host to use.",
         
     | 
| 
      
 272 
     | 
    
         
            +
                        _default: "local",
         
     | 
| 
      
 273 
     | 
    
         
            +
                        _plugin: false,
         
     | 
| 
      
 274 
     | 
    
         
            +
                        _example: 'myremote'
         
     | 
| 
      
 275 
     | 
    
         
            +
                      },
         
     | 
| 
       269 
276 
     | 
    
         
             
                      "run-as" => {
         
     | 
| 
       270 
277 
     | 
    
         
             
                        type: String,
         
     | 
| 
       271 
278 
     | 
    
         
             
                        description: "The user to run commands as after login. The run-as user must be different than the "\
         
     | 
    
        data/lib/bolt/executor.rb
    CHANGED
    
    | 
         @@ -484,22 +484,30 @@ module Bolt 
     | 
|
| 
       484 
484 
     | 
    
         
             
                end
         
     | 
| 
       485 
485 
     | 
    
         | 
| 
       486 
486 
     | 
    
         
             
                def prompt(prompt, options)
         
     | 
| 
       487 
     | 
    
         
            -
                  @prompting = true
         
     | 
| 
       488 
487 
     | 
    
         
             
                  unless $stdin.tty?
         
     | 
| 
      
 488 
     | 
    
         
            +
                    return options[:default] if options[:default]
         
     | 
| 
       489 
489 
     | 
    
         
             
                    raise Bolt::Error.new('STDIN is not a tty, unable to prompt', 'bolt/no-tty-error')
         
     | 
| 
       490 
490 
     | 
    
         
             
                  end
         
     | 
| 
       491 
491 
     | 
    
         | 
| 
       492 
     | 
    
         
            -
                   
     | 
| 
      
 492 
     | 
    
         
            +
                  @prompting = true
         
     | 
| 
      
 493 
     | 
    
         
            +
             
     | 
| 
      
 494 
     | 
    
         
            +
                  if options[:default] && !options[:sensitive]
         
     | 
| 
      
 495 
     | 
    
         
            +
                    $stderr.print("#{prompt} [#{options[:default]}]: ")
         
     | 
| 
      
 496 
     | 
    
         
            +
                  else
         
     | 
| 
      
 497 
     | 
    
         
            +
                    $stderr.print("#{prompt}: ")
         
     | 
| 
      
 498 
     | 
    
         
            +
                  end
         
     | 
| 
       493 
499 
     | 
    
         | 
| 
       494 
500 
     | 
    
         
             
                  value = if options[:sensitive]
         
     | 
| 
       495 
501 
     | 
    
         
             
                            $stdin.noecho(&:gets).to_s.chomp
         
     | 
| 
       496 
502 
     | 
    
         
             
                          else
         
     | 
| 
       497 
503 
     | 
    
         
             
                            $stdin.gets.to_s.chomp
         
     | 
| 
       498 
504 
     | 
    
         
             
                          end
         
     | 
| 
      
 505 
     | 
    
         
            +
             
     | 
| 
       499 
506 
     | 
    
         
             
                  @prompting = false
         
     | 
| 
       500 
507 
     | 
    
         | 
| 
       501 
508 
     | 
    
         
             
                  $stderr.puts if options[:sensitive]
         
     | 
| 
       502 
509 
     | 
    
         | 
| 
      
 510 
     | 
    
         
            +
                  value = options[:default] if value.empty?
         
     | 
| 
       503 
511 
     | 
    
         
             
                  value
         
     | 
| 
       504 
512 
     | 
    
         
             
                end
         
     | 
| 
       505 
513 
     | 
    
         | 
    
        data/lib/bolt/node/output.rb
    CHANGED
    
    | 
         @@ -6,13 +6,23 @@ require 'bolt/result' 
     | 
|
| 
       6 
6 
     | 
    
         
             
            module Bolt
         
     | 
| 
       7 
7 
     | 
    
         
             
              class Node
         
     | 
| 
       8 
8 
     | 
    
         
             
                class Output
         
     | 
| 
       9 
     | 
    
         
            -
                  attr_reader :stdout, : 
     | 
| 
      
 9 
     | 
    
         
            +
                  attr_reader :stderr, :stdout, :merged_output
         
     | 
| 
       10 
10 
     | 
    
         
             
                  attr_accessor :exit_code
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
                  def initialize
         
     | 
| 
       13 
     | 
    
         
            -
                    @stdout 
     | 
| 
       14 
     | 
    
         
            -
                    @stderr 
     | 
| 
       15 
     | 
    
         
            -
                    @ 
     | 
| 
      
 13 
     | 
    
         
            +
                    @stdout        = StringIO.new
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @stderr        = StringIO.new
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @merged_output = StringIO.new
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @exit_code     = 'unknown'
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def to_h
         
     | 
| 
      
 20 
     | 
    
         
            +
                    {
         
     | 
| 
      
 21 
     | 
    
         
            +
                      'stdout'        => @stdout.string,
         
     | 
| 
      
 22 
     | 
    
         
            +
                      'stderr'        => @stderr.string,
         
     | 
| 
      
 23 
     | 
    
         
            +
                      'merged_output' => @merged_output.string,
         
     | 
| 
      
 24 
     | 
    
         
            +
                      'exit_code'     => @exit_code
         
     | 
| 
      
 25 
     | 
    
         
            +
                    }
         
     | 
| 
       16 
26 
     | 
    
         
             
                  end
         
     | 
| 
       17 
27 
     | 
    
         
             
                end
         
     | 
| 
       18 
28 
     | 
    
         
             
              end
         
     | 
    
        data/lib/bolt/outputter/human.rb
    CHANGED
    
    | 
         @@ -142,16 +142,9 @@ module Bolt 
     | 
|
| 
       142 
142 
     | 
    
         
             
                      end
         
     | 
| 
       143 
143 
     | 
    
         | 
| 
       144 
144 
     | 
    
         
             
                      # Use special handling if the result looks like a command or script result
         
     | 
| 
       145 
     | 
    
         
            -
                      if result.generic_value.keys == %w[stdout stderr exit_code]
         
     | 
| 
      
 145 
     | 
    
         
            +
                      if result.generic_value.keys == %w[stdout stderr merged_output exit_code]
         
     | 
| 
       146 
146 
     | 
    
         
             
                        safe_value = result.safe_value
         
     | 
| 
       147 
     | 
    
         
            -
                        unless safe_value[' 
     | 
| 
       148 
     | 
    
         
            -
                          @stream.puts(indent(2, "STDOUT:"))
         
     | 
| 
       149 
     | 
    
         
            -
                          @stream.puts(indent(4, safe_value['stdout']))
         
     | 
| 
       150 
     | 
    
         
            -
                        end
         
     | 
| 
       151 
     | 
    
         
            -
                        unless safe_value['stderr'].strip.empty?
         
     | 
| 
       152 
     | 
    
         
            -
                          @stream.puts(indent(2, "STDERR:"))
         
     | 
| 
       153 
     | 
    
         
            -
                          @stream.puts(indent(4, safe_value['stderr']))
         
     | 
| 
       154 
     | 
    
         
            -
                        end
         
     | 
| 
      
 147 
     | 
    
         
            +
                        @stream.puts(indent(2, safe_value['merged_output'])) unless safe_value['merged_output'].strip.empty?
         
     | 
| 
       155 
148 
     | 
    
         
             
                      elsif result.generic_value.any?
         
     | 
| 
       156 
149 
     | 
    
         
             
                        @stream.puts(indent(2, ::JSON.pretty_generate(result.generic_value)))
         
     | 
| 
       157 
150 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -282,7 +275,7 @@ module Bolt 
     | 
|
| 
       282 
275 
     | 
    
         
             
                      pretty_params << "- #{k}: #{v['type'] || 'Any'}\n"
         
     | 
| 
       283 
276 
     | 
    
         
             
                      pretty_params << "    Default: #{v['default'].inspect}\n" if v.key?('default')
         
     | 
| 
       284 
277 
     | 
    
         
             
                      pretty_params << "    #{v['description']}\n" if v['description']
         
     | 
| 
       285 
     | 
    
         
            -
                      usage << if v['type'] 
     | 
| 
      
 278 
     | 
    
         
            +
                      usage << if v['type']&.start_with?("Optional")
         
     | 
| 
       286 
279 
     | 
    
         
             
                                 " [#{k}=<value>]"
         
     | 
| 
       287 
280 
     | 
    
         
             
                               else
         
     | 
| 
       288 
281 
     | 
    
         
             
                                 " #{k}=<value>"
         
     | 
| 
         @@ -290,7 +283,7 @@ module Bolt 
     | 
|
| 
       290 
283 
     | 
    
         
             
                    end
         
     | 
| 
       291 
284 
     | 
    
         | 
| 
       292 
285 
     | 
    
         
             
                    if task.supports_noop
         
     | 
| 
       293 
     | 
    
         
            -
                      usage << Bolt::Util.powershell? ? '[-Noop]' : '[--noop]'
         
     | 
| 
      
 286 
     | 
    
         
            +
                      usage << (Bolt::Util.powershell? ? ' [-Noop]' : ' [--noop]')
         
     | 
| 
       294 
287 
     | 
    
         
             
                    end
         
     | 
| 
       295 
288 
     | 
    
         | 
| 
       296 
289 
     | 
    
         
             
                    task_info << "\n#{task.name}"
         
     | 
    
        data/lib/bolt/pal.rb
    CHANGED
    
    | 
         @@ -521,10 +521,30 @@ module Bolt 
     | 
|
| 
       521 
521 
     | 
    
         
             
                  end
         
     | 
| 
       522 
522 
     | 
    
         
             
                end
         
     | 
| 
       523 
523 
     | 
    
         | 
| 
       524 
     | 
    
         
            -
                def convert_plan( 
     | 
| 
      
 524 
     | 
    
         
            +
                def convert_plan(plan)
         
     | 
| 
      
 525 
     | 
    
         
            +
                  path = File.expand_path(plan)
         
     | 
| 
      
 526 
     | 
    
         
            +
             
     | 
| 
      
 527 
     | 
    
         
            +
                  # If the path doesn't exist, check if it's a plan name
         
     | 
| 
      
 528 
     | 
    
         
            +
                  unless File.exist?(path)
         
     | 
| 
      
 529 
     | 
    
         
            +
                    in_bolt_compiler do |compiler|
         
     | 
| 
      
 530 
     | 
    
         
            +
                      sig = compiler.plan_signature(plan)
         
     | 
| 
      
 531 
     | 
    
         
            +
             
     | 
| 
      
 532 
     | 
    
         
            +
                      # If the plan was loaded, look for it on the module loader
         
     | 
| 
      
 533 
     | 
    
         
            +
                      # There has to be an easier way to do this...
         
     | 
| 
      
 534 
     | 
    
         
            +
                      if sig
         
     | 
| 
      
 535 
     | 
    
         
            +
                        type = compiler.list_plans.find { |p| p.name == plan }
         
     | 
| 
      
 536 
     | 
    
         
            +
                        path = sig.instance_variable_get(:@plan_func)
         
     | 
| 
      
 537 
     | 
    
         
            +
                                  .loader
         
     | 
| 
      
 538 
     | 
    
         
            +
                                  .find(type)
         
     | 
| 
      
 539 
     | 
    
         
            +
                                  .origin
         
     | 
| 
      
 540 
     | 
    
         
            +
                                  .first
         
     | 
| 
      
 541 
     | 
    
         
            +
                      end
         
     | 
| 
      
 542 
     | 
    
         
            +
                    end
         
     | 
| 
      
 543 
     | 
    
         
            +
                  end
         
     | 
| 
      
 544 
     | 
    
         
            +
             
     | 
| 
       525 
545 
     | 
    
         
             
                  Puppet[:tasks] = true
         
     | 
| 
       526 
546 
     | 
    
         
             
                  transpiler = YamlPlan::Transpiler.new
         
     | 
| 
       527 
     | 
    
         
            -
                  transpiler.transpile( 
     | 
| 
      
 547 
     | 
    
         
            +
                  transpiler.transpile(path)
         
     | 
| 
       528 
548 
     | 
    
         
             
                end
         
     | 
| 
       529 
549 
     | 
    
         | 
| 
       530 
550 
     | 
    
         
             
                # Returns a mapping of all modules available to the Bolt compiler
         
     | 
| 
         @@ -13,6 +13,14 @@ module Bolt 
     | 
|
| 
       13 
13 
     | 
    
         
             
                        Set['command', 'targets']
         
     | 
| 
       14 
14 
     | 
    
         
             
                      end
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
      
 16 
     | 
    
         
            +
                      def self.validate_step_keys(body, number)
         
     | 
| 
      
 17 
     | 
    
         
            +
                        super
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                        if body.key?('env_vars') && ![Hash, String].include?(body['env_vars'].class)
         
     | 
| 
      
 20 
     | 
    
         
            +
                          raise StepError.new('env_vars key must be a hash or evaluable string', body['name'], number)
         
     | 
| 
      
 21 
     | 
    
         
            +
                        end
         
     | 
| 
      
 22 
     | 
    
         
            +
                      end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
       16 
24 
     | 
    
         
             
                      # Returns an array of arguments to pass to the step's function call
         
     | 
| 
       17 
25 
     | 
    
         
             
                      #
         
     | 
| 
       18 
26 
     | 
    
         
             
                      private def format_args(body)
         
     | 
| 
         @@ -27,6 +27,10 @@ module Bolt 
     | 
|
| 
       27 
27 
     | 
    
         
             
                        if body.key?('pwsh_params') && !body['pwsh_params'].nil? && !body['pwsh_params'].is_a?(Hash)
         
     | 
| 
       28 
28 
     | 
    
         
             
                          raise StepError.new('pwsh_params key must be a hash', body['name'], number)
         
     | 
| 
       29 
29 
     | 
    
         
             
                        end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                        if body.key?('env_vars') && ![Hash, String].include?(body['env_vars'].class)
         
     | 
| 
      
 32 
     | 
    
         
            +
                          raise StepError.new('env_vars key must be a hash or evaluable string', body['name'], number)
         
     | 
| 
      
 33 
     | 
    
         
            +
                        end
         
     | 
| 
       30 
34 
     | 
    
         
             
                      end
         
     | 
| 
       31 
35 
     | 
    
         | 
| 
       32 
36 
     | 
    
         
             
                      # Returns an array of arguments to pass to the step's function call
         
     | 
| 
         @@ -14,8 +14,8 @@ module Bolt 
     | 
|
| 
       14 
14 
     | 
    
         
             
                      end
         
     | 
| 
       15 
15 
     | 
    
         
             
                    end
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
     | 
    
         
            -
                    def transpile( 
     | 
| 
       18 
     | 
    
         
            -
                      @plan_path =  
     | 
| 
      
 17 
     | 
    
         
            +
                    def transpile(plan_path)
         
     | 
| 
      
 18 
     | 
    
         
            +
                      @plan_path = plan_path
         
     | 
| 
       19 
19 
     | 
    
         
             
                      @modulename = Bolt::Util.module_name(@plan_path)
         
     | 
| 
       20 
20 
     | 
    
         
             
                      @filename = @plan_path.split(File::SEPARATOR)[-1]
         
     | 
| 
       21 
21 
     | 
    
         
             
                      validate_path
         
     | 
    
        data/lib/bolt/result.rb
    CHANGED
    
    | 
         @@ -28,20 +28,14 @@ module Bolt 
     | 
|
| 
       28 
28 
     | 
    
         
             
                  %w[file line].zip(position).to_h.compact
         
     | 
| 
       29 
29 
     | 
    
         
             
                end
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
                def self.for_command(target,  
     | 
| 
       32 
     | 
    
         
            -
                  value = {
         
     | 
| 
       33 
     | 
    
         
            -
                    'stdout' => stdout,
         
     | 
| 
       34 
     | 
    
         
            -
                    'stderr' => stderr,
         
     | 
| 
       35 
     | 
    
         
            -
                    'exit_code' => exit_code
         
     | 
| 
       36 
     | 
    
         
            -
                  }
         
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
      
 31 
     | 
    
         
            +
                def self.for_command(target, value, action, command, position)
         
     | 
| 
       38 
32 
     | 
    
         
             
                  details = create_details(position)
         
     | 
| 
       39 
     | 
    
         
            -
                  unless exit_code == 0
         
     | 
| 
       40 
     | 
    
         
            -
                    details['exit_code'] = exit_code
         
     | 
| 
      
 33 
     | 
    
         
            +
                  unless value['exit_code'] == 0
         
     | 
| 
      
 34 
     | 
    
         
            +
                    details['exit_code'] = value['exit_code']
         
     | 
| 
       41 
35 
     | 
    
         
             
                    value['_error'] = {
         
     | 
| 
       42 
36 
     | 
    
         
             
                      'kind' => 'puppetlabs.tasks/command-error',
         
     | 
| 
       43 
37 
     | 
    
         
             
                      'issue_code' => 'COMMAND_ERROR',
         
     | 
| 
       44 
     | 
    
         
            -
                      'msg' => "The command failed with exit code #{exit_code}",
         
     | 
| 
      
 38 
     | 
    
         
            +
                      'msg' => "The command failed with exit code #{value['exit_code']}",
         
     | 
| 
       45 
39 
     | 
    
         
             
                      'details' => details
         
     | 
| 
       46 
40 
     | 
    
         
             
                    }
         
     | 
| 
       47 
41 
     | 
    
         
             
                  end
         
     | 
    
        data/lib/bolt/shell/bash.rb
    CHANGED
    
    | 
         @@ -24,9 +24,7 @@ module Bolt 
     | 
|
| 
       24 
24 
     | 
    
         
             
                    running_as(options[:run_as]) do
         
     | 
| 
       25 
25 
     | 
    
         
             
                      output = execute(command, environment: options[:env_vars], sudoable: true)
         
     | 
| 
       26 
26 
     | 
    
         
             
                      Bolt::Result.for_command(target,
         
     | 
| 
       27 
     | 
    
         
            -
                                               output. 
     | 
| 
       28 
     | 
    
         
            -
                                               output.stderr.string,
         
     | 
| 
       29 
     | 
    
         
            -
                                               output.exit_code,
         
     | 
| 
      
 27 
     | 
    
         
            +
                                               output.to_h,
         
     | 
| 
       30 
28 
     | 
    
         
             
                                               'command',
         
     | 
| 
       31 
29 
     | 
    
         
             
                                               command,
         
     | 
| 
       32 
30 
     | 
    
         
             
                                               position)
         
     | 
| 
         @@ -98,9 +96,7 @@ module Bolt 
     | 
|
| 
       98 
96 
     | 
    
         
             
                        dir.chown(run_as)
         
     | 
| 
       99 
97 
     | 
    
         
             
                        output = execute([path, *arguments], environment: options[:env_vars], sudoable: true)
         
     | 
| 
       100 
98 
     | 
    
         
             
                        Bolt::Result.for_command(target,
         
     | 
| 
       101 
     | 
    
         
            -
                                                 output. 
     | 
| 
       102 
     | 
    
         
            -
                                                 output.stderr.string,
         
     | 
| 
       103 
     | 
    
         
            -
                                                 output.exit_code,
         
     | 
| 
      
 99 
     | 
    
         
            +
                                                 output.to_h,
         
     | 
| 
       104 
100 
     | 
    
         
             
                                                 'script',
         
     | 
| 
       105 
101 
     | 
    
         
             
                                                 script,
         
     | 
| 
       106 
102 
     | 
    
         
             
                                                 position)
         
     | 
| 
         @@ -149,21 +145,21 @@ module Bolt 
     | 
|
| 
       149 
145 
     | 
    
         | 
| 
       150 
146 
     | 
    
         
             
                        remote_task_path = write_executable(task_dir, executable)
         
     | 
| 
       151 
147 
     | 
    
         | 
| 
      
 148 
     | 
    
         
            +
                        execute_options[:stdin] = stdin
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
       152 
150 
     | 
    
         
             
                        # Avoid the horrors of passing data on stdin via a tty on multiple platforms
         
     | 
| 
       153 
151 
     | 
    
         
             
                        # by writing a wrapper script that directs stdin to the task.
         
     | 
| 
       154 
152 
     | 
    
         
             
                        if stdin && target.options['tty']
         
     | 
| 
       155 
153 
     | 
    
         
             
                          wrapper = make_wrapper_stringio(remote_task_path, stdin, execute_options[:interpreter])
         
     | 
| 
      
 154 
     | 
    
         
            +
                          # Wrapper script handles interpreter and stdin. Delete these execute options
         
     | 
| 
       156 
155 
     | 
    
         
             
                          execute_options.delete(:interpreter)
         
     | 
| 
      
 156 
     | 
    
         
            +
                          execute_options.delete(:stdin)
         
     | 
| 
       157 
157 
     | 
    
         
             
                          execute_options[:wrapper] = true
         
     | 
| 
       158 
158 
     | 
    
         
             
                          remote_task_path = write_executable(dir, wrapper, 'wrapper.sh')
         
     | 
| 
       159 
159 
     | 
    
         
             
                        end
         
     | 
| 
       160 
160 
     | 
    
         | 
| 
       161 
161 
     | 
    
         
             
                        dir.chown(run_as)
         
     | 
| 
       162 
162 
     | 
    
         | 
| 
       163 
     | 
    
         
            -
                        # Don't pass parameters on stdin if using a tty, as the parameters are
         
     | 
| 
       164 
     | 
    
         
            -
                        # already part of the wrapper script.
         
     | 
| 
       165 
     | 
    
         
            -
                        execute_options[:stdin] = stdin unless stdin && target.options['tty']
         
     | 
| 
       166 
     | 
    
         
            -
             
     | 
| 
       167 
163 
     | 
    
         
             
                        execute_options[:sudoable] = true if run_as
         
     | 
| 
       168 
164 
     | 
    
         
             
                        output = execute(remote_task_path, **execute_options)
         
     | 
| 
       169 
165 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -424,7 +420,8 @@ module Bolt 
     | 
|
| 
       424 
420 
     | 
    
         
             
                          @stream_logger.warn(formatted)
         
     | 
| 
       425 
421 
     | 
    
         
             
                        end
         
     | 
| 
       426 
422 
     | 
    
         | 
| 
       427 
     | 
    
         
            -
                        read_streams[stream] 
     | 
| 
      
 423 
     | 
    
         
            +
                        read_streams[stream]        << to_print
         
     | 
| 
      
 424 
     | 
    
         
            +
                        result_output.merged_output << to_print
         
     | 
| 
       428 
425 
     | 
    
         
             
                      rescue EOFError
         
     | 
| 
       429 
426 
     | 
    
         
             
                      end
         
     | 
| 
       430 
427 
     | 
    
         | 
| 
         @@ -474,7 +471,8 @@ module Bolt 
     | 
|
| 
       474 
471 
     | 
    
         
             
                    when 126
         
     | 
| 
       475 
472 
     | 
    
         
             
                      msg = "\n\nThis might be caused by the default tmpdir being mounted "\
         
     | 
| 
       476 
473 
     | 
    
         
             
                        "using 'noexec'. See http://pup.pt/task-failure for details and workarounds."
         
     | 
| 
       477 
     | 
    
         
            -
                      result_output.stderr 
     | 
| 
      
 474 
     | 
    
         
            +
                      result_output.stderr        << msg
         
     | 
| 
      
 475 
     | 
    
         
            +
                      result_output.merged_output << msg
         
     | 
| 
       478 
476 
     | 
    
         
             
                      @logger.trace { "Command #{command_str} failed with exit code #{result_output.exit_code}" }
         
     | 
| 
       479 
477 
     | 
    
         
             
                    else
         
     | 
| 
       480 
478 
     | 
    
         
             
                      @logger.trace { "Command #{command_str} failed with exit code #{result_output.exit_code}" }
         
     | 
| 
         @@ -195,9 +195,7 @@ module Bolt 
     | 
|
| 
       195 
195 
     | 
    
         
             
                    wrap_command = conn.is_a?(Bolt::Transport::Local::Connection)
         
     | 
| 
       196 
196 
     | 
    
         
             
                    output = execute(command, wrap_command)
         
     | 
| 
       197 
197 
     | 
    
         
             
                    Bolt::Result.for_command(target,
         
     | 
| 
       198 
     | 
    
         
            -
                                             output. 
     | 
| 
       199 
     | 
    
         
            -
                                             output.stderr.string,
         
     | 
| 
       200 
     | 
    
         
            -
                                             output.exit_code,
         
     | 
| 
      
 198 
     | 
    
         
            +
                                             output.to_h,
         
     | 
| 
       201 
199 
     | 
    
         
             
                                             'command',
         
     | 
| 
       202 
200 
     | 
    
         
             
                                             command,
         
     | 
| 
       203 
201 
     | 
    
         
             
                                             position)
         
     | 
| 
         @@ -224,9 +222,7 @@ module Bolt 
     | 
|
| 
       224 
222 
     | 
    
         
             
                      output = execute([shell_init, *env_assignments, command].join("\r\n"))
         
     | 
| 
       225 
223 
     | 
    
         | 
| 
       226 
224 
     | 
    
         
             
                      Bolt::Result.for_command(target,
         
     | 
| 
       227 
     | 
    
         
            -
                                               output. 
     | 
| 
       228 
     | 
    
         
            -
                                               output.stderr.string,
         
     | 
| 
       229 
     | 
    
         
            -
                                               output.exit_code,
         
     | 
| 
      
 225 
     | 
    
         
            +
                                               output.to_h,
         
     | 
| 
       230 
226 
     | 
    
         
             
                                               'script',
         
     | 
| 
       231 
227 
     | 
    
         
             
                                               script,
         
     | 
| 
       232 
228 
     | 
    
         
             
                                               position)
         
     | 
| 
         @@ -322,7 +318,8 @@ module Bolt 
     | 
|
| 
       322 
318 
     | 
    
         
             
                        end.join("\n")
         
     | 
| 
       323 
319 
     | 
    
         
             
                        @stream_logger.warn(formatted)
         
     | 
| 
       324 
320 
     | 
    
         
             
                      end
         
     | 
| 
       325 
     | 
    
         
            -
                      result.stdout 
     | 
| 
      
 321 
     | 
    
         
            +
                      result.stdout        << to_print
         
     | 
| 
      
 322 
     | 
    
         
            +
                      result.merged_output << to_print
         
     | 
| 
       326 
323 
     | 
    
         
             
                    end
         
     | 
| 
       327 
324 
     | 
    
         
             
                    stderr = Thread.new do
         
     | 
| 
       328 
325 
     | 
    
         
             
                      encoding = err.external_encoding
         
     | 
| 
         @@ -334,7 +331,8 @@ module Bolt 
     | 
|
| 
       334 
331 
     | 
    
         
             
                        end.join("\n")
         
     | 
| 
       335 
332 
     | 
    
         
             
                        @stream_logger.warn(formatted)
         
     | 
| 
       336 
333 
     | 
    
         
             
                      end
         
     | 
| 
       337 
     | 
    
         
            -
                      result.stderr 
     | 
| 
      
 334 
     | 
    
         
            +
                      result.stderr        << to_print
         
     | 
| 
      
 335 
     | 
    
         
            +
                      result.merged_output << to_print
         
     | 
| 
       338 
336 
     | 
    
         
             
                    end
         
     | 
| 
       339 
337 
     | 
    
         | 
| 
       340 
338 
     | 
    
         
             
                    stdout.join
         
     | 
| 
         @@ -24,17 +24,17 @@ module Bolt 
     | 
|
| 
       24 
24 
     | 
    
         
             
                    end
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         
             
                    def container_id
         
     | 
| 
       27 
     | 
    
         
            -
                      " 
     | 
| 
      
 27 
     | 
    
         
            +
                      "#{@target.transport_config['remote']}:#{@target.host}"
         
     | 
| 
       28 
28 
     | 
    
         
             
                    end
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
                    def connect
         
     | 
| 
       31 
     | 
    
         
            -
                      out, err, status = execute_local_command(% 
     | 
| 
      
 31 
     | 
    
         
            +
                      out, err, status = execute_local_command(%W[list #{container_id} --format json])
         
     | 
| 
       32 
32 
     | 
    
         
             
                      unless status.exitstatus.zero?
         
     | 
| 
       33 
33 
     | 
    
         
             
                        raise "Error listing available containers: #{err}"
         
     | 
| 
       34 
34 
     | 
    
         
             
                      end
         
     | 
| 
       35 
     | 
    
         
            -
                      containers = JSON.parse(out) 
     | 
| 
       36 
     | 
    
         
            -
                       
     | 
| 
       37 
     | 
    
         
            -
                        raise "Could not find a container with name or ID matching '#{ 
     | 
| 
      
 35 
     | 
    
         
            +
                      containers = JSON.parse(out)
         
     | 
| 
      
 36 
     | 
    
         
            +
                      if containers.empty?
         
     | 
| 
      
 37 
     | 
    
         
            +
                        raise "Could not find a container with name or ID matching '#{container_id}'"
         
     | 
| 
       38 
38 
     | 
    
         
             
                      end
         
     | 
| 
       39 
39 
     | 
    
         
             
                      @logger.trace("Opened session")
         
     | 
| 
       40 
40 
     | 
    
         
             
                      true
         
     | 
    
        data/lib/bolt/transport/orch.rb
    CHANGED
    
    | 
         @@ -59,6 +59,18 @@ module Bolt 
     | 
|
| 
       59 
59 
     | 
    
         
             
                      # the result otherwise make sure an error is generated
         
     | 
| 
       60 
60 
     | 
    
         
             
                      if state == 'finished' || (result && result['_error'])
         
     | 
| 
       61 
61 
     | 
    
         
             
                        if result['_error']
         
     | 
| 
      
 62 
     | 
    
         
            +
                          unless result['_error'].is_a?(Hash)
         
     | 
| 
      
 63 
     | 
    
         
            +
                            result['_error'] = { 'kind' => 'puppetlabs.tasks/task-error',
         
     | 
| 
      
 64 
     | 
    
         
            +
                                                 'issue_code' => 'TASK_ERROR',
         
     | 
| 
      
 65 
     | 
    
         
            +
                                                 'msg' => result['_error'],
         
     | 
| 
      
 66 
     | 
    
         
            +
                                                 'details' => {} }
         
     | 
| 
      
 67 
     | 
    
         
            +
                          end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                          result['_error']['details'] ||= {}
         
     | 
| 
      
 70 
     | 
    
         
            +
                          unless result['_error']['details'].is_a?(Hash)
         
     | 
| 
      
 71 
     | 
    
         
            +
                            deets = result['_error']['details']
         
     | 
| 
      
 72 
     | 
    
         
            +
                            result['_error']['details'] = { 'msg' => deets }
         
     | 
| 
      
 73 
     | 
    
         
            +
                          end
         
     | 
| 
       62 
74 
     | 
    
         
             
                          file_line = %w[file line].zip(position).to_h.compact
         
     | 
| 
       63 
75 
     | 
    
         
             
                          result['_error']['details'].merge!(file_line) unless result['_error']['details']['file']
         
     | 
| 
       64 
76 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -252,11 +264,7 @@ module Bolt 
     | 
|
| 
       252 
264 
     | 
    
         | 
| 
       253 
265 
     | 
    
         
             
                    # If we get here, there's no error so we don't need the file or line
         
     | 
| 
       254 
266 
     | 
    
         
             
                    # number
         
     | 
| 
       255 
     | 
    
         
            -
                    Bolt::Result.for_command(target,
         
     | 
| 
       256 
     | 
    
         
            -
                                             result.value['stdout'],
         
     | 
| 
       257 
     | 
    
         
            -
                                             result.value['stderr'],
         
     | 
| 
       258 
     | 
    
         
            -
                                             result.value['exit_code'],
         
     | 
| 
       259 
     | 
    
         
            -
                                             action, obj, [])
         
     | 
| 
      
 267 
     | 
    
         
            +
                    Bolt::Result.for_command(target, result.value, action, obj, [])
         
     | 
| 
       260 
268 
     | 
    
         
             
                  end
         
     | 
| 
       261 
269 
     | 
    
         
             
                end
         
     | 
| 
       262 
270 
     | 
    
         
             
              end
         
     | 
    
        data/lib/bolt/util.rb
    CHANGED
    
    | 
         @@ -77,6 +77,14 @@ module Bolt 
     | 
|
| 
       77 
77 
     | 
    
         
             
                    File.exist?(path) ? read_yaml_hash(path, file_name) : {}
         
     | 
| 
       78 
78 
     | 
    
         
             
                  end
         
     | 
| 
       79 
79 
     | 
    
         | 
| 
      
 80 
     | 
    
         
            +
                  def first_runs_free
         
     | 
| 
      
 81 
     | 
    
         
            +
                    Bolt::Config.user_path + '.first_runs_free'
         
     | 
| 
      
 82 
     | 
    
         
            +
                  end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                  def first_run?
         
     | 
| 
      
 85 
     | 
    
         
            +
                    Bolt::Config.user_path && !File.exist?(first_runs_free)
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
       80 
88 
     | 
    
         
             
                  # Accepts a path with either 'plans' or 'tasks' in it and determines
         
     | 
| 
       81 
89 
     | 
    
         
             
                  # the name of the module
         
     | 
| 
       82 
90 
     | 
    
         
             
                  def module_name(path)
         
     | 
    
        data/lib/bolt/version.rb
    CHANGED
    
    
| 
         @@ -29,7 +29,14 @@ module BoltSpec 
     | 
|
| 
       29 
29 
     | 
    
         
             
                  end
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
31 
     | 
    
         
             
                  def result_for(target, stdout: '', stderr: '')
         
     | 
| 
       32 
     | 
    
         
            -
                     
     | 
| 
      
 32 
     | 
    
         
            +
                    value = {
         
     | 
| 
      
 33 
     | 
    
         
            +
                      'stdout'        => stdout,
         
     | 
| 
      
 34 
     | 
    
         
            +
                      'stderr'        => stderr,
         
     | 
| 
      
 35 
     | 
    
         
            +
                      'merged_output' => "#{stdout}\n#{stderr}".strip,
         
     | 
| 
      
 36 
     | 
    
         
            +
                      'exit_code'     => 0
         
     | 
| 
      
 37 
     | 
    
         
            +
                    }
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    Bolt::Result.for_command(target, value, 'command', '', [])
         
     | 
| 
       33 
40 
     | 
    
         
             
                  end
         
     | 
| 
       34 
41 
     | 
    
         | 
| 
       35 
42 
     | 
    
         
             
                  # Public methods
         
     | 
| 
         @@ -35,7 +35,14 @@ module BoltSpec 
     | 
|
| 
       35 
35 
     | 
    
         
             
                  end
         
     | 
| 
       36 
36 
     | 
    
         | 
| 
       37 
37 
     | 
    
         
             
                  def result_for(target, stdout: '', stderr: '')
         
     | 
| 
       38 
     | 
    
         
            -
                     
     | 
| 
      
 38 
     | 
    
         
            +
                    value = {
         
     | 
| 
      
 39 
     | 
    
         
            +
                      'stdout'        => stdout,
         
     | 
| 
      
 40 
     | 
    
         
            +
                      'stderr'        => stderr,
         
     | 
| 
      
 41 
     | 
    
         
            +
                      'merged_output' => "#{stdout}\n#{stderr}".strip,
         
     | 
| 
      
 42 
     | 
    
         
            +
                      'exit_code'     => 0
         
     | 
| 
      
 43 
     | 
    
         
            +
                    }
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    Bolt::Result.for_command(target, value, 'script', '', [])
         
     | 
| 
       39 
46 
     | 
    
         
             
                  end
         
     | 
| 
       40 
47 
     | 
    
         | 
| 
       41 
48 
     | 
    
         
             
                  # Public methods
         
     | 
    
        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.4.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-03- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2021-03-23 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: addressable
         
     | 
| 
         @@ -444,6 +444,7 @@ files: 
     | 
|
| 
       444 
444 
     | 
    
         
             
            - bolt-modules/file/lib/puppet/functions/file/write.rb
         
     | 
| 
       445 
445 
     | 
    
         
             
            - bolt-modules/out/lib/puppet/functions/out/message.rb
         
     | 
| 
       446 
446 
     | 
    
         
             
            - bolt-modules/prompt/lib/puppet/functions/prompt.rb
         
     | 
| 
      
 447 
     | 
    
         
            +
            - bolt-modules/prompt/lib/puppet/functions/prompt/menu.rb
         
     | 
| 
       447 
448 
     | 
    
         
             
            - bolt-modules/system/lib/puppet/functions/system/env.rb
         
     | 
| 
       448 
449 
     | 
    
         
             
            - exe/bolt
         
     | 
| 
       449 
450 
     | 
    
         
             
            - guides/inventory.txt
         
     |