choria-colt 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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