bolt 0.14.0 → 0.15.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/exe/bolt +3 -2
- data/lib/bolt/cli.rb +99 -92
- data/lib/bolt/config.rb +7 -8
- data/lib/bolt/error.rb +20 -3
- data/lib/bolt/executor.rb +44 -45
- data/lib/bolt/logger.rb +28 -52
- data/lib/bolt/node.rb +12 -41
- data/lib/bolt/node/orch.rb +28 -34
- data/lib/bolt/node/ssh.rb +26 -21
- data/lib/bolt/node/winrm.rb +41 -19
- data/lib/bolt/notifier.rb +2 -2
- data/lib/bolt/outputter/human.rb +34 -29
- data/lib/bolt/outputter/json.rb +4 -10
- data/lib/bolt/pal.rb +106 -0
- data/lib/bolt/result.rb +90 -87
- data/lib/bolt/result_set.rb +94 -0
- data/lib/bolt/target.rb +61 -13
- data/lib/bolt/version.rb +1 -1
- data/modules/boltlib/lib/puppet/datatypes/result.rb +18 -0
- data/modules/boltlib/lib/puppet/datatypes/resultset.rb +22 -0
- data/modules/boltlib/lib/puppet/datatypes/target.rb +4 -1
- data/modules/boltlib/lib/puppet/functions/file_upload.rb +15 -10
- data/modules/boltlib/lib/puppet/functions/run_command.rb +15 -8
- data/modules/boltlib/lib/puppet/functions/run_script.rb +15 -26
- data/modules/boltlib/lib/puppet/functions/run_task.rb +17 -15
- metadata +23 -9
- data/lib/bolt/execution_result.rb +0 -109
- data/lib/bolt/formatter.rb +0 -9
- data/lib/bolt/node_uri.rb +0 -42
- data/modules/boltlib/lib/puppet/datatypes/executionresult.rb +0 -30
    
        data/lib/bolt/result.rb
    CHANGED
    
    | @@ -3,9 +3,9 @@ require 'bolt/error' | |
| 3 3 |  | 
| 4 4 | 
             
            module Bolt
         | 
| 5 5 | 
             
              class Result
         | 
| 6 | 
            -
                attr_reader : | 
| 6 | 
            +
                attr_reader :target, :value
         | 
| 7 7 |  | 
| 8 | 
            -
                def self.from_exception(exception)
         | 
| 8 | 
            +
                def self.from_exception(target, exception)
         | 
| 9 9 | 
             
                  @exception = exception
         | 
| 10 10 | 
             
                  if @exception.is_a?(Bolt::Error)
         | 
| 11 11 | 
             
                    error = @exception.to_h
         | 
| @@ -18,121 +18,124 @@ module Bolt | |
| 18 18 | 
             
                    }
         | 
| 19 19 | 
             
                    error['details']['stack_trace'] = exception.backtrace.join('\n') if exception.backtrace
         | 
| 20 20 | 
             
                  end
         | 
| 21 | 
            -
                  Result.new(error)
         | 
| 21 | 
            +
                  Result.new(target, error: error)
         | 
| 22 22 | 
             
                end
         | 
| 23 23 |  | 
| 24 | 
            -
                def  | 
| 25 | 
            -
                   | 
| 26 | 
            -
             | 
| 24 | 
            +
                def self.for_command(target, stdout, stderr, exit_code)
         | 
| 25 | 
            +
                  value = {
         | 
| 26 | 
            +
                    'stdout' => stdout,
         | 
| 27 | 
            +
                    'stderr' => stderr,
         | 
| 28 | 
            +
                    'exit_code' => exit_code
         | 
| 29 | 
            +
                  }
         | 
| 30 | 
            +
                  unless exit_code == 0
         | 
| 31 | 
            +
                    value['_error'] = {
         | 
| 32 | 
            +
                      'kind' => 'puppetlabs.tasks/command-error',
         | 
| 33 | 
            +
                      'issue_code' => 'COMMAND_ERROR',
         | 
| 34 | 
            +
                      'msg' => "The command failed with exit code #{exit_code}",
         | 
| 35 | 
            +
                      'details' => { 'exit_code' => exit_code }
         | 
| 36 | 
            +
                    }
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                  new(target, value: value)
         | 
| 27 39 | 
             
                end
         | 
| 28 40 |  | 
| 29 | 
            -
                def  | 
| 30 | 
            -
                   | 
| 41 | 
            +
                def self.for_task(target, stdout, stderr, exit_code)
         | 
| 42 | 
            +
                  begin
         | 
| 43 | 
            +
                    value = JSON.parse(stdout)
         | 
| 44 | 
            +
                    unless value.is_a? Hash
         | 
| 45 | 
            +
                      value = nil
         | 
| 46 | 
            +
                    end
         | 
| 47 | 
            +
                  rescue JSON::ParserError
         | 
| 48 | 
            +
                    value = nil
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                  value ||= { '_output' => stdout }
         | 
| 51 | 
            +
                  if exit_code != 0 && value['_error'].nil?
         | 
| 52 | 
            +
                    msg = if stdout.empty?
         | 
| 53 | 
            +
                            "The task failed with exit code #{exit_code}:\n#{stderr}"
         | 
| 54 | 
            +
                          else
         | 
| 55 | 
            +
                            "The task failed with exit code #{exit_code}"
         | 
| 56 | 
            +
                          end
         | 
| 57 | 
            +
                    value['_error'] = { 'kind' => 'puppetlabs.tasks/task-error',
         | 
| 58 | 
            +
                                        'issue_code' => 'TASK_ERROR',
         | 
| 59 | 
            +
                                        'msg' => msg,
         | 
| 60 | 
            +
                                        'details' => { 'exit_code' => exit_code } }
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
                  new(target, value: value)
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                def self.for_upload(target, source, destination)
         | 
| 66 | 
            +
                  new(target, message: "Uploaded '#{source}' to '#{target.host}:#{destination}'")
         | 
| 31 67 | 
             
                end
         | 
| 32 68 |  | 
| 33 | 
            -
                def  | 
| 34 | 
            -
                   | 
| 35 | 
            -
                   | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
                    h['value'] = { '_output' => message }
         | 
| 69 | 
            +
                def initialize(target, error: nil, message: nil, value: nil)
         | 
| 70 | 
            +
                  @target = target
         | 
| 71 | 
            +
                  @value = value || {}
         | 
| 72 | 
            +
                  @value_set = !value.nil?
         | 
| 73 | 
            +
                  if error && !error.is_a?(Hash)
         | 
| 74 | 
            +
                    raise "TODO: how did we get a string error"
         | 
| 40 75 | 
             
                  end
         | 
| 41 | 
            -
                   | 
| 42 | 
            -
                   | 
| 76 | 
            +
                  @value['_error'] = error if error
         | 
| 77 | 
            +
                  @value['_output'] = message if message
         | 
| 43 78 | 
             
                end
         | 
| 44 79 |  | 
| 45 | 
            -
                def  | 
| 46 | 
            -
                   | 
| 47 | 
            -
                  # use this hash instead
         | 
| 48 | 
            -
                  special_keys = {}
         | 
| 49 | 
            -
                  special_keys['_error'] = error if error
         | 
| 50 | 
            -
                  special_keys['_output'] = message if message
         | 
| 51 | 
            -
                  val = value || {}
         | 
| 52 | 
            -
                  val.merge(special_keys)
         | 
| 80 | 
            +
                def message
         | 
| 81 | 
            +
                  @value['_output']
         | 
| 53 82 | 
             
                end
         | 
| 54 83 |  | 
| 55 | 
            -
                def  | 
| 56 | 
            -
                   | 
| 84 | 
            +
                def status_hash
         | 
| 85 | 
            +
                  { node: @target.name,
         | 
| 86 | 
            +
                    status: ok? ? 'success' : 'failure',
         | 
| 87 | 
            +
                    result: @value }
         | 
| 57 88 | 
             
                end
         | 
| 58 | 
            -
              end
         | 
| 59 89 |  | 
| 60 | 
            -
             | 
| 61 | 
            -
                 | 
| 90 | 
            +
                # TODO: what to call this it's the value minus special keys
         | 
| 91 | 
            +
                # This should be {} if a value was set otherwise it's nil
         | 
| 92 | 
            +
                def generic_value
         | 
| 93 | 
            +
                  if @value_set
         | 
| 94 | 
            +
                    value.reject { |k, _| %w[_error _output].include? k }
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
                end
         | 
| 62 97 |  | 
| 63 | 
            -
                def  | 
| 64 | 
            -
                   | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 98 | 
            +
                def eql?(other)
         | 
| 99 | 
            +
                  self.class == other.class &&
         | 
| 100 | 
            +
                    target == other.target &&
         | 
| 101 | 
            +
                    value == other.value
         | 
| 67 102 | 
             
                end
         | 
| 68 103 |  | 
| 69 | 
            -
                def  | 
| 70 | 
            -
                   | 
| 71 | 
            -
                  @stderr = stderr || ""
         | 
| 72 | 
            -
                  @exit_code = exit_code
         | 
| 104 | 
            +
                def [](key)
         | 
| 105 | 
            +
                  value[key]
         | 
| 73 106 | 
             
                end
         | 
| 74 107 |  | 
| 75 | 
            -
                def  | 
| 76 | 
            -
                   | 
| 77 | 
            -
                    'stdout' => @stdout,
         | 
| 78 | 
            -
                    'stderr' => @stderr,
         | 
| 79 | 
            -
                    'exit_code' => @exit_code
         | 
| 80 | 
            -
                  }
         | 
| 108 | 
            +
                def ==(other)
         | 
| 109 | 
            +
                  eql?(other)
         | 
| 81 110 | 
             
                end
         | 
| 82 111 |  | 
| 112 | 
            +
                # TODO: remove in favor of ok?
         | 
| 83 113 | 
             
                def success?
         | 
| 84 | 
            -
                   | 
| 114 | 
            +
                  ok?
         | 
| 85 115 | 
             
                end
         | 
| 86 116 |  | 
| 87 | 
            -
                def  | 
| 88 | 
            -
                   | 
| 89 | 
            -
                    {
         | 
| 90 | 
            -
                      'kind' => 'puppetlabs.tasks/command-error',
         | 
| 91 | 
            -
                      'issue_code' => 'COMMAND_ERROR',
         | 
| 92 | 
            -
                      'msg' => "The command failed with exit code #{@exit_code}",
         | 
| 93 | 
            -
                      'details' => { 'exit_code' => @exit_code }
         | 
| 94 | 
            -
                    }
         | 
| 95 | 
            -
                  end
         | 
| 117 | 
            +
                def ok?
         | 
| 118 | 
            +
                  error_hash.nil?
         | 
| 96 119 | 
             
                end
         | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
              class TaskResult < CommandResult
         | 
| 100 | 
            -
                attr_reader :value
         | 
| 120 | 
            +
                alias ok ok?
         | 
| 101 121 |  | 
| 102 | 
            -
                 | 
| 103 | 
            -
             | 
| 104 | 
            -
             | 
| 105 | 
            -
                   | 
| 106 | 
            -
                  @error = @value.delete('_error')
         | 
| 122 | 
            +
                # This allows access to errors outside puppet compilation
         | 
| 123 | 
            +
                # it should be prefered over error in bolt code
         | 
| 124 | 
            +
                def error_hash
         | 
| 125 | 
            +
                  value['_error']
         | 
| 107 126 | 
             
                end
         | 
| 108 127 |  | 
| 128 | 
            +
                # Warning: This will fail outside of a compilation.
         | 
| 129 | 
            +
                # Use error_hash inside bolt.
         | 
| 130 | 
            +
                # Is it crazy for this to behave differently outside a compiler?
         | 
| 109 131 | 
             
                def error
         | 
| 110 | 
            -
                   | 
| 111 | 
            -
                     | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 115 | 
            -
                            "The task failed with exit code #{@exit_code}:\n#{@stderr}"
         | 
| 116 | 
            -
                          end
         | 
| 117 | 
            -
                    { 'kind' => 'puppetlabs.tasks/task-error',
         | 
| 118 | 
            -
                      'issue_code' => 'TASK_ERROR',
         | 
| 119 | 
            -
                      'msg' => msg,
         | 
| 120 | 
            -
                      'details' => { 'exit_code' => @exit_code } }
         | 
| 121 | 
            -
                  end
         | 
| 122 | 
            -
                end
         | 
| 132 | 
            +
                  if error_hash
         | 
| 133 | 
            +
                    Puppet::DataTypes::Error.new(error_hash['msg'],
         | 
| 134 | 
            +
                                                 error_hash['kind'],
         | 
| 135 | 
            +
                                                 nil, nil,
         | 
| 136 | 
            +
                                                 error_hash['details'])
         | 
| 123 137 |  | 
| 124 | 
            -
                private
         | 
| 125 | 
            -
             | 
| 126 | 
            -
                def parse_output(output)
         | 
| 127 | 
            -
                  begin
         | 
| 128 | 
            -
                    obj = JSON.parse(output)
         | 
| 129 | 
            -
                    unless obj.is_a? Hash
         | 
| 130 | 
            -
                      obj = nil
         | 
| 131 | 
            -
                    end
         | 
| 132 | 
            -
                  rescue JSON::ParserError
         | 
| 133 | 
            -
                    obj = nil
         | 
| 134 138 | 
             
                  end
         | 
| 135 | 
            -
                  obj || { '_output' => output }
         | 
| 136 139 | 
             
                end
         | 
| 137 140 | 
             
              end
         | 
| 138 141 | 
             
            end
         | 
| @@ -0,0 +1,94 @@ | |
| 1 | 
            +
            module Bolt
         | 
| 2 | 
            +
              class ResultSet
         | 
| 3 | 
            +
                attr_reader :results
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                include Enumerable
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                # We only want want to include these when puppet is loaded
         | 
| 8 | 
            +
                def self.include_iterable
         | 
| 9 | 
            +
                  include(Puppet::Pops::Types::Iterable)
         | 
| 10 | 
            +
                  include(Puppet::Pops::Types::IteratorProducer)
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def iterator
         | 
| 14 | 
            +
                  if Object.const_defined?(:Puppet) && Puppet.const_defined?(:Pops) &&
         | 
| 15 | 
            +
                     self.class.included_modules.include?(Puppet::Pops::Types::Iterable)
         | 
| 16 | 
            +
                    Puppet::Pops::Types::Iterable.on(@results, Bolt::Result)
         | 
| 17 | 
            +
                  else
         | 
| 18 | 
            +
                    raise NotImplementedError, "iterator requires puppet code to be loaded."
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def initialize(results)
         | 
| 23 | 
            +
                  @results = results
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def each
         | 
| 27 | 
            +
                  @results.each { |r| yield r }
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def result_hash
         | 
| 31 | 
            +
                  @result_hash ||= @results.each_with_object({}) do |result, acc|
         | 
| 32 | 
            +
                    acc[result.target.name] = result
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def count
         | 
| 37 | 
            +
                  @results.size
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
                alias length count
         | 
| 40 | 
            +
                alias size count
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                def empty
         | 
| 43 | 
            +
                  @results.empty?
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
                alias empty? empty
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def targets
         | 
| 48 | 
            +
                  results.map(&:target)
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                def names
         | 
| 52 | 
            +
                  @results.map { |r| r.target.name }
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                def ok
         | 
| 56 | 
            +
                  @results.all?(&:ok?)
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
                alias ok? ok
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                def error_set
         | 
| 61 | 
            +
                  filtered = @results.reject(&:ok?)
         | 
| 62 | 
            +
                  ResultSet.new(filtered)
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                def ok_set
         | 
| 66 | 
            +
                  filtered = @results.select(&:success?)
         | 
| 67 | 
            +
                  self.class.new(filtered)
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                def find(target_name)
         | 
| 71 | 
            +
                  result_hash[target_name]
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                def first
         | 
| 75 | 
            +
                  @results.first
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                def eql?(other)
         | 
| 79 | 
            +
                  self.class == other.class && @results == other.results
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                def to_json(opts = nil)
         | 
| 83 | 
            +
                  @results.map(&:status_hash).to_json(opts)
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                def to_s
         | 
| 87 | 
            +
                  to_json
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                def ==(other)
         | 
| 91 | 
            +
                  eql?(other)
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
              end
         | 
| 94 | 
            +
            end
         | 
    
        data/lib/bolt/target.rb
    CHANGED
    
    | @@ -1,32 +1,80 @@ | |
| 1 | 
            +
            require 'addressable/uri'
         | 
| 2 | 
            +
            require 'bolt/error'
         | 
| 3 | 
            +
             | 
| 1 4 | 
             
            module Bolt
         | 
| 2 5 | 
             
              class Target
         | 
| 3 | 
            -
                attr_reader : | 
| 6 | 
            +
                attr_reader :uri, :options
         | 
| 4 7 |  | 
| 8 | 
            +
                # Satisfies the Puppet datatypes API
         | 
| 5 9 | 
             
                def self.from_asserted_hash(hash)
         | 
| 6 | 
            -
                  new(hash[' | 
| 10 | 
            +
                  new(hash['uri'], hash['options'])
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def self.from_uri(uri)
         | 
| 14 | 
            +
                  new(uri)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def self.parse_urls(urls)
         | 
| 18 | 
            +
                  urls.split(/[[:space:],]+/).reject(&:empty?).uniq.map { |url| from_uri(url) }
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def initialize(uri, options = nil)
         | 
| 22 | 
            +
                  @uri = uri
         | 
| 23 | 
            +
                  @uri_obj = parse(uri)
         | 
| 24 | 
            +
                  @options = options || {}
         | 
| 7 25 | 
             
                end
         | 
| 8 26 |  | 
| 9 | 
            -
                def  | 
| 10 | 
            -
                   | 
| 11 | 
            -
             | 
| 27 | 
            +
                def parse(string)
         | 
| 28 | 
            +
                  if string =~ %r{^[^:]+://}
         | 
| 29 | 
            +
                    Addressable::URI.parse(string)
         | 
| 30 | 
            +
                  else
         | 
| 31 | 
            +
                    # Initialize with an empty scheme to ensure we parse the hostname correctly
         | 
| 32 | 
            +
                    Addressable::URI.parse("//#{string}")
         | 
| 33 | 
            +
                  end
         | 
| 12 34 | 
             
                end
         | 
| 35 | 
            +
                private :parse
         | 
| 13 36 |  | 
| 14 37 | 
             
                def eql?(other)
         | 
| 15 | 
            -
                  self.class.equal?(other.class) && @ | 
| 38 | 
            +
                  self.class.equal?(other.class) && @uri == other.uri && @options == other.options
         | 
| 16 39 | 
             
                end
         | 
| 17 40 | 
             
                alias == eql?
         | 
| 18 41 |  | 
| 19 42 | 
             
                def hash
         | 
| 20 | 
            -
                  @ | 
| 43 | 
            +
                  @uri.hash ^ @options.hash
         | 
| 21 44 | 
             
                end
         | 
| 22 45 |  | 
| 23 46 | 
             
                def to_s
         | 
| 24 | 
            -
                  #  | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 47 | 
            +
                  "Target('#{@uri}', #{@options})"
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def host
         | 
| 51 | 
            +
                  @uri_obj.hostname
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def port
         | 
| 55 | 
            +
                  @uri_obj.port
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                # name is currently just uri but should be be used instead to identify the
         | 
| 59 | 
            +
                # Target ouside the transport or uri options.
         | 
| 60 | 
            +
                def name
         | 
| 61 | 
            +
                  uri
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                def user
         | 
| 65 | 
            +
                  Addressable::URI.unencode_component(
         | 
| 66 | 
            +
                    @uri_obj.user
         | 
| 67 | 
            +
                  )
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                def password
         | 
| 71 | 
            +
                  Addressable::URI.unencode_component(
         | 
| 72 | 
            +
                    @uri_obj.password
         | 
| 73 | 
            +
                  )
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                def protocol
         | 
| 77 | 
            +
                  @uri_obj.scheme
         | 
| 30 78 | 
             
                end
         | 
| 31 79 | 
             
              end
         | 
| 32 80 | 
             
            end
         | 
    
        data/lib/bolt/version.rb
    CHANGED
    
    
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            Puppet::DataTypes.create_type('Result') do
         | 
| 2 | 
            +
              interface <<-PUPPET
         | 
| 3 | 
            +
                attributes => {
         | 
| 4 | 
            +
                  'value' => Hash[String[1], Data],
         | 
| 5 | 
            +
                  'target' => Target
         | 
| 6 | 
            +
                },
         | 
| 7 | 
            +
                functions => {
         | 
| 8 | 
            +
                  error => Callable[[], Optional[Error]],
         | 
| 9 | 
            +
                  message => Callable[[], Optional[String]],
         | 
| 10 | 
            +
                  ok => Callable[[], Boolean],
         | 
| 11 | 
            +
                  '[]' => Callable[[String[1]], Data]
         | 
| 12 | 
            +
                }
         | 
| 13 | 
            +
              PUPPET
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              load_file('bolt/result')
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              implementation_class Bolt::Result
         | 
| 18 | 
            +
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            Puppet::DataTypes.create_type('ResultSet') do
         | 
| 2 | 
            +
              interface <<-PUPPET
         | 
| 3 | 
            +
                attributes => {
         | 
| 4 | 
            +
                  'results' => Array[Result],
         | 
| 5 | 
            +
                },
         | 
| 6 | 
            +
                functions => {
         | 
| 7 | 
            +
                  count => Callable[[], Integer],
         | 
| 8 | 
            +
                  empty => Callable[[], Boolean],
         | 
| 9 | 
            +
                  error_set => Callable[[], ResultSet],
         | 
| 10 | 
            +
                  find => Callable[[String[1]], Optional[Result]],
         | 
| 11 | 
            +
                  first => Callable[[], Optional[Result]],
         | 
| 12 | 
            +
                  names => Callable[[], Array[String[1]]],
         | 
| 13 | 
            +
                  ok => Callable[[], Boolean],
         | 
| 14 | 
            +
                  ok_set => Callable[[], ResultSet],
         | 
| 15 | 
            +
                  targets => Callable[[], Array[Target]],
         | 
| 16 | 
            +
                }
         | 
| 17 | 
            +
              PUPPET
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              load_file('bolt/result_set')
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              implementation_class Bolt::ResultSet
         | 
| 22 | 
            +
            end
         |