From a2437db19364ebcc0035e1e5cb8cc81d01a690f4 Mon Sep 17 00:00:00 2001 From: Vaiz <4908982+Vaiz@users.noreply.github.com> Date: Thu, 3 Sep 2026 08:29:45 +0100 Subject: [PATCH 1/6] fix(cargo-anvil): stop anvil-msrv-test from executing benchmarks `anvil-msrv-test` ran `cargo test --all-targets`. That flag expands to `--lib --bins --tests --benches --examples`, so the recipe built AND EXECUTED every bench target as part of the minimum-version check. A bench declared `harness = false` delegates its run to a separate driver binary -- criterion's, or a profiler runner such as `gungraun-runner` driving Valgrind. `anvil-msrv-test-setup` installs only `cargo-delta` and the MSRV toolchain, so that driver is never present and the group fails on a prerequisite it does not declare: --> Error in ae_basic_operations_cg: Failed to run benchmarks: No such file or directory (os error 2). Is gungraun-runner installed and gungraun-runner in your $PATH? error: recipe `anvil-msrv-test` failed with exit code 1 That failure carries no minimum-version signal. An MSRV check exists to prove the affected packages still compile and their tests still pass under the declared minimum compiler; running benchmark harnesses is not part of that, and it breaks the check for any adopter with a `harness = false` bench. Observed on microsoft/oxidizer#718 (linux and linux-arm legs). Use `--tests` instead. Chosen over the literally-equivalent `--lib --bins --tests` because `--lib` errors with "no library targets found" on a bin-only affected package under impact scoping -- the same reason `anvil-miri` already selects `--tests`, documented in `miri.just`. `--tests` selects exactly the targets carrying `test = true`: lib unit tests, bin unit tests and integration tests. A compile-only `--all-targets --no-run` pass was considered and rejected. Benches and examples are dev-only targets that no consumer compiles, so they do not constrain the crate's real MSRV, and the repository already covers "do they still build" without running them: `anvil-bench` is `cargo bench --no-run` and `anvil-examples` is `cargo build --examples`. Adding the pass would double MSRV build time on the PR critical path for a signal already owned elsewhere. This change makes `msrv-test` consistent with that existing repository-wide policy. No doctest coverage is lost: `--all-targets` suppresses doctests as well, and `anvil-doc-test` owns them. `msrv-test.just` was the only template with `cargo test --all-targets`. `clippy.just` and `udeps.just` also pass `--all-targets`, but to `cargo clippy` and `cargo udeps`, which compile without executing; both are left as they are. `anvil-llvm-cov` and the other nextest paths are untouched. The `impact.rs` contract test pinned the old argv; it now pins the new one and additionally asserts that neither `--all-targets` nor `--benches` ever reaches the MSRV invocations, so a regression fails loudly rather than silently re-enabling bench execution. Design doc, README and the mirrored lib.rs table updated to match; the three emitted-tree snapshots re-recorded and reviewed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- crates/cargo-anvil/README.md | 2 +- crates/cargo-anvil/docs/design/checks.md | 28 +++++++++++++++---- crates/cargo-anvil/src/lib.rs | 2 +- .../justfiles/anvil/checks/msrv-test.just | 25 +++++++++++++++-- crates/cargo-anvil/tests/impact.rs | 11 ++++++-- .../snapshots/snapshots__ado_backend.snap | 25 +++++++++++++++-- .../snapshots/snapshots__github_backend.snap | 25 +++++++++++++++-- .../snapshots/snapshots__local_only.snap | 25 +++++++++++++++-- 8 files changed, 125 insertions(+), 18 deletions(-) diff --git a/crates/cargo-anvil/README.md b/crates/cargo-anvil/README.md index d3eb1fb2..5e4f4b20 100644 --- a/crates/cargo-anvil/README.md +++ b/crates/cargo-anvil/README.md @@ -298,7 +298,7 @@ both locally and in cloud workflows. `pr-fast` is one job, while the pr-slowpr-testllvm-covdual feature-config; gated by cargo-coverage-gate doc-testruns both feature configs examplescompile-only - pr-msrvmsrv-testdual feature-config, all-target tests under the declared MSRV + pr-msrvmsrv-testdual feature-config; lib/bin/integration tests under the declared MSRV (benches and examples are not run) pr-runtime-analysismirilibtest, not nextest carefulself-cleans on a toolchain bump loomopt-in targets only diff --git a/crates/cargo-anvil/docs/design/checks.md b/crates/cargo-anvil/docs/design/checks.md index 7ccb2499..aebbc965 100644 --- a/crates/cargo-anvil/docs/design/checks.md +++ b/crates/cargo-anvil/docs/design/checks.md @@ -211,20 +211,36 @@ matrix overhead. #### `pr-msrv` (minimum-version tests) -When the root manifest declares an MSRV, Anvil runs `cargo test --all-targets` -for affected packages under that compiler. Cargo's all-target set covers -library and binary unit tests, integration tests, examples, and benches as test -targets. Anvil runs exactly two feature configurations: `--all-features` and +When the root manifest declares an MSRV, Anvil runs `cargo test --tests` +for affected packages under that compiler. `--tests` selects every target that +carries `test = true` -- library and binary unit tests, and integration tests. +Anvil runs exactly two feature configurations: `--all-features` and the default features. It does not add a `--no-default-features` pass; such a pass can exercise feature-negative code, but it is outside the current policy. -This is the all-target test execution at the minimum supported compiler; +This is the test execution at the minimum supported compiler; `pr-test` runs the same affected suite through coverage instrumentation on the catalog nightly. Other checks that use the selected stable compiler do not execute -this all-target suite, so an MSRV fallback does not make `pr-msrv` a duplicate. +this suite, so an MSRV fallback does not make `pr-msrv` a duplicate. A selecting toolchain file does not suppress the MSRV run, even when it selects the same compiler, because the MSRV group is the authoritative minimum-version test result. +The check deliberately does **not** use `--all-targets`. That flag expands to +`--lib --bins --tests --benches --examples`, which makes `cargo test` build *and +execute* every bench harness. A bench declared `harness = false` delegates its +run to a separate driver binary -- criterion's, or a profiler runner such as +`gungraun-runner` driving Valgrind -- and `anvil-msrv-test-setup` installs only +the MSRV toolchain, so that driver is absent and the group fails on a +prerequisite it never declares. That failure says nothing about the minimum +supported version. It also matches the repository-wide policy that benches and +examples are compiled but never run: `bench` uses `cargo bench --no-run` and +`examples` uses `cargo build --examples`, and both keep that compile coverage on +the selected stable compiler. `--tests` is preferred over the equivalent +`--lib --bins --tests` because `--lib` errors with "no library targets found" on +a bin-only affected package under impact scoping, the same reason `miri` uses it. +No doctest coverage is lost, since `--all-targets` suppresses doctests too and +`doc-test` owns them. + The group uses the same OS/architecture matrix and per-OS impact sets as `pr-test` so cfg-gated targets and dependencies are exercised under the MSRV. It runs in parallel with the other PR groups. When no root MSRV exists, diff --git a/crates/cargo-anvil/src/lib.rs b/crates/cargo-anvil/src/lib.rs index 31fd7881..1d665f5e 100644 --- a/crates/cargo-anvil/src/lib.rs +++ b/crates/cargo-anvil/src/lib.rs @@ -299,7 +299,7 @@ //! pr-slowpr-testllvm-covdual feature-config; gated by cargo-coverage-gate //! doc-testruns both feature configs //! examplescompile-only -//! pr-msrvmsrv-testdual feature-config, all-target tests under the declared MSRV +//! pr-msrvmsrv-testdual feature-config; lib/bin/integration tests under the declared MSRV (benches and examples are not run) //! pr-runtime-analysismirilibtest, not nextest //! carefulself-cleans on a toolchain bump //! loomopt-in targets only diff --git a/crates/cargo-anvil/templates/justfiles/anvil/checks/msrv-test.just b/crates/cargo-anvil/templates/justfiles/anvil/checks/msrv-test.just index f95b38cf..915cc742 100644 --- a/crates/cargo-anvil/templates/justfiles/anvil/checks/msrv-test.just +++ b/crates/cargo-anvil/templates/justfiles/anvil/checks/msrv-test.just @@ -23,9 +23,30 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact exit 0 } $pkg = @(if ($include) { -split $include } else { '--workspace' }) - & cargo "+$toolchain" test @pkg --all-targets --all-features --locked + # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected + # packages still COMPILE and their tests still PASS under the declared + # minimum compiler. `--all-targets` expands to + # `--lib --bins --tests --benches --examples`, so `cargo test` would also + # build and EXECUTE every bench harness. A bench declared `harness = false` + # delegates its run to a separate driver binary (criterion's, or a profiler + # runner such as `gungraun-runner`, itself usually driving Valgrind). The + # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that + # driver is absent and the check fails on a prerequisite this group never + # declares -- a failure unrelated to the minimum-version signal. Benches and + # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`) + # and `anvil-examples` (`cargo build --examples`); this recipe keeps that + # same repository-wide policy. + # + # `--tests` selects exactly the targets that carry `test = true`: lib unit + # tests, bin unit tests, and integration tests. It is used in preference to + # `--lib --bins --tests` because `--lib` errors with "no library targets + # found" on a bin-only affected package under impact scoping, whereas + # `--tests` already covers lib unit tests and tolerates libless packages. + # No doctest coverage is lost: `--all-targets` suppresses doctests as well, + # and `anvil-doc-test` owns them. + & cargo "+$toolchain" test @pkg --tests --all-features --locked if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - & cargo "+$toolchain" test @pkg --all-targets --locked + & cargo "+$toolchain" test @pkg --tests --locked if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Install the declared MSRV toolchain only when this check is required. diff --git a/crates/cargo-anvil/tests/impact.rs b/crates/cargo-anvil/tests/impact.rs index bb7649b0..9afcae29 100644 --- a/crates/cargo-anvil/tests/impact.rs +++ b/crates/cargo-anvil/tests/impact.rs @@ -1036,11 +1036,18 @@ fn msrv_test_uses_affected_packages_for_both_feature_modes_and_skips_without_msr assert!(output.status.success(), "anvil-msrv-test failed:\n{combined}"); let argv = fs::read_to_string(&log).unwrap(); for expected in [ - format!("+1.97 test {affected} --all-targets --all-features --locked"), - format!("+1.97 test {affected} --all-targets --locked"), + format!("+1.97 test {affected} --tests --all-features --locked"), + format!("+1.97 test {affected} --tests --locked"), ] { assert!(argv.contains(&expected), "missing MSRV invocation '{expected}' in:\n{argv}"); } + // The MSRV check must not build or execute bench targets: `--all-targets` + // expands to include `--benches`, and a `harness = false` bench then runs + // through a driver binary the msrv setup chain never installs. + assert!( + !argv.contains("--all-targets") && !argv.contains("--benches"), + "MSRV invocations must not select bench targets; captured argv:\n{argv}" + ); let manifest = fs::read_to_string(root.join("Cargo.toml")).unwrap(); fs::write( diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap b/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap index bbcffad6..1d74fd1b 100644 --- a/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap +++ b/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap @@ -2790,9 +2790,30 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact exit 0 } $pkg = @(if ($include) { -split $include } else { '--workspace' }) - & cargo "+$toolchain" test @pkg --all-targets --all-features --locked + # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected + # packages still COMPILE and their tests still PASS under the declared + # minimum compiler. `--all-targets` expands to + # `--lib --bins --tests --benches --examples`, so `cargo test` would also + # build and EXECUTE every bench harness. A bench declared `harness = false` + # delegates its run to a separate driver binary (criterion's, or a profiler + # runner such as `gungraun-runner`, itself usually driving Valgrind). The + # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that + # driver is absent and the check fails on a prerequisite this group never + # declares -- a failure unrelated to the minimum-version signal. Benches and + # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`) + # and `anvil-examples` (`cargo build --examples`); this recipe keeps that + # same repository-wide policy. + # + # `--tests` selects exactly the targets that carry `test = true`: lib unit + # tests, bin unit tests, and integration tests. It is used in preference to + # `--lib --bins --tests` because `--lib` errors with "no library targets + # found" on a bin-only affected package under impact scoping, whereas + # `--tests` already covers lib unit tests and tolerates libless packages. + # No doctest coverage is lost: `--all-targets` suppresses doctests as well, + # and `anvil-doc-test` owns them. + & cargo "+$toolchain" test @pkg --tests --all-features --locked if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - & cargo "+$toolchain" test @pkg --all-targets --locked + & cargo "+$toolchain" test @pkg --tests --locked if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Install the declared MSRV toolchain only when this check is required. diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap b/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap index 3a91bee1..b2f359f4 100644 --- a/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap +++ b/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap @@ -2927,9 +2927,30 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact exit 0 } $pkg = @(if ($include) { -split $include } else { '--workspace' }) - & cargo "+$toolchain" test @pkg --all-targets --all-features --locked + # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected + # packages still COMPILE and their tests still PASS under the declared + # minimum compiler. `--all-targets` expands to + # `--lib --bins --tests --benches --examples`, so `cargo test` would also + # build and EXECUTE every bench harness. A bench declared `harness = false` + # delegates its run to a separate driver binary (criterion's, or a profiler + # runner such as `gungraun-runner`, itself usually driving Valgrind). The + # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that + # driver is absent and the check fails on a prerequisite this group never + # declares -- a failure unrelated to the minimum-version signal. Benches and + # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`) + # and `anvil-examples` (`cargo build --examples`); this recipe keeps that + # same repository-wide policy. + # + # `--tests` selects exactly the targets that carry `test = true`: lib unit + # tests, bin unit tests, and integration tests. It is used in preference to + # `--lib --bins --tests` because `--lib` errors with "no library targets + # found" on a bin-only affected package under impact scoping, whereas + # `--tests` already covers lib unit tests and tolerates libless packages. + # No doctest coverage is lost: `--all-targets` suppresses doctests as well, + # and `anvil-doc-test` owns them. + & cargo "+$toolchain" test @pkg --tests --all-features --locked if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - & cargo "+$toolchain" test @pkg --all-targets --locked + & cargo "+$toolchain" test @pkg --tests --locked if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Install the declared MSRV toolchain only when this check is required. diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap b/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap index 9855809a..fb61a923 100644 --- a/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap +++ b/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap @@ -1660,9 +1660,30 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact exit 0 } $pkg = @(if ($include) { -split $include } else { '--workspace' }) - & cargo "+$toolchain" test @pkg --all-targets --all-features --locked + # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected + # packages still COMPILE and their tests still PASS under the declared + # minimum compiler. `--all-targets` expands to + # `--lib --bins --tests --benches --examples`, so `cargo test` would also + # build and EXECUTE every bench harness. A bench declared `harness = false` + # delegates its run to a separate driver binary (criterion's, or a profiler + # runner such as `gungraun-runner`, itself usually driving Valgrind). The + # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that + # driver is absent and the check fails on a prerequisite this group never + # declares -- a failure unrelated to the minimum-version signal. Benches and + # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`) + # and `anvil-examples` (`cargo build --examples`); this recipe keeps that + # same repository-wide policy. + # + # `--tests` selects exactly the targets that carry `test = true`: lib unit + # tests, bin unit tests, and integration tests. It is used in preference to + # `--lib --bins --tests` because `--lib` errors with "no library targets + # found" on a bin-only affected package under impact scoping, whereas + # `--tests` already covers lib unit tests and tolerates libless packages. + # No doctest coverage is lost: `--all-targets` suppresses doctests as well, + # and `anvil-doc-test` owns them. + & cargo "+$toolchain" test @pkg --tests --all-features --locked if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - & cargo "+$toolchain" test @pkg --all-targets --locked + & cargo "+$toolchain" test @pkg --tests --locked if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Install the declared MSRV toolchain only when this check is required. From 7897ecf20d0c15aa507e88911d877384a0a5c6d2 Mon Sep 17 00:00:00 2001 From: Vaiz <4908982+Vaiz@users.noreply.github.com> Date: Thu, 3 Sep 2026 08:30:51 +0100 Subject: [PATCH 2/6] docs(cargo-anvil): name the mechanism in the action tag-pin comments The generated workflows carried this comment at every tag-pinned action: uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved The claim is true for these specific pins -- GitHub's immutable-releases feature does lock the tag to a commit, and the REST API reports `"immutable": true` for each of them. But the sentence asserts a property of the TAG, and read on its own it looks like a general claim that Git tags are stable, which is false and is exactly the belief SHA-pinning exists to defend against. Read that way it is also self-undermining: if tags could not be moved, the SHA pins on `actions/checkout` and `actions/download-artifact` in the same file would be pointless. On microsoft/oxidizer#718 this produced four separate automated-reviewer findings that a human had to rebut one at a time. Reword to name the mechanism the pin depends on instead: # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) Same length class, one line, and it no longer generalises: it says why THIS pin is safe rather than what tags are. Applied to all five sites -- `cargo-bins/cargo-binstall` in setup-action.yml, `codecov/codecov-action` in both pr- and scheduled-impl-workflow.yml, and both `marocchino/sticky-pull-request-comment` uses in pr-impl-workflow.yml. `docs/design/github.md` reproduces both the comment and a sample step, so both copies are updated to keep the doc and the templates from drifting, plus a sentence recording why the comment names a mechanism rather than asserting tag stability. The "Action pinning" section already explained that immutability is per-release and must be re-confirmed on a version bump; added one sentence stating that `actions/checkout` and `actions/download-artifact` stay SHA-pinned because immutable releases are opt-in per publisher and theirs have not enabled it -- not because those actions are less trusted. Behaviour is unchanged: comments only, same action versions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- crates/cargo-anvil/docs/design/github.md | 12 +++++++++--- .../templates/github/pr-impl-workflow.yml | 6 +++--- .../templates/github/scheduled-impl-workflow.yml | 2 +- crates/cargo-anvil/templates/github/setup-action.yml | 2 +- .../tests/snapshots/snapshots__github_backend.snap | 10 +++++----- 5 files changed, 19 insertions(+), 13 deletions(-) diff --git a/crates/cargo-anvil/docs/design/github.md b/crates/cargo-anvil/docs/design/github.md index 83f16ec9..c1ebd151 100644 --- a/crates/cargo-anvil/docs/design/github.md +++ b/crates/cargo-anvil/docs/design/github.md @@ -990,11 +990,17 @@ the repository is deleted and recreated, and publishing generates a release attestation covering the tag, commit SHA and assets. The tag is a stable identifier under those rules, and unlike a SHA it stays readable in the diff when the pin is bumped. Generated files carry a -`# immutable release, the tag cannot be moved` comment at each such pin, so the reason -a tag appears where a SHA is otherwise expected is visible at the use site. +`# pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)` +comment at each such pin, so the reason a tag appears where a SHA is otherwise +expected is visible at the use site. The comment names the mechanism the pin relies +on rather than asserting that tags are stable in general -- they are not, and a +reader who takes it that way will draw the wrong conclusion about the other pins. Every other action is pinned by commit SHA with the version in a trailing comment, for example `actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1`. +`actions/checkout` and `actions/download-artifact` are in this group not because they +are less trusted but because immutable releases are opt-in per publisher and theirs +have not enabled it, so a SHA is the only pin that fixes the code being run. Immutability is a property of one published release, not a standing guarantee about the publisher. When bumping a tag-pinned action, confirm the new release still reports @@ -1031,7 +1037,7 @@ The upload step: ```yaml - name: Upload coverage to Codecov if: always() && matrix.os != 'windows-arm' && hashFiles('target/coverage/lcov-all-features.info') != '' && hashFiles('target/coverage/lcov-no-default.info') != '' - uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved + uses: codecov/codecov-action@v7.0.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: files: target/coverage/lcov-all-features.info,target/coverage/lcov-no-default.info flags: ${{ matrix.os }} diff --git a/crates/cargo-anvil/templates/github/pr-impl-workflow.yml b/crates/cargo-anvil/templates/github/pr-impl-workflow.yml index d7738e37..3827022c 100644 --- a/crates/cargo-anvil/templates/github/pr-impl-workflow.yml +++ b/crates/cargo-anvil/templates/github/pr-impl-workflow.yml @@ -154,13 +154,13 @@ jobs: # write tokens). - name: Upsert anvil-semver advisory if: always() && github.event_name == 'pull_request' && matrix.os == 'linux' && github.event.pull_request.head.repo.full_name == github.repository && hashFiles('target/anvil/comments/semver.md') != '' - uses: marocchino/sticky-pull-request-comment@v3.0.5 # immutable release, the tag cannot be moved + uses: marocchino/sticky-pull-request-comment@v3.0.5 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: header: anvil-semver path: target/anvil/comments/semver.md - name: Clear anvil-semver advisory if: always() && github.event_name == 'pull_request' && matrix.os == 'linux' && github.event.pull_request.head.repo.full_name == github.repository && hashFiles('target/anvil/comments/semver.md') == '' - uses: marocchino/sticky-pull-request-comment@v3.0.5 # immutable release, the tag cannot be moved + uses: marocchino/sticky-pull-request-comment@v3.0.5 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: header: anvil-semver delete: true @@ -216,7 +216,7 @@ jobs: # fails. The separate hashFiles predicates require both feature # configurations; one multi-pattern call would accept a partial pair. if: always() && matrix.os != 'windows-arm' && hashFiles('target/coverage/lcov-all-features.info') != '' && hashFiles('target/coverage/lcov-no-default.info') != '' - uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved + uses: codecov/codecov-action@v7.0.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: files: target/coverage/lcov-all-features.info,target/coverage/lcov-no-default.info flags: ${{ matrix.os }} diff --git a/crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml b/crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml index fae9fd00..e2917666 100644 --- a/crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml +++ b/crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml @@ -73,7 +73,7 @@ jobs: # the Codecov UI can distinguish PR-tier uploads from scheduled # uploads while still tracking each platform separately. if: always() && matrix.os != 'windows-arm' && hashFiles('target/coverage/lcov-all-features.info') != '' && hashFiles('target/coverage/lcov-no-default.info') != '' - uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved + uses: codecov/codecov-action@v7.0.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: files: target/coverage/lcov-all-features.info,target/coverage/lcov-no-default.info flags: scheduled,${{ matrix.os }} diff --git a/crates/cargo-anvil/templates/github/setup-action.yml b/crates/cargo-anvil/templates/github/setup-action.yml index 0c5c0077..1441dbc4 100644 --- a/crates/cargo-anvil/templates/github/setup-action.yml +++ b/crates/cargo-anvil/templates/github/setup-action.yml @@ -109,7 +109,7 @@ runs: # cargo-binstall keeps the cold bootstrap path fast. - name: Install cargo-binstall - uses: cargo-bins/cargo-binstall@v1.21.0 # immutable release, the tag cannot be moved + uses: cargo-bins/cargo-binstall@v1.21.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) - name: Install just shell: bash diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap b/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap index b2f359f4..7e566f1f 100644 --- a/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap +++ b/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap @@ -597,7 +597,7 @@ runs: # cargo-binstall keeps the cold bootstrap path fast. - name: Install cargo-binstall - uses: cargo-bins/cargo-binstall@v1.21.0 # immutable release, the tag cannot be moved + uses: cargo-bins/cargo-binstall@v1.21.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) - name: Install just shell: bash @@ -997,13 +997,13 @@ jobs: # write tokens). - name: Upsert anvil-semver advisory if: always() && github.event_name == 'pull_request' && matrix.os == 'linux' && github.event.pull_request.head.repo.full_name == github.repository && hashFiles('target/anvil/comments/semver.md') != '' - uses: marocchino/sticky-pull-request-comment@v3.0.5 # immutable release, the tag cannot be moved + uses: marocchino/sticky-pull-request-comment@v3.0.5 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: header: anvil-semver path: target/anvil/comments/semver.md - name: Clear anvil-semver advisory if: always() && github.event_name == 'pull_request' && matrix.os == 'linux' && github.event.pull_request.head.repo.full_name == github.repository && hashFiles('target/anvil/comments/semver.md') == '' - uses: marocchino/sticky-pull-request-comment@v3.0.5 # immutable release, the tag cannot be moved + uses: marocchino/sticky-pull-request-comment@v3.0.5 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: header: anvil-semver delete: true @@ -1059,7 +1059,7 @@ jobs: # fails. The separate hashFiles predicates require both feature # configurations; one multi-pattern call would accept a partial pair. if: always() && matrix.os != 'windows-arm' && hashFiles('target/coverage/lcov-all-features.info') != '' && hashFiles('target/coverage/lcov-no-default.info') != '' - uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved + uses: codecov/codecov-action@v7.0.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: files: target/coverage/lcov-all-features.info,target/coverage/lcov-no-default.info flags: ${{ matrix.os }} @@ -1292,7 +1292,7 @@ jobs: # the Codecov UI can distinguish PR-tier uploads from scheduled # uploads while still tracking each platform separately. if: always() && matrix.os != 'windows-arm' && hashFiles('target/coverage/lcov-all-features.info') != '' && hashFiles('target/coverage/lcov-no-default.info') != '' - uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved + uses: codecov/codecov-action@v7.0.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: files: target/coverage/lcov-all-features.info,target/coverage/lcov-no-default.info flags: scheduled,${{ matrix.os }} From 8e68a0a020bb27b38ebb64ce56f242cb3636fe68 Mon Sep 17 00:00:00 2001 From: Vaiz <4908982+Vaiz@users.noreply.github.com> Date: Thu, 3 Sep 2026 08:47:54 +0100 Subject: [PATCH 3/6] chore(anvil): regenerate repository anvil state ox-tools consumes its own cargo-anvil templates, so the two preceding template changes leave the checked-in generated files stale and `regenerate-check` fails with: Repository anvil state is out of date. Run 'cargo run -p cargo-anvil -- anvil' and commit the diff. Regenerated with `cargo run -p cargo-anvil -- anvil`. The diff is exactly the emitted counterpart of the two template edits, nothing else: - justfiles/anvil/checks/msrv-test.just `cargo test --all-targets` -> `--tests`, plus the rationale comment. This repository's own MSRV check therefore stops building and running bench targets too. - .github/actions/anvil-setup/action.yml cargo-binstall pin comment. - .github/workflows/anvil-pr-impl.yml codecov and both sticky-pull-request-comment pin comments. - .github/workflows/anvil-scheduled-impl.yml codecov pin comment. `.anvil.lock` records the new catalog checksum and the four file checksums. No other emitted file changed (84 unchanged). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .anvil.lock | 8 +++---- .github/actions/anvil-setup/action.yml | 2 +- .github/workflows/anvil-pr-impl.yml | 6 +++--- .github/workflows/anvil-scheduled-impl.yml | 2 +- justfiles/anvil/checks/msrv-test.just | 25 ++++++++++++++++++++-- 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/.anvil.lock b/.anvil.lock index c1bee4b7..f450afd2 100644 --- a/.anvil.lock +++ b/.anvil.lock @@ -21,7 +21,7 @@ checksum = "sha256:d564a0ce424cda58c8f5b2476cf0c8b36e759afbdf8227608bd1f3fc74913 [[file]] path = ".github/actions/anvil-setup/action.yml" -checksum = "sha256:e1029f7ff95a5966184b4c04ccbed04ee8ba93bfc93bc9ac307d3dcef31374fb" +checksum = "sha256:a8e3cb37301ef39783721603b5145ab73dc79b7b4897c06b43b03db1f224a8a8" [[file]] path = ".github/actions/anvil-setup/just-problem-matcher.json" @@ -33,7 +33,7 @@ checksum = "sha256:7c43a36153ec346427892dca414fe971da616f99827fb5241167b1cf58a97 [[file]] path = ".github/workflows/anvil-pr-impl.yml" -checksum = "sha256:70c77226f9efe7252047d9ea4be93a1ac328708e72f4665214cb0c13e06b5c80" +checksum = "sha256:6368d048bf4921279b4f67306b22125cd48778e9d299508af1cb34f67f1de1a5" [[file]] path = ".github/workflows/anvil-pr.yml" @@ -41,7 +41,7 @@ checksum = "sha256:0c2530d9a38e6a74e0a7fd4f999b4a1790f97de30b58b68c6c2344600da19 [[file]] path = ".github/workflows/anvil-scheduled-impl.yml" -checksum = "sha256:ee1261dc018f6bdf3252890b57f0bc9510810c69505a64d3aef6d26315b824a3" +checksum = "sha256:5550d9e336bff247a92cbea1698b38dde7b0f97ae811928f23e023fd773e3652" [[file]] path = ".github/workflows/anvil-scheduled.yml" @@ -141,7 +141,7 @@ checksum = "sha256:9e9d0cbfef1e1e1586c2af4e9c387719c2f017ea1203d326baacc3ae25df8 [[file]] path = "justfiles/anvil/checks/msrv-test.just" -checksum = "sha256:9c25b140dcaa4b38db7701fd627dd9a2d5ad5f9bb83d4490c146058bf4328cc8" +checksum = "sha256:d6301aa12b97a6176dd75a7921666f43f02fee6e88b9b2930b5d03d462908ec2" [[file]] path = "justfiles/anvil/checks/mutants-diff.just" diff --git a/.github/actions/anvil-setup/action.yml b/.github/actions/anvil-setup/action.yml index 0c5c0077..1441dbc4 100644 --- a/.github/actions/anvil-setup/action.yml +++ b/.github/actions/anvil-setup/action.yml @@ -109,7 +109,7 @@ runs: # cargo-binstall keeps the cold bootstrap path fast. - name: Install cargo-binstall - uses: cargo-bins/cargo-binstall@v1.21.0 # immutable release, the tag cannot be moved + uses: cargo-bins/cargo-binstall@v1.21.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) - name: Install just shell: bash diff --git a/.github/workflows/anvil-pr-impl.yml b/.github/workflows/anvil-pr-impl.yml index d7738e37..3827022c 100644 --- a/.github/workflows/anvil-pr-impl.yml +++ b/.github/workflows/anvil-pr-impl.yml @@ -154,13 +154,13 @@ jobs: # write tokens). - name: Upsert anvil-semver advisory if: always() && github.event_name == 'pull_request' && matrix.os == 'linux' && github.event.pull_request.head.repo.full_name == github.repository && hashFiles('target/anvil/comments/semver.md') != '' - uses: marocchino/sticky-pull-request-comment@v3.0.5 # immutable release, the tag cannot be moved + uses: marocchino/sticky-pull-request-comment@v3.0.5 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: header: anvil-semver path: target/anvil/comments/semver.md - name: Clear anvil-semver advisory if: always() && github.event_name == 'pull_request' && matrix.os == 'linux' && github.event.pull_request.head.repo.full_name == github.repository && hashFiles('target/anvil/comments/semver.md') == '' - uses: marocchino/sticky-pull-request-comment@v3.0.5 # immutable release, the tag cannot be moved + uses: marocchino/sticky-pull-request-comment@v3.0.5 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: header: anvil-semver delete: true @@ -216,7 +216,7 @@ jobs: # fails. The separate hashFiles predicates require both feature # configurations; one multi-pattern call would accept a partial pair. if: always() && matrix.os != 'windows-arm' && hashFiles('target/coverage/lcov-all-features.info') != '' && hashFiles('target/coverage/lcov-no-default.info') != '' - uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved + uses: codecov/codecov-action@v7.0.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: files: target/coverage/lcov-all-features.info,target/coverage/lcov-no-default.info flags: ${{ matrix.os }} diff --git a/.github/workflows/anvil-scheduled-impl.yml b/.github/workflows/anvil-scheduled-impl.yml index fae9fd00..e2917666 100644 --- a/.github/workflows/anvil-scheduled-impl.yml +++ b/.github/workflows/anvil-scheduled-impl.yml @@ -73,7 +73,7 @@ jobs: # the Codecov UI can distinguish PR-tier uploads from scheduled # uploads while still tracking each platform separately. if: always() && matrix.os != 'windows-arm' && hashFiles('target/coverage/lcov-all-features.info') != '' && hashFiles('target/coverage/lcov-no-default.info') != '' - uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved + uses: codecov/codecov-action@v7.0.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: files: target/coverage/lcov-all-features.info,target/coverage/lcov-no-default.info flags: scheduled,${{ matrix.os }} diff --git a/justfiles/anvil/checks/msrv-test.just b/justfiles/anvil/checks/msrv-test.just index f95b38cf..915cc742 100644 --- a/justfiles/anvil/checks/msrv-test.just +++ b/justfiles/anvil/checks/msrv-test.just @@ -23,9 +23,30 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact exit 0 } $pkg = @(if ($include) { -split $include } else { '--workspace' }) - & cargo "+$toolchain" test @pkg --all-targets --all-features --locked + # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected + # packages still COMPILE and their tests still PASS under the declared + # minimum compiler. `--all-targets` expands to + # `--lib --bins --tests --benches --examples`, so `cargo test` would also + # build and EXECUTE every bench harness. A bench declared `harness = false` + # delegates its run to a separate driver binary (criterion's, or a profiler + # runner such as `gungraun-runner`, itself usually driving Valgrind). The + # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that + # driver is absent and the check fails on a prerequisite this group never + # declares -- a failure unrelated to the minimum-version signal. Benches and + # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`) + # and `anvil-examples` (`cargo build --examples`); this recipe keeps that + # same repository-wide policy. + # + # `--tests` selects exactly the targets that carry `test = true`: lib unit + # tests, bin unit tests, and integration tests. It is used in preference to + # `--lib --bins --tests` because `--lib` errors with "no library targets + # found" on a bin-only affected package under impact scoping, whereas + # `--tests` already covers lib unit tests and tolerates libless packages. + # No doctest coverage is lost: `--all-targets` suppresses doctests as well, + # and `anvil-doc-test` owns them. + & cargo "+$toolchain" test @pkg --tests --all-features --locked if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - & cargo "+$toolchain" test @pkg --all-targets --locked + & cargo "+$toolchain" test @pkg --tests --locked if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Install the declared MSRV toolchain only when this check is required. From 38e0ebab60a67f48c192d9987aba00ad52285b0a Mon Sep 17 00:00:00 2001 From: Vaiz <4908982+Vaiz@users.noreply.github.com> Date: Thu, 3 Sep 2026 09:04:27 +0100 Subject: [PATCH 4/6] fix(cargo-anvil): trim in-recipe prose and finish the pin-comment sweep Three follow-ups from review. 1. The rationale comment in `msrv-test.just` was 22 lines. That text is emitted verbatim into every adopter's `justfiles/`, where nobody is looking for a design essay. Cut to 5 lines, each carrying a fact a reader of the generated recipe needs; the full reasoning already lives in `docs/design/checks.md`, which is where it belongs. 2. Dropped two paragraphs added to `docs/design/github.md` in the previous commit. Both restated what the surrounding text already said. 3. The pin-comment reword had only covered the anvil templates. The repository's own hand-maintained CI carried the same overstated wording on actions the templates never emit, so `# immutable release, the tag cannot be moved` still shipped from here. Updated all six: - .github/workflows/main.yml (sticky-pull-request-comment x2, codecov) - .github/workflows/codeql.yml (codeql-action init and analyze) - .github/actions/setup/action.yml (taiki-e/install-action) Every tag-pinned action in the repository now carries the new comment; SHA-pinned actions keep their `# vX.Y.Z` version comment. Also finished the `--all-targets` documentation sweep the first commit missed. These still described the MSRV check as running all targets, which would have reintroduced the bench-execution pitfall for anyone following the docs: - docs/design/ado.md, the `pr_msrv` stage - docs/design/local.md, `anvil-msrv-test` (it explicitly listed "examples, and benches as test targets") - docs/design/local.md and docs/design/README.md, the no-tooling fallback snippet, which told a cargo-only user to run `cargo test --workspace --all-targets` -- the exact command that executes bench harnesses. Now `--tests`, which also restores the claim that the snippet matches the recipe bodies. Templates, generated output and `.anvil.lock` regenerated; snapshots re-recorded. No `cargo test --all-targets` remains anywhere in the repo. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .anvil.lock | 4 +-- .github/actions/setup/action.yml | 2 +- .github/workflows/codeql.yml | 4 +-- .github/workflows/main.yml | 6 ++--- crates/cargo-anvil/docs/design/README.md | 2 +- crates/cargo-anvil/docs/design/ado.md | 2 +- crates/cargo-anvil/docs/design/github.md | 7 +---- crates/cargo-anvil/docs/design/local.md | 9 ++++--- .../justfiles/anvil/checks/msrv-test.just | 26 ++++--------------- .../snapshots/snapshots__ado_backend.snap | 26 ++++--------------- .../snapshots/snapshots__github_backend.snap | 26 ++++--------------- .../snapshots/snapshots__local_only.snap | 26 ++++--------------- justfiles/anvil/checks/msrv-test.just | 26 ++++--------------- 13 files changed, 41 insertions(+), 125 deletions(-) diff --git a/.anvil.lock b/.anvil.lock index f450afd2..d6fa3360 100644 --- a/.anvil.lock +++ b/.anvil.lock @@ -1,7 +1,7 @@ version = 1 tool = "anvil" tool_version = "0.6.0" -catalog_checksum = "sha256:b1b94e5783dbe34fbf8f9c69a5e14cec3ece374e58876358ef4cd151f3f94e68" +catalog_checksum = "sha256:177e1baf0a827f5bcee78730506e6dc8da92be11a6d836c045a0b4020fb2ed9f" [[file]] path = ".anvil/container/Dockerfile.dockerignore" @@ -141,7 +141,7 @@ checksum = "sha256:9e9d0cbfef1e1e1586c2af4e9c387719c2f017ea1203d326baacc3ae25df8 [[file]] path = "justfiles/anvil/checks/msrv-test.just" -checksum = "sha256:d6301aa12b97a6176dd75a7921666f43f02fee6e88b9b2930b5d03d462908ec2" +checksum = "sha256:3f8690b4b8ec60b1b1aa3f35b32797f7b81eb64b347080ba9ee8b21e1b55ecce" [[file]] path = "justfiles/anvil/checks/mutants-diff.just" diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index b80e103d..7e4532ab 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -107,7 +107,7 @@ runs: - name: Install Cargo Tools if: inputs.cargo-tools != '' - uses: taiki-e/install-action@v2.81.8 # immutable release, the tag cannot be moved + uses: taiki-e/install-action@v2.81.8 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: tool: ${{ steps.expand.outputs.cargo_tools }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ae85e8aa..51d29ffa 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -69,7 +69,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v4.37.7 # immutable release, the tag cannot be moved + uses: github/codeql-action/init@v4.37.7 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} @@ -98,6 +98,6 @@ jobs: exit 1 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4.37.7 # immutable release, the tag cannot be moved + uses: github/codeql-action/analyze@v4.37.7 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d61280d1..3fb03f4c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -154,14 +154,14 @@ jobs: - name: Post Semver Failure Comment if: steps.semver.outcome == 'failure' && github.event.pull_request.head.repo.full_name == github.repository - uses: marocchino/sticky-pull-request-comment@v3.0.5 # immutable release, the tag cannot be moved + uses: marocchino/sticky-pull-request-comment@v3.0.5 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: header: semver-check path: semver-comment.txt - name: Remove Semver Comment on Success if: steps.semver.outcome == 'success' && github.event.pull_request.head.repo.full_name == github.repository - uses: marocchino/sticky-pull-request-comment@v3.0.5 # immutable release, the tag cannot be moved + uses: marocchino/sticky-pull-request-comment@v3.0.5 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: header: semver-check delete: true @@ -262,7 +262,7 @@ jobs: - name: Generate Coverage (no-default-features) run: cargo +${{ env.RUST_NIGHTLY }} llvm-cov --no-default-features --workspace --lcov --output-path lcov-no-def.info - name: Upload Coverage to Codecov - uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved + uses: codecov/codecov-action@v7.0.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit) with: token: ${{ secrets.CODECOV_TOKEN }} files: lcov-all.info,lcov-no-def.info diff --git a/crates/cargo-anvil/docs/design/README.md b/crates/cargo-anvil/docs/design/README.md index 601deede..6b144daf 100644 --- a/crates/cargo-anvil/docs/design/README.md +++ b/crates/cargo-anvil/docs/design/README.md @@ -206,7 +206,7 @@ update the recipes or cloud-workflow building blocks. A user with only `cargo` (no `just`, no `cargo-anvil`) can still run the basics: ```sh -cargo test --workspace --all-targets --all-features --locked +cargo test --workspace --tests --all-features --locked cargo clippy --workspace --all-targets --all-features --locked -- -D warnings cargo fmt --check ``` diff --git a/crates/cargo-anvil/docs/design/ado.md b/crates/cargo-anvil/docs/design/ado.md index 135df73a..a8d6db50 100644 --- a/crates/cargo-anvil/docs/design/ado.md +++ b/crates/cargo-anvil/docs/design/ado.md @@ -373,7 +373,7 @@ x86_64 jobs and per-OS affected-package impact sets as `pr_test`, and invokes `anvil-pr-msrv`. The stage consumes the per-OS impact artifact like the other PR groups; when the root manifest declares no MSRV, the recipe exits successfully after reporting that it skipped the test. Otherwise it runs affected-package -`cargo test --all-targets` in all-features and default-features configurations. +`cargo test --tests` in all-features and default-features configurations. Ordinary stable checks honor a caller-provided `RUSTUP_TOOLCHAIN`. The dedicated MSRV setup ensures the declared root MSRV is available through rustup. diff --git a/crates/cargo-anvil/docs/design/github.md b/crates/cargo-anvil/docs/design/github.md index c1ebd151..f97255ae 100644 --- a/crates/cargo-anvil/docs/design/github.md +++ b/crates/cargo-anvil/docs/design/github.md @@ -992,15 +992,10 @@ under those rules, and unlike a SHA it stays readable in the diff when the pin i bumped. Generated files carry a `# pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)` comment at each such pin, so the reason a tag appears where a SHA is otherwise -expected is visible at the use site. The comment names the mechanism the pin relies -on rather than asserting that tags are stable in general -- they are not, and a -reader who takes it that way will draw the wrong conclusion about the other pins. +expected is visible at the use site. Every other action is pinned by commit SHA with the version in a trailing comment, for example `actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1`. -`actions/checkout` and `actions/download-artifact` are in this group not because they -are less trusted but because immutable releases are opt-in per publisher and theirs -have not enabled it, so a SHA is the only pin that fixes the code being run. Immutability is a property of one published release, not a standing guarantee about the publisher. When bumping a tag-pinned action, confirm the new release still reports diff --git a/crates/cargo-anvil/docs/design/local.md b/crates/cargo-anvil/docs/design/local.md index f2aecb66..7cec05ca 100644 --- a/crates/cargo-anvil/docs/design/local.md +++ b/crates/cargo-anvil/docs/design/local.md @@ -439,9 +439,10 @@ compiler. Anvil does not provision a separate tooling compiler; checks that require nightly continue to use their catalog-pinned nightly. When the root manifest declares an MSRV, `anvil-msrv-test` runs affected-package -`cargo test --all-targets` in all-features and default-features configurations -under that compiler. This includes library and binary unit tests, integration -tests, examples, and benches as test targets. It does not add a +`cargo test --tests` in all-features and default-features configurations +under that compiler. This covers library and binary unit tests and integration +tests; benches and examples are deliberately excluded, because `cargo test` +would execute bench harnesses. It does not add a `--no-default-features` pass. A root toolchain file does not suppress this minimum-version run. Without a root MSRV the recipe is a no-op. @@ -690,7 +691,7 @@ exactly the same arguments cloud workflows uses, because cloud workflows invokes A user with only `cargo` (no `just`, no `cargo-anvil`) can still run the basics: ```sh -cargo test --workspace --all-targets --all-features --locked +cargo test --workspace --tests --all-features --locked cargo clippy --workspace --all-targets --all-features --locked -- -D warnings cargo fmt --check ``` diff --git a/crates/cargo-anvil/templates/justfiles/anvil/checks/msrv-test.just b/crates/cargo-anvil/templates/justfiles/anvil/checks/msrv-test.just index 915cc742..915ac428 100644 --- a/crates/cargo-anvil/templates/justfiles/anvil/checks/msrv-test.just +++ b/crates/cargo-anvil/templates/justfiles/anvil/checks/msrv-test.just @@ -23,27 +23,11 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact exit 0 } $pkg = @(if ($include) { -split $include } else { '--workspace' }) - # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected - # packages still COMPILE and their tests still PASS under the declared - # minimum compiler. `--all-targets` expands to - # `--lib --bins --tests --benches --examples`, so `cargo test` would also - # build and EXECUTE every bench harness. A bench declared `harness = false` - # delegates its run to a separate driver binary (criterion's, or a profiler - # runner such as `gungraun-runner`, itself usually driving Valgrind). The - # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that - # driver is absent and the check fails on a prerequisite this group never - # declares -- a failure unrelated to the minimum-version signal. Benches and - # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`) - # and `anvil-examples` (`cargo build --examples`); this recipe keeps that - # same repository-wide policy. - # - # `--tests` selects exactly the targets that carry `test = true`: lib unit - # tests, bin unit tests, and integration tests. It is used in preference to - # `--lib --bins --tests` because `--lib` errors with "no library targets - # found" on a bin-only affected package under impact scoping, whereas - # `--tests` already covers lib unit tests and tolerates libless packages. - # No doctest coverage is lost: `--all-targets` suppresses doctests as well, - # and `anvil-doc-test` owns them. + # `--tests` = lib/bin unit tests + integration tests. NOT `--all-targets`, + # which adds `--benches`: `cargo test` EXECUTES bench harnesses, and a + # `harness = false` bench needs a driver binary this group never installs. + # Benches/examples stay compile-only (`anvil-bench`, `anvil-examples`). + # `--tests` over `--lib --bins --tests`: `--lib` fails on bin-only packages. & cargo "+$toolchain" test @pkg --tests --all-features --locked if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & cargo "+$toolchain" test @pkg --tests --locked diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap b/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap index 1d74fd1b..c6ba50a5 100644 --- a/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap +++ b/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap @@ -2790,27 +2790,11 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact exit 0 } $pkg = @(if ($include) { -split $include } else { '--workspace' }) - # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected - # packages still COMPILE and their tests still PASS under the declared - # minimum compiler. `--all-targets` expands to - # `--lib --bins --tests --benches --examples`, so `cargo test` would also - # build and EXECUTE every bench harness. A bench declared `harness = false` - # delegates its run to a separate driver binary (criterion's, or a profiler - # runner such as `gungraun-runner`, itself usually driving Valgrind). The - # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that - # driver is absent and the check fails on a prerequisite this group never - # declares -- a failure unrelated to the minimum-version signal. Benches and - # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`) - # and `anvil-examples` (`cargo build --examples`); this recipe keeps that - # same repository-wide policy. - # - # `--tests` selects exactly the targets that carry `test = true`: lib unit - # tests, bin unit tests, and integration tests. It is used in preference to - # `--lib --bins --tests` because `--lib` errors with "no library targets - # found" on a bin-only affected package under impact scoping, whereas - # `--tests` already covers lib unit tests and tolerates libless packages. - # No doctest coverage is lost: `--all-targets` suppresses doctests as well, - # and `anvil-doc-test` owns them. + # `--tests` = lib/bin unit tests + integration tests. NOT `--all-targets`, + # which adds `--benches`: `cargo test` EXECUTES bench harnesses, and a + # `harness = false` bench needs a driver binary this group never installs. + # Benches/examples stay compile-only (`anvil-bench`, `anvil-examples`). + # `--tests` over `--lib --bins --tests`: `--lib` fails on bin-only packages. & cargo "+$toolchain" test @pkg --tests --all-features --locked if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & cargo "+$toolchain" test @pkg --tests --locked diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap b/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap index 7e566f1f..ade9fb80 100644 --- a/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap +++ b/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap @@ -2927,27 +2927,11 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact exit 0 } $pkg = @(if ($include) { -split $include } else { '--workspace' }) - # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected - # packages still COMPILE and their tests still PASS under the declared - # minimum compiler. `--all-targets` expands to - # `--lib --bins --tests --benches --examples`, so `cargo test` would also - # build and EXECUTE every bench harness. A bench declared `harness = false` - # delegates its run to a separate driver binary (criterion's, or a profiler - # runner such as `gungraun-runner`, itself usually driving Valgrind). The - # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that - # driver is absent and the check fails on a prerequisite this group never - # declares -- a failure unrelated to the minimum-version signal. Benches and - # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`) - # and `anvil-examples` (`cargo build --examples`); this recipe keeps that - # same repository-wide policy. - # - # `--tests` selects exactly the targets that carry `test = true`: lib unit - # tests, bin unit tests, and integration tests. It is used in preference to - # `--lib --bins --tests` because `--lib` errors with "no library targets - # found" on a bin-only affected package under impact scoping, whereas - # `--tests` already covers lib unit tests and tolerates libless packages. - # No doctest coverage is lost: `--all-targets` suppresses doctests as well, - # and `anvil-doc-test` owns them. + # `--tests` = lib/bin unit tests + integration tests. NOT `--all-targets`, + # which adds `--benches`: `cargo test` EXECUTES bench harnesses, and a + # `harness = false` bench needs a driver binary this group never installs. + # Benches/examples stay compile-only (`anvil-bench`, `anvil-examples`). + # `--tests` over `--lib --bins --tests`: `--lib` fails on bin-only packages. & cargo "+$toolchain" test @pkg --tests --all-features --locked if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & cargo "+$toolchain" test @pkg --tests --locked diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap b/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap index fb61a923..df2d8cc6 100644 --- a/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap +++ b/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap @@ -1660,27 +1660,11 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact exit 0 } $pkg = @(if ($include) { -split $include } else { '--workspace' }) - # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected - # packages still COMPILE and their tests still PASS under the declared - # minimum compiler. `--all-targets` expands to - # `--lib --bins --tests --benches --examples`, so `cargo test` would also - # build and EXECUTE every bench harness. A bench declared `harness = false` - # delegates its run to a separate driver binary (criterion's, or a profiler - # runner such as `gungraun-runner`, itself usually driving Valgrind). The - # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that - # driver is absent and the check fails on a prerequisite this group never - # declares -- a failure unrelated to the minimum-version signal. Benches and - # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`) - # and `anvil-examples` (`cargo build --examples`); this recipe keeps that - # same repository-wide policy. - # - # `--tests` selects exactly the targets that carry `test = true`: lib unit - # tests, bin unit tests, and integration tests. It is used in preference to - # `--lib --bins --tests` because `--lib` errors with "no library targets - # found" on a bin-only affected package under impact scoping, whereas - # `--tests` already covers lib unit tests and tolerates libless packages. - # No doctest coverage is lost: `--all-targets` suppresses doctests as well, - # and `anvil-doc-test` owns them. + # `--tests` = lib/bin unit tests + integration tests. NOT `--all-targets`, + # which adds `--benches`: `cargo test` EXECUTES bench harnesses, and a + # `harness = false` bench needs a driver binary this group never installs. + # Benches/examples stay compile-only (`anvil-bench`, `anvil-examples`). + # `--tests` over `--lib --bins --tests`: `--lib` fails on bin-only packages. & cargo "+$toolchain" test @pkg --tests --all-features --locked if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & cargo "+$toolchain" test @pkg --tests --locked diff --git a/justfiles/anvil/checks/msrv-test.just b/justfiles/anvil/checks/msrv-test.just index 915cc742..915ac428 100644 --- a/justfiles/anvil/checks/msrv-test.just +++ b/justfiles/anvil/checks/msrv-test.just @@ -23,27 +23,11 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact exit 0 } $pkg = @(if ($include) { -split $include } else { '--workspace' }) - # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected - # packages still COMPILE and their tests still PASS under the declared - # minimum compiler. `--all-targets` expands to - # `--lib --bins --tests --benches --examples`, so `cargo test` would also - # build and EXECUTE every bench harness. A bench declared `harness = false` - # delegates its run to a separate driver binary (criterion's, or a profiler - # runner such as `gungraun-runner`, itself usually driving Valgrind). The - # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that - # driver is absent and the check fails on a prerequisite this group never - # declares -- a failure unrelated to the minimum-version signal. Benches and - # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`) - # and `anvil-examples` (`cargo build --examples`); this recipe keeps that - # same repository-wide policy. - # - # `--tests` selects exactly the targets that carry `test = true`: lib unit - # tests, bin unit tests, and integration tests. It is used in preference to - # `--lib --bins --tests` because `--lib` errors with "no library targets - # found" on a bin-only affected package under impact scoping, whereas - # `--tests` already covers lib unit tests and tolerates libless packages. - # No doctest coverage is lost: `--all-targets` suppresses doctests as well, - # and `anvil-doc-test` owns them. + # `--tests` = lib/bin unit tests + integration tests. NOT `--all-targets`, + # which adds `--benches`: `cargo test` EXECUTES bench harnesses, and a + # `harness = false` bench needs a driver binary this group never installs. + # Benches/examples stay compile-only (`anvil-bench`, `anvil-examples`). + # `--tests` over `--lib --bins --tests`: `--lib` fails on bin-only packages. & cargo "+$toolchain" test @pkg --tests --all-features --locked if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & cargo "+$toolchain" test @pkg --tests --locked From 3b98234b3830d4fce81e00c3d97a70ab355868a6 Mon Sep 17 00:00:00 2001 From: Vaiz <4908982+Vaiz@users.noreply.github.com> Date: Thu, 3 Sep 2026 09:26:29 +0100 Subject: [PATCH 5/6] chore(cargo-anvil): refresh the README doc2readme fingerprint `_anvil-readme` was failing on every leg with "The documentation in your source code has changed" for cargo-anvil. The README body was already in sync with the rustdoc in `src/lib.rs` -- the stale part was the `[__cargo_doc2readme_dependencies_info]` fingerprint, which encodes a hash of the doc comments doc2readme generated the link table from. The rustdoc edits in the earlier commits changed that hash without changing any rendered text, so a by-eye comparison of the two sides looked clean while `cargo doc2readme --check` still rejected it. Regenerated with `just package=cargo-anvil readme`; the only resulting change is the fingerprint line. `cargo run -p cargo-anvil -- anvil` reports all 88 generated items unchanged, so no other artifact drifted. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- crates/cargo-anvil/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cargo-anvil/README.md b/crates/cargo-anvil/README.md index 5e4f4b20..cafec43c 100644 --- a/crates/cargo-anvil/README.md +++ b/crates/cargo-anvil/README.md @@ -491,7 +491,7 @@ And `docs/verification.md` for the continuous-validation strategy. This crate was developed as part of The Oxidizer Project. Browse this crate's source code. - [__cargo_doc2readme_dependencies_info]: ggGmYW0CYXZlMC43LjNhdIQbFhzZ8rzWNNYbuRaDSGWynFgbH4PMdoT7GNcbVwNPtPjAhvFhYvRhcoQbLvVGTNtetQUbnp9vX0Ew7_gbkZEyxfXZXyMbltL72AXa-o1hZIGDa2NhcmdvLWFudmlsZTAuNi4wa2NhcmdvX2Fudmls + [__cargo_doc2readme_dependencies_info]: ggGmYW0CYXZlMC43LjNhdIQbFhzZ8rzWNNYbuRaDSGWynFgbH4PMdoT7GNcbVwNPtPjAhvFhYvRhcoQbVqn03OrTnSYblGjeKgXeGVgb6z3iwQiK18Abc5kLxsXto9xhZIGDa2NhcmdvLWFudmlsZTAuNi4wa2NhcmdvX2Fudmls [__link0]: https://crates.io/crates/cargo-delta [__link1]: https://docs.rs/cargo-anvil/0.6.0/cargo_anvil/?search=artifacts::container [__link10]: https://docs.rs/cargo-anvil/0.6.0/cargo_anvil/?search=artifacts From 946afed0535256298e0489a527053861ca7c6dce Mon Sep 17 00:00:00 2001 From: Vaiz <4908982+Vaiz@users.noreply.github.com> Date: Thu, 3 Sep 2026 11:30:19 +0100 Subject: [PATCH 6/6] chore(anvil): recompute the .anvil.lock catalog checksum after rebase Rebasing onto main conflicted on `catalog_checksum` alone -- both sides rewrote that one line and git cannot merge a hash. main has since added a catalog item (the plan is now 92 items, up from 91), so neither side's value was correct on the new base. Resolved by regenerating rather than picking a side: `cargo run -p cargo-anvil -- anvil` recomputes the checksum from the merged catalog. It reports the other 89 generated items unchanged, so the emitted workflows, actions and justfiles this branch touches survived the rebase intact and only the lock needed updating. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .anvil.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.anvil.lock b/.anvil.lock index d6fa3360..f37bc73e 100644 --- a/.anvil.lock +++ b/.anvil.lock @@ -1,7 +1,7 @@ version = 1 tool = "anvil" tool_version = "0.6.0" -catalog_checksum = "sha256:177e1baf0a827f5bcee78730506e6dc8da92be11a6d836c045a0b4020fb2ed9f" +catalog_checksum = "sha256:3415a24c3e1b7216ecfd37ecfda02b4e6039851b70f07e45a676597254874191" [[file]] path = ".anvil/container/Dockerfile.dockerignore"