roast-ai 0.4.4 → 0.4.6
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/.github/CODEOWNERS +2 -0
- data/.github/workflows/ci.yaml +1 -0
- data/.gitignore +0 -26
- data/.rubocop.yml +13 -0
- data/.rubocop_todo.yml +21 -0
- data/CHANGELOG.md +37 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +43 -1
- data/bin/rubocop +27 -0
- data/bin/spoom +27 -0
- data/bin/srb +27 -0
- data/bin/srb-rbi +27 -0
- data/bin/tapioca +27 -0
- data/docs/INSTRUMENTATION.md +3 -3
- data/dsl/simple.rb +10 -0
- data/examples/retry/workflow.yml +23 -0
- data/lib/roast/dsl/executor.rb +26 -0
- data/lib/roast/dsl.rb +7 -0
- data/lib/roast/errors.rb +1 -0
- data/lib/roast/factories/api_provider_factory.rb +1 -0
- data/lib/roast/helpers/function_caching_interceptor.rb +3 -0
- data/lib/roast/helpers/logger.rb +6 -9
- data/lib/roast/helpers/metadata_access.rb +1 -0
- data/lib/roast/helpers/minitest_coverage_runner.rb +1 -0
- data/lib/roast/helpers/path_resolver.rb +8 -18
- data/lib/roast/helpers/prompt_loader.rb +3 -2
- data/lib/roast/helpers/timeout_handler.rb +3 -5
- data/lib/roast/initializers.rb +1 -0
- data/lib/roast/resources/api_resource.rb +4 -3
- data/lib/roast/resources/base_resource.rb +1 -0
- data/lib/roast/resources/directory_resource.rb +1 -0
- data/lib/roast/resources/file_resource.rb +1 -0
- data/lib/roast/resources/none_resource.rb +1 -0
- data/lib/roast/resources/url_resource.rb +2 -1
- data/lib/roast/resources.rb +1 -2
- data/lib/roast/services/context_threshold_checker.rb +1 -0
- data/lib/roast/services/token_counting_service.rb +1 -0
- data/lib/roast/tools/apply_diff.rb +1 -0
- data/lib/roast/tools/ask_user.rb +1 -0
- data/lib/roast/tools/bash.rb +1 -0
- data/lib/roast/tools/cmd.rb +1 -0
- data/lib/roast/tools/coding_agent.rb +1 -0
- data/lib/roast/tools/context_summarizer.rb +1 -0
- data/lib/roast/tools/grep.rb +1 -0
- data/lib/roast/tools/helpers/coding_agent_message_formatter.rb +1 -0
- data/lib/roast/tools/read_file.rb +1 -0
- data/lib/roast/tools/search_file.rb +1 -0
- data/lib/roast/tools/swarm.rb +1 -0
- data/lib/roast/tools/update_files.rb +1 -0
- data/lib/roast/tools/write_file.rb +1 -0
- data/lib/roast/tools.rb +2 -0
- data/lib/roast/value_objects/api_token.rb +1 -0
- data/lib/roast/value_objects/step_name.rb +1 -0
- data/lib/roast/value_objects/uri_base.rb +1 -0
- data/lib/roast/value_objects/workflow_path.rb +1 -0
- data/lib/roast/value_objects.rb +1 -0
- data/lib/roast/version.rb +2 -1
- data/lib/roast/workflow/agent_step.rb +1 -0
- data/lib/roast/workflow/api_configuration.rb +1 -0
- data/lib/roast/workflow/base_iteration_step.rb +1 -0
- data/lib/roast/workflow/base_step.rb +1 -0
- data/lib/roast/workflow/base_workflow.rb +1 -0
- data/lib/roast/workflow/case_executor.rb +1 -0
- data/lib/roast/workflow/case_step.rb +1 -0
- data/lib/roast/workflow/command_executor.rb +1 -0
- data/lib/roast/workflow/conditional_executor.rb +1 -0
- data/lib/roast/workflow/conditional_step.rb +1 -0
- data/lib/roast/workflow/configuration.rb +9 -0
- data/lib/roast/workflow/configuration_loader.rb +4 -1
- data/lib/roast/workflow/context_manager.rb +1 -0
- data/lib/roast/workflow/context_path_resolver.rb +1 -0
- data/lib/roast/workflow/dot_access_hash.rb +1 -0
- data/lib/roast/workflow/each_step.rb +1 -0
- data/lib/roast/workflow/error_handler.rb +39 -3
- data/lib/roast/workflow/expression_evaluator.rb +1 -0
- data/lib/roast/workflow/expression_utils.rb +1 -0
- data/lib/roast/workflow/file_state_repository.rb +2 -1
- data/lib/roast/workflow/input_executor.rb +1 -0
- data/lib/roast/workflow/input_step.rb +1 -0
- data/lib/roast/workflow/interpolator.rb +2 -1
- data/lib/roast/workflow/iteration_executor.rb +1 -0
- data/lib/roast/workflow/llm_boolean_coercer.rb +1 -0
- data/lib/roast/workflow/metadata_manager.rb +1 -0
- data/lib/roast/workflow/output_handler.rb +1 -0
- data/lib/roast/workflow/output_manager.rb +1 -0
- data/lib/roast/workflow/parallel_executor.rb +1 -0
- data/lib/roast/workflow/prompt_step.rb +1 -0
- data/lib/roast/workflow/repeat_step.rb +1 -0
- data/lib/roast/workflow/replay_handler.rb +1 -0
- data/lib/roast/workflow/resource_resolver.rb +2 -6
- data/lib/roast/workflow/session_manager.rb +1 -0
- data/lib/roast/workflow/shell_script_step.rb +1 -0
- data/lib/roast/workflow/sqlite_state_repository.rb +1 -0
- data/lib/roast/workflow/state_manager.rb +1 -0
- data/lib/roast/workflow/state_repository.rb +1 -0
- data/lib/roast/workflow/state_repository_factory.rb +4 -2
- data/lib/roast/workflow/step_completion_reporter.rb +1 -0
- data/lib/roast/workflow/step_executor_coordinator.rb +17 -6
- data/lib/roast/workflow/step_executor_factory.rb +1 -0
- data/lib/roast/workflow/step_executor_registry.rb +2 -3
- data/lib/roast/workflow/step_executor_with_reporting.rb +1 -0
- data/lib/roast/workflow/step_executors/base_step_executor.rb +1 -0
- data/lib/roast/workflow/step_executors/hash_step_executor.rb +1 -0
- data/lib/roast/workflow/step_executors/parallel_step_executor.rb +1 -0
- data/lib/roast/workflow/step_executors/string_step_executor.rb +1 -0
- data/lib/roast/workflow/step_factory.rb +1 -0
- data/lib/roast/workflow/step_finder.rb +1 -0
- data/lib/roast/workflow/step_loader.rb +1 -0
- data/lib/roast/workflow/step_name_extractor.rb +1 -0
- data/lib/roast/workflow/step_runner.rb +1 -0
- data/lib/roast/workflow/step_type_resolver.rb +1 -0
- data/lib/roast/workflow/validation_command.rb +1 -0
- data/lib/roast/workflow/validator.rb +1 -0
- data/lib/roast/workflow/validators/base_validator.rb +1 -0
- data/lib/roast/workflow/validators/dependency_validator.rb +1 -0
- data/lib/roast/workflow/validators/linting_validator.rb +1 -0
- data/lib/roast/workflow/validators/schema_validator.rb +1 -0
- data/lib/roast/workflow/validators/step_collector.rb +1 -0
- data/lib/roast/workflow/validators/validation_orchestrator.rb +1 -0
- data/lib/roast/workflow/workflow_context.rb +1 -0
- data/lib/roast/workflow/workflow_execution_context.rb +1 -0
- data/lib/roast/workflow/workflow_executor.rb +2 -1
- data/lib/roast/workflow/workflow_initializer.rb +16 -1
- data/lib/roast/workflow/workflow_runner.rb +66 -55
- data/lib/roast/workflow.rb +1 -0
- data/lib/roast/workflow_diagram_generator.rb +3 -2
- data/lib/roast.rb +23 -8
- data/sorbet/config +8 -0
- data/sorbet/rbi/dsl/.gitattributes +1 -0
- data/sorbet/rbi/dsl/active_support/callbacks.rbi +21 -0
- data/sorbet/rbi/gems/.gitattributes +1 -0
- data/sorbet/rbi/gems/activesupport@8.0.2.rbi +19107 -0
- data/sorbet/rbi/gems/addressable@2.8.7.rbi +1994 -0
- data/sorbet/rbi/gems/ast@2.4.3.rbi +585 -0
- data/sorbet/rbi/gems/base64@0.3.0.rbi +545 -0
- data/sorbet/rbi/gems/benchmark@0.4.1.rbi +619 -0
- data/sorbet/rbi/gems/bigdecimal@3.2.2.rbi +62 -0
- data/sorbet/rbi/gems/cgi@0.5.0.rbi +2961 -0
- data/sorbet/rbi/gems/claude_swarm@0.1.19.rbi +568 -0
- data/sorbet/rbi/gems/cli-kit@5.0.1.rbi +1991 -0
- data/sorbet/rbi/gems/cli-ui@2.3.0.rbi +3181 -0
- data/sorbet/rbi/gems/coderay@1.1.3.rbi +9 -0
- data/sorbet/rbi/gems/concurrent-ruby@1.3.5.rbi +11657 -0
- data/sorbet/rbi/gems/connection_pool@2.5.3.rbi +9 -0
- data/sorbet/rbi/gems/crack@1.0.0.rbi +145 -0
- data/sorbet/rbi/gems/diff-lcs@1.6.2.rbi +972 -0
- data/sorbet/rbi/gems/dotenv@3.1.8.rbi +295 -0
- data/sorbet/rbi/gems/drb@2.2.3.rbi +1661 -0
- data/sorbet/rbi/gems/dry-configurable@1.3.0.rbi +672 -0
- data/sorbet/rbi/gems/dry-core@1.1.0.rbi +1894 -0
- data/sorbet/rbi/gems/dry-inflector@1.2.0.rbi +659 -0
- data/sorbet/rbi/gems/dry-initializer@3.2.0.rbi +781 -0
- data/sorbet/rbi/gems/dry-logic@1.6.0.rbi +1127 -0
- data/sorbet/rbi/gems/dry-schema@1.14.1.rbi +3727 -0
- data/sorbet/rbi/gems/dry-types@1.8.3.rbi +3969 -0
- data/sorbet/rbi/gems/erubi@1.13.1.rbi +155 -0
- data/sorbet/rbi/gems/event_stream_parser@1.0.0.rbi +49 -0
- data/sorbet/rbi/gems/faraday-multipart@1.1.1.rbi +283 -0
- data/sorbet/rbi/gems/faraday-net_http@3.4.1.rbi +147 -0
- data/sorbet/rbi/gems/faraday-retry@2.3.2.rbi +9 -0
- data/sorbet/rbi/gems/faraday@2.13.1.rbi +2977 -0
- data/sorbet/rbi/gems/fast-mcp-annotations@1.5.3.rbi +1588 -0
- data/sorbet/rbi/gems/ffi@1.17.2.rbi +9 -0
- data/sorbet/rbi/gems/formatador@1.1.0.rbi +9 -0
- data/sorbet/rbi/gems/guard-compat@1.2.1.rbi +102 -0
- data/sorbet/rbi/gems/guard-minitest@2.4.6.rbi +402 -0
- data/sorbet/rbi/gems/guard@2.19.1.rbi +2283 -0
- data/sorbet/rbi/gems/hashdiff@1.2.0.rbi +355 -0
- data/sorbet/rbi/gems/i18n@1.14.7.rbi +2359 -0
- data/sorbet/rbi/gems/json-schema@5.1.1.rbi +1466 -0
- data/sorbet/rbi/gems/json@2.12.2.rbi +2051 -0
- data/sorbet/rbi/gems/language_server-protocol@3.17.0.5.rbi +9 -0
- data/sorbet/rbi/gems/lint_roller@1.1.0.rbi +9 -0
- data/sorbet/rbi/gems/listen@3.9.0.rbi +1206 -0
- data/sorbet/rbi/gems/logger@1.7.0.rbi +963 -0
- data/sorbet/rbi/gems/lumberjack@1.2.10.rbi +1830 -0
- data/sorbet/rbi/gems/method_source@1.1.0.rbi +9 -0
- data/sorbet/rbi/gems/mime-types-data@3.2025.0617.rbi +136 -0
- data/sorbet/rbi/gems/mime-types@3.7.0.rbi +1342 -0
- data/sorbet/rbi/gems/minitest-rg@5.3.0.rbi +160 -0
- data/sorbet/rbi/gems/minitest@5.25.5.rbi +1640 -0
- data/sorbet/rbi/gems/mocha@2.7.1.rbi +12 -0
- data/sorbet/rbi/gems/multipart-post@2.4.1.rbi +244 -0
- data/sorbet/rbi/gems/nenv@0.3.0.rbi +147 -0
- data/sorbet/rbi/gems/net-http@0.6.0.rbi +4247 -0
- data/sorbet/rbi/gems/netrc@0.11.0.rbi +159 -0
- data/sorbet/rbi/gems/notiffany@0.1.3.rbi +1079 -0
- data/sorbet/rbi/gems/open_router@0.3.3.rbi +230 -0
- data/sorbet/rbi/gems/ostruct@0.6.2.rbi +354 -0
- data/sorbet/rbi/gems/parallel@1.27.0.rbi +291 -0
- data/sorbet/rbi/gems/parser@3.3.8.0.rbi +5535 -0
- data/sorbet/rbi/gems/prism@1.4.0.rbi +41732 -0
- data/sorbet/rbi/gems/pry@0.15.2.rbi +9 -0
- data/sorbet/rbi/gems/public_suffix@6.0.2.rbi +936 -0
- data/sorbet/rbi/gems/racc@1.8.1.rbi +158 -0
- data/sorbet/rbi/gems/rack@2.2.17.rbi +5659 -0
- data/sorbet/rbi/gems/rainbow@3.1.1.rbi +9 -0
- data/sorbet/rbi/gems/raix@1.0.2.rbi +1104 -0
- data/sorbet/rbi/gems/rake@13.3.0.rbi +3036 -0
- data/sorbet/rbi/gems/rb-fsevent@0.11.2.rbi +9 -0
- data/sorbet/rbi/gems/rb-inotify@0.11.1.rbi +9 -0
- data/sorbet/rbi/gems/rbi@0.3.6.rbi +6893 -0
- data/sorbet/rbi/gems/rbs@3.9.4.rbi +6978 -0
- data/sorbet/rbi/gems/regexp_parser@2.10.0.rbi +9 -0
- data/sorbet/rbi/gems/rexml@3.4.1.rbi +5346 -0
- data/sorbet/rbi/gems/rubocop-ast@1.45.1.rbi +9 -0
- data/sorbet/rbi/gems/rubocop-shopify@2.17.1.rbi +9 -0
- data/sorbet/rbi/gems/rubocop@1.77.0.rbi +9 -0
- data/sorbet/rbi/gems/ruby-graphviz@1.2.5.rbi +1333 -0
- data/sorbet/rbi/gems/ruby-openai@8.1.0.rbi +758 -0
- data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +9 -0
- data/sorbet/rbi/gems/ruby2_keywords@0.0.5.rbi +9 -0
- data/sorbet/rbi/gems/securerandom@0.4.1.rbi +75 -0
- data/sorbet/rbi/gems/shellany@0.0.1.rbi +102 -0
- data/sorbet/rbi/gems/spoom@1.6.3.rbi +6985 -0
- data/sorbet/rbi/gems/sqlite3@2.7.0.rbi +1900 -0
- data/sorbet/rbi/gems/tapioca@0.16.11.rbi +3628 -0
- data/sorbet/rbi/gems/thor@1.4.0.rbi +4399 -0
- data/sorbet/rbi/gems/tzinfo@2.0.6.rbi +5918 -0
- data/sorbet/rbi/gems/unicode-display_width@3.1.4.rbi +9 -0
- data/sorbet/rbi/gems/unicode-emoji@4.0.4.rbi +9 -0
- data/sorbet/rbi/gems/uri@1.0.3.rbi +2349 -0
- data/sorbet/rbi/gems/vcr@6.3.1.rbi +3040 -0
- data/sorbet/rbi/gems/webmock@3.25.1.rbi +1792 -0
- data/sorbet/rbi/gems/yard-sorbet@0.9.0.rbi +435 -0
- data/sorbet/rbi/gems/yard@0.9.37.rbi +18492 -0
- data/sorbet/rbi/gems/zeitwerk@2.7.3.rbi +1429 -0
- data/sorbet/tapioca/config.yml +13 -0
- data/sorbet/tapioca/require.rb +36 -0
- metadata +114 -2
- data/lib/roast/workflow/configuration_parser.rb +0 -54
@@ -1,3 +1,4 @@
|
|
1
|
+
# typed: true
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Roast
|
@@ -59,6 +60,10 @@ module Roast
|
|
59
60
|
Thread.current[:current_step_name] = step_name if step_name
|
60
61
|
Thread.current[:workflow_metadata] = @context.workflow.metadata
|
61
62
|
|
63
|
+
unless options[:retries]
|
64
|
+
options[:retries] = @context.config_hash[step_name]&.fetch("retries", 0) || 0
|
65
|
+
end
|
66
|
+
|
62
67
|
case step_type
|
63
68
|
when StepTypeResolver::COMMAND_STEP
|
64
69
|
# Command steps should also go through interpolation
|
@@ -145,9 +150,12 @@ module Roast
|
|
145
150
|
def execute_command_step(step, options)
|
146
151
|
exit_on_error = options.fetch(:exit_on_error, true)
|
147
152
|
resource_type = @context.resource_type
|
153
|
+
step_key = options[:step_key]
|
154
|
+
display_name = step_key || step
|
155
|
+
retries = options.fetch(:retries, 0)
|
148
156
|
|
149
|
-
error_handler.with_error_handling(
|
150
|
-
$stderr.puts "Executing: #{
|
157
|
+
error_handler.with_error_handling(display_name, resource_type: resource_type, retries:) do
|
158
|
+
$stderr.puts "Executing: #{display_name} (Resource type: #{resource_type || "unknown"})"
|
151
159
|
|
152
160
|
begin
|
153
161
|
output = command_executor.execute(step, exit_on_error: exit_on_error)
|
@@ -169,7 +177,7 @@ module Roast
|
|
169
177
|
output
|
170
178
|
rescue CommandExecutor::CommandExecutionError => e
|
171
179
|
# Print user-friendly error message
|
172
|
-
$stderr.puts "\n❌ Command failed: #{
|
180
|
+
$stderr.puts "\n❌ Command failed: #{display_name}"
|
173
181
|
$stderr.puts " Exit status: #{e.exit_status}" if e.exit_status
|
174
182
|
|
175
183
|
# Show command output if available
|
@@ -257,9 +265,11 @@ module Roast
|
|
257
265
|
interpolated_step = interpolator.interpolate(step)
|
258
266
|
|
259
267
|
if StepTypeResolver.command_step?(interpolated_step)
|
260
|
-
# Command step - execute directly, preserving any passed options
|
268
|
+
# Command step - execute directly, preserving any passed options including step_key
|
261
269
|
exit_on_error = options.fetch(:exit_on_error, true)
|
262
|
-
|
270
|
+
step_key = options[:step_key]
|
271
|
+
retries = options[:retries] || 0
|
272
|
+
execute_command_step(interpolated_step, { exit_on_error:, step_key:, retries: })
|
263
273
|
else
|
264
274
|
exit_on_error = options.fetch(:exit_on_error, context.exit_on_error?(step))
|
265
275
|
execute_standard_step(interpolated_step, options.merge(exit_on_error:))
|
@@ -282,8 +292,9 @@ module Roast
|
|
282
292
|
|
283
293
|
def execute_custom_step(name, step_key: nil, **options)
|
284
294
|
resource_type = @context.workflow.respond_to?(:resource) ? @context.workflow.resource&.type : nil
|
295
|
+
retries = options[:retries] || 0
|
285
296
|
|
286
|
-
error_handler.with_error_handling(name, resource_type: resource_type) do
|
297
|
+
error_handler.with_error_handling(name, resource_type: resource_type, retries:) do
|
287
298
|
$stderr.puts "Executing: #{name} (Resource type: #{resource_type || "unknown"})"
|
288
299
|
|
289
300
|
# Use step_key for loading if provided, otherwise use name
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# typed: true
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Roast
|
@@ -54,9 +55,7 @@ module Roast
|
|
54
55
|
private
|
55
56
|
|
56
57
|
def find_executor_class(step)
|
57
|
-
|
58
|
-
executor_class = @executors[step.class]
|
59
|
-
return executor_class if executor_class
|
58
|
+
return @executors[step.class] if @executors[step.class]
|
60
59
|
|
61
60
|
# Then check custom matchers
|
62
61
|
matcher_entry = @type_matchers.find { |entry| entry[:matcher].call(step) }
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# typed: true
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Roast
|
@@ -61,7 +62,7 @@ module Roast
|
|
61
62
|
)
|
62
63
|
|
63
64
|
# Dependencies with defaults
|
64
|
-
@error_handler = error_handler || ErrorHandler.new
|
65
|
+
@error_handler = error_handler || ErrorHandler.new(workflow)
|
65
66
|
@step_loader = step_loader || StepLoader.new(workflow, config_hash, context_path, phase: phase)
|
66
67
|
@command_executor = command_executor || CommandExecutor.new(logger: @error_handler)
|
67
68
|
@interpolator = interpolator || Interpolator.new(workflow, logger: @error_handler)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# typed: false
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Roast
|
@@ -28,6 +29,9 @@ module Roast
|
|
28
29
|
# Only check if the workflow has steps that would need API access
|
29
30
|
return if @configuration.steps.empty?
|
30
31
|
|
32
|
+
# Strip whitespace from existing Raix clients
|
33
|
+
strip_tokens_from_existing_clients
|
34
|
+
|
31
35
|
# Check if Raix has been configured with the appropriate client
|
32
36
|
case @configuration.api_provider
|
33
37
|
when :openai
|
@@ -214,7 +218,7 @@ module Roast
|
|
214
218
|
|
215
219
|
def client_options
|
216
220
|
{
|
217
|
-
access_token: @configuration.api_token,
|
221
|
+
access_token: @configuration.api_token&.strip,
|
218
222
|
uri_base: @configuration.uri_base&.to_s,
|
219
223
|
}.compact
|
220
224
|
end
|
@@ -264,6 +268,17 @@ module Roast
|
|
264
268
|
end
|
265
269
|
interpolated
|
266
270
|
end
|
271
|
+
|
272
|
+
def strip_tokens_from_existing_clients
|
273
|
+
strip_token_in_client(Raix.configuration.openai_client)
|
274
|
+
strip_token_in_client(Raix.configuration.openrouter_client)
|
275
|
+
end
|
276
|
+
|
277
|
+
def strip_token_in_client(client)
|
278
|
+
return unless client.respond_to?(:access_token)
|
279
|
+
|
280
|
+
client.instance_variable_set(:@access_token, client.access_token&.strip)
|
281
|
+
end
|
267
282
|
end
|
268
283
|
end
|
269
284
|
end
|
@@ -1,83 +1,67 @@
|
|
1
|
+
# typed: true
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Roast
|
4
5
|
module Workflow
|
5
|
-
# Handles running workflows for files/targets and orchestrating execution
|
6
6
|
class WorkflowRunner
|
7
|
-
|
8
|
-
|
7
|
+
attr_reader :configuration, :options, :files
|
8
|
+
|
9
|
+
def initialize(workflow_path, files = [], options = {})
|
10
|
+
@configuration = Configuration.new(workflow_path, options)
|
9
11
|
@options = options
|
12
|
+
@files = files || []
|
10
13
|
@output_handler = OutputHandler.new
|
11
14
|
@execution_context = WorkflowExecutionContext.new
|
12
|
-
end
|
13
|
-
|
14
|
-
def run_for_files(files)
|
15
|
-
if @configuration.has_target?
|
16
|
-
$stderr.puts "WARNING: Ignoring target parameter because files were provided: #{@configuration.target}"
|
17
|
-
end
|
18
15
|
|
19
|
-
|
20
|
-
|
21
|
-
$stderr.puts "Running pre-processing steps..."
|
22
|
-
run_pre_processing
|
23
|
-
end
|
24
|
-
|
25
|
-
# Execute main workflow for each file
|
26
|
-
files.each do |file|
|
27
|
-
$stderr.puts "Running workflow for file: #{file}"
|
28
|
-
run_single_workflow(file.strip)
|
29
|
-
end
|
30
|
-
|
31
|
-
# Execute post-processing steps once after all targets
|
32
|
-
if @configuration.post_processing.any?
|
33
|
-
$stderr.puts "Running post-processing steps..."
|
34
|
-
run_post_processing
|
35
|
-
end
|
16
|
+
initializer = WorkflowInitializer.new(@configuration)
|
17
|
+
initializer.setup
|
36
18
|
end
|
37
19
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
20
|
+
def begin!
|
21
|
+
start_time = Time.now
|
22
|
+
$stderr.puts "Starting workflow..."
|
23
|
+
$stderr.puts "Workflow: #{configuration.workflow_path}"
|
24
|
+
$stderr.puts "Options: #{options}"
|
25
|
+
|
26
|
+
ActiveSupport::Notifications.instrument("roast.workflow.start", {
|
27
|
+
workflow_path: configuration.workflow_path,
|
28
|
+
options: options,
|
29
|
+
name: configuration.basename,
|
30
|
+
})
|
41
31
|
|
42
32
|
# Execute pre-processing steps once before any targets
|
43
|
-
if @configuration.pre_processing
|
33
|
+
if @configuration.pre_processing?
|
44
34
|
$stderr.puts "Running pre-processing steps..."
|
45
35
|
run_pre_processing
|
46
36
|
end
|
47
37
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
38
|
+
if files.any?
|
39
|
+
run_for_files(files)
|
40
|
+
elsif configuration.has_target?
|
41
|
+
run_for_targets
|
42
|
+
else
|
43
|
+
run_targetless
|
52
44
|
end
|
53
45
|
|
54
46
|
# Execute post-processing steps once after all targets
|
55
|
-
if @configuration.post_processing
|
47
|
+
if @configuration.post_processing?
|
56
48
|
$stderr.puts "Running post-processing steps..."
|
57
49
|
run_post_processing
|
58
50
|
end
|
51
|
+
rescue Roast::Errors::ExitEarly
|
52
|
+
$stderr.puts "Exiting workflow early."
|
53
|
+
ensure
|
54
|
+
execution_time = Time.now - start_time
|
55
|
+
|
56
|
+
ActiveSupport::Notifications.instrument("roast.workflow.complete", {
|
57
|
+
workflow_path: configuration.workflow_path,
|
58
|
+
success: !$ERROR_INFO,
|
59
|
+
execution_time: execution_time,
|
60
|
+
})
|
59
61
|
end
|
60
62
|
|
61
|
-
|
62
|
-
$stderr.puts "Running targetless workflow"
|
63
|
-
|
64
|
-
# Execute pre-processing steps
|
65
|
-
if @configuration.pre_processing.any?
|
66
|
-
$stderr.puts "Running pre-processing steps..."
|
67
|
-
run_pre_processing
|
68
|
-
end
|
69
|
-
|
70
|
-
# Execute main workflow
|
71
|
-
run_single_workflow(nil)
|
72
|
-
|
73
|
-
# Execute post-processing steps
|
74
|
-
if @configuration.post_processing.any?
|
75
|
-
$stderr.puts "Running post-processing steps..."
|
76
|
-
run_post_processing
|
77
|
-
end
|
78
|
-
end
|
63
|
+
private
|
79
64
|
|
80
|
-
# Public for backward compatibility with tests
|
81
65
|
def execute_workflow(workflow)
|
82
66
|
steps = @configuration.steps
|
83
67
|
|
@@ -98,7 +82,34 @@ module Roast
|
|
98
82
|
$stderr.puts "🔥🔥🔥 ROAST COMPLETE! 🔥🔥🔥"
|
99
83
|
end
|
100
84
|
|
101
|
-
|
85
|
+
def run_for_files(files)
|
86
|
+
if @configuration.has_target?
|
87
|
+
$stderr.puts "WARNING: Ignoring target parameter because files were provided: #{@configuration.target}"
|
88
|
+
end
|
89
|
+
|
90
|
+
# Execute main workflow for each file
|
91
|
+
files.each do |file|
|
92
|
+
$stderr.puts "Running workflow for file: #{file}"
|
93
|
+
run_single_workflow(file.strip)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def run_for_targets
|
98
|
+
# Split targets by line and clean up
|
99
|
+
target_lines = @configuration.target.lines.map(&:strip).reject(&:empty?)
|
100
|
+
|
101
|
+
# Execute main workflow for each target
|
102
|
+
target_lines.each do |file|
|
103
|
+
$stderr.puts "Running workflow for file: #{file}"
|
104
|
+
run_single_workflow(file)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def run_targetless
|
109
|
+
$stderr.puts "Running targetless workflow"
|
110
|
+
# Execute main workflow
|
111
|
+
run_single_workflow(nil)
|
112
|
+
end
|
102
113
|
|
103
114
|
def run_single_workflow(file)
|
104
115
|
# Pass pre-processing data to target workflows
|
data/lib/roast/workflow.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# typed: true
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Roast
|
@@ -74,7 +75,7 @@ module Roast
|
|
74
75
|
when Hash
|
75
76
|
process_control_flow(step)
|
76
77
|
else
|
77
|
-
::
|
78
|
+
Roast::Helpers::Logger.warn("Unexpected step type in workflow diagram: #{step.class} - #{step.inspect}")
|
78
79
|
nil
|
79
80
|
end
|
80
81
|
end
|
@@ -112,7 +113,7 @@ module Roast
|
|
112
113
|
elsif control_flow.key?("case")
|
113
114
|
process_case(control_flow)
|
114
115
|
else
|
115
|
-
::
|
116
|
+
Roast::Helpers::Logger.warn("Unexpected control flow structure in workflow diagram: #{control_flow.keys.join(", ")}")
|
116
117
|
nil
|
117
118
|
end
|
118
119
|
end
|
data/lib/roast.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# typed: true
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
4
|
# Standard library requires
|
@@ -13,6 +14,7 @@ require "pathname"
|
|
13
14
|
require "securerandom"
|
14
15
|
require "shellwords"
|
15
16
|
require "tempfile"
|
17
|
+
require "timeout"
|
16
18
|
require "uri"
|
17
19
|
require "yaml"
|
18
20
|
|
@@ -40,6 +42,7 @@ require "zeitwerk"
|
|
40
42
|
|
41
43
|
# Set up Zeitwerk autoloader
|
42
44
|
loader = Zeitwerk::Loader.for_gem
|
45
|
+
loader.inflector.inflect("dsl" => "DSL")
|
43
46
|
loader.setup
|
44
47
|
|
45
48
|
module Roast
|
@@ -54,21 +57,33 @@ module Roast
|
|
54
57
|
option :replay, type: :string, aliases: "-r", desc: "Resume workflow from a specific step. Format: step_name or session_timestamp:step_name"
|
55
58
|
option :pause, type: :string, aliases: "-p", desc: "Pause workflow after a specific step. Format: step_name"
|
56
59
|
option :file_storage, type: :boolean, aliases: "-f", desc: "Use filesystem storage for sessions instead of SQLite"
|
60
|
+
option :executor, type: :string, default: "default", desc: "Set workflow executor - experimental syntax"
|
57
61
|
|
58
62
|
def execute(*paths)
|
59
63
|
raise Thor::Error, "Workflow configuration file is required" if paths.empty?
|
60
64
|
|
61
65
|
workflow_path, *files = paths
|
62
66
|
|
63
|
-
|
64
|
-
|
67
|
+
if options[:executor] == "dsl"
|
68
|
+
puts "⚠️ WARNING: This is an experimental syntax and may break at any time. Don't depend on it."
|
69
|
+
Roast::DSL::Executor.from_file(workflow_path)
|
65
70
|
else
|
66
|
-
|
67
|
-
|
71
|
+
expanded_workflow_path = if workflow_path.include?("workflow.yml")
|
72
|
+
File.expand_path(workflow_path)
|
73
|
+
else
|
74
|
+
File.expand_path("roast/#{workflow_path}/workflow.yml")
|
75
|
+
end
|
68
76
|
|
69
|
-
|
77
|
+
raise Thor::Error, "Expected a Roast workflow configuration file, got directory: #{expanded_workflow_path}" if File.directory?(expanded_workflow_path)
|
70
78
|
|
71
|
-
|
79
|
+
Roast::Workflow::WorkflowRunner.new(expanded_workflow_path, files, options.transform_keys(&:to_sym)).begin!
|
80
|
+
end
|
81
|
+
rescue => e
|
82
|
+
if options[:verbose]
|
83
|
+
raise e
|
84
|
+
else
|
85
|
+
$stderr.puts e.message
|
86
|
+
end
|
72
87
|
end
|
73
88
|
|
74
89
|
desc "resume WORKFLOW_FILE", "Resume a paused workflow with an event"
|
@@ -106,7 +121,7 @@ module Roast
|
|
106
121
|
session_id: session_id,
|
107
122
|
)
|
108
123
|
|
109
|
-
Roast::Workflow::
|
124
|
+
Roast::Workflow::WorkflowRunner.new(expanded_workflow_path, [], resume_options).begin!
|
110
125
|
end
|
111
126
|
|
112
127
|
desc "version", "Display the current version of Roast"
|
@@ -336,7 +351,7 @@ module Roast
|
|
336
351
|
|
337
352
|
begin
|
338
353
|
# Execute the workflow generator (it will handle user input)
|
339
|
-
Roast::Workflow::
|
354
|
+
Roast::Workflow::WorkflowRunner.new(generator_path, [], {}).begin!
|
340
355
|
|
341
356
|
puts
|
342
357
|
puts("Workflow generation complete!")
|
data/sorbet/config
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
**/*.rbi linguist-generated=true
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# typed: true
|
2
|
+
|
3
|
+
# DO NOT EDIT MANUALLY
|
4
|
+
# This is an autogenerated file for dynamic methods in `ActiveSupport::Callbacks`.
|
5
|
+
# Please instead update this file by running `bin/tapioca dsl ActiveSupport::Callbacks`.
|
6
|
+
|
7
|
+
|
8
|
+
module ActiveSupport::Callbacks
|
9
|
+
include GeneratedInstanceMethods
|
10
|
+
|
11
|
+
mixes_in_class_methods GeneratedClassMethods
|
12
|
+
|
13
|
+
module GeneratedClassMethods
|
14
|
+
def __callbacks; end
|
15
|
+
def __callbacks=(value); end
|
16
|
+
end
|
17
|
+
|
18
|
+
module GeneratedInstanceMethods
|
19
|
+
def __callbacks; end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
**/*.rbi linguist-generated=true
|