cargo-coverage-gate 0.1.0

A cargo subcommand that gates pull requests on per-package line coverage measured by cargo-llvm-cov
Documentation

Cargo-Coverage-Gate

crates.io docs.rs MSRV CI Coverage License

cargo-coverage-gate

A pull-request-time gate that compares per-package line coverage produced by cargo-llvm-cov against per-package thresholds carried in Cargo.toml. The accompanying cargo-coverage-gate binary reads the coverage lcov tracefile, resolves each package’s threshold from a small three-layer lookup, and emits a verdict table to stdout (and, optionally, to a Markdown summary file for CI step summaries).

Threshold resolution

For each workspace member, the effective threshold is the first match among:

  1. [package.metadata.coverage-gate] min-lines-percent = N in the package’s Cargo.toml,
  2. [workspace.metadata.coverage-gate] min-lines-percent = N in the workspace root Cargo.toml, or
  3. The built-in default of 100.0 — full coverage required.

Setting min-lines-percent = 0.0 explicitly opts a package out of gating.

Why lcov, not the JSON?

cargo-llvm-cov exports the same instrumentation run in several formats (JSON, lcov, cobertura, codecov-custom-JSON). The gate consumes lcov because that is what every other coverage report fed by the same data sees: Codecov ingests lcov uploads directly, ADO consumes cobertura that cargo-llvm-cov derives from lcov, and the lcov line semantics (“a line is covered if any region on it was hit”) match the human reading of “did we hit this line”. The JSON export uses a stricter “every region on the line must be hit” interpretation that systematically reports a couple of percentage-points lower, which makes calibrating thresholds against Codecov / ADO numbers confusing.

Binary usage

cargo coverage-gate  [--lcov <path>] [-p|--package <spec>]...
                     [--summary-file <path>] [--quiet]

Exit codes: 0 if every gated package meets its threshold, 1 if any gated package falls below its threshold, and 2 for configuration errors (unparseable lcov, missing data for a gated package, a --package selector that matches no member, an out-of-range min-lines-percent value, …).

When --summary-file is unset, the binary falls back to $GITHUB_STEP_SUMMARY and then $COVERAGE_GATE_SUMMARY to decide where to write the Markdown verdict table.

Library usage

use std::io;

let lcov = std::fs::read_to_string("target/coverage/lcov.info")?;
let report = cargo_coverage_gate::evaluate(&lcov, None, &[])?;
report.render_text(&mut io::stdout())?;
let code = report.verdict().as_exit_code();

Public API

The library exposes evaluate, which returns an EvaluatedReport. The report can be rendered as plain text via EvaluatedReport::render_text or as GitHub-flavored Markdown via EvaluatedReport::render_markdown, and reduced to a single Verdict via EvaluatedReport::verdict. The accompanying binary loads the lcov tracefile from disk and orchestrates rendering plus the appropriate exit code.