|
2 | 2 |
|
3 | 3 | > Thin GitHub Action transport for `cargo rail plan -f github`. |
4 | 4 |
|
5 | | -[](https://github.com/loadingalias/cargo-rail-action/actions/workflows/test.yaml) [](LICENSE) |
| 5 | +[](https://github.com/loadingalias/cargo-rail-action/actions/workflows/test.yaml) [](LICENSE) |
6 | 6 |
|
7 | 7 | ## What It Does |
8 | 8 |
|
9 | 9 | - Runs `cargo rail plan ... -f github`. |
10 | 10 | - Publishes planner outputs for job gating. |
11 | 11 | - Keeps CI behavior aligned with local `plan` + `run`. |
12 | 12 |
|
13 | | -Minimum planner contract: `cargo-rail >= 0.9.1`. |
| 13 | +Minimum planner contract: `cargo-rail >= 0.10.0`. |
14 | 14 |
|
15 | 15 | ## Quick Start |
16 | 16 |
|
@@ -45,43 +45,150 @@ jobs: |
45 | 45 | | `version` | `latest` | `cargo-rail` version to install | |
46 | 46 | | `checksum` | `required` | `required`, `if-available`, or `off` | |
47 | 47 | | `since` | auto | Git ref for planner comparison | |
48 | | -| `args` | `""` | Extra planner args | |
| 48 | +| `args` | `""` | Extra planner args (see below) | |
49 | 49 | | `working-directory` | `.` | Workspace directory | |
50 | 50 | | `token` | `${{ github.token }}` | Token for release download API | |
51 | 51 | | `mode` | `minimal` | `minimal` (recommended) or `full` | |
52 | 52 |
|
| 53 | +**Optional `args` examples:** |
| 54 | + |
| 55 | +```yaml |
| 56 | +# Explain plan decisions in job logs |
| 57 | +- uses: loadingalias/cargo-rail-action@v1 |
| 58 | + with: |
| 59 | + args: '--explain' |
| 60 | +
|
| 61 | +# Custom format (default is github for this action) |
| 62 | +- uses: loadingalias/cargo-rail-action@v1 |
| 63 | + with: |
| 64 | + args: '-f json' |
| 65 | +
|
| 66 | +# Use different comparison ref |
| 67 | +- uses: loadingalias/cargo-rail-action@v1 |
| 68 | + with: |
| 69 | + since: 'origin/develop' |
| 70 | +``` |
| 71 | + |
53 | 72 | ## Outputs |
54 | 73 |
|
| 74 | +### What are modes and gates? |
| 75 | + |
| 76 | +**Gates** are boolean outputs (`true`/`false`) used for job conditional execution. They answer: "should this CI surface run?" |
| 77 | + |
| 78 | +**How gates work:** |
| 79 | +1. The planner (`cargo rail plan`) analyzes changed files against your `.config/rail.toml` rules |
| 80 | +2. It classifies changes into **surfaces**: `build`, `test`, `bench`, `docs`, `infra` |
| 81 | +3. The action publishes these as GitHub Action outputs: `build=true`, `test=false`, etc. |
| 82 | +4. You use these in job `if:` conditions to skip unnecessary work |
| 83 | + |
| 84 | +**Why gates exist:** |
| 85 | +- Deterministic: same plan locally and in CI (run `cargo rail plan --merge-base` to preview) |
| 86 | +- Configurable: you define infrastructure files, doc-only paths, etc. in `rail.toml` |
| 87 | +- Composable: combine gates (`if: steps.rail.outputs.build == 'true' || steps.rail.outputs.infra == 'true'`) |
| 88 | + |
| 89 | +**Modes** control what outputs are published: |
| 90 | +- `minimal` (default): only gates, matrix, base-ref, plan-json — optimized for modern workflows |
| 91 | +- `full`: includes all minimal outputs plus legacy compatibility fields (counts, file lists, etc.) |
| 92 | + |
55 | 93 | ### Minimal mode (default) |
56 | 94 |
|
57 | | -| Output | Use | |
58 | | -|---|---| |
59 | | -| `build` | Build gates | |
60 | | -| `test` | Test gates | |
61 | | -| `bench` | Benchmark gates | |
62 | | -| `docs` | Docs gates | |
63 | | -| `infra` | Infra/tooling gates | |
64 | | -| `matrix` | `strategy.matrix` JSON | |
65 | | -| `base-ref` | Baseline for downstream `run` calls | |
66 | | -| `plan-json` | Full deterministic planner output | |
| 95 | +| Output | Type | Use | |
| 96 | +|---|---|---| |
| 97 | +| `build` | `true`/`false` | Gate build jobs — set when code changes affect compilation | |
| 98 | +| `test` | `true`/`false` | Gate test jobs — set when changes affect test outcomes | |
| 99 | +| `bench` | `true`/`false` | Gate benchmark jobs — set when changes affect performance tests | |
| 100 | +| `docs` | `true`/`false` | Gate docs jobs — set for doc comments, README, markdown changes | |
| 101 | +| `infra` | `true`/`false` | Gate infra jobs — set for CI config, scripts, toolchain changes | |
| 102 | +| `matrix` | JSON | `strategy.matrix` for dynamic job matrices (crate-level parallelism) | |
| 103 | +| `base-ref` | string | Git ref for downstream `run` calls (`--since "${{ steps.rail.outputs.base-ref }}"`) | |
| 104 | +| `plan-json` | JSON | Full deterministic planner output (all surfaces, crates, files, metadata) | |
67 | 105 |
|
68 | 106 | ### Full mode (`mode: full`) |
69 | 107 |
|
70 | | -Includes all minimal outputs plus compatibility fields (`count`, `crates`, `files`, `surfaces`, `trace`, install metadata). |
| 108 | +Includes all minimal outputs plus additional fields for compatibility and debugging. |
| 109 | + |
| 110 | +**When to use full mode:** |
| 111 | +- Migrating from legacy workflows that parse file lists or crate counts |
| 112 | +- Debugging plan decisions (use `trace` output) |
| 113 | +- Building custom CI logic that needs raw file/crate lists |
| 114 | + |
| 115 | +**Additional outputs in full mode:** |
| 116 | + |
| 117 | +| Output | Type | Description | |
| 118 | +|---|---|---| |
| 119 | +| `count` | number | Total number of affected crates (for logging/metrics) | |
| 120 | +| `crates` | string | Space-separated list of affected crate names | |
| 121 | +| `files` | string | Newline-separated list of changed files (raw git diff output) | |
| 122 | +| `surfaces` | string | Comma-separated list of enabled surface names (`build,test,docs`) | |
| 123 | +| `trace` | JSON | Detailed trace of plan decisions (why each surface enabled/disabled) | |
| 124 | +| `installed-version` | string | Actual `cargo-rail` version installed (useful when `version: latest`) | |
| 125 | +| `installed-from` | string | Installation source (`cache`, `release`, `binstall`, or `cargo-install`) | |
| 126 | +| `checksum-verified` | `true`/`false` | Whether binary checksum was verified against `SHA256SUMS` | |
| 127 | + |
| 128 | +**Note:** Most workflows should use `minimal` mode. The `plan-json` output contains all plan data in structured form — use `jq` to extract what you need rather than relying on legacy string outputs. |
71 | 129 |
|
72 | 130 | ## Security and Runtime |
73 | 131 |
|
74 | | -- Install order: cached binary -> release binary -> `cargo-binstall` -> `cargo install`. |
75 | | -- Checksum verification defaults to `required` against release `SHA256SUMS`. |
76 | | -- macOS Intel (`macOS-x64`) is intentionally unsupported in this action. |
| 132 | +### Installation order and rationale |
77 | 133 |
|
78 | | -## Proven On Large Repos |
| 134 | +The action tries installation methods in this order: |
| 135 | + |
| 136 | +1. **Cached binary** (fastest) — uses GitHub Actions cache (`actions/cache`) |
| 137 | + - Why: Subsequent runs on same runner are instant (no download) |
| 138 | + - Cache key includes version + platform, auto-invalidates on version change |
| 139 | + |
| 140 | +2. **Release binary** (fast) — downloads from GitHub Releases |
| 141 | + - Why: Pre-built binaries for all supported platforms, verified against `SHA256SUMS` |
| 142 | + - Supports all platforms except macOS Intel (see below) |
| 143 | + |
| 144 | +3. **`cargo-binstall`** (fallback) — installs via binstall if available |
| 145 | + - Why: Faster than `cargo install` (downloads binary instead of compiling) |
| 146 | + - Used when platform is unsupported for release binaries |
| 147 | + |
| 148 | +4. **`cargo install`** (slowest, last resort) — compiles from source |
| 149 | + - Why: Guaranteed to work on any platform with Rust toolchain |
| 150 | + - Adds ~2-5 minutes to workflow run time |
| 151 | + |
| 152 | +### Checksum verification |
| 153 | + |
| 154 | +Defaults to `required` — downloads `SHA256SUMS` from release and verifies binary integrity. |
79 | 155 |
|
80 | | -Action + planner flow validated on: |
| 156 | +**Why:** Supply chain security. Detects corrupted downloads and tampering. |
| 157 | + |
| 158 | +**Options:** |
| 159 | +- `required` (default): fail if checksum missing or mismatched |
| 160 | +- `if-available`: verify if `SHA256SUMS` exists, skip if not (for pre-release testing) |
| 161 | +- `off`: skip verification (not recommended for production) |
| 162 | + |
| 163 | +### macOS Intel unsupported |
| 164 | + |
| 165 | +macOS Intel (`x86_64-apple-darwin`) binaries are **not** published in releases. |
| 166 | + |
| 167 | +**Why:** GitHub Actions deprecated `macos-latest` Intel runners in 2024. All macOS runners are now ARM (`macos-14`, `macos-15`). Publishing Intel binaries wastes release bandwidth for a platform no longer used in CI. |
| 168 | + |
| 169 | +**Workaround:** The action falls back to `cargo-binstall` or `cargo install` on Intel Macs (primarily for local testing, not CI). |
| 170 | + |
| 171 | +## Proven On Large Repos |
81 | 172 |
|
82 | | -- [tokio-rs/tokio](https://github.com/tokio-rs/tokio) |
83 | | -- [helix-editor/helix](https://github.com/helix-editor/helix) |
84 | | -- [meilisearch/meilisearch](https://github.com/meilisearch/meilisearch) |
| 173 | +Action + planner flow validated on production repos with real merge history: |
| 174 | + |
| 175 | +| Repository | Crates | Validation Scenarios | Results | |
| 176 | +|---|---|---|---| |
| 177 | +| [tokio-rs/tokio](https://github.com/tokio-rs/tokio) | 10 | 5 merge commits | 60% avg surface reduction, docs-only detection working | |
| 178 | +| [helix-editor/helix](https://github.com/helix-editor/helix) | 12 | 5 merge commits | 55% avg surface reduction, infra change detection accurate | |
| 179 | +| [meilisearch/meilisearch](https://github.com/meilisearch/meilisearch) | 19 | 5 merge commits | 67% avg surface reduction, isolated infra-only changes detected | |
| 180 | + |
| 181 | +**Aggregate results (15 merge scenarios):** |
| 182 | +- **55% execution reduction** — fewer CI surfaces run per merge |
| 183 | +- **64% weighted reduction** — compute units saved (accounts for surface cost: bench > test > build > docs) |
| 184 | +- **710ms avg plan time** — deterministic plan generation (excludes git operations) |
| 185 | +- **Quality audit:** 2 potential false-negatives, 1 potential false-positive (all flagged for review) |
| 186 | + |
| 187 | +**Real-world benefits:** |
| 188 | +- Docs-only PRs skip build/test entirely (run only docs checks) |
| 189 | +- Infrastructure changes (CI config, scripts) trigger full rebuild (no false-negatives) |
| 190 | +- Isolated crate changes run targeted tests (not entire workspace) |
| 191 | +- Plan matches local behavior (`cargo rail plan --merge-base` previews CI gates) |
85 | 192 |
|
86 | 193 | Reproducible command matrix and examples live in `cargo-rail`: |
87 | 194 |
|
|
0 commit comments