Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
8487432
Design and planning for cargo-ox-check-update
martin-kolinek Jun 9, 2026
f4c5bf1
MVP implementation: CLI, manifest, decision algorithm, GH/ADO emitters
martin-kolinek Jun 9, 2026
f8aa750
Post-MVP refactors and snapshot tests
martin-kolinek Jun 9, 2026
fa04cc0
Implementation plan 0001 phases P0-P6
martin-kolinek Jun 9, 2026
28cd95f
Cross-OS matrix work and ADO job.yml extensibility wrapper
martin-kolinek Jun 9, 2026
fe48c45
Dogfood-surfaced fixes: cache, binstall, Justfile case, spellcheck
martin-kolinek Jun 9, 2026
1b44e03
Per-check tuning: deny, udeps, semver-check, external-types, aprz
martin-kolinek Jun 9, 2026
a755bcb
Catalog tightening: pinned nightly toolchains + lint catalog reorgani…
martin-kolinek Jun 9, 2026
7d35daa
ADO impact bootstrap + per-OS impact stages + system-deps probe
martin-kolinek Jun 9, 2026
53c7c0f
Recipe TODO cleanup + cargo-heather README + advisory PR comments
martin-kolinek Jun 9, 2026
ce1bdd7
PR-tier reorg: unified setup, exact-pin, miri/careful + pr-slow split
martin-kolinek Jun 9, 2026
d5355c6
Diagram polish + crate restructure (cargo-ox-check-update)
martin-kolinek Jun 9, 2026
b7eb8c0
Refactor tools setup into layered recipes
martin-kolinek Jun 10, 2026
4270669
Bump cargo-audit to 0.22.2 (CVSS 4.0 support)
martin-kolinek Jun 10, 2026
3edfc14
Probe libclang on ARM Linux multiarch path
martin-kolinek Jun 10, 2026
8173d46
Bump cargo-spellcheck to 0.15.7 and dedupe miri cfg_attr
martin-kolinek Jun 11, 2026
6dcaf2c
Dedupe one more miri cfg_attr in lcov_cov.rs
martin-kolinek Jun 12, 2026
f21cc3d
Rename cargo-ox-check-update to cargo-anvil
martin-kolinek Jun 12, 2026
52ccc36
Add naming rationale to design.md
martin-kolinek Jun 12, 2026
86c284a
Use cargo-bins/cargo-binstall action in setup-action.yml
martin-kolinek Jun 15, 2026
71ad75c
Replace 'CI' with 'cloud workflows' in cargo-anvil docs/comments
martin-kolinek Jun 15, 2026
8639a43
Fix anvil-readme-check on rebased branch
martin-kolinek Jun 15, 2026
01c92a8
Regenerate cargo-heather README (drift from v0.2.1 -> v0.3.0 bump)
martin-kolinek Jun 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions .anvil.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
version = 1
rendered_by = "cargo-anvil 0.1.0"

[[file]]
path = ".github/actions/anvil-impact/action.yml"
checksum = "sha256:7d2f0dcafd024407c8e73370c19afdb882e4cb807f6113258561d665bd2b8a0a"

[[file]]
path = ".github/actions/anvil-pr-fast/action.yml"
checksum = "sha256:6d93a456cdeb9668d713c623cb649732e731ec31a3761b4ad971acb3b9827ea5"

[[file]]
path = ".github/actions/anvil-pr-mutants/action.yml"
checksum = "sha256:4053a6023ddcd01eee22911e0080031e1bcd8c502ffc75acfb20d4c02a038685"

[[file]]
path = ".github/actions/anvil-pr-runtime-analysis/action.yml"
checksum = "sha256:326cc30bfb67bc1d23be50d37c57e542466bce813a56b38a0c2a015e8d13a540"

[[file]]
path = ".github/actions/anvil-pr-test/action.yml"
checksum = "sha256:ba33cd6a826d2a6e63e88fd6e4795496717b697d64bf93f133333d916952cdb5"

[[file]]
path = ".github/actions/anvil-scheduled-advisories/action.yml"
checksum = "sha256:c05a587116e84f5da346f8faf994503c6b0ab578fb2534d5e586fa4bbb261cd6"

[[file]]
path = ".github/actions/anvil-scheduled-exhaustive/action.yml"
checksum = "sha256:6a56421f666b92239a952e0ef351c803c59f5d24bd22b34f8695581fa175bdea"

[[file]]
path = ".github/actions/anvil-scheduled-test/action.yml"
checksum = "sha256:a42cf49d0e203db5545a797888c8c62e1564f5914a2588e2a40cb3b2cf8b0ad3"

[[file]]
path = ".github/actions/anvil-setup/action.yml"
checksum = "sha256:065181e093ed68c83d5f974ebde2980f26cc70f954d965b2c0ca1b63042d3a1e"

[[file]]
path = ".github/workflows/anvil-pr-impl.yml"
checksum = "sha256:70b2f188d3cc0fee5c9502534611121db9ff8b2c27cd6dfa176bf9a9ba9d2d2e"

[[file]]
path = ".github/workflows/anvil-pr.yml"
checksum = "sha256:14c3541e39a7918497cb400ea20232340bc056da6d862a951568c09e32f4f2f7"

[[file]]
path = ".github/workflows/anvil-scheduled-impl.yml"
checksum = "sha256:bee7c741ee336c43b75754a0a902d6a64f8df971a95121acc7c6d66bbf2bacc8"

[[file]]
path = ".github/workflows/anvil-scheduled.yml"
checksum = "sha256:a45359b92a6d851fc39bfa1c03aeb489b544ae37a1cea390dbbf860b2def8205"

[[file]]
path = "justfiles/anvil/checks.just"
checksum = "sha256:d7c4e8c7eb70c4214ae5bd527636c2c865605bd91c82dd32625a35f6f0b203be"

[[file]]
path = "justfiles/anvil/groups.just"
checksum = "sha256:6fa13e5e760a490c5c466efee538513bc9a73deffd58d8a05f13b71f3b9b4f10"

[[file]]
path = "justfiles/anvil/mod.just"
checksum = "sha256:06b486f1d154b36cf1c1a43333addd2e3ade8c69646600f7409a0c6a1c08cedb"

[[file]]
path = "justfiles/anvil/tiers.just"
checksum = "sha256:fd65dc16029c0e347f55f406e005ca1b264db4b482e3f1e8f6ef94aad7c51b64"

[[file]]
path = "justfiles/anvil/tools.just"
checksum = "sha256:7c92f6cadca16c4e2d6897b1c9304e7a541fb7c7e380e27165304d4071a6d27c"

[[file]]
path = "justfiles/anvil/versions.just"
checksum = "sha256:42bea708c5dc7fc08847dcf4bfed8941b084ac98dbd43b6c28582c5d59449895"

[[region]]
host = ".delta.toml"
id = "anvil-delta"
checksum = "sha256:ef049abc4bba5e6dac7dfc07a4852d821de4682fe6ad46aace7ddfb2455cb597"

[[region]]
host = "Cargo.toml"
id = "anvil-workspace-lints"
checksum = "sha256:d66a878609d0bf11e3aa52f3d28ef674de9333c97b3f5d5ffdc7c7b487ac5792"

[[region]]
host = "Justfile"
id = "anvil-imports"
checksum = "sha256:f8affd59b69c7083c2f3b6f593c63672116dda974c1e661dcb66a4412eb3eada"

[[region]]
host = "clippy.toml"
id = "anvil-clippy"
checksum = "sha256:aba0733632eac4cb54c4768db578fe1f7b7cfe730aa0d7dc13e2828c9062d67d"

[[region]]
host = "crates/automation/Cargo.toml"
id = "anvil-lints"
checksum = "sha256:2dd7c0f21339fd17092b8dedfe924aa86732c3520baab84f914c2d8f4103ac40"

[[region]]
host = "crates/cargo-anvil/Cargo.toml"
id = "anvil-lints"
checksum = "sha256:2dd7c0f21339fd17092b8dedfe924aa86732c3520baab84f914c2d8f4103ac40"

[[region]]
host = "crates/cargo-coverage-gate/Cargo.toml"
id = "anvil-lints"
checksum = "sha256:2dd7c0f21339fd17092b8dedfe924aa86732c3520baab84f914c2d8f4103ac40"

[[region]]
host = "crates/cargo-heather/Cargo.toml"
id = "anvil-lints"
checksum = "sha256:2dd7c0f21339fd17092b8dedfe924aa86732c3520baab84f914c2d8f4103ac40"

[[region]]
host = "crates/cargo_ensure_no_cyclic_deps/Cargo.toml"
id = "anvil-lints"
checksum = "sha256:2dd7c0f21339fd17092b8dedfe924aa86732c3520baab84f914c2d8f4103ac40"

[[region]]
host = "deny.toml"
id = "anvil-deny"
checksum = "sha256:3d38154ac70567b4b6b39699e244040a1ed869471d3501f7147b5c3c9a748ade"

[[region]]
host = "rustfmt.toml"
id = "anvil-rustfmt"
checksum = "sha256:c21c68f3f9e46e8a958513e80ebce393d2e2ec8b90e2ded5416bca4215ffa8b7"

[[region]]
host = "spellcheck.toml"
id = "anvil-spellcheck"
checksum = "sha256:3d85d17a4e9a9a6770738b67d93a801375ffadd159e506eef81e5a9ffe1da0d7"
17 changes: 16 additions & 1 deletion .cargo-heather.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
header = """
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.
"""
"""

# Excluded directories. These hold content that legitimately should NOT
# carry the Microsoft copyright header:
#
# - `crates/cargo-anvil/templates/regions/`: managed-region body
# snippets embedded into adopters' config files via include_str!.
# A header here would inject it into every adopter's deny.toml /
# rustfmt.toml / etc.
# - `crates/cargo-anvil/tests/fixtures/`: simulated adopter repos
# used as test inputs. They model arbitrary user content and
# should not inherit our header policy.
exclude = [
"crates/cargo-anvil/templates/regions",
"crates/cargo-anvil/tests/fixtures",
]
11 changes: 11 additions & 0 deletions .delta.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,14 @@ assume_patterns = [
# The remote branch to compare against for determining changed files
# If not specified, uses the default branch detection
remote_branch = "origin/main"

# >>> anvil-managed: anvil-delta
[delta]
# Include the workspace root files that should invalidate every member's
# impact analysis when changed (lockfile, root manifest, toolchain).
root-files = [
"Cargo.lock",
"Cargo.toml",
"rust-toolchain.toml",
]
# <<< anvil-managed: anvil-delta
127 changes: 127 additions & 0 deletions .github/actions/anvil-impact/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Owned by cargo-anvil; edit via `cargo anvil`.
name: anvil-impact
description: |
Compute the cargo-delta impact set for this PR and emit per-tier
include lists.

Outputs:
include_modified - "--package X --package Y" string for crates whose
source files changed in the diff, or "--skip" if
the modified set is empty.
include_affected - same shape, for crates in the affected set
(modified ∪ rev-deps).
include_required - same shape, for crates in the required set
(affected ∪ workspace-internal transitive deps).

Recipes in checks.just interpret each variable per their tier:
modified-tier recipes (fmt, license-headers, spellcheck, ...) short-
circuit on "--skip"; affected-tier recipes (clippy, tests, ...) and
required-tier recipes (doc, cargo-hack, udeps) splice their include
list into the cargo invocation, defaulting to --workspace when unset
(local runs without impact wiring).

Unscoped recipes (deny, audit, aprz, pr-title) ignore all three
variables and always run unconditionally.
outputs:
include_modified:
description: Pre-formatted --package args for the modified tier.
value: ${{ steps.compute.outputs.include_modified }}
include_affected:
description: Pre-formatted --package args for the affected tier.
value: ${{ steps.compute.outputs.include_affected }}
include_required:
description: Pre-formatted --package args for the required tier.
value: ${{ steps.compute.outputs.include_required }}
runs:
using: composite
steps:
# anvil-setup with group=none bootstraps the rust toolchain +
# just + binstall + cache, but skips the full catalog install.
# We follow it with just the cargo-delta install (the only tool
# this composite needs). This keeps the impact stage lean -- it's
# the critical-path gating dep for every PR-tier group job.
- uses: ./.github/actions/anvil-setup
with:
group: none
- name: Install cargo-delta
shell: bash
run: just anvil-tool-cargo-delta-install binstall
- id: compute
name: Compute impact
shell: bash
run: |
set -euo pipefail
# GITHUB_BASE_REF is the target-branch name on a PR event
# (e.g. "main"); we resolve it to origin/<name>. Adopters can
# override via the BASE_REF env var.
base="${BASE_REF:-origin/${GITHUB_BASE_REF:-main}}"
# cargo delta has no --base flag; the flow is two snapshots
# (baseline at the merge target + current at HEAD) compared by
# `cargo delta impact`. We use a temporary worktree to snapshot
# the baseline without disturbing the checked-out tree.
cargo delta snapshot > "$RUNNER_TEMP/anvil-current.json"
git worktree add --detach "$RUNNER_TEMP/anvil-baseline" "$base"
( cd "$RUNNER_TEMP/anvil-baseline" && cargo delta snapshot ) \
> "$RUNNER_TEMP/anvil-baseline.json"
git worktree remove --force "$RUNNER_TEMP/anvil-baseline"
result="$(cargo delta impact \
--baseline "$RUNNER_TEMP/anvil-baseline.json" \
--current "$RUNNER_TEMP/anvil-current.json" \
--format json)"
# cargo-delta emits TitleCase keys (Modified / Affected /
# Required), not lowercase. Format each tier into the
# `--package X --package Y` shape recipes expect, or the
# literal "--skip" sentinel when the tier is empty.
#
# cargo-delta's impact output uses *library names* (snake_case)
# rather than cargo *package names* (which may use hyphens). For
# hyphenated packages — e.g. `cargo-anvil` — that means it
# emits `cargo_anvil`, which cargo rejects as a --package
# specification. We build:
# * `pkg_map`: lib-name -> package-name (and identity for
# package-name -> package-name), for translation;
# * `valid_pkgs`: set of all known package names, for
# validation. Names cargo-delta emits that aren't valid
# packages (e.g. directory-leaf ambiguities like `ffi` /
# `ffi_build` in deeply nested workspaces) are dropped with a
# warning rather than failing the whole build.
declare -A pkg_map
declare -A valid_pkgs
while IFS=$'\t' read -r pkg_name lib_name; do
valid_pkgs["$pkg_name"]=1
pkg_map["$pkg_name"]="$pkg_name"
[ -n "$lib_name" ] && pkg_map["$lib_name"]="$pkg_name"
done < <(cargo metadata --no-deps --format-version 1 \
| jq -r '.packages[] as $p | ($p.targets[] | select(.kind | index("lib")) | "\($p.name)\t\(.name)"), "\($p.name)\t"')
format_set() {
local field="$1"
local pkgs
pkgs=$(printf '%s' "$result" | jq -r --arg f "$field" '(.[$f] // []) | .[]' 2>/dev/null || true)
if [ -z "$pkgs" ] ; then
printf '%s' "--skip"
else
local out=""
while IFS= read -r pkg ; do
[ -z "$pkg" ] && continue
local mapped="${pkg_map[$pkg]:-$pkg}"
if [ -z "${valid_pkgs[$mapped]:-}" ] ; then
echo "anvil impact: dropping unknown package '$pkg' (-> '$mapped') from $field set" >&2
continue
fi
out="$out --package $mapped"
done <<EOF
$pkgs
EOF
if [ -z "$out" ] ; then
printf '%s' "--skip"
else
# shellcheck disable=SC2001
printf '%s' "${out# }"
fi
fi
}
echo "include_modified=$(format_set Modified)" >> "$GITHUB_OUTPUT"
echo "include_affected=$(format_set Affected)" >> "$GITHUB_OUTPUT"
echo "include_required=$(format_set Required)" >> "$GITHUB_OUTPUT"
44 changes: 44 additions & 0 deletions .github/actions/anvil-pr-fast/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Owned by cargo-anvil; edit via `cargo anvil`.
# The token pr-fast is substituted by cargo-anvil at emit time with
# the concrete check-group name (pr-fast, pr-test, scheduled-runtime, ...).
name: anvil-pr-fast
description: Run the pr-fast check group.
inputs:
include_modified:
description: |
Pre-formatted --package args (e.g. "--package alpha --package beta")
for the modified tier, or the sentinel "--skip" when nothing
modified. Local invocations leave it unset; recipes default to
--workspace.
default: ""
required: false
include_affected:
description: |
Same shape as include_modified, but for the affected tier
(modified ∪ rev-deps).
default: ""
required: false
include_required:
description: |
Same shape as include_modified, but for the required tier
(affected ∪ workspace-internal transitive deps).
default: ""
required: false
runs:
using: composite
steps:
- uses: ./.github/actions/anvil-setup
with:
group: pr-fast
- name: Run just anvil-pr-fast
shell: bash
env:
ANVIL_INCLUDE_MODIFIED: ${{ inputs.include_modified }}
ANVIL_INCLUDE_AFFECTED: ${{ inputs.include_affected }}
ANVIL_INCLUDE_REQUIRED: ${{ inputs.include_required }}
# cargo-aprz hits the GitHub API (unauthenticated = 60 req/hr); pass the
# built-in token so it can use the 1000 req/hr authenticated quota.
GITHUB_TOKEN: ${{ github.token }}
run: just anvil-pr-fast
44 changes: 44 additions & 0 deletions .github/actions/anvil-pr-mutants/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Owned by cargo-anvil; edit via `cargo anvil`.
# The token pr-mutants is substituted by cargo-anvil at emit time with
# the concrete check-group name (pr-fast, pr-test, scheduled-runtime, ...).
name: anvil-pr-mutants
description: Run the pr-mutants check group.
inputs:
include_modified:
description: |
Pre-formatted --package args (e.g. "--package alpha --package beta")
for the modified tier, or the sentinel "--skip" when nothing
modified. Local invocations leave it unset; recipes default to
--workspace.
default: ""
required: false
include_affected:
description: |
Same shape as include_modified, but for the affected tier
(modified ∪ rev-deps).
default: ""
required: false
include_required:
description: |
Same shape as include_modified, but for the required tier
(affected ∪ workspace-internal transitive deps).
default: ""
required: false
runs:
using: composite
steps:
- uses: ./.github/actions/anvil-setup
with:
group: pr-mutants
- name: Run just anvil-pr-mutants
shell: bash
env:
ANVIL_INCLUDE_MODIFIED: ${{ inputs.include_modified }}
ANVIL_INCLUDE_AFFECTED: ${{ inputs.include_affected }}
ANVIL_INCLUDE_REQUIRED: ${{ inputs.include_required }}
# cargo-aprz hits the GitHub API (unauthenticated = 60 req/hr); pass the
# built-in token so it can use the 1000 req/hr authenticated quota.
GITHUB_TOKEN: ${{ github.token }}
run: just anvil-pr-mutants
Loading
Loading