cmdx 0.2.0 → 0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 198e34bfa10cf9b640e3a768e335e3901063e2cde3817be7c63fb710b322acc6
4
- data.tar.gz: 59f99b87b1c2cc5fff64e2092f3f5ef5230a43d11de6f27c6609802627509164
3
+ metadata.gz: 00e2b2067ace8ed3afdb75bc07e3f3c5ec3ed40233a63cc3a9abc495c3a3199c
4
+ data.tar.gz: 053c7a3a6e3c70808b4dba6d916a35419ee0c858145dbace0d83d89e0583d05a
5
5
  SHA512:
6
- metadata.gz: e60556e4f9af0a9af56d748a1084d95e5fecbe5316268d1d2f1414e5d4c323be81a7c56066bf19edf121eab3fb48080d6b5b3470086ee96241008eb28df9a152
7
- data.tar.gz: cc37a5a0029f708f624e449b0526060e203b649d282f33f69551c641ae06f34a3d53886b346b8e48b68f6dbaff23654171d34e58e7d854429c58f0c3d90c62af
6
+ metadata.gz: 2de61e9b7e43d9e1187b4c6c925c930ae55163a5075ac624f4a9c29595588b10aacd007d64654397dc458a9c704d9175dd884eadafbef614bb8f01182f022cf0
7
+ data.tar.gz: 52dcb48c2e9538d33fea460946fde8f25814127aa490895fc4a676f865423d0b915ad1e7c5daae88ebe46e4bff01a36f850fa704bff312fa938ed5e3a7ea879a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.4.0] - 2025-03-17
4
+
5
+ ### Added
6
+ - Add ansi util
7
+ - Add string to json parsing in hash coercion
8
+ - Add string to json parsing in array coercion
9
+ ### Changed
10
+ - Skip assigning log settings if logger is nil
11
+ - Improve ANSI escape sequence
12
+ - Improve run inspector output
13
+
14
+ ## [0.3.0] - 2025-03-14
15
+ ### Added
16
+ - Add `progname` to logger instances
17
+ - Add `LoggerSerializer` to standardize log output
18
+ ### Changed
19
+ - Revert default log formatter to `Line`
20
+ - Removed `pid` from result serializer
21
+ - Fix serialization of frozen run
22
+ - Fix `call!` not marking state of failure as interrupted
23
+
3
24
  ## [0.2.0] - 2025-03-12
4
25
  ### Added
5
26
  - Add `PrettyJson` log formatter
data/docs/logging.md CHANGED
@@ -11,27 +11,27 @@ Built-in log formatters are:
11
11
 
12
12
  #### Success:
13
13
  ```txt
14
- I, [2022-07-17T18:43:15.000000 #3784] INFO -- CMDx: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 state=complete status=success outcome=success metadata={} runtime=0 tags=[] pid=3784
14
+ I, [2022-07-17T18:43:15.000000 #3784] INFO -- SimulationTask: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 tags=[] state=complete status=success outcome=success metadata={} runtime=0 origin=CMDx
15
15
  ```
16
16
 
17
17
  #### Skipped:
18
18
  ```txt
19
- W, [2022-07-17T18:43:15.000000 #3784] WARN -- CMDx: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 state=interrupted status=skipped outcome=skipped metadata={} runtime=0 tags=[] pid=3784
19
+ W, [2022-07-17T18:43:15.000000 #3784] WARN -- SimulationTask: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 tags=[] state=interrupted status=skipped outcome=skipped metadata={} runtime=0 origin=CMDx
20
20
  ```
21
21
 
22
22
  #### Failed:
23
23
  ```txt
24
- E, [2022-07-17T18:43:15.000000 #3784] ERROR -- CMDx: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 state=interrupted status=failed outcome=failed metadata={} runtime=0 tags=[] pid=3784
24
+ E, [2022-07-17T18:43:15.000000 #3784] ERROR -- SimulationTask: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 tags=[] state=interrupted status=failed outcome=failed metadata={} runtime=0 origin=CMDx
25
25
  ```
26
26
 
27
27
  #### Level 1 subtask failure:
28
28
  ```txt
29
- E, [2022-07-17T18:43:15.000000 #3784] ERROR -- CMDx: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 state=interrupted status=failed outcome=interrupted metadata={} runtime=0 tags=[] pid=3784 caused_failure={:index=>1, :run_id=>"018c2b95-b764-7615-a924-cc5b910ed1e5", :type=>"Task", :class=>"SimulationTask", :id=>"018c2b95-b764-7615-a924-cc5b910ed1e5", :state=>"interrupted", :status=>"failed", :outcome=>"failed", :metadata=>{}, :runtime=>0, :tags=>[], :pid=>3784} threw_failure={:index=>1, :run_id=>"018c2b95-b764-7615-a924-cc5b910ed1e5", :type=>"Task", :class=>"SimulationTask", :id=>"018c2b95-b764-7615-a924-cc5b910ed1e5", :state=>"interrupted", :status=>"failed", :outcome=>"failed", :metadata=>{}, :runtime=>0, :tags=>[], :pid=>3784}
29
+ E, [2022-07-17T18:43:15.000000 #3784] ERROR -- SimulationTask: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 tags=[] state=interrupted status=failed outcome=interrupted metadata={} runtime=0 caused_failure={index: 1, run_id: "018c2b95-b764-7615-a924-cc5b910ed1e5", type: "Task", class: "SimulationTask", id: "018c2b95-b764-7615-a924-cc5b910ed1e5", tags: [], state: "interrupted", status: "failed", outcome: "failed", metadata: {}, runtime: 0} threw_failure={index: 1, run_id: "018c2b95-b764-7615-a924-cc5b910ed1e5", type: "Task", class: "SimulationTask", id: "018c2b95-b764-7615-a924-cc5b910ed1e5", tags: [], state: "interrupted", status: "failed", outcome: "failed", metadata: {}, runtime: 0} origin=CMDx
30
30
  ```
31
31
 
32
32
  #### Level 2+ subtask failure:
33
33
  ```txt
34
- E, [2022-07-17T18:43:15.000000 #3784] ERROR -- CMDx: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 state=interrupted status=failed outcome=interrupted metadata={} runtime=0 tags=[] pid=3784 caused_failure={:index=>2, :run_id=>"018c2b95-b764-7615-a924-cc5b910ed1e5", :type=>"Task", :class=>"SimulationTask", :id=>"018c2b95-b764-7615-a924-cc5b910ed1e5", :state=>"interrupted", :status=>"failed", :outcome=>"failed", :metadata=>{}, :runtime=>0, :tags=>[], :pid=>3784} threw_failure={:index=>1, :run_id=>"018c2b95-b764-7615-a924-cc5b910ed1e5", :type=>"Task", :class=>"SimulationTask", :id=>"018c2b95-b764-7615-a924-cc5b910ed1e5", :state=>"interrupted", :status=>"failed", :outcome=>"interrupted", :metadata=>{}, :runtime=>0, :tags=>[], :pid=>3784}
34
+ E, [2022-07-17T18:43:15.000000 #3784] ERROR -- SimulationTask: index=0 run_id=018c2b95-b764-7615-a924-cc5b910ed1e5 type=Task class=SimulationTask id=018c2b95-b764-7615-a924-cc5b910ed1e5 tags=[] state=interrupted status=failed outcome=interrupted metadata={} runtime=0 caused_failure={index: 2, run_id: "018c2b95-b764-7615-a924-cc5b910ed1e5", type: "Task", class: "SimulationTask", id: "018c2b95-b764-7615-a924-cc5b910ed1e5", tags: [], state: "interrupted", status: "failed", outcome: "failed", metadata: {}, runtime: 0} threw_failure={index: 1, run_id: "018c2b95-b764-7615-a924-cc5b910ed1e5", type: "Task", class: "SimulationTask", id: "018c2b95-b764-7615-a924-cc5b910ed1e5", tags: [], state: "interrupted", status: "failed", outcome: "interrupted", metadata: {}, runtime: 0} origin=CMDx
35
35
  ```
36
36
 
37
37
  ## Logger
@@ -92,7 +92,7 @@ Define a custom log formatter to match your expected output, for example one tha
92
92
 
93
93
  ```ruby
94
94
  class CustomCmdxLogFormat
95
- def call(severity, time, progname, message)
95
+ def call(severity, time, task, message)
96
96
  # Return string, hash, array, etc to output...
97
97
  end
98
98
  end
@@ -7,7 +7,11 @@ module CMDx
7
7
  module_function
8
8
 
9
9
  def call(value, _options = {})
10
- Array(value)
10
+ if value.is_a?(::String) && value.start_with?("[")
11
+ JSON.parse(value)
12
+ else
13
+ Array(value)
14
+ end
11
15
  end
12
16
 
13
17
  end
@@ -8,11 +8,16 @@ module CMDx
8
8
 
9
9
  def call(value, _options = {})
10
10
  case value.class.name
11
- when "Hash", "ActionController::Parameters" then value
12
- when "Array" then ::Hash[*value]
13
- else raise_coercion_error!
11
+ when "Hash", "ActionController::Parameters"
12
+ value
13
+ when "Array"
14
+ ::Hash[*value]
15
+ when "String"
16
+ value.start_with?("{") ? JSON.parse(value) : raise_coercion_error!
17
+ else
18
+ raise_coercion_error!
14
19
  end
15
- rescue ArgumentError, TypeError
20
+ rescue ArgumentError, TypeError, JSON::ParserError
16
21
  raise_coercion_error!
17
22
  end
18
23
 
@@ -14,7 +14,7 @@ module CMDx
14
14
 
15
15
  def reset_configuration!
16
16
  @configuration = LazyStruct.new(
17
- logger: ::Logger.new($stdout, formatter: CMDx::LogFormatters::PrettyLine.new),
17
+ logger: ::Logger.new($stdout, formatter: CMDx::LogFormatters::Line.new),
18
18
  task_halt: CMDx::Result::FAILED,
19
19
  task_timeout: nil,
20
20
  batch_halt: CMDx::Result::FAILED,
@@ -4,9 +4,14 @@ module CMDx
4
4
  module LogFormatters
5
5
  class Json
6
6
 
7
- def call(_severity, _time, _progname, message)
8
- message = message.to_h if message.is_a?(Result)
9
- JSON.dump(message) << "\n"
7
+ def call(severity, time, task, message)
8
+ m = LoggerSerializer.call(severity, time, task, message).merge!(
9
+ severity:,
10
+ pid: Process.pid,
11
+ timestamp: Utils::LogTimestamp.call(time.utc)
12
+ )
13
+
14
+ JSON.dump(m) << "\n"
10
15
  end
11
16
 
12
17
  end
@@ -4,14 +4,15 @@ module CMDx
4
4
  module LogFormatters
5
5
  class KeyValue
6
6
 
7
- def call(_severity, _time, _progname, message)
8
- if message.is_a?(Result)
9
- message = message.to_h.map do |k, v|
10
- "#{k}=#{v}"
11
- end.join(" ")
12
- end
7
+ def call(severity, time, task, message)
8
+ m = LoggerSerializer.call(severity, time, task, message).merge!(
9
+ severity:,
10
+ pid: Process.pid,
11
+ timestamp: Utils::LogTimestamp.call(time.utc)
12
+ )
13
13
 
14
- message << "\n"
14
+ m = m.map { |k, v| "#{k}=#{v}" }.join(" ") if m.is_a?(Hash)
15
+ m << "\n"
15
16
  end
16
17
 
17
18
  end
@@ -4,11 +4,12 @@ module CMDx
4
4
  module LogFormatters
5
5
  class Line
6
6
 
7
- def call(severity, time, progname, message)
8
- timestamp = Utils::LogTimestamp.call(time.utc)
9
- message = KeyValue.new.call(severity, time, progname, message).chomp
7
+ def call(severity, time, task, message)
8
+ t = Utils::LogTimestamp.call(time.utc)
9
+ m = LoggerSerializer.call(severity, time, task, message)
10
+ m = m.map { |k, v| "#{k}=#{v}" }.join(" ") if m.is_a?(Hash)
10
11
 
11
- "#{severity[0]}, [#{timestamp} ##{Process.pid}] #{severity} -- #{progname || 'CMDx'}: #{message}\n"
12
+ "#{severity[0]}, [#{t} ##{Process.pid}] #{severity} -- #{task.class.name}: #{m}\n"
12
13
  end
13
14
 
14
15
  end
@@ -4,15 +4,15 @@ module CMDx
4
4
  module LogFormatters
5
5
  class Logstash
6
6
 
7
- def call(_severity, time, _progname, message)
8
- message = message.to_h if message.is_a?(Result)
7
+ def call(severity, time, task, message)
8
+ m = LoggerSerializer.call(severity, time, task, message).merge!(
9
+ severity:,
10
+ pid: Process.pid,
11
+ "@version" => "1",
12
+ "@timestamp" => Utils::LogTimestamp.call(time.utc)
13
+ )
9
14
 
10
- if message.is_a?(Hash)
11
- message["@version"] ||= "1"
12
- message["@timestamp"] ||= Utils::LogTimestamp.call(time.utc)
13
- end
14
-
15
- JSON.dump(message) << "\n"
15
+ JSON.dump(m) << "\n"
16
16
  end
17
17
 
18
18
  end
@@ -4,9 +4,14 @@ module CMDx
4
4
  module LogFormatters
5
5
  class PrettyJson
6
6
 
7
- def call(_severity, _time, _progname, message)
8
- message = message.to_h if message.is_a?(Result)
9
- JSON.pretty_generate(message) << "\n"
7
+ def call(severity, time, task, message)
8
+ m = LoggerSerializer.call(severity, time, task, message).merge!(
9
+ severity:,
10
+ pid: Process.pid,
11
+ timestamp: Utils::LogTimestamp.call(time.utc)
12
+ )
13
+
14
+ JSON.pretty_generate(m) << "\n"
10
15
  end
11
16
 
12
17
  end
@@ -4,19 +4,15 @@ module CMDx
4
4
  module LogFormatters
5
5
  class PrettyKeyValue
6
6
 
7
- COLORED_KEYS = %i[
8
- state status outcome
9
- ].freeze
7
+ def call(severity, time, task, message)
8
+ m = LoggerSerializer.call(severity, time, task, message, ansi_colorize: true).merge!(
9
+ severity:,
10
+ pid: Process.pid,
11
+ timestamp: Utils::LogTimestamp.call(time.utc)
12
+ )
10
13
 
11
- def call(_severity, _time, _progname, message)
12
- if message.is_a?(Result)
13
- message = message.to_h.map do |k, v|
14
- v = ResultAnsi.call(v) if COLORED_KEYS.include?(k)
15
- "#{k}=#{v}"
16
- end.join(" ")
17
- end
18
-
19
- message << "\n"
14
+ m = m.map { |k, v| "#{k}=#{v}" }.join(" ") if m.is_a?(Hash)
15
+ m << "\n"
20
16
  end
21
17
 
22
18
  end
@@ -4,13 +4,14 @@ module CMDx
4
4
  module LogFormatters
5
5
  class PrettyLine
6
6
 
7
- def call(severity, time, progname, message)
8
- indicator = LoggerAnsi.call(severity[0])
9
- severity = LoggerAnsi.call(severity)
10
- timestamp = Utils::LogTimestamp.call(time.utc)
11
- message = PrettyKeyValue.new.call(severity, time, progname, message).chomp
7
+ def call(severity, time, task, message)
8
+ i = LoggerAnsi.call(severity[0])
9
+ s = LoggerAnsi.call(severity)
10
+ t = Utils::LogTimestamp.call(time.utc)
11
+ m = LoggerSerializer.call(severity, time, task, message, ansi_colorize: true)
12
+ m = m.map { |k, v| "#{k}=#{v}" }.join(" ") if m.is_a?(Hash)
12
13
 
13
- "#{indicator}, [#{timestamp} ##{Process.pid}] #{severity} -- #{progname || 'CMDx'}: #{message}\n"
14
+ "#{i}, [#{t} ##{Process.pid}] #{s} -- #{task.class.name}: #{m}\n"
14
15
  end
15
16
 
16
17
  end
@@ -4,7 +4,7 @@ module CMDx
4
4
  module LogFormatters
5
5
  class Raw
6
6
 
7
- def call(_severity, _time, _progname, message)
7
+ def call(_severity, _time, _task, message)
8
8
  message.inspect << "\n"
9
9
  end
10
10
 
data/lib/cmdx/logger.rb CHANGED
@@ -6,9 +6,14 @@ module CMDx
6
6
  module_function
7
7
 
8
8
  def call(task)
9
- logger = task.task_setting(:logger)
10
- logger.formatter = task.task_setting(:log_formatter) if task.task_setting?(:log_formatter)
11
- logger.level = task.task_setting(:log_level) if task.task_setting?(:log_level)
9
+ logger = task.task_setting(:logger)
10
+
11
+ unless logger.nil?
12
+ logger.formatter = task.task_setting(:log_formatter) if task.task_setting?(:log_formatter)
13
+ logger.level = task.task_setting(:log_level) if task.task_setting?(:log_level)
14
+ logger.progname = task
15
+ end
16
+
12
17
  logger
13
18
  end
14
19
 
@@ -3,19 +3,20 @@
3
3
  module CMDx
4
4
  module LoggerAnsi
5
5
 
6
- SEVERITY_COLOR_CODES = {
7
- "D" => 34, # DEBUG - Blue
8
- "I" => 32, # INFO - Green
9
- "W" => 33, # WARN - Yellow
10
- "E" => 31, # ERROR - Red
11
- "F" => 35 # FATAL - Magenta
6
+ SEVERITY_COLORS = {
7
+ "D" => :blue,
8
+ "I" => :green,
9
+ "W" => :yellow,
10
+ "E" => :red,
11
+ "F" => :magenta
12
12
  }.freeze
13
13
 
14
14
  module_function
15
15
 
16
16
  def call(s)
17
- c = SEVERITY_COLOR_CODES[s[0]] || 39 # Default
18
- "\e[1;#{c}m#{s}\e[0m"
17
+ color = SEVERITY_COLORS[s[0]] || :default
18
+
19
+ Utils::AnsiColor.call(s, color:, mode: :bold)
19
20
  end
20
21
 
21
22
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module LoggerSerializer
5
+
6
+ COLORED_KEYS = %i[
7
+ state status outcome
8
+ ].freeze
9
+
10
+ module_function
11
+
12
+ def call(_severity, _time, task, message, **options)
13
+ m = message.respond_to?(:to_h) ? message.to_h : {}
14
+
15
+ if options.delete(:ansi_colorize) && message.is_a?(Result)
16
+ COLORED_KEYS.each { |k| m[k] = ResultAnsi.call(m[k]) if m.key?(k) }
17
+ elsif !message.is_a?(Result)
18
+ m.merge!(
19
+ TaskSerializer.call(task),
20
+ message: message
21
+ )
22
+ end
23
+
24
+ m[:origin] ||= "CMDx"
25
+ m
26
+ end
27
+
28
+ end
29
+ end
data/lib/cmdx/result.rb CHANGED
@@ -28,6 +28,10 @@ module CMDx
28
28
  define_method(:"#{s}?") { state == s }
29
29
  end
30
30
 
31
+ def executed!
32
+ success? ? complete! : interrupt!
33
+ end
34
+
31
35
  def executed?
32
36
  complete? || interrupted?
33
37
  end
@@ -3,23 +3,24 @@
3
3
  module CMDx
4
4
  module ResultAnsi
5
5
 
6
- STATE_COLOR_CODES = {
7
- Result::INITIALIZED => 34, # Blue
8
- Result::EXECUTING => 33, # Yellow
9
- Result::COMPLETE => 32, # Green
10
- Result::INTERRUPTED => 31 # Red
6
+ STATE_COLORS = {
7
+ Result::INITIALIZED => :blue,
8
+ Result::EXECUTING => :yellow,
9
+ Result::COMPLETE => :green,
10
+ Result::INTERRUPTED => :red
11
11
  }.freeze
12
- STATUS_COLOR_CODES = {
13
- Result::SUCCESS => 32, # Green
14
- Result::SKIPPED => 33, # Yellow
15
- Result::FAILED => 31 # Red
12
+ STATUS_COLORS = {
13
+ Result::SUCCESS => :green,
14
+ Result::SKIPPED => :yellow,
15
+ Result::FAILED => :red
16
16
  }.freeze
17
17
 
18
18
  module_function
19
19
 
20
20
  def call(s)
21
- c = STATE_COLOR_CODES[s] || STATUS_COLOR_CODES[s] || 39 # Default
22
- "\e[1;#{c}m#{s}\e[0m"
21
+ color = STATE_COLORS[s] || STATUS_COLORS[s] || :default
22
+
23
+ Utils::AnsiColor.call(s, color:)
23
24
  end
24
25
 
25
26
  end
@@ -12,7 +12,9 @@ module CMDx
12
12
  module_function
13
13
 
14
14
  def call(result)
15
- logger = result.task.send(:logger)
15
+ logger = result.task.send(:logger)
16
+ return if logger.nil?
17
+
16
18
  severity = STATUS_TO_SEVERITY[result.status]
17
19
 
18
20
  logger.with_level(severity) do
@@ -13,20 +13,15 @@ module CMDx
13
13
  module_function
14
14
 
15
15
  def call(result)
16
- {
17
- index: result.index,
18
- run_id: result.run.id,
19
- type: result.task.is_a?(Batch) ? "Batch" : "Task",
20
- class: result.task.class.name,
21
- id: result.task.id,
22
- state: result.state,
23
- status: result.status,
24
- outcome: result.outcome,
25
- metadata: result.metadata,
26
- runtime: result.runtime,
27
- tags: result.task.task_setting(:tags),
28
- pid: Process.pid
29
- }.tap do |hash|
16
+ TaskSerializer.call(result.task).tap do |hash|
17
+ hash.merge!(
18
+ state: result.state,
19
+ status: result.status,
20
+ outcome: result.outcome,
21
+ metadata: result.metadata,
22
+ runtime: result.runtime
23
+ )
24
+
30
25
  if result.failed?
31
26
  STRIP_FAILURE.call(hash, result, :caused_failure)
32
27
  STRIP_FAILURE.call(hash, result, :threw_failure)
data/lib/cmdx/run.rb CHANGED
@@ -13,6 +13,11 @@ module CMDx
13
13
  @results = Array(attributes[:results])
14
14
  end
15
15
 
16
+ def freeze
17
+ first_result
18
+ super
19
+ end
20
+
16
21
  def to_h
17
22
  RunSerializer.call(self)
18
23
  end
@@ -3,18 +3,23 @@
3
3
  module CMDx
4
4
  module RunInspector
5
5
 
6
- ORDERED_KEYS = %i[
6
+ FOOTER_KEYS = %i[
7
7
  state status outcome runtime
8
8
  ].freeze
9
9
 
10
10
  module_function
11
11
 
12
12
  def call(run)
13
- header = "Run: #{run.id}"
14
- footer = ORDERED_KEYS.map { |key| "#{key}=#{run.send(key)}" }.join(" ")
13
+ header = "\nrun: #{run.id}"
14
+ footer = FOOTER_KEYS.map { |key| "#{key}: #{run.send(key)}" }.join(" | ")
15
15
  spacer = "=" * [header.size, footer.size].max
16
16
 
17
- run.results.map(&:to_s).unshift(header, spacer).push(spacer, footer).join("\n")
17
+ run
18
+ .results
19
+ .map { |r| r.to_h.except(:run_id).pretty_inspect }
20
+ .unshift(header, "#{spacer}\n")
21
+ .push(spacer, "#{footer}\n\n")
22
+ .join("\n")
18
23
  end
19
24
 
20
25
  end
data/lib/cmdx/task.rb CHANGED
@@ -103,7 +103,6 @@ module CMDx
103
103
  end
104
104
 
105
105
  def after_call
106
- result.send(result.success? ? :complete! : :interrupt!)
107
106
  TaskHook.call(self, :"on_#{result.status}")
108
107
  TaskHook.call(self, :"on_#{result.state}")
109
108
 
@@ -126,6 +125,7 @@ module CMDx
126
125
  rescue StandardError => e
127
126
  fail!(reason: "[#{e.class}] #{e.message}", original_exception: e)
128
127
  ensure
128
+ result.executed!
129
129
  after_call
130
130
  end
131
131
 
@@ -139,10 +139,12 @@ module CMDx
139
139
  rescue UndefinedCallError => e
140
140
  raise(e)
141
141
  rescue Fault => e
142
+ result.executed!
142
143
  raise(e) if Array(task_setting(:task_halt)).include?(e.result.status)
143
144
 
144
145
  after_call # HACK: treat as NO-OP
145
146
  else
147
+ result.executed!
146
148
  after_call # ELSE: treat as success
147
149
  end
148
150
 
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module TaskSerializer
5
+
6
+ module_function
7
+
8
+ def call(task)
9
+ {
10
+ index: task.result.index,
11
+ run_id: task.run.id,
12
+ type: task.is_a?(Batch) ? "Batch" : "Task",
13
+ class: task.class.name,
14
+ id: task.id,
15
+ tags: task.task_setting(:tags)
16
+ }
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CMDx
4
+ module Utils
5
+ module AnsiColor
6
+
7
+ COLOR_CODES = {
8
+ black: 30,
9
+ red: 31,
10
+ green: 32,
11
+ yellow: 33,
12
+ blue: 34,
13
+ magenta: 35,
14
+ cyan: 36,
15
+ white: 37,
16
+ default: 39,
17
+ light_black: 90,
18
+ light_red: 91,
19
+ light_green: 92,
20
+ light_yellow: 93,
21
+ light_blue: 94,
22
+ light_magenta: 95,
23
+ light_cyan: 96,
24
+ light_white: 97
25
+ }.freeze
26
+ MODE_CODES = {
27
+ default: 0,
28
+ bold: 1,
29
+ dim: 2,
30
+ italic: 3,
31
+ underline: 4,
32
+ blink: 5,
33
+ blink_slow: 5,
34
+ blink_fast: 6,
35
+ invert: 7,
36
+ hide: 8,
37
+ strike: 9,
38
+ double_underline: 20,
39
+ reveal: 28,
40
+ overlined: 53
41
+ }.freeze
42
+
43
+ module_function
44
+
45
+ def call(value, color:, mode: :default)
46
+ color_code = COLOR_CODES.fetch(color)
47
+ mode_code = MODE_CODES.fetch(mode)
48
+
49
+ "\e[#{mode_code};#{color_code};49m#{value}\e[0m"
50
+ end
51
+
52
+ end
53
+ end
54
+ end
data/lib/cmdx/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module CMDx
4
4
 
5
- VERSION = "0.2.0"
5
+ VERSION = "0.4.0"
6
6
 
7
7
  end
data/lib/cmdx.rb CHANGED
@@ -5,6 +5,7 @@ require "date"
5
5
  require "i18n"
6
6
  require "json"
7
7
  require "logger"
8
+ require "pp"
8
9
  require "securerandom"
9
10
  require "time"
10
11
  require "timeout"
@@ -41,6 +42,7 @@ require_relative "cmdx/validators/inclusion"
41
42
  require_relative "cmdx/validators/length"
42
43
  require_relative "cmdx/validators/numeric"
43
44
  require_relative "cmdx/validators/presence"
45
+ require_relative "cmdx/utils/ansi_color"
44
46
  require_relative "cmdx/utils/log_timestamp"
45
47
  require_relative "cmdx/utils/name_affix"
46
48
  require_relative "cmdx/utils/monotonic_runtime"
@@ -48,6 +50,7 @@ require_relative "cmdx/error"
48
50
  require_relative "cmdx/errors"
49
51
  require_relative "cmdx/fault"
50
52
  require_relative "cmdx/faults"
53
+ require_relative "cmdx/logger_serializer"
51
54
  require_relative "cmdx/logger_ansi"
52
55
  require_relative "cmdx/logger"
53
56
  require_relative "cmdx/lazy_struct"
@@ -71,6 +74,7 @@ require_relative "cmdx/result_ansi"
71
74
  require_relative "cmdx/result_logger"
72
75
  require_relative "cmdx/task"
73
76
  require_relative "cmdx/task_hook"
77
+ require_relative "cmdx/task_serializer"
74
78
  require_relative "cmdx/batch"
75
79
  require_relative "cmdx/immutator"
76
80
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cmdx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Gomez
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-03-13 00:00:00.000000000 Z
10
+ date: 2025-03-17 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: bigdecimal
@@ -225,6 +225,7 @@ files:
225
225
  - lib/cmdx/log_formatters/raw.rb
226
226
  - lib/cmdx/logger.rb
227
227
  - lib/cmdx/logger_ansi.rb
228
+ - lib/cmdx/logger_serializer.rb
228
229
  - lib/cmdx/parameter.rb
229
230
  - lib/cmdx/parameter_inspector.rb
230
231
  - lib/cmdx/parameter_serializer.rb
@@ -244,6 +245,8 @@ files:
244
245
  - lib/cmdx/run_serializer.rb
245
246
  - lib/cmdx/task.rb
246
247
  - lib/cmdx/task_hook.rb
248
+ - lib/cmdx/task_serializer.rb
249
+ - lib/cmdx/utils/ansi_color.rb
247
250
  - lib/cmdx/utils/log_timestamp.rb
248
251
  - lib/cmdx/utils/monotonic_runtime.rb
249
252
  - lib/cmdx/utils/name_affix.rb