ci(link): gate pull requests into main on fmt, clippy, and test #23

Merged
whitlocktech merged 2 commits from ci/pr-checks into main 2026-08-01 06:50:18 +00:00
Member

Follow-up to #22, which fixed the symptom. This fixes the cause.

Why

link/ has no pull_request workflow — only release.yml (push to main), sonarqube.yml (push to main), and sync-project-tree.yml. Nothing looks at code before it merges. So release.yml's first Rust gate, cargo fmt --check, doubled as this repo's de-facto lint — and when it tripped on the 3.0 cutover merge (2301c57), it took the whole release with it: no test, no build, no tag, no published binary. The failure surfaced at the worst possible moment, on main, after review had already passed.

What

.gitea/workflows/pr-checks.yml — one job, three gates, on pull_request into main:

Gate Command
Format cargo fmt --check
Lint cargo clippy --locked --all-targets -- -D warnings
Test cargo test --locked

Design decisions worth reviewing:

  • Mirrors release.yml, in the same order. Same commands, same --locked, cheapest-first. The point is that a green PR implies the release will clear its own gates — if the two drift, the guarantee is gone.
  • One job, not three parallel ones. The toolchain bootstrap dominates (~45s in release.yml); splitting fmt/clippy/test across jobs pays it three times for no wall-clock gain.
  • Clippy at -D warnings is newrelease.yml doesn't run it. Verified the crate is already clean at that bar, so it starts green and only fires on regressions. Say the word if you'd rather it be advisory and I'll drop the -D.
  • Host target only. The MinGW cross-compile deps are omitted; the Windows build stays a release-time concern. cargo test compiles everything for the host, so a PR still catches real compile breaks.
  • Cache on ~/.cargo + sidecar/target, keyed on Cargo.lock. A miss is slower, never wrong.
  • main only, per the ask. Work that lands on edge first is still caught on the edgemain PR — which is exactly the hop (#21) that would have caught this one. Adding edge to the branches: list is a one-line change if you want it earlier.

Also updates link/README.md: the layout table lists the new workflow, and the build section gives the three commands to run locally before pushing.

Verification

All three gates run locally against this branch:

cargo fmt --check                                    # clean
cargo clippy --locked --all-targets -- -D warnings   # clean
cargo test --locked                                  # ok (0 tests)

The workflow YAML parses, and the job/step graph is what's intended.

This branch was cut on top of #22 so its own run would be green; now that #22 has merged, the PR is a single commit — just the workflow and the README note.

One-time manual step after merge

CI reporting a status doesn't block anything until Gitea is told to require it: Settings → Branches → Branch Protection on main → enable Status Check → pattern PR Checks / *. Gitea only offers a context in its dropdown once it has reported, so let this run on one PR first; the glob matches without the dropdown.


AI-assisted: written with Claude Code (Claude Opus 5).

Follow-up to #22, which fixed the symptom. This fixes the cause. ## Why `link/` has no `pull_request` workflow — only `release.yml` (push to `main`), `sonarqube.yml` (push to `main`), and `sync-project-tree.yml`. Nothing looks at code *before* it merges. So `release.yml`'s first Rust gate, `cargo fmt --check`, doubled as this repo's de-facto lint — and when it tripped on the 3.0 cutover merge (`2301c57`), it took the whole release with it: no test, no build, no tag, no published binary. The failure surfaced at the worst possible moment, on `main`, after review had already passed. ## What `.gitea/workflows/pr-checks.yml` — one job, three gates, on `pull_request` into `main`: | Gate | Command | |---|---| | Format | `cargo fmt --check` | | Lint | `cargo clippy --locked --all-targets -- -D warnings` | | Test | `cargo test --locked` | Design decisions worth reviewing: - **Mirrors `release.yml`, in the same order.** Same commands, same `--locked`, cheapest-first. The point is that a green PR *implies* the release will clear its own gates — if the two drift, the guarantee is gone. - **One job, not three parallel ones.** The toolchain bootstrap dominates (~45s in `release.yml`); splitting fmt/clippy/test across jobs pays it three times for no wall-clock gain. - **Clippy at `-D warnings` is new** — `release.yml` doesn't run it. Verified the crate is already clean at that bar, so it starts green and only fires on regressions. Say the word if you'd rather it be advisory and I'll drop the `-D`. - **Host target only.** The MinGW cross-compile deps are omitted; the Windows build stays a release-time concern. `cargo test` compiles everything for the host, so a PR still catches real compile breaks. - **Cache** on `~/.cargo` + `sidecar/target`, keyed on `Cargo.lock`. A miss is slower, never wrong. - **`main` only**, per the ask. Work that lands on `edge` first is still caught on the `edge`→`main` PR — which is exactly the hop (#21) that would have caught this one. Adding `edge` to the `branches:` list is a one-line change if you want it earlier. Also updates `link/README.md`: the layout table lists the new workflow, and the build section gives the three commands to run locally before pushing. ## Verification All three gates run locally against this branch: ``` cargo fmt --check # clean cargo clippy --locked --all-targets -- -D warnings # clean cargo test --locked # ok (0 tests) ``` The workflow YAML parses, and the job/step graph is what's intended. This branch was cut on top of #22 so its own run would be green; now that #22 has merged, the PR is a single commit — just the workflow and the README note. ## One-time manual step after merge CI reporting a status doesn't block anything until Gitea is told to require it: **Settings → Branches → Branch Protection** on `main` → enable Status Check → pattern `PR Checks / *`. Gitea only offers a context in its dropdown once it has reported, so let this run on one PR first; the glob matches without the dropdown. --- AI-assisted: written with Claude Code (Claude Opus 5).
wtclaude added 1 commit 2026-08-01 06:44:53 +00:00
ci(link): gate pull requests into main on fmt, clippy, and test
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 2m47s
f4b71f58fd
This repo had no pull_request workflow at all — release.yml runs only
after merge, so its `cargo fmt --check` gate was the first thing to see
new code, and an unformatted commit killed the release job before it
could build, tag, or publish (run for 2301c57).

Add pr-checks.yml, mirroring release.yml's gates in the same order so a
green PR implies the release clears its own gates:

  cargo fmt --check
  cargo clippy --locked --all-targets -- -D warnings
  cargo test --locked

One job, not three: bootstrapping the toolchain costs more than the
checks, so parallel jobs would pay it three times for no wall-clock win.
Cargo registry and target/ are cached on Cargo.lock. The crate is
already clean at `-D warnings`, so clippy starts green.

Co-Authored-By: Claude <noreply@anthropic.com>
whitlocktech added 1 commit 2026-08-01 06:47:39 +00:00
Merge branch 'main' into ci/pr-checks
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 2m14s
5c4b77d957
whitlocktech merged commit 295defb89f into main 2026-08-01 06:50:18 +00:00
whitlocktech deleted branch ci/pr-checks 2026-08-01 06:50:19 +00:00
Sign in to join this conversation.
No description provided.