choria-colt 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a899af183eb44fcd18e470166a824da35e0ab2ed46ab25c9f001c716442edfe
4
- data.tar.gz: 891b29051dacb1ca6e2fa801ae38f0800e8cdb7decc734590c3354bdb5d12dee
3
+ metadata.gz: 17cd0f4a8fd7bc14aed8bd1f702405d257c8ab18b31406eb13eb3b3b3d6623cd
4
+ data.tar.gz: 9ad55b6d635820f4486476ed9722e23f68f85037f0b94c0ed93d500a64e10e29
5
5
  SHA512:
6
- metadata.gz: 98a116297f7f1d4f4384042f43d0fc90b07e85ea4546a799391271dc2c2b2b0602a4e400754f795ee1c499c027b0861de3d713fea2dc132d1d8a88d6bab2f9ab
7
- data.tar.gz: 51bd11e393b922ae49113fa6784fd24aeb31a592f093ba95b4de0e5a02973a004030233302ff401d58d01fbef411aa4c87ac98dd1a6e219c6219d61727c0181e
6
+ metadata.gz: cac0c586629af294b520c29e4967824cd832b257405be6a95ba4e2a552f1a92cba936b22e219ed0342b8b1cfff34b3257a5c3cf5ab6607f66450d864b636ba12
7
+ data.tar.gz: 6d6cf405dd1973a4e7d813a58de872a8b37514e821ea90c216a42b3242240895ed1fb4adda8dd24d065fbbf926b7ae186fea610b9e54f5c2e5df3a7fa75b94ef
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.rubocop.yml CHANGED
@@ -1,3 +1,5 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
1
3
  AllCops:
2
4
  TargetRubyVersion: 2.5
3
5
  Exclude:
@@ -9,7 +11,7 @@ Metrics/AbcSize:
9
11
  Max: 20
10
12
 
11
13
  Metrics/MethodLength:
12
- Max: 17
14
+ Max: 20
13
15
 
14
16
  Layout/LineLength:
15
17
  Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,22 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2022-04-07 15:43:34 UTC using RuboCop version 1.26.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Configuration parameters: CountComments, CountAsOne.
11
+ Metrics/ClassLength:
12
+ Max: 109
13
+
14
+ # Offense count: 1
15
+ # Configuration parameters: IgnoredMethods.
16
+ Metrics/CyclomaticComplexity:
17
+ Max: 9
18
+
19
+ # Offense count: 1
20
+ # Configuration parameters: IgnoredMethods.
21
+ Metrics/PerceivedComplexity:
22
+ Max: 9
data/choria-colt.gemspec CHANGED
@@ -28,15 +28,20 @@ Gem::Specification.new do |spec|
28
28
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
29
29
  spec.require_paths = ['lib']
30
30
 
31
+ spec.add_dependency 'activesupport'
31
32
  spec.add_dependency 'choria-mcorpc-support'
32
33
  spec.add_dependency 'deep_merge'
34
+ spec.add_dependency 'pastel'
33
35
  spec.add_dependency 'puppet'
34
36
  spec.add_dependency 'thor'
37
+ spec.add_dependency 'tty-logger'
35
38
 
39
+ # spec.add_development_dependency 'byebug'
36
40
  spec.add_development_dependency 'rake'
37
41
  spec.add_development_dependency 'rspec'
38
42
  spec.add_development_dependency 'rubocop'
39
- #spec.add_development_dependency 'byebug'
43
+ spec.add_development_dependency 'rubocop-rake'
44
+ spec.add_development_dependency 'rubocop-rspec'
40
45
 
41
46
  # For more information and examples about making a new gem, check out our
42
47
  # guide at: https://bundler.io/guides/creating_gem.html
@@ -0,0 +1,67 @@
1
+ require 'choria/colt/cli'
2
+ require 'choria/colt/cli/thor'
3
+
4
+ module Choria
5
+ class Colt
6
+ class CLI < Thor
7
+ class Formatter
8
+ attr_reader :pastel
9
+
10
+ def initialize(colored:)
11
+ @pastel = Pastel.new(enabled: colored)
12
+ pastel.alias_color(:host, :cyan)
13
+ end
14
+
15
+ def process_result(result)
16
+ return process_error(result) unless result.dig(:data, :exitcode)&.zero?
17
+
18
+ process_success(result)
19
+ end
20
+
21
+ def process_success(result)
22
+ output_lines = [
23
+ "#{pastel.host(result[:sender]).ljust(60, ' ')}duration: #{pastel.bright_white result[:data][:runtime]}",
24
+ ]
25
+
26
+ output_lines += if result.dig(:result, :_output).nil?
27
+ JSON.pretty_generate(result[:result]).split("\n").map { |line| " #{line}" }
28
+ else
29
+ result.dig(:result, :_output).map { |line| " #{line}" }
30
+ end
31
+
32
+ output_lines.join("\n")
33
+ end
34
+
35
+ def process_error(result) # rubocop:disable Metrics/AbcSize
36
+ host = "#{pastel.bright_red '⨯'} #{pastel.host(result[:sender]).ljust(60, ' ')}duration: #{pastel.bright_white result[:data][:runtime]}"
37
+ output = result.dig(:result, '_output')
38
+ error_details = JSON.pretty_generate(result.dig(:result, :_error, :details)).split "\n"
39
+ error_description = [
40
+ "#{pastel.bright_red result.dig(:result, :_error, :kind)}: #{pastel.bright_white result.dig(:result, :_error, :msg)}",
41
+ " details: #{error_details.shift}",
42
+ error_details.map { |line| " #{line}" },
43
+ ]
44
+ output_description = if output.nil? || output.empty?
45
+ []
46
+ else
47
+ [
48
+ nil,
49
+ pastel.bright_red('output:'),
50
+ output,
51
+ ]
52
+ end
53
+
54
+ headline = "#{pastel.on_red ' '} "
55
+
56
+ [
57
+ host,
58
+ [
59
+ error_description,
60
+ output_description,
61
+ ].flatten.map { |line| "#{headline}#{line}" },
62
+ ].flatten.join("\n")
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -1,13 +1,17 @@
1
1
  require 'choria/colt'
2
+ require 'choria/colt/cli/formatter'
2
3
  require 'choria/colt/cli/thor'
3
4
 
4
5
  require 'json'
5
- require 'logger'
6
+ require 'tty/logger'
6
7
 
7
8
  module Choria
8
9
  class Colt
9
10
  class CLI < Thor
10
11
  class Tasks < Thor
12
+ class_option :log_level,
13
+ desc: 'Set log level for CLI',
14
+ default: 'info'
11
15
  # BOLT: desc 'run <task name> [parameters] {--targets TARGETS | --query QUERY | --rerun FILTER} [options]', 'Run a Bolt task'
12
16
  desc 'run <task name> [parameters] --targets TARGETS [options]', 'Run a Bolt task'
13
17
  long_desc <<~DESC
@@ -17,24 +21,30 @@ module Choria
17
21
  DESC
18
22
  option :targets,
19
23
  aliases: ['--target', '-t'],
20
- desc: 'Identifies the targets of the command.',
21
- required: true
22
- def run(*args)
24
+ desc: 'Identifies the targets of the command.'
25
+ option :targets_with_classes,
26
+ aliases: ['--targets-with-class', '-C'],
27
+ desc: 'Select the targets which have the specified Puppet classes.'
28
+ def run(*args) # rubocop:disable Metrics/AbcSize
23
29
  input = extract_task_parameters_from_args(args)
24
30
 
25
31
  raise Thor::Error, 'Task name is required' if args.empty?
26
32
  raise Thor::Error, "Too many arguments: #{args}" unless args.count == 1
27
33
 
34
+ raise Thor::Error, 'Flag --targets or --targets-with-class is required' if options['targets'].nil? && options['targets_with_classes'].nil?
35
+
28
36
  task_name = args.shift
29
37
 
30
- targets = options['targets'].split ','
38
+ targets = options['targets']&.split(',')
31
39
  targets = nil if options['targets'] == 'all'
32
40
 
33
- results = colt.run_bolt_task task_name, input: input, targets: targets
41
+ targets_with_classes = options['targets_with_classes']&.split(',')
34
42
 
35
- File.write 'last_run.json', JSON.pretty_generate(results)
43
+ results = colt.run_bolt_task task_name, input: input, targets: targets, targets_with_classes: targets_with_classes do |result|
44
+ $stdout.puts formatter.process_result(result)
45
+ end
36
46
 
37
- show_results(results)
47
+ File.write 'last_run.json', JSON.pretty_generate(results)
38
48
  rescue Choria::Orchestrator::Error => e
39
49
  raise Thor::Error, "#{e.class}: #{e}"
40
50
  end
@@ -68,9 +78,23 @@ module Choria
68
78
  end
69
79
  end
70
80
 
71
- no_commands do
81
+ no_commands do # rubocop:disable Metrics/BlockLength
72
82
  def colt
73
- @colt ||= Choria::Colt.new logger: Logger.new($stdout)
83
+ @colt ||= Choria::Colt.new logger: logger
84
+ end
85
+
86
+ def logger
87
+ @logger ||= TTY::Logger.new do |config|
88
+ config.handlers = [
89
+ [:console, { output: $stderr, level: options['log_level'].to_sym }],
90
+ [:stream, { output: File.open('colt-debug.log', 'a'), level: :debug }],
91
+ ]
92
+ config.metadata = %i[date time]
93
+ end
94
+ end
95
+
96
+ def formatter
97
+ @formatter ||= Formatter.new(colored: $stdout.tty?)
74
98
  end
75
99
 
76
100
  def extract_task_parameters_from_args(args)
@@ -78,7 +102,14 @@ module Choria
78
102
  args.reject! { |arg| arg =~ /^\w+=/ }
79
103
 
80
104
  parameters.map do |parameter|
81
- key, value = parameter.split('=')
105
+ key, value = parameter.split('=', 2)
106
+
107
+ # TODO: Convert to boolean only if the expected type of parameter is boolean
108
+ # TODO: Support String to integer convertion
109
+ # TODO: Support @notation from parameter and/or whole input
110
+ value = true if value == 'true'
111
+ value = false if value == 'false'
112
+
82
113
  [key, value]
83
114
  end.to_h
84
115
  end
@@ -87,7 +118,7 @@ module Choria
87
118
  tasks.reject! { |_task, metadata| metadata['metadata']['private'] }
88
119
 
89
120
  puts <<~OUTPUT
90
- Tasks
121
+ #{pastel.title 'Tasks'}
91
122
  #{tasks.map { |task, metadata| "#{task}#{' ' * (60 - task.size)}#{metadata['metadata']['description']}" }.join("\n").gsub(/^/, ' ')}
92
123
  OUTPUT
93
124
  end
@@ -95,30 +126,35 @@ module Choria
95
126
  def show_task_details(task_name, tasks)
96
127
  metadata = tasks[task_name]
97
128
  puts <<~OUTPUT
98
- Task: '#{task_name}'
129
+ #{pastel.title "Task: #{task_name}"}
99
130
  #{metadata['metadata']['description']}
100
131
 
101
- Parameters:
102
- #{JSON.pretty_generate(metadata['metadata']['parameters']).gsub(/^/, ' ')}
132
+ #{pastel.title 'Parameters'}
133
+ #{format_task_parameters(metadata['metadata']['parameters']).gsub(/^/, ' ')}
103
134
  OUTPUT
104
135
  end
105
136
 
106
- def show_results(results)
107
- results.each { |result| show_result(result) }
137
+ def format_task_parameters(parameters)
138
+ parameters.map do |parameter, metadata|
139
+ output = <<~OUTPUT
140
+ #{pastel.parameter(parameter)} #{pastel.parameter_type metadata['type']}
141
+ #{metadata['description']}
142
+ OUTPUT
143
+ output += " Default: #{metadata['default']}" unless metadata['default'].nil?
144
+ output
145
+ end.join "\n"
108
146
  end
109
147
 
110
- def show_result(result)
111
- return show_generic_output(result) unless result.dig(:result, '_output').nil? || (result.dig(:result, 'exit_code') != 0)
112
-
113
- $stdout.puts JSON.pretty_generate(result)
148
+ def pastel
149
+ @pastel ||= _pastel
114
150
  end
115
151
 
116
- def show_generic_output(result)
117
- target = result[:sender]
118
-
119
- output = result.dig(:result, '_output')
120
- $stdout.puts "'#{target}':"
121
- output.split("\n").each { |line| $stdout.puts(" #{line}") }
152
+ def _pastel
153
+ pastel = Pastel.new(enabled: $stdout.tty?)
154
+ pastel.alias_color(:title, :cyan)
155
+ pastel.alias_color(:parameter, :yellow)
156
+ pastel.alias_color(:parameter_type, :bright_white)
157
+ pastel
122
158
  end
123
159
  end
124
160
  end
@@ -0,0 +1,26 @@
1
+ module Choria
2
+ class Colt
3
+ module DataStructurer
4
+ def self.structure(res) # rubocop:disable Metrics/AbcSize
5
+ # data.stdout seems to always be JSON, so parse it once.
6
+ res[:result] = JSON.parse res[:data][:stdout]
7
+ res[:data].delete :stdout
8
+
9
+ # On one side, data.stderr is filled by the remote execution stderr.
10
+ # On the other side, error description is in JSON (ie. '_error')
11
+ # So merge data.stderr in '_error'.'details'
12
+ unless res[:data][:stderr].empty?
13
+ raise NotImplementedError, 'What to do when res[:data][:stderr] contains something?' if res[:result]['_error'].empty?
14
+
15
+ res[:result]['_error']['details'].merge!({ 'stderr' => res[:data][:stderr].split("\n") })
16
+ end
17
+ res[:data].delete :stderr
18
+
19
+ # Convert '_output' (ie. stdout) lines into array
20
+ res[:result]['_output'] = res[:result]['_output'].split("\n") unless res[:result]['_output'].nil?
21
+
22
+ res
23
+ end
24
+ end
25
+ end
26
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Choria
4
4
  class Colt
5
- VERSION = '0.2.0'
5
+ VERSION = '0.3.0'
6
6
  end
7
7
  end
data/lib/choria/colt.rb CHANGED
@@ -19,11 +19,13 @@ module Choria
19
19
  @orchestrator = Choria::Orchestrator.new logger: @logger
20
20
  end
21
21
 
22
- def run_bolt_task(task_name, input: {}, targets: nil)
22
+ def run_bolt_task(task_name, input: {}, targets: nil, targets_with_classes: nil, &block)
23
23
  logger.debug "Instantiate task '#{task_name}' and validate input"
24
24
  task = Choria::Orchestrator::Task.new(task_name, input: input, orchestrator: orchestrator)
25
25
 
26
- orchestrator.run(task, targets: targets)
26
+ task.on_result(&block) if block_given?
27
+
28
+ orchestrator.run(task, targets: targets, targets_with_classes: targets_with_classes)
27
29
  task.wait
28
30
  task.results
29
31
  rescue Choria::Orchestrator::Error => e
@@ -36,14 +38,6 @@ module Choria
36
38
  task['name']
37
39
  end
38
40
 
39
- def tasks_metadata(tasks, environment)
40
- tasks.map do |task|
41
- logger.debug "Fetching metadata for task '#{task}' (environment: '#{environment}')"
42
- metadata = orchestrator.tasks_support.task_metadata(task, environment)
43
- [task, metadata]
44
- end.to_h
45
- end
46
-
47
41
  return tasks_metadata(tasks_names, environment) if cache.nil?
48
42
 
49
43
  cached_tasks = cache.load
@@ -54,5 +48,17 @@ module Choria
54
48
 
55
49
  updated_tasks
56
50
  end
51
+
52
+ private
53
+
54
+ def tasks_metadata(tasks, environment)
55
+ logger.info "Fetching metadata for tasks (environment: '#{environment}')"
56
+
57
+ tasks.map do |task|
58
+ logger.debug "Fetching metadata for task '#{task}' (environment: '#{environment}')"
59
+ metadata = orchestrator.tasks_support.task_metadata(task, environment)
60
+ [task, metadata]
61
+ end.to_h
62
+ end
57
63
  end
58
64
  end
@@ -1,17 +1,25 @@
1
+ require 'choria/colt/data_structurer'
2
+
3
+ require 'active_support'
4
+ require 'active_support/core_ext/hash/indifferent_access'
5
+
1
6
  module Choria
2
7
  class Orchestrator
3
8
  class Task
4
9
  class Error < Orchestrator::Error; end
5
10
 
6
- attr_reader :name, :input, :environment, :rpc_results
11
+ attr_reader :name, :input, :environment, :rpc_results, :results
7
12
  attr_accessor :rpc_responses
8
13
 
9
14
  def initialize(name, orchestrator:, input: {}, environment: 'production')
10
15
  @name = name
11
- @input = input
12
16
  @environment = environment
13
17
  @orchestrator = orchestrator
18
+ @input = default_input.merge input
14
19
 
20
+ @results = []
21
+
22
+ logger.debug "Task inputs: #{input}"
15
23
  validate_inputs
16
24
  end
17
25
 
@@ -23,37 +31,93 @@ module Choria
23
31
  metadata['files'].to_json
24
32
  end
25
33
 
26
- def wait
27
- task_ids = rpc_responses.map { |res| res[:body][:data][:task_id] }.uniq
34
+ def wait # rubocop:disable Metrics/AbcSize
35
+ rpc_responses_ok, rpc_responses_error = rpc_responses.partition { |res| (res[:body][:statuscode]).zero? }
36
+ rpc_responses_error.each do |res|
37
+ logger.error "Task request failed on '#{res[:senderid]}':\n#{pp res}"
38
+ end
39
+
40
+ task_ids = rpc_responses_ok.map { |res| res[:body][:data][:task_id] }.uniq
41
+
28
42
  raise NotImplementedError, "Multiple task IDs: #{task_ids}" unless task_ids.count == 1
29
43
 
30
- @rpc_results = @orchestrator.wait_results task_id: task_ids.first
44
+ @id = task_ids.first
45
+
46
+ wait_results
47
+ end
48
+
49
+ def on_result(&block)
50
+ @on_result = lambda { |result|
51
+ block.call(result)
52
+ }
53
+ end
54
+
55
+ private
56
+
57
+ def rpc_results=(results)
58
+ new_result_hosts = (results.map { |res| res[:sender] }) - (@results.map { |res| res[:sender] })
59
+
60
+ new_result_hosts.each do |host|
61
+ result = results.find { |res| res[:sender] == host }
62
+
63
+ next unless result[:data][:exitcode] != -1
64
+
65
+ logger.debug "New result for task ##{@id}: #{result}"
66
+ structured_result = Choria::Colt::DataStructurer.structure(result).with_indifferent_access
67
+
68
+ @on_result&.call(structured_result)
69
+
70
+ @results << structured_result
71
+ end
72
+
73
+ @rpc_results = results
31
74
  end
32
75
 
33
- def results
34
- @rpc_results.map do |res|
35
- raise NotImplementedError, 'What to do when res[:data][:stderr] contains something?' unless res[:data][:stderr].empty?
76
+ def wait_results
77
+ raise 'Task ID is required!' if @id.nil?
36
78
 
37
- res[:result] = JSON.parse res[:data][:stdout]
38
- res[:data].delete :stderr
39
- res[:data].delete :stdout
40
- res
79
+ logger.info 'Waiting task results…'
80
+
81
+ @results = []
82
+ @rpc_results = []
83
+
84
+ loop do
85
+ self.rpc_results = @orchestrator.rpc_client.task_status(task_id: @id).map(&:results)
86
+
87
+ break if terminated?
41
88
  end
42
89
  end
43
90
 
44
- private
91
+ def terminated?
92
+ @rpc_results.each do |result|
93
+ return false if result[:data][:exitcode] == -1
94
+ end
95
+
96
+ true
97
+ end
45
98
 
46
99
  def _metadata
47
- # puts 'Retrieving task metadata for task %s from the Puppet Server' % task if verbose
100
+ logger.info 'Downloading task metadata from the Puppet Server'
48
101
  @orchestrator.tasks_support.task_metadata(@name, @environment)
49
102
  rescue RuntimeError => e
50
103
  raise Error, e.message
51
104
  end
52
105
 
106
+ def default_input
107
+ parameters_with_defaults = metadata['metadata']['parameters'].reject { |_k, v| v['default'].nil? }
108
+ parameters_with_defaults.transform_values do |meta|
109
+ meta['default']
110
+ end
111
+ end
112
+
53
113
  def validate_inputs
54
114
  ok, reason = @orchestrator.tasks_support.validate_task_inputs(@input, metadata)
55
115
  raise Error, reason.sub(/^\n/, '') unless ok
56
116
  end
117
+
118
+ def logger
119
+ @orchestrator.logger
120
+ end
57
121
  end
58
122
  end
59
123
  end
@@ -21,21 +21,25 @@ module Choria
21
21
  @tasks_support ||= MCollective::Util::Choria.new.tasks_support
22
22
  end
23
23
 
24
- def run(task, targets: nil, verbose: false)
25
- logger.debug "Running task: '#{task.name}' (targets: #{targets.nil? ? 'all' : targets})"
24
+ def run(task, targets: nil, targets_with_classes: nil, verbose: false) # rubocop:disable Metrics/AbcSize
26
25
  rpc_client.progress = verbose
27
26
 
27
+ logger.debug "Running task: '#{task.name}' (targets: #{targets.nil? ? 'all' : targets})"
28
28
  targets&.each { |target| rpc_client.identity_filter target }
29
29
 
30
- raise DiscoverError, 'No request sent, no node discovered' if rpc_client.discover.size.zero?
30
+ unless targets_with_classes.nil?
31
+ logger.debug "Filtering targets with classes: #{targets_with_classes}"
32
+ targets_with_classes.each { |klass| rpc_client.class_filter klass }
33
+ end
31
34
 
32
- logger.info "Attempting to download and run task '#{task.name}' on #{rpc_client.discover.size} nodes"
35
+ logger.info 'Discovering targets…'
36
+ raise DiscoverError, 'No request sent, no node discovered' if rpc_client.discover.size.zero?
33
37
 
38
+ logger.info "Downloading task '#{task.name}' on #{rpc_client.discover.size} nodes…"
34
39
  rpc_client.download(task: task.name, files: task.files, verbose: verbose)
35
40
 
36
- # TODO: Extract error from 'rpc' (see MCollective::RPC#printrpc)
37
-
38
41
  responses = []
42
+ logger.info "Starting task '#{task.name}' on #{rpc_client.discover.size} nodes…"
39
43
  rpc_client.run_no_wait(task: task.name, files: task.files, input: task.input.to_json, verbose: verbose) do |response|
40
44
  logger.debug " Response: '#{response}'"
41
45
  responses << response
@@ -46,37 +50,16 @@ module Choria
46
50
  task.rpc_responses = responses
47
51
  end
48
52
 
49
- def wait_results(task_id:)
50
- raise 'Task ID is required!' if task_id.nil?
51
-
52
- task_status_results = nil
53
- loop do
54
- task_status_results = rpc_client.task_status(task_id: task_id).map(&:results)
55
- logger.debug "Task ##{task_id} status: #{task_status_results}"
56
- break if task_completed? task_status_results
57
- end
58
-
59
- task_status_results
60
- end
61
-
62
- def task_completed?(results)
63
- results.each do |result|
64
- return false unless result[:data][:completed]
65
- end
66
-
67
- true
68
- end
69
-
70
53
  def validate_rpc_result(result)
71
54
  raise Error, "The RPC agent returned an error: #{result[:statusmsg]}" unless (result[:statuscode]).zero?
72
55
  end
73
56
 
74
- private
75
-
76
57
  def rpc_client
77
58
  @rpc_client ||= rpcclient('bolt_tasks', options: rpc_options)
78
59
  end
79
60
 
61
+ private
62
+
80
63
  def rpc_options
81
64
  {
82
65
  verbose: false,
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: choria-colt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Romuald Conty
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-03-03 00:00:00.000000000 Z
11
+ date: 2022-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: choria-mcorpc-support
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +52,20 @@ dependencies:
38
52
  - - ">="
39
53
  - !ruby/object:Gem::Version
40
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pastel
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: puppet
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +94,20 @@ dependencies:
66
94
  - - ">="
67
95
  - !ruby/object:Gem::Version
68
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: tty-logger
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
69
111
  - !ruby/object:Gem::Dependency
70
112
  name: rake
71
113
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +150,34 @@ dependencies:
108
150
  - - ">="
109
151
  - !ruby/object:Gem::Version
110
152
  version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rubocop-rake
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rubocop-rspec
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
111
181
  description: Colt eases the Bolt tasks run through Choria
112
182
  email:
113
183
  - romuald@opus-codium.fr
@@ -116,7 +186,9 @@ executables:
116
186
  extensions: []
117
187
  extra_rdoc_files: []
118
188
  files:
189
+ - ".rspec"
119
190
  - ".rubocop.yml"
191
+ - ".rubocop_todo.yml"
120
192
  - Gemfile
121
193
  - README.md
122
194
  - Rakefile
@@ -125,7 +197,9 @@ files:
125
197
  - lib/choria/colt.rb
126
198
  - lib/choria/colt/cache.rb
127
199
  - lib/choria/colt/cli.rb
200
+ - lib/choria/colt/cli/formatter.rb
128
201
  - lib/choria/colt/cli/thor.rb
202
+ - lib/choria/colt/data_structurer.rb
129
203
  - lib/choria/colt/version.rb
130
204
  - lib/choria/orchestrator.rb
131
205
  - lib/choria/orchestrator/task.rb