|
| 1 | +  |
| 2 | + |
| 3 | +# Summary |
| 4 | + |
| 5 | +Unifies **5 competing PRs** (#198, #292, #379, #534, #643) into a single coherent Ruby on Rails implementation for RTK. |
| 6 | + |
| 7 | +Adds **RSpec**, **RuboCop**, **Minitest** (via rake/rails test), and **Bundler** support with 3 new Rust command modules, 1 TOML filter, shared Ruby infrastructure, and automatic discover/rewrite rules. |
| 8 | + |
| 9 | +Includes **56 unit tests** across the 3 modules and 4 inline TOML tests — all 1035 tests passing. |
| 10 | + |
| 11 | +# New Commands |
| 12 | + |
| 13 | +| Command | Supported Formats | Token Savings | Notes | |
| 14 | +| :--- | :--- | :--- | :--- | |
| 15 | +| **`rtk rspec`** | JSON, Text fallback |   | Injects `--format json` automatically. Falls back to text parsing when user specifies a custom format. | |
| 16 | +| **`rtk rubocop`** | JSON, Autocorrect |  | Injects `--format json`, groups offenses by cop name and severity. Skips JSON in autocorrect mode (`-a`, `-A`). | |
| 17 | +| **`rtk rake test`** | Text (state machine) |  | Parses Minitest output. Handles both standard and minitest-reporters formats. | |
| 18 | +| **`rtk bundle install`** | TOML filter |  | Strips `Using` lines, short-circuits to `ok bundle: complete` on success. | |
| 19 | + |
| 20 | +<details> |
| 21 | +<summary><b>Key Design Decisions</b> (click to expand)</summary> |
| 22 | + |
| 23 | +1. **JSON injection for rspec/rubocop** — Injects `--format json` unless user specified `-f`/`--format`/`-fj`/`--format=...`. Detects autocorrect mode (`-a`, `-A`) in rubocop to skip JSON. |
| 24 | +2. **Noise stripping in rspec** — Strips Spring preloader, SimpleCov coverage reports, DEPRECATION warnings, `Finished in` timing, and Capybara screenshot details (keeps only path). |
| 25 | +3. **3-tier JSON fallback in rspec** — Strip noise, parse JSON, try original, text parser, `fallback_tail()`. Logs serde error on final fallback for debugging. |
| 26 | +4. **Safe JSON fallback in rubocop** — JSON parse failure uses `fallback_tail()` instead of feeding JSON through the text parser. |
| 27 | +5. **State machine parsers** — Both rspec (text fallback) and minitest use state-machine text parsers for structured extraction. |
| 28 | +6. **TOML for bundle** — `bundle install/update` has simple output with a `match_output` short-circuit (90%+ savings on success), making it a natural fit for the TOML DSL rather than a full Rust module. |
| 29 | +7. **Defensive arithmetic** — `saturating_sub` throughout, graceful degradation on parse failure. |
| 30 | +8. **Signal-aware exit codes** — `exit_code_from_output` returns `128 + signal` on Unix per convention. |
| 31 | + |
| 32 | +</details> |
| 33 | + |
| 34 | +<details> |
| 35 | +<summary><b>Shared Infrastructure & Registry</b> (click to expand)</summary> |
| 36 | + |
| 37 | +### Shared Infrastructure (`utils.rs`) |
| 38 | +- **`ruby_exec(tool)`** — Auto-detects `bundle exec` when `Gemfile` exists in working directory. Transitive deps like `rake` (pulled in via `rails`) still go through bundler for version isolation. |
| 39 | +- **`fallback_tail(output, label, n)`** — Last-resort filter fallback showing final N lines with diagnostic logging. |
| 40 | +- **`exit_code_from_output(output, label)`** — Signal-aware exit code extraction: returns `128 + signal` on Unix per convention. |
| 41 | +- **`count_tokens(text)`** — Shared test helper for token savings assertions. |
| 42 | + |
| 43 | +### Discover Registry |
| 44 | +- Detection patterns for `rspec`, `rubocop`, `rake test`, `rails test`, `bundle install/update` (with `bundle exec` and `bin/` variants) |
| 45 | +- Rewrite prefixes cover all common invocation patterns including `bin/rspec`, `bin/rails test`, `bundle exec rake test` |
| 46 | + |
| 47 | +</details> |
| 48 | + |
| 49 | +# Hook Integration |
| 50 | + |
| 51 | +The discover registry now correctly rewrites the following commands: |
| 52 | + |
| 53 | +| Rewritten to | From input | |
| 54 | +| :--- | :--- | |
| 55 | +| `rtk rspec` | `rspec`, `bundle exec rspec`, `bin/rspec` | |
| 56 | +| `rtk rubocop` | `rubocop`, `bundle exec rubocop` | |
| 57 | +| `rtk rake test` | `rake test`, `rails test`, `bundle exec rake test`, `bundle exec rails test`, `bin/rails test` | |
| 58 | +| `rtk bundle ...` | `bundle install`, `bundle update` | |
| 59 | + |
| 60 | +# How to Test |
| 61 | + |
| 62 | +```bash |
| 63 | +# 1. Run unit tests (no Ruby required) |
| 64 | +cargo test --all |
| 65 | + |
| 66 | +# 2. Run Ruby-specific tests only |
| 67 | +cargo test rspec_cmd # 28 tests |
| 68 | +cargo test rubocop_cmd # 18 tests |
| 69 | +cargo test rake_cmd # 10 tests |
| 70 | + |
| 71 | +# 3. Build and install locally |
| 72 | +cargo install --path . |
| 73 | + |
| 74 | +# 4. Manual testing (requires Ruby/Rails project) |
| 75 | +rtk rspec spec/models/ |
| 76 | +rtk rubocop |
| 77 | +rtk rake test |
| 78 | +rtk bundle install |
| 79 | +``` |
| 80 | + |
| 81 | +# Attribution |
| 82 | + |
| 83 | +> [!NOTE] |
| 84 | +> This PR unifies 5 competing implementations. Below is what was taken from each and why. |
| 85 | +
|
| 86 | +### PR #198 (by @deril) — RSpec only |
| 87 | +- **Incorporated**: `#[serde(default)]` on `backtrace` field — reviewer-requested fix for RSpec versions that omit backtrace from JSON |
| 88 | +- **Not taken**: Simpler rspec implementation — superseded by #292/#643's more robust version with noise stripping and state-machine text parser |
| 89 | + |
| 90 | +### PR #292 (by @navidemad) — RSpec + RuboCop |
| 91 | +- **Incorporated**: **Primary source** for `rspec_cmd.rs`, `rubocop_cmd.rs`, and shared utils (`ruby_exec`, `fallback_tail`, `exit_code_from_output`, `count_tokens`) — the most mature implementations with noise-stripping regex, 3-tier JSON fallback, state-machine text parser, and signal-aware exit codes |
| 92 | +- **Not taken**: E2E smoke test script (`test-ruby.sh`) — requires Rails installed on CI |
| 93 | + |
| 94 | +### PR #379 (by @navidemad) — Bundle + Rails (TOML DSL hybrid) |
| 95 | +- **Incorporated**: The **TOML filter concept** for `bundle install/update` — simpler than a full Rust module for low-savings commands |
| 96 | +- **Not taken**: The 7 Rails TOML filters (db:migrate, generate, etc.) — lower savings (10-40%) and tightly coupled to TOML DSL internals. Also `rails_cmd.rs` routes/other routing — too complex for initial merge |
| 97 | + |
| 98 | +### PR #534 (by @cosgroveb) — RSpec with parser trait |
| 99 | +- **Incorporated**: **Improved format flag detection** — handles `-fj`, `-fjson`, `-fdocumentation`, `--format=...` patterns that the other PRs missed, plus 4 dedicated tests |
| 100 | +- **Not taken**: `parser` module trait-based architecture (adds indirection without benefit for standalone modules), tempfile `--out` approach (adds complexity and temp file cleanup), `Gemfile.lock` detection (the `Gemfile` check is simpler and covers the same cases) |
| 101 | + |
| 102 | +### PR #643 (by @Maimer) — Most Complete |
| 103 | +- **Incorporated**: `rake_cmd.rs` (**unique** to this PR — only implementation of Minitest parsing), discover rules structure (most comprehensive), `bundle-install.toml`. **Preferred as base** when approaches conflicted. |
| 104 | + |
| 105 | +### Summary |
| 106 | + |
| 107 | +| Module | Source PRs | Tests | |
| 108 | +| :--- | :--- | :--- | |
| 109 | +| `rspec_cmd.rs` | #292/#643 + #534 format detection + #198 serde fix | 28 | |
| 110 | +| `rubocop_cmd.rs` | #292/#643 | 18 | |
| 111 | +| `rake_cmd.rs` | #643 (unique) | 10 | |
| 112 | +| `bundle-install.toml` | #643 + #379 (concept) | 4 | |
| 113 | +| `utils.rs` additions | #292/#643 | — | |
| 114 | +| `discover/rules.rs` | #643 (most complete) | — | |
| 115 | + |
| 116 | +Closes #292, #379 |
| 117 | + |
| 118 | +Based on work by @deril (#198), @cosgroveb (#534), and @Maimer (#643) — thank you for your contributions. |
0 commit comments