patchcov 0.2.0

Patch coverage for git diffs: attribute lcov, llvm-cov, Cobertura, Go and JaCoCo reports to a diff and gate on it.
Documentation

patchcov

Patch coverage for git diffs. patchcov attributes a per-line coverage report to a git diff and tells you what share of the lines a change added are covered, which new lines are not, and whether anything moved on code the change did not touch.

  • Reads lcov, llvm-cov JSON, Cobertura, JaCoCo XML and Go coverprofiles, detected from the content.
  • Reports patch coverage, the uncovered new lines, per-file project deltas and indirect changes, as a markdown PR comment, YAML or JSON.
  • Gates a branch with --fail-under-patch and --fail-under-lines.
  • Merges the reports of a sharded CI run into one file, or takes them directly.
  • Silences known-flaky regions with source markers, and files with a repo-level ignore list, without hiding real coverage.

Why patchcov

patchcov does one job: it tells you, precisely and repeatably, whether a change is covered by tests. It is built to be a clear signal, not a dashboard.

  • A precise signal. The headline number is the share of added lines that are covered, with the uncovered ones listed as file:line. Whoever or whatever reads it (a reviewer, a script, an AI agent) knows what to do next without interpreting charts or trends.
  • Machine-readable and gateable. JSON and YAML output, --collapse-ranges for a compact list, and exit codes from --fail-under-patch and --fail-under-lines make it easy to automate, including in a loop where an agent adds tests until the gate passes.
  • No service in the loop, so no outage to block you. It reads report files from disk and sends nothing anywhere: no account, upload token or server to be down, slow or rate-limited. It runs on the same runners as your other CI jobs, so the coverage gate is available whenever your CI is, and a hosted quality server going down for days cannot block merges. It runs the same on a laptop or in a sandbox, so a coverage check is a command you can run before you push, not something you learn about afterwards.
  • Quiet by construction. Coverage that flaps between runs (a region gated on a runtime CPU feature, say) is the usual source of phantom regressions. Per-file scoping, a tolerance on the headline delta and tolerate source markers keep that noise from reading as a regression while the reported numbers stay honest.
  • Fails loudly. An empty report, a failed shard or a malformed marker is an error, not a quietly lower number. Everything that silences coverage needs a stated reason and is listed in the PR comment, and settings live in .patchcov/config.yaml in version control, so a reviewer can see what a gate does and what was excluded.
  • One tool across languages. Five report formats are detected from content, so the same command works for Rust, Go, Java and Kotlin, JavaScript and TypeScript, Python, C and C++ and more.

When to choose patchcov

Choose patchcov when:

  • the question you need answered is "did this change add untested code, and where?";
  • coverage is checked by automation, including AI agents, as much as by people;
  • you want the coverage gate to depend on nothing but your own CI runners, so an outage of an external quality server or coverage service cannot block your work;
  • you want the check to run locally and in CI without sending code coverage to an external service;
  • your coverage is noisy and you need regressions you can trust;
  • you run a sharded CI job and want a single combined result and gate.

Choose something else, or use patchcov alongside it, when you need:

  • a hosted dashboard with coverage history, trend graphs or cross-repository views;
  • branch coverage (patchcov reads line coverage only);
  • a broader code-quality platform that covers coverage along with static analysis and security scanning.

patchcov measures whether lines ran, not whether the tests assert anything useful about them. Treat it as a regression signal, and pair it with review, or mutation testing, for confidence in the tests themselves.

Install

cargo install patchcov

Prebuilt binaries for Linux (glibc 2.35 or newer), macOS and Windows (x86_64 MSVC) are attached to each GitHub release, along with SHA-256 checksums. Linux and macOS builds use .tar.gz archives; Windows builds use patchcov-v<version>-x86_64-pc-windows-msvc.zip. Extract the Windows ZIP and add the directory containing patchcov.exe to your PATH.

Use

# Produce a per-line report (any tool that writes one of the supported formats).
cargo llvm-cov --no-report
cargo llvm-cov report --lcov --output-path head.lcov

# Patch coverage against the merge base with origin/main.
patchcov diff --report head.lcov

# Fail the job if patch coverage is under 80% or overall coverage under 70%.
patchcov diff --report head.lcov --fail-under-patch 80 --fail-under-lines 70

# Merge the shards of a sharded run, then gate as usual.
patchcov merge shard-1.lcov shard-2.lcov -o merged.lcov

# Check source markers without a coverage report.
patchcov lint-markers

The full guide is in docs/usage.md: input formats and path mapping for non-Rust languages, gating semantics, sharded runs, the ignore list, source markers and the flag reference.

GitHub Action

action-works/patchcov-action runs patchcov in a pull-request workflow. It installs a cached patchcov binary, runs cargo-llvm-cov (or takes a report you produced in any language), posts a sticky PR comment with patch coverage and the uncovered new lines, publishes the baseline on main and applies the gates after the comment posts. It also combines the reports of sharded runs.

jobs:
  coverage:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write        # to post the coverage comment
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0          # full history so the merge base resolves
      - uses: action-works/patchcov-action@v1
        with:
          fail-under-patch: 80

See the action's README for thin mode, sharded runs and its inputs.

Configuration

Settings that belong to a repository live in .patchcov/config.yaml, found by walking up from the repository root. --config-dir and the PATCHCOV_CONFIG_DIR environment variable override the location. There are no user-level or machine-level settings, so what a gate reports is visible in version control.

Library

The analysis is a library as well as a command: patchcov::parse reads a report, patchcov::DiffModel builds the added-line sets from git2, patchcov::analyze attributes coverage to the diff and patchcov::render formats the result.

Contributing

See CONTRIBUTING.md for local checks and the merge queue flow.

Releasing

See docs/RELEASE.md.

License

BSD-3-Clause. See LICENSE.