cargo-affected
Like pytest-testmon for Rust. Maps each test to the source-line ranges it
touches via LLVM coverage, then reruns only the tests whose ranges overlap
git diff hunks.
Status: extremely early. Mac & linux only at this stage. The author is starting to use this in their own repos; others probably shouldn't yet. The schema can change without migration, behavior may break, and there is no support promise. CI should still run the full test suite.
Installation
Not on crates.io yet. Install from source:
Quick start
# Build with coverage instrumentation and record what each test touches.
# After editing:
run diffs the working tree against the git sha that was HEAD when
collect last ran. Recollect periodically — every committed change since
the last collect adds to the diff and broadens selection.
How it works
collect:
cargo nextest listenumerates every test.cargo nextest runruns them with-C instrument-coverageand a per-testLLVM_PROFILE_FILE.- For each test,
llvm-profdatamerges its profraw andllvm-cov exportlists every hit function with its source-line regions. - Per
(test, file, function), the min/max line span is stored intarget/affected/coverage.db(SQLite), keyed by a fingerprint ofCargo.lock, all workspaceCargo.tomls,rustc -vV,RUSTFLAGS, andCARGO_BUILD_TARGET. The git HEAD sha is recorded alongside.
run:
git diff -U0 <collect_sha>produces OLD-side line ranges for changed files — same coordinate system as storage.- For each changed file, the DB returns stored function ranges overlapping
any hunk; the union of matching tests is run via
cargo nextest run. - If a hunk overlaps no stored range (struct fields,
#[derive],const,use,mod), a per-file backstop selects every test that touched the file. Crate roots (lib.rs/main.rs/tests/*.rs) are stored with a sentinel range covering the whole file, so any edit there reselects every test that covered the crate root.
Accuracy model
cargo affected run is an approximation — it trades correctness for speed.
CI should still run the full suite.
False positives (tests selected that didn't need to run)
- Function-level granularity. A hit function's full line span is treated as one range, so an edit anywhere inside it reruns every test that touched the function — even if the edited line is unreachable from those tests.
- Structural-edit backstop. Hunks outside any LLVM region (struct
fields, derives, consts,
use,mod) reselect every test that touched the file. - Crate roots. Any edit to
lib.rs/main.rs/tests/*.rsreruns every test that covered that crate root. - Comment- and whitespace-only edits. Selection diffs lines, not semantics.
False negatives (tests skipped that should have run)
- Non-Rust sources.
include_str!/include_bytes!targets, SQL files, migrations, assets, and templates aren't seen by llvm-cov. - Build-time inputs not in the fingerprint. The fingerprint covers
Cargo.lock, workspaceCargo.tomls,rustc -vV,RUSTFLAGS, andCARGO_BUILD_TARGET. Changes tobuild.rs,rust-toolchain.toml, or.cargo/config.tomldon't currently invalidate the cache. - Proc-macro crate source. A proc-macro's own source files compile into a host dylib, not the test binary, so editing a proc-macro crate won't reselect its downstream tests.
- External state. Tests that read env vars, filesystem state, or the network can change outcome without any source file changing.
When in doubt, cargo affected collect to refresh coverage, or skip
cargo-affected and run the full suite.
License
Dual-licensed under MIT or Apache-2.0 at your option.