cmdx 1.5.2 → 1.6.1
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 +4 -4
- data/CHANGELOG.md +14 -1
- data/LLM.md +7 -2
- data/README.md +1 -1
- data/docs/internationalization.md +4 -2
- data/docs/workflows.md +3 -0
- data/lib/cmdx/{worker.rb → executor.rb} +12 -12
- data/lib/cmdx/pipeline.rb +99 -0
- data/lib/cmdx/task.rb +1 -1
- data/lib/cmdx/version.rb +1 -1
- data/lib/cmdx/workflow.rb +10 -28
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c054b422d416bb8f3605c0c75961c2dc65fc3ba7aba3125fcd66f1107276dc8a
|
4
|
+
data.tar.gz: 05b168249fcf03d62cee5a68a98b30fb038f5da90bea4044809a6e52ee1f2ca2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe3426a7c2d2a8839583695c9682fb3499bc6e2707349a5e872b293a7100442a7f328212783e083c68f3995379fd8db0cf44b56156506b71e14abf59f3c0d3ec
|
7
|
+
data.tar.gz: d29594887e332518500b3af872f987540fc41ff8293a13252bf665b0a2669da38944875b91caab1916d004de6e7b616ef17016de55b667ad80fcff301a153dc7
|
data/CHANGELOG.md
CHANGED
@@ -6,10 +6,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
|
7
7
|
## [TODO]
|
8
8
|
|
9
|
+
## [1.6.1] - 2025-08-23
|
10
|
+
|
11
|
+
### Changes
|
12
|
+
- Log task results before freezing
|
13
|
+
- Rename `execute_tasks_sequentially` to `execute_tasks_in_sequence`
|
14
|
+
|
15
|
+
## [1.6.0] - 2025-08-22
|
16
|
+
|
17
|
+
### Changes
|
18
|
+
- Rename `Worker` class to `Executor`
|
19
|
+
- Move workflow `work` logic into `Pipeline`
|
20
|
+
- Add workflow task `:breakpoints`
|
21
|
+
|
9
22
|
## [1.5.2] - 2025-08-22
|
10
23
|
|
11
24
|
### Changes
|
12
|
-
- Rename
|
25
|
+
- Rename workflow `execution_groups` attribute to `pipeline`
|
13
26
|
|
14
27
|
## [1.5.1] - 2025-08-21
|
15
28
|
|
data/LLM.md
CHANGED
@@ -2794,8 +2794,7 @@ CMDx provides comprehensive internationalization support for all error messages,
|
|
2794
2794
|
|
2795
2795
|
## Localization
|
2796
2796
|
|
2797
|
-
|
2798
|
-
> CMDx automatically localizes all error messages based on the `I18n.locale` setting.
|
2797
|
+
CMDx automatically localizes all error messages based on the `I18n.locale` setting.
|
2799
2798
|
|
2800
2799
|
```ruby
|
2801
2800
|
class ProcessQuote < CMDx::Task
|
@@ -2812,6 +2811,9 @@ I18n.with_locale(:fr) do
|
|
2812
2811
|
end
|
2813
2812
|
```
|
2814
2813
|
|
2814
|
+
> [!TIP]
|
2815
|
+
> CMDx supports 85+ locales via the [cmdx-i18n](https://github.com/drexed/cmdx-i18n) gem.
|
2816
|
+
|
2815
2817
|
---
|
2816
2818
|
|
2817
2819
|
url: https://github.com/drexed/cmdx/blob/main/docs/deprecation.md
|
@@ -2991,6 +2993,9 @@ class OnboardingWorkflow < CMDx::Task
|
|
2991
2993
|
end
|
2992
2994
|
```
|
2993
2995
|
|
2996
|
+
> [!TIP]
|
2997
|
+
> Execute tasks in parallel via the [cmdx-parallel](https://github.com/drexed/cmdx-parallel) gem.
|
2998
|
+
|
2994
2999
|
### Group
|
2995
3000
|
|
2996
3001
|
Group related tasks for better organization and shared configuration:
|
data/README.md
CHANGED
@@ -123,11 +123,11 @@ end
|
|
123
123
|
## Ecosystem
|
124
124
|
|
125
125
|
- [cmdx-i18n](https://github.com/drexed/cmdx-i18n) - 85+ translations
|
126
|
+
- [cmdx-parallel](https://github.com/drexed/cmdx-parallel) - Parallel workflow tasks
|
126
127
|
|
127
128
|
The following gems are currently under development:
|
128
129
|
|
129
130
|
- `cmdx-testing` - RSpec and Minitest matchers
|
130
|
-
- `cmdx-parallel` - Parallel workflow task execution
|
131
131
|
|
132
132
|
## Development
|
133
133
|
|
@@ -8,8 +8,7 @@ CMDx provides comprehensive internationalization support for all error messages,
|
|
8
8
|
|
9
9
|
## Localization
|
10
10
|
|
11
|
-
|
12
|
-
> CMDx automatically localizes all error messages based on the `I18n.locale` setting.
|
11
|
+
CMDx automatically localizes all error messages based on the `I18n.locale` setting.
|
13
12
|
|
14
13
|
```ruby
|
15
14
|
class ProcessQuote < CMDx::Task
|
@@ -26,6 +25,9 @@ I18n.with_locale(:fr) do
|
|
26
25
|
end
|
27
26
|
```
|
28
27
|
|
28
|
+
> [!TIP]
|
29
|
+
> CMDx supports 85+ locales via the [cmdx-i18n](https://github.com/drexed/cmdx-i18n) gem.
|
30
|
+
|
29
31
|
---
|
30
32
|
|
31
33
|
- **Prev:** [Logging](logging.md)
|
data/docs/workflows.md
CHANGED
@@ -33,6 +33,9 @@ class OnboardingWorkflow < CMDx::Task
|
|
33
33
|
end
|
34
34
|
```
|
35
35
|
|
36
|
+
> [!TIP]
|
37
|
+
> Execute tasks in parallel via the [cmdx-parallel](https://github.com/drexed/cmdx-parallel) gem.
|
38
|
+
|
36
39
|
### Group
|
37
40
|
|
38
41
|
Group related tasks for better organization and shared configuration:
|
@@ -3,19 +3,19 @@
|
|
3
3
|
module CMDx
|
4
4
|
# Executes CMDx tasks with middleware support, error handling, and lifecycle management.
|
5
5
|
#
|
6
|
-
# The
|
6
|
+
# The Executor class is responsible for orchestrating task execution, including
|
7
7
|
# pre-execution validation, execution with middleware, post-execution callbacks,
|
8
8
|
# and proper error handling for different types of failures.
|
9
|
-
class
|
9
|
+
class Executor
|
10
10
|
|
11
11
|
attr_reader :task
|
12
12
|
|
13
13
|
# @param task [CMDx::Task] The task to execute
|
14
14
|
#
|
15
|
-
# @return [CMDx::
|
15
|
+
# @return [CMDx::Executor] A new executor instance
|
16
16
|
#
|
17
17
|
# @example
|
18
|
-
#
|
18
|
+
# executor = CMDx::Executor.new(my_task)
|
19
19
|
def initialize(task)
|
20
20
|
@task = task
|
21
21
|
end
|
@@ -30,8 +30,8 @@ module CMDx
|
|
30
30
|
# @raise [StandardError] When raise is true and execution fails
|
31
31
|
#
|
32
32
|
# @example
|
33
|
-
# CMDx::
|
34
|
-
# CMDx::
|
33
|
+
# CMDx::Executor.execute(my_task)
|
34
|
+
# CMDx::Executor.execute(my_task, raise: true)
|
35
35
|
def self.execute(task, raise: false)
|
36
36
|
instance = new(task)
|
37
37
|
raise ? instance.execute! : instance.execute
|
@@ -42,8 +42,8 @@ module CMDx
|
|
42
42
|
# @return [CMDx::Result] The execution result
|
43
43
|
#
|
44
44
|
# @example
|
45
|
-
#
|
46
|
-
# result =
|
45
|
+
# executor = CMDx::Executor.new(my_task)
|
46
|
+
# result = executor.execute
|
47
47
|
def execute
|
48
48
|
task.class.settings[:middlewares].call!(task) do
|
49
49
|
pre_execution!
|
@@ -69,8 +69,8 @@ module CMDx
|
|
69
69
|
# @raise [StandardError] When execution fails
|
70
70
|
#
|
71
71
|
# @example
|
72
|
-
#
|
73
|
-
# result =
|
72
|
+
# executor = CMDx::Executor.new(my_task)
|
73
|
+
# result = executor.execute!
|
74
74
|
def execute!
|
75
75
|
task.class.settings[:middlewares].call!(task) do
|
76
76
|
pre_execution!
|
@@ -165,13 +165,13 @@ module CMDx
|
|
165
165
|
|
166
166
|
# Finalizes execution by freezing the task and logging results.
|
167
167
|
def finalize_execution!
|
168
|
-
Freezer.immute(task)
|
169
|
-
|
170
168
|
task.logger.tap do |logger|
|
171
169
|
logger.with_level(:info) do
|
172
170
|
logger.info { task.result.to_h }
|
173
171
|
end
|
174
172
|
end
|
173
|
+
|
174
|
+
Freezer.immute(task)
|
175
175
|
end
|
176
176
|
|
177
177
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMDx
|
4
|
+
# Executes workflows by processing task groups with conditional logic and breakpoint handling.
|
5
|
+
# The Pipeline class manages the execution flow of workflow tasks, evaluating conditions
|
6
|
+
# and handling breakpoints that can interrupt execution at specific task statuses.
|
7
|
+
class Pipeline
|
8
|
+
|
9
|
+
# @return [Workflow] The workflow instance being executed
|
10
|
+
attr_reader :workflow
|
11
|
+
|
12
|
+
# @param workflow [Workflow] The workflow to execute
|
13
|
+
#
|
14
|
+
# @return [Pipeline] A new pipeline instance
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# pipeline = Pipeline.new(my_workflow)
|
18
|
+
def initialize(workflow)
|
19
|
+
@workflow = workflow
|
20
|
+
end
|
21
|
+
|
22
|
+
# Executes a workflow using a new pipeline instance.
|
23
|
+
#
|
24
|
+
# @param workflow [Workflow] The workflow to execute
|
25
|
+
#
|
26
|
+
# @return [void]
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# Pipeline.execute(my_workflow)
|
30
|
+
def self.execute(workflow)
|
31
|
+
new(workflow).execute
|
32
|
+
end
|
33
|
+
|
34
|
+
# Executes the workflow by processing all task groups in sequence.
|
35
|
+
# Each group is evaluated against its conditions, and breakpoints are checked
|
36
|
+
# after each task execution to determine if workflow should continue or halt.
|
37
|
+
#
|
38
|
+
# @return [void]
|
39
|
+
#
|
40
|
+
# @example
|
41
|
+
# pipeline = Pipeline.new(my_workflow)
|
42
|
+
# pipeline.execute
|
43
|
+
def execute
|
44
|
+
workflow.class.pipeline.each do |group|
|
45
|
+
next unless Utils::Condition.evaluate(workflow, group.options, workflow)
|
46
|
+
|
47
|
+
breakpoints = group.options[:breakpoints] ||
|
48
|
+
workflow.class.settings[:breakpoints] ||
|
49
|
+
workflow.class.settings[:workflow_breakpoints]
|
50
|
+
breakpoints = Array(breakpoints).map(&:to_s).uniq
|
51
|
+
|
52
|
+
execute_group_tasks(group, breakpoints)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
# Executes tasks within a group using the configured execution strategy.
|
59
|
+
# Override this method to implement custom execution strategies like parallel
|
60
|
+
# processing or conditional task execution.
|
61
|
+
#
|
62
|
+
# @param group [ExecutionGroup] The group of tasks to execute
|
63
|
+
# @param breakpoints [Array<String>] Breakpoint statuses that trigger workflow interruption
|
64
|
+
#
|
65
|
+
# @return [void]
|
66
|
+
#
|
67
|
+
# @example
|
68
|
+
# def execute_group_tasks(group, breakpoints)
|
69
|
+
# # Custom parallel execution strategy
|
70
|
+
# group.tasks.map { |task| Thread.new { task.execute(workflow.context) } }
|
71
|
+
# end
|
72
|
+
def execute_group_tasks(group, breakpoints)
|
73
|
+
# NOTE: Override this method to introduce alternative execution strategies
|
74
|
+
execute_tasks_in_sequence(group, breakpoints)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Executes tasks sequentially within a group, checking breakpoints after each task.
|
78
|
+
# If a task result status matches a breakpoint, the workflow is interrupted.
|
79
|
+
#
|
80
|
+
# @param group [ExecutionGroup] The group of tasks to execute
|
81
|
+
# @param breakpoints [Array<String>] Breakpoint statuses that trigger workflow interruption
|
82
|
+
#
|
83
|
+
# @return [void]
|
84
|
+
#
|
85
|
+
# @raise [HaltError] When a task result status matches a breakpoint
|
86
|
+
#
|
87
|
+
# @example
|
88
|
+
# execute_tasks_in_sequence(group, ["failed", "skipped"])
|
89
|
+
def execute_tasks_in_sequence(group, breakpoints)
|
90
|
+
group.tasks.each do |task|
|
91
|
+
task_result = task.execute(workflow.context)
|
92
|
+
next unless breakpoints.include?(task_result.status)
|
93
|
+
|
94
|
+
workflow.throw!(task_result)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
data/lib/cmdx/task.rb
CHANGED
@@ -200,7 +200,7 @@ module CMDx
|
|
200
200
|
# result = task.execute
|
201
201
|
# result = task.execute(raise: true)
|
202
202
|
def execute(raise: false)
|
203
|
-
|
203
|
+
Executor.execute(self, raise:)
|
204
204
|
end
|
205
205
|
|
206
206
|
# @raise [UndefinedMethodError] Always raised as this method must be overridden
|
data/lib/cmdx/version.rb
CHANGED
data/lib/cmdx/workflow.rb
CHANGED
@@ -87,39 +87,21 @@ module CMDx
|
|
87
87
|
base.extend(ClassMethods)
|
88
88
|
end
|
89
89
|
|
90
|
-
# Executes the workflow by processing
|
91
|
-
#
|
90
|
+
# Executes the workflow by processing all tasks in the pipeline.
|
91
|
+
# This method delegates execution to the Pipeline class which handles
|
92
|
+
# the processing of tasks with proper error handling and context management.
|
92
93
|
#
|
93
|
-
# @return [void]
|
94
|
-
#
|
95
|
-
# @raise [CMDx::Fault] If a breakpoint is encountered during execution
|
96
|
-
#
|
97
|
-
# @example
|
98
|
-
# workflow = MyWorkflow.new
|
99
|
-
# workflow.work # Executes all tasks in the workflow
|
100
94
|
# @example
|
101
|
-
# class
|
95
|
+
# class MyWorkflow
|
102
96
|
# include CMDx::Workflow
|
103
|
-
# task
|
104
|
-
# task
|
105
|
-
# task NotifyCompletionTask
|
97
|
+
# task ValidateTask
|
98
|
+
# task ProcessTask
|
106
99
|
# end
|
107
|
-
#
|
108
|
-
# workflow
|
100
|
+
#
|
101
|
+
# workflow = MyWorkflow.new
|
102
|
+
# result = workflow.work
|
109
103
|
def work
|
110
|
-
self
|
111
|
-
next unless Utils::Condition.evaluate(self, group.options, self)
|
112
|
-
|
113
|
-
breakpoints = group.options[:breakpoints] || self.class.settings[:workflow_breakpoints]
|
114
|
-
breakpoints = Array(breakpoints).map(&:to_s).uniq
|
115
|
-
|
116
|
-
group.tasks.each do |task|
|
117
|
-
task_result = task.execute(context)
|
118
|
-
next unless breakpoints.include?(task_result.status)
|
119
|
-
|
120
|
-
throw!(task_result)
|
121
|
-
end
|
122
|
-
end
|
104
|
+
Pipeline.execute(self)
|
123
105
|
end
|
124
106
|
|
125
107
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cmdx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Juan Gomez
|
@@ -235,6 +235,7 @@ files:
|
|
235
235
|
- lib/cmdx/deprecator.rb
|
236
236
|
- lib/cmdx/errors.rb
|
237
237
|
- lib/cmdx/exceptions.rb
|
238
|
+
- lib/cmdx/executor.rb
|
238
239
|
- lib/cmdx/faults.rb
|
239
240
|
- lib/cmdx/freezer.rb
|
240
241
|
- lib/cmdx/identifier.rb
|
@@ -248,6 +249,7 @@ files:
|
|
248
249
|
- lib/cmdx/middlewares/correlate.rb
|
249
250
|
- lib/cmdx/middlewares/runtime.rb
|
250
251
|
- lib/cmdx/middlewares/timeout.rb
|
252
|
+
- lib/cmdx/pipeline.rb
|
251
253
|
- lib/cmdx/railtie.rb
|
252
254
|
- lib/cmdx/result.rb
|
253
255
|
- lib/cmdx/task.rb
|
@@ -262,7 +264,6 @@ files:
|
|
262
264
|
- lib/cmdx/validators/numeric.rb
|
263
265
|
- lib/cmdx/validators/presence.rb
|
264
266
|
- lib/cmdx/version.rb
|
265
|
-
- lib/cmdx/worker.rb
|
266
267
|
- lib/cmdx/workflow.rb
|
267
268
|
- lib/generators/cmdx/install_generator.rb
|
268
269
|
- lib/generators/cmdx/task_generator.rb
|