roast-ai 0.1.0 → 0.1.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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/cla.yml +1 -1
  3. data/.gitignore +1 -0
  4. data/CHANGELOG.md +20 -0
  5. data/CLAUDE.md +3 -1
  6. data/Gemfile +0 -1
  7. data/Gemfile.lock +3 -4
  8. data/README.md +418 -4
  9. data/Rakefile +1 -6
  10. data/docs/INSTRUMENTATION.md +202 -0
  11. data/examples/api_workflow/README.md +85 -0
  12. data/examples/api_workflow/fetch_api_data/prompt.md +10 -0
  13. data/examples/api_workflow/generate_report/prompt.md +10 -0
  14. data/examples/api_workflow/prompt.md +10 -0
  15. data/examples/api_workflow/transform_data/prompt.md +10 -0
  16. data/examples/api_workflow/workflow.yml +30 -0
  17. data/examples/grading/workflow.yml +2 -2
  18. data/examples/instrumentation.rb +76 -0
  19. data/examples/rspec_to_minitest/README.md +68 -0
  20. data/examples/rspec_to_minitest/analyze_spec/prompt.md +30 -0
  21. data/examples/rspec_to_minitest/create_minitest/prompt.md +33 -0
  22. data/examples/rspec_to_minitest/run_and_improve/prompt.md +35 -0
  23. data/examples/rspec_to_minitest/workflow.md +10 -0
  24. data/examples/rspec_to_minitest/workflow.yml +40 -0
  25. data/lib/roast/helpers/function_caching_interceptor.rb +72 -8
  26. data/lib/roast/helpers/prompt_loader.rb +2 -0
  27. data/lib/roast/resources/api_resource.rb +137 -0
  28. data/lib/roast/resources/base_resource.rb +47 -0
  29. data/lib/roast/resources/directory_resource.rb +40 -0
  30. data/lib/roast/resources/file_resource.rb +33 -0
  31. data/lib/roast/resources/none_resource.rb +29 -0
  32. data/lib/roast/resources/url_resource.rb +63 -0
  33. data/lib/roast/resources.rb +100 -0
  34. data/lib/roast/tools/coding_agent.rb +69 -0
  35. data/lib/roast/tools.rb +1 -0
  36. data/lib/roast/version.rb +1 -1
  37. data/lib/roast/workflow/base_step.rb +21 -17
  38. data/lib/roast/workflow/base_workflow.rb +49 -16
  39. data/lib/roast/workflow/configuration.rb +83 -8
  40. data/lib/roast/workflow/configuration_parser.rb +171 -3
  41. data/lib/roast/workflow/file_state_repository.rb +126 -0
  42. data/lib/roast/workflow/prompt_step.rb +16 -0
  43. data/lib/roast/workflow/session_manager.rb +82 -0
  44. data/lib/roast/workflow/state_repository.rb +21 -0
  45. data/lib/roast/workflow/workflow_executor.rb +99 -9
  46. data/lib/roast/workflow.rb +4 -0
  47. data/lib/roast.rb +2 -5
  48. data/roast.gemspec +1 -1
  49. data/schema/workflow.json +12 -0
  50. metadata +31 -6
  51. data/.rspec +0 -1
@@ -0,0 +1,202 @@
1
+ # Instrumentation Hooks in Roast
2
+
3
+ Roast provides built-in instrumentation hooks using ActiveSupport::Notifications, allowing you to track workflow execution, monitor performance, and integrate with your own monitoring systems.
4
+
5
+ ## Overview
6
+
7
+ The instrumentation system emits events at key points during workflow execution:
8
+
9
+ - Workflow lifecycle (start, complete)
10
+ - Step execution (start, complete, error)
11
+ - Chat completion/AI calls (start, complete, error)
12
+ - Tool function execution
13
+
14
+ ## Configuration
15
+
16
+ To add custom instrumentation, create Ruby files in your project's `.roast/initializers/` directory. These files will be automatically loaded during workflow startup.
17
+
18
+ Example structure:
19
+ ```
20
+ your-project/
21
+ ├── .roast/
22
+ │ └── initializers/
23
+ │ ├── logging.rb
24
+ │ ├── metrics.rb
25
+ │ └── monitoring.rb
26
+ └── ...
27
+ ```
28
+
29
+ ## Available Events
30
+
31
+ ### Workflow Events
32
+
33
+ - `roast.workflow.start` - Emitted when a workflow begins
34
+ - Payload: `{ workflow_path:, options:, name: }`
35
+
36
+ - `roast.workflow.complete` - Emitted when a workflow completes
37
+ - Payload: `{ workflow_path:, success:, execution_time: }`
38
+
39
+ ### Step Events
40
+
41
+ - `roast.step.start` - Emitted when a step begins execution
42
+ - Payload: `{ step_name: }`
43
+
44
+ - `roast.step.complete` - Emitted when a step completes successfully
45
+ - Payload: `{ step_name:, success: true, execution_time:, result_size: }`
46
+
47
+ - `roast.step.error` - Emitted when a step encounters an error
48
+ - Payload: `{ step_name:, error:, message:, execution_time: }`
49
+
50
+ ### AI/Chat Completion Events
51
+
52
+ - `roast.chat_completion.start` - Emitted before an AI API call
53
+ - Payload: `{ model:, parameters: }`
54
+
55
+ - `roast.chat_completion.complete` - Emitted after successful AI API call
56
+ - Payload: `{ success: true, model:, parameters:, execution_time:, response_size: }`
57
+
58
+ - `roast.chat_completion.error` - Emitted when AI API call fails
59
+ - Payload: `{ error:, message:, model:, parameters:, execution_time: }`
60
+
61
+ ### Tool Execution Events
62
+
63
+ - `roast.tool.execute` - Emitted when a tool function is called
64
+ - Payload: `{ function_name:, params: }`
65
+
66
+ - `roast.tool.complete` - Emitted when a tool function completes
67
+ - Payload: `{ function_name:, execution_time:, cache_enabled: }`
68
+
69
+ - `roast.tool.error` - Emitted when a tool execution fails
70
+ - Payload: `{ function_name:, error:, message:, execution_time: }`
71
+
72
+ ## Example Usage
73
+
74
+ ### Basic Logging
75
+
76
+ ```ruby
77
+ # .roast/initializers/logging.rb
78
+ ActiveSupport::Notifications.subscribe(/roast\./) do |name, start, finish, id, payload|
79
+ duration = finish - start
80
+ puts "[#{name}] completed in #{duration.round(3)}s"
81
+ end
82
+ ```
83
+
84
+ ### Performance Monitoring
85
+
86
+ ```ruby
87
+ # .roast/initializers/performance.rb
88
+ ActiveSupport::Notifications.subscribe("roast.step.complete") do |name, start, finish, id, payload|
89
+ duration = finish - start
90
+ if duration > 10.0
91
+ puts "WARNING: Step '#{payload[:step_name]}' took #{duration.round(1)}s"
92
+ end
93
+ end
94
+ ```
95
+
96
+ ### Integration with External Services
97
+
98
+ ```ruby
99
+ # .roast/initializers/metrics.rb
100
+ ActiveSupport::Notifications.subscribe("roast.workflow.complete") do |name, start, finish, id, payload|
101
+ duration = finish - start
102
+
103
+ # Send to your metrics service
104
+ MyMetricsService.track_event("workflow_execution", {
105
+ workflow_path: payload[:workflow_path],
106
+ duration: duration,
107
+ success: payload[:success]
108
+ })
109
+ end
110
+ ```
111
+
112
+ ### Internal Shopify Example
113
+
114
+ For the internal Shopify version, you can use these instrumentation hooks to track metrics with Monorail:
115
+
116
+ ```ruby
117
+ # .roast/initializers/monorail.rb
118
+
119
+ # Track workflow execution
120
+ ActiveSupport::Notifications.subscribe("roast.workflow.start") do |name, start, finish, id, payload|
121
+ Roast::Support::Monorail.track_command("run", {
122
+ "workflow_path" => payload[:workflow_path],
123
+ "options" => payload[:options],
124
+ "name" => payload[:name]
125
+ })
126
+ end
127
+
128
+ ActiveSupport::Notifications.subscribe("roast.workflow.complete") do |name, start, finish, id, payload|
129
+ Roast::Support::Monorail.track_command("run_complete", {
130
+ "workflow_path" => payload[:workflow_path],
131
+ "success" => payload[:success],
132
+ "execution_time" => payload[:execution_time]
133
+ })
134
+ end
135
+
136
+ # Track AI model usage and performance
137
+ ActiveSupport::Notifications.subscribe("roast.chat_completion.complete") do |name, start, finish, id, payload|
138
+ Roast::Support::Monorail.track_command("ai_usage", {
139
+ "model" => payload[:model],
140
+ "execution_time" => payload[:execution_time],
141
+ "response_size" => payload[:response_size],
142
+ "has_json" => payload[:parameters][:json] || false,
143
+ "has_loop" => payload[:parameters][:loop] || false
144
+ })
145
+ end
146
+
147
+ # Track tool execution and caching
148
+ ActiveSupport::Notifications.subscribe("roast.tool.complete") do |name, start, finish, id, payload|
149
+ Roast::Support::Monorail.track_command("tool_usage", {
150
+ "function_name" => payload[:function_name],
151
+ "execution_time" => payload[:execution_time],
152
+ "cache_enabled" => payload[:cache_enabled]
153
+ })
154
+ end
155
+ ```
156
+
157
+ See `examples/monorail_initializer.rb` for a complete example of Monorail integration.
158
+
159
+ ## Best Practices
160
+
161
+ 1. **Keep initializers focused**: Each initializer should handle a specific concern (logging, metrics, error reporting, etc.)
162
+
163
+ 2. **Handle errors gracefully**: Wrap your subscriber code in error handling to prevent crashes:
164
+ ```ruby
165
+ ActiveSupport::Notifications.subscribe("roast.workflow.start") do |name, start, finish, id, payload|
166
+ begin
167
+ # Your instrumentation code here
168
+ rescue => e
169
+ $stderr.puts "Instrumentation error: #{e.message}"
170
+ end
171
+ end
172
+ ```
173
+
174
+ 3. **Avoid blocking operations**: Instrumentation should be fast and non-blocking. For heavy operations, consider using async processing.
175
+
176
+ 4. **Use pattern matching**: Subscribe to specific event patterns to reduce overhead:
177
+ ```ruby
178
+ # Subscribe only to workflow events
179
+ ActiveSupport::Notifications.subscribe(/roast\.workflow\./) do |name, start, finish, id, payload|
180
+ # Handle only workflow events
181
+ end
182
+ ```
183
+
184
+ 5. **Consider performance impact**: While instrumentation is valuable, too many subscribers can impact performance. Be selective about what you instrument.
185
+
186
+ ## Testing Your Instrumentation
187
+
188
+ You can test your instrumentation by creating a simple workflow and observing the events:
189
+
190
+ ```yaml
191
+ # test_instrumentation.yml
192
+ name: instrumentation_test
193
+ steps:
194
+ - test_step
195
+ ```
196
+
197
+ Then run:
198
+ ```bash
199
+ roast execute test_instrumentation.yml some_file.rb
200
+ ```
201
+
202
+ Your instrumentation should capture the workflow start, step execution, and workflow completion events.
@@ -0,0 +1,85 @@
1
+ # API Workflow Example
2
+
3
+ This example demonstrates a targetless workflow that interacts with APIs rather than operating on specific files.
4
+
5
+ ## Structure
6
+
7
+ The workflow consists of three steps that work together to create a complete API integration process:
8
+
9
+ 1. `fetch_api_data` - Simulates fetching data from a weather API and returns a structured JSON response
10
+ 2. `transform_data` - Processes the JSON data into a human-readable markdown format
11
+ 3. `generate_report` - Creates a polished report with recommendations based on the weather data
12
+
13
+ ## Running the Example
14
+
15
+ To run this example, you need to have a valid API token. The example is configured to fetch a token using a shell command:
16
+
17
+ ```yaml
18
+ # Dynamic API token using shell command
19
+ api_token: $(print-token --key)
20
+ ```
21
+
22
+ You can modify this to use your own token source, such as:
23
+
24
+ ```yaml
25
+ # Using an environment variable
26
+ api_token: $(echo $OPENAI_API_KEY)
27
+
28
+ # Or a direct value (not recommended for production)
29
+ api_token: $(echo "sk-your-actual-token")
30
+ ```
31
+
32
+ Then run the workflow:
33
+
34
+ ```bash
35
+ # Run the targetless workflow
36
+ roast execute examples/api_workflow/workflow.yml
37
+
38
+ # Save the output to a file
39
+ roast execute examples/api_workflow/workflow.yml -o weather_report.md
40
+ ```
41
+
42
+ ## How Targetless Workflows Work
43
+
44
+ Targetless workflows operate without a specific target file. This is useful for:
45
+
46
+ - API integrations
47
+ - Content generation
48
+ - Data analysis
49
+ - Report creation
50
+ - Interactive tools
51
+
52
+ Unlike file-based workflows that process each target separately, targetless workflows run once and can retrieve their own data sources (like API calls) or generate content from scratch.
53
+
54
+ ## Workflow Definition
55
+
56
+ ```yaml
57
+ name: API Integration Workflow
58
+ # Default model for all steps
59
+ model: gpt-4o-mini
60
+
61
+ tools:
62
+ - Roast::Tools::ReadFile
63
+ - Roast::Tools::Grep
64
+ - Roast::Tools::WriteFile
65
+
66
+ steps:
67
+ - fetch_api_data
68
+ - transform_data
69
+ - generate_report
70
+
71
+ # Tool configurations for API calls (no need to specify model here since it uses global model)
72
+ fetch_api_data:
73
+ print_response: true
74
+ ```
75
+
76
+ ## Creating Your Own Targetless Workflows
77
+
78
+ To create your own targetless workflow:
79
+
80
+ 1. Create a workflow YAML file without a `target` parameter
81
+ 2. Define the steps your workflow will execute
82
+ 3. Create prompt files for each step
83
+ 4. Run the workflow with `roast execute your_workflow.yml`
84
+
85
+ Your steps can use the workflow's `output` hash to pass data between them, just like in file-based workflows.
@@ -0,0 +1,10 @@
1
+ You are an assistant helping with retrieving data from an API source.
2
+
3
+ Your task is to simulate fetching data from a weather API using mock data.
4
+
5
+ 1. Imagine you are retrieving current weather conditions for various cities
6
+ 2. Create a structured JSON response that represents typical weather API data
7
+ 3. The response should include temperature, conditions, wind, and other relevant weather metrics
8
+ 4. Format the response as valid JSON that could be parsed programmatically
9
+
10
+ Return only the JSON data without any additional explanation.
@@ -0,0 +1,10 @@
1
+ You are an assistant helping to generate a final weather report.
2
+
3
+ Based on the transformed data from the previous step, create a polished report that could be sent to stakeholders.
4
+
5
+ 1. Take the transformed weather data and enhance it with recommendations and insights
6
+ 2. Add relevant suggestions based on the weather conditions (like what to wear, activities that would be appropriate, etc.)
7
+ 3. Include a "forecast overview" section that summarizes the key points
8
+ 4. Format the output as a professional-looking report with proper headings and structure
9
+
10
+ The report should be comprehensive yet concise, easy to scan, and provide actionable insights based on the weather data.
@@ -0,0 +1,10 @@
1
+ # API Integration Workflow
2
+
3
+ This workflow demonstrates how to create an API integration that:
4
+ 1. Fetches data from an external source
5
+ 2. Transforms the data into a usable format
6
+ 3. Generates a report based on the processed data
7
+
8
+ The workflow doesn't require a target file because it's designed to work with external APIs and data sources rather than processing specific files.
9
+
10
+ You'll be working through a weather data processing example. This is a simulation to demonstrate the workflow pattern - no actual API calls are made.
@@ -0,0 +1,10 @@
1
+ You are an assistant helping to transform API data.
2
+
3
+ Your task is to process weather data from a JSON format into a more readable summary.
4
+
5
+ 1. Review the weather data provided in the previous step
6
+ 2. Transform the technical JSON data into a human-readable summary
7
+ 3. Format the output as markdown with appropriate sections and highlights
8
+ 4. Focus on the most relevant information that would be useful to a typical user
9
+
10
+ Return a well-formatted markdown summary of the weather data.
@@ -0,0 +1,30 @@
1
+ # API Integration Workflow
2
+
3
+ # This workflow demonstrates how to create an API integration that:
4
+ # 1. Fetches data from an external source
5
+ # 2. Transforms the data into a usable format
6
+ # 3. Generates a report based on the processed data
7
+
8
+ # The workflow doesn't require a target file because it's designed to work with external APIs and data sources rather than processing specific files.
9
+
10
+ # You'll be working through a weather data processing example. This is a simulation to demonstrate the workflow pattern - no actual API calls are made.
11
+
12
+ name: API Integration Workflow
13
+ model: gpt-4o-mini
14
+
15
+ tools:
16
+ - Roast::Tools::ReadFile
17
+ - Roast::Tools::Grep
18
+ - Roast::Tools::WriteFile
19
+
20
+ # For demonstration purposes only - in production you would use a real token command
21
+ # api_token: $(echo "demo_token_123456")
22
+
23
+ steps:
24
+ - fetch_api_data
25
+ - transform_data
26
+ - generate_report
27
+
28
+ # Tool configurations for API calls
29
+ fetch_api_data:
30
+ print_response: true
@@ -23,7 +23,7 @@ steps:
23
23
  # set non-default attributes for steps below
24
24
  analyze_coverage:
25
25
  model: gpt-4.1-mini
26
- loop: false
26
+ auto_loop: false
27
27
  json: true
28
28
 
29
29
  generate_grades:
@@ -32,7 +32,7 @@ generate_grades:
32
32
 
33
33
  generate_recommendations:
34
34
  model: o3
35
- loop: false
35
+ auto_loop: false
36
36
  json: true
37
37
  params:
38
38
  max_completion_tokens: 5_000
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Demonstration of how to use the Roast instrumentation hooks
4
+ # This file would typically be placed in PROJECT_ROOT/.roast/initializers/
5
+ # for automatic loading during workflow execution
6
+
7
+ # Example: Log all workflow and step events
8
+ ActiveSupport::Notifications.subscribe(/roast\.workflow\./) do |name, start, finish, _id, payload|
9
+ duration = finish - start
10
+
11
+ case name
12
+ when "roast.workflow.start"
13
+ puts "\n🚀 Workflow starting: #{payload[:name]}"
14
+ puts " Path: #{payload[:workflow_path]}"
15
+ puts " Options: #{payload[:options]}"
16
+ when "roast.workflow.complete"
17
+ status = payload[:success] ? "✅ Successfully" : "❌ With errors"
18
+ puts "\n#{status} completed workflow in #{duration.round(2)} seconds"
19
+ end
20
+ end
21
+
22
+ # Example: Track step execution times
23
+ ActiveSupport::Notifications.subscribe(/roast\.step\./) do |name, start, finish, _id, payload|
24
+ duration = finish - start
25
+
26
+ case name
27
+ when "roast.step.start"
28
+ puts "\n ▶️ Step starting: #{payload[:step_name]}"
29
+ when "roast.step.complete"
30
+ puts " ✅ Step completed: #{payload[:step_name]} (#{duration.round(3)}s)"
31
+ when "roast.step.error"
32
+ puts " ❌ Step failed: #{payload[:step_name]}"
33
+ puts " Error: #{payload[:error]} - #{payload[:message]}"
34
+ end
35
+ end
36
+
37
+ # Example: Monitor AI interactions
38
+ ActiveSupport::Notifications.subscribe(/roast\.chat_completion\./) do |name, start, finish, _id, payload|
39
+ case name
40
+ when "roast.chat_completion.start"
41
+ puts "\n 🤖 AI request starting (model: #{payload[:model]})"
42
+ puts " Parameters: #{payload[:parameters].inspect}" if payload[:parameters].any?
43
+ when "roast.chat_completion.complete"
44
+ duration = finish - start
45
+ puts " 🤖 AI request completed in #{duration.round(2)}s (execution time: #{payload[:execution_time].round(2)}s)"
46
+ puts " Response size: #{payload[:response_size]} characters"
47
+ when "roast.chat_completion.error"
48
+ puts " 🤖 AI request failed: #{payload[:error]} - #{payload[:message]}"
49
+ puts " Execution time: #{payload[:execution_time].round(2)}s"
50
+ end
51
+ end
52
+
53
+ # Example: Track tool executions
54
+ ActiveSupport::Notifications.subscribe(/roast\.tool\./) do |name, _start, _finish, _id, payload|
55
+ case name
56
+ when "roast.tool.execute"
57
+ puts "\n 🔧 Executing tool: #{payload[:function_name]}"
58
+ when "roast.tool.complete"
59
+ puts " 🔧 Tool completed: #{payload[:function_name]} (#{payload[:execution_time].round(3)}s)"
60
+ puts " Cache enabled: #{payload[:cache_enabled]}"
61
+ when "roast.tool.error"
62
+ puts " 🔧 Tool failed: #{payload[:function_name]}"
63
+ puts " Error: #{payload[:error]} - #{payload[:message]}"
64
+ puts " Execution time: #{payload[:execution_time].round(3)}s"
65
+ end
66
+ end
67
+
68
+ # In a Shopify-specific initializer (e.g., .roast/initializers/monorail.rb),
69
+ # you could replace these logging examples with actual Monorail tracking:
70
+ #
71
+ # ActiveSupport::Notifications.subscribe("roast.workflow.start") do |name, start, finish, id, payload|
72
+ # Roast::Support::Monorail.track_command("run", {
73
+ # "workflow_path" => payload[:workflow_path],
74
+ # "name" => payload[:name]
75
+ # })
76
+ # end
@@ -0,0 +1,68 @@
1
+ # RSpec to Minitest Migration Workflow
2
+
3
+ This workflow demonstrates how to automate the migration of RSpec tests to their Minitest equivalents, following a structured approach to ensure proper test coverage and functionality.
4
+
5
+ ## Workflow Overview
6
+
7
+ The workflow consists of three main steps:
8
+
9
+ 1. **Analyze Spec**: Understand the purpose and structure of the RSpec test, including its dependencies and testing patterns.
10
+ 2. **Create Minitest**: Generate a new Minitest file with equivalent test coverage and assertions.
11
+ 3. **Run and Improve**: Execute the Minitest file and iteratively improve it until all tests pass.
12
+
13
+ ## Prerequisites
14
+
15
+ - Ruby environment with both RSpec and Minitest gems installed
16
+ - Access to the original codebase being tested
17
+ - Ability to run tests in the target environment
18
+
19
+ ## Usage
20
+
21
+ To use this workflow:
22
+
23
+ 1. Configure the target pattern in `workflow.yml` to match the RSpec files you want to convert (or pass in via CLI --target option):
24
+ ```yaml
25
+ target: "path/to/specs/**/*_spec.rb"
26
+ ```
27
+
28
+ 2. Run the workflow with:
29
+ ```
30
+ roast execute examples/rspec_to_minitest/workflow.yml
31
+ ```
32
+
33
+ 3. Review the generated Minitest files and ensure they're correctly placed in your test directory.
34
+
35
+ ## Implementation Details
36
+
37
+ The workflow leverages the following tools:
38
+
39
+ - Standard file operations (read/write)
40
+ - Code search capabilities to find related files
41
+ - Command execution to run tests
42
+ - CodingAgent for iterative improvements using AI-powered coding assistance
43
+
44
+ ## Required Tool: CodingAgent
45
+
46
+ This workflow introduces a new tool called `CodingAgent` which leverages Claude Code to perform code-related tasks:
47
+
48
+ 1. Running tests
49
+ 2. Analyzing errors and failures
50
+ 3. Making iterative improvements to code
51
+
52
+ The CodingAgent tool is implemented in `lib/roast/tools/coding_agent.rb`.
53
+
54
+ ## Conversion Mappings
55
+
56
+ The workflow handles these common RSpec to Minitest conversions:
57
+
58
+ | RSpec Feature | Minitest Equivalent |
59
+ |---------------|---------------------|
60
+ | `describe/context` | Test class |
61
+ | `it` blocks | `test_*` methods |
62
+ | `before/after` | `setup/teardown` methods |
63
+ | `let/let!` | Instance variables or helper methods |
64
+ | `expect(x).to eq(y)` | `assert_equal y, x` |
65
+ | `expect(x).to be_truthy` | `assert x` |
66
+ | `expect(x).to be_falsey` | `refute x` |
67
+ | `expect { ... }.to raise_error` | `assert_raises { ... }` |
68
+ | Mocks/doubles | Minitest mocking or Mocha |
@@ -0,0 +1,30 @@
1
+ In this first step, try to understand the purpose and dependencies of the spec we will be migrating.
2
+
3
+ 1. Read the provided RSpec file carefully to understand:
4
+ - The purpose of the test suite
5
+ - The subject under test (SUT)
6
+ - Test structure and organization
7
+ - Dependencies and fixtures used
8
+ - Mocks, stubs, and doubles
9
+
10
+ 2. Use your tools to search for the SUT implementation and any other important dependent files so that they will be in the context for future steps in this process.
11
+ - Dependencies include fixtures
12
+ - Note that test/fixtures already has quite a bit of fixture files present
13
+ - If any fixtures are missing, copy them over when you write the new test file later
14
+
15
+ 3. Identify RSpec-specific features being used, such as:
16
+ - describe/context blocks
17
+ - before/after hooks
18
+ - let and let! declarations
19
+ - expect(...).to syntax and matchers
20
+ - shared examples/contexts
21
+ - metadata and tags
22
+
23
+ 4. Provide a summary of your analysis, including:
24
+ - Purpose of the test suite
25
+ - Main subject under test
26
+ - Key dependencies
27
+ - Testing patterns used
28
+ - Any potentially challenging aspects for Minitest conversion
29
+
30
+ This analysis will guide the next steps of creating an equivalent Minitest implementation.
@@ -0,0 +1,33 @@
1
+ You are a Ruby testing expert assisting with migrating RSpec tests to Minitest.
2
+
3
+ In this step, you'll create a new Minitest file that replicates the functionality of the analyzed RSpec test.
4
+
5
+ ## Your tasks:
6
+
7
+ 1. Convert the RSpec test to an equivalent Minitest test, following these guidelines:
8
+ - Replace RSpec's `describe`/`context` blocks with Minitest test classes
9
+ - Convert `it` blocks to Minitest test methods (prefixed with `test_`)
10
+ - Transform `before`/`after` hooks to `setup`/`teardown` methods
11
+ - Replace `let`/`let!` declarations with instance variables or helper methods
12
+ - Convert `expect(...).to` assertions to Minitest assertions
13
+ - Replace RSpec matchers with equivalent Minitest assertions
14
+ - Handle mocks and stubs using Minitest's mocking capabilities and Mocha
15
+
16
+ 2. Follow Minitest conventions:
17
+ - Name the file with `_test.rb` suffix instead of `_spec.rb`
18
+ - Create a class that inherits from `ActiveSupport::TestCase`
19
+ - Use that class's `test "description of the test` method to declare tests kind of like RSpec does
20
+ - Use Minitest's assertion methods (`assert`, `assert_equal`, etc.)
21
+ - Implement proper setup and teardown methods as needed
22
+
23
+ 3. Pay attention to:
24
+ - Maintaining test coverage with equivalent assertions
25
+ - Preserving the original test's intent and behavior
26
+ - Handling RSpec-specific features appropriately
27
+ - Adding necessary require statements for Minitest and dependencies
28
+
29
+ 4. Write the complete Minitest file and save it to the appropriate location, replacing `_spec.rb` with `_test.rb` in the filename.
30
+
31
+ Your converted Minitest file should maintain at least the same test coverage and intent as the original RSpec test while following Minitest's conventions and patterns.
32
+
33
+ IMPORTANT: If you see opportunities to improve the test coverage in the newly written tests, you have my permission to do so. However, note that we should focus on testing behavior, not implementation. Do not test private methods, and never use Ruby tricks to make private methods public. Try to avoid mocking or stubbing anything on the SUT class.
@@ -0,0 +1,35 @@
1
+ You are a Ruby testing expert assisting with migrating RSpec tests to Minitest.
2
+
3
+ In this final step, you'll use the `cmd` and `coding_agent` tool functions to run the newly created Minitest file and iteratively improve it until all tests pass correctly.
4
+
5
+ ## Your tasks:
6
+
7
+ 1. Run the converted Minitest file to see if it passes all tests. Use the `cmd` tool function to execute the test using the following syntax:
8
+ ```ruby
9
+ ruby -Ilib:test path/to/minitest_file.rb
10
+ ```
11
+
12
+ 2. Analyze any failures or errors that occur during test execution:
13
+ - Syntax errors
14
+ - Missing dependencies
15
+ - Assertion failures
16
+ - Test setup/teardown issues
17
+ - Unexpected behavior
18
+
19
+ 3. For each issue identified, prompt the `coding_agent` tool to make necessary improvements:
20
+ - Fix syntax errors
21
+ - Correct assertion formats
22
+ - Add missing dependencies
23
+ - Adjust test setup or teardown
24
+ - Modify assertions to match expected behavior
25
+
26
+ 4. Run the test again after each set of improvements.
27
+
28
+ 5. Continue this iterative process until all tests pass successfully.
29
+
30
+ 6. Once all tests pass, provide a summary of:
31
+ - Changes made to fix issues
32
+ - Any remaining considerations or edge cases
33
+ - Confirmation of test coverage compared to original RSpec tests
34
+
35
+ Again, your goal is to ensure the Minitest version provides at least the same test coverage and reliability as the original RSpec tests, while following Minitest best practices and conventions.
@@ -0,0 +1,10 @@
1
+ You are a Ruby testing expert assisting with migrating RSpec tests to Minitest. Note that all of your responses should be in nicely formatted markdown.
2
+
3
+ Here is the spec we're going to be migrating today:
4
+
5
+ ```
6
+ # <%= file %>
7
+ <%= File.read(file) %>
8
+ ```
9
+
10
+ I have given you powerful tool functions to do this work. The coding_agent is especially powerful and you should delegate complex tasks to it whenever possible.
@@ -0,0 +1,40 @@
1
+ # RSpec to Minitest Migration Workflow
2
+
3
+ # This workflow demonstrates how to convert RSpec test files to Minitest:
4
+ # 1. Analyzes the RSpec test to understand its purpose and dependencies
5
+ # 2. Creates a new Minitest file with equivalent assertions and test structure
6
+ # 3. Runs the tests and makes improvements until they pass
7
+
8
+ name: RSpec to Minitest Migration
9
+ model: gpt-4.1
10
+
11
+ # Target expects a glob pattern matching RSpec files to be converted
12
+ # target: "**/*_spec.rb"
13
+
14
+ tools:
15
+ - Roast::Tools::ReadFile
16
+ - Roast::Tools::WriteFile
17
+ - Roast::Tools::Grep
18
+ - Roast::Tools::Cmd
19
+ - Roast::Tools::CodingAgent
20
+
21
+ steps:
22
+ - analyze_spec
23
+ - create_minitest
24
+ - run_and_improve
25
+ - rubocop: $(bundle exec rubocop -A)
26
+ - Summarize the changes made to the codebase.
27
+
28
+ # Configure the steps
29
+ analyze_spec:
30
+ print_response: false
31
+
32
+ create_minitest:
33
+ print_response: true
34
+
35
+ run_and_improve:
36
+ print_response: true
37
+
38
+ functions:
39
+ grep:
40
+ cache: true