Skip to content

Latest commit

 

History

History
568 lines (463 loc) · 36.4 KB

reference.md

File metadata and controls

568 lines (463 loc) · 36.4 KB

Reference

Exact flags, config keys, output fields, exit codes and environment variables. For how to do a task see usage; for the reasoning behind the numbers see explanation. patchcov <command> --help prints the same flags from the binary you have.

Contents

Commands

Command Purpose
patchcov diff Attribute a coverage report to a git diff; report and gate on it
patchcov merge Merge the per-shard reports of a sharded run into one lcov file
patchcov lint-markers Check patchcov: coverage source markers without a coverage report

-C, --repo <PATH> is accepted by every command, before or after the subcommand. It runs patchcov as if started in <PATH>, like git -C. --error-format <text|json> is accepted the same way and chooses how a failure is printed; see error output. -h/--help and -V/--version work everywhere.

diff discovers the nearest enclosing git repository from the current directory or -C (including a subdirectory). Relative --report and --baseline-report paths are resolved from that invocation directory, not the discovered repository root. For example, from <repo>/sub, use patchcov diff --report ../head.lcov --base-sha HEAD~1 to read <repo>/head.lcov. Default config discovery, report path stripping and Go module detection use the repository working directory.

patchcov diff flags

Flag Purpose
--report <PATH> Head coverage report (required); repeat once per shard to merge a sharded run
--report-format <FMT> Format of every --report: auto (default) | lcov | llvm-cov-json | cobertura | jacoco | go-coverprofile
--base-ref <REV> Base revision (default: merge base of the default branch and HEAD). An explicit revision is compared directly with the head, not via a merge base; see choosing the base
--head-ref <REV> Head revision the report was measured at (default: HEAD)
--baseline-report <PATH> Base-side report; enables project deltas and indirect changes. Takes one report
--baseline-report-format <FMT> Format of --baseline-report (auto-detected by default); same values as --report-format
-o, --output <FMT> markdown (default) | yaml | json
--no-explanation Omit the explanation block from JSON/YAML output; no effect on markdown
--fail-under-patch <PCT> Exit non-zero when patch coverage is below <PCT>, a finite number of at least 0 (nan, inf and negative values are usage errors). No added lines passes
--fail-under-lines <PCT> Exit non-zero when overall line coverage is below <PCT>, a finite number of at least 0 (nan, inf and negative values are usage errors), or the report has no executable lines
--fail-on-unmeasured <GLOB> Exit non-zero for matching touched files absent from every report (repeatable; unioned with diff.require-measured)
--branch-coverage Score lines with missed lcov/Cobertura branches as uncovered, in head and baseline
--collapse-ranges Collapse consecutive uncovered new lines into ranges (9-11) in the markdown per-file table; JSON and YAML always list single lines
--all-files Report deltas and indirect changes for all files, not just touched ones
--allow-path-mismatch Warn, instead of failing, when a nonempty head, shard or baseline report has no path matching a tracked file after normalization. Off by default: such a report fails. Unioned with diff.allow-path-mismatch
--strip-prefix <PATH> Prefix stripped from report paths to make them repo-relative (default: the repository working directory)
--ignore-filename-regex <REGEX> Exclude matching files from both reports (repeatable or comma-separated); unioned with diff.ignore-filename-regex
--config-dir <PATH> Directory searched for config.yaml (default: the discovered .patchcov/, honouring PATCHCOV_CONFIG_DIR)
--artifact-url <URL> Link to the full coverage-summary artifact, in the markdown footer
--run-url <URL> Link to the CI run, in the markdown footer, independently of --artifact-url
--commit-url <URL> Commit-URL prefix for linking SHAs
--base-sha <SHA> / --head-sha <SHA> SHAs shown in the markdown Comparing line (both are needed for the line to appear)

Markdown reports omit artifact guidance when no nonempty artifact URL is supplied. An explicit --artifact-url (or COVERAGE_ARTIFACT_URL) is labeled as a full per-file coverage summary; only use it for an artifact containing that summary. A run URL renders even without an artifact URL. Without --baseline-report, per-file deltas and indirect coverage changes are unavailable; the report makes no assumptions about CI baseline publication.

For both --fail-under-* flags, space-separated negative float values such as -inf, -nan and -.5 receive the same explanatory usage error as the --flag=value spelling. A following option instead of a value reports a value is required.

The five footer and link flags fall back to environment variables; see Environment variables. --format is a hidden, deprecated alias of -o/--output that prints a warning. --fail-on-path-mismatch is a hidden, deprecated no-op (failing is now the default) that prints a warning; --allow-path-mismatch still wins over it.

patchcov merge flags

Flag Purpose
<REPORT>... Reports to merge, one per shard (required); lcov, llvm-cov JSON, Cobertura, JaCoCo or Go coverprofile
--report-format <FMT> Format of every report: auto (default) | lcov | llvm-cov-json | cobertura | jacoco | go-coverprofile
-o, --output <PATH> File to write the merged lcov report to (required); a path, not a format
--strip-prefix <PATH> Prefix stripped from report paths (default: the repository working directory, if there is one)

patchcov lint-markers flags

Flag Purpose
[PATH]... Files to check (default: every tracked text file); an explicit path ignores --include and the config list
--include <GLOB> Check only tracked files matching this glob (repeatable); replaces lint-markers.include

Exit codes

Each class of failure has its own exit code, so a script can tell a failed gate from an unreadable report without parsing stderr. The message on stderr is unchanged (its last line starts with Error:) unless you ask for JSON. The report itself, on stdout, is still printed when a gate fails, so a CI job can post it first.

Code Meaning Examples (stderr)
0 Success. The report was printed and no gate failed. Warnings on stderr (a path mismatch you allowed, a lint glob that matched nothing) do not change it
1 A gate failed (diff) patch coverage 61.11% is below the --fail-under-patch threshold of 80.00%
line coverage 75.00% is below the --fail-under-lines threshold of 100.00%
the report has no executable lines, so the --fail-under-lines threshold of 50.00% cannot be met
touched files absent from every coverage report (--fail-on-unmeasured / diff.require-measured): src/a.rs. Every failed gate is named, joined by ;
2 Usage error: reported by the argument parser before anything runs, or a combination of flags it cannot check the following required arguments were not provided: --report <PATH>
invalid value 'abc' for '--fail-under-patch <PCT>' (also nan, inf, a negative value such as -5, and any value that overflows to infinity)
unrecognized subcommand
--branch-coverage supports only lcov and Cobertura reports: ./go.cover
-o/--output is the file to write, but json looks like an output format ... (merge)
3 A report is unreadable, empty or unparseable (diff, merge) could not read coverage report ./missing.lcov: No such file or directory
could not parse coverage report ./empty.lcov: coverage report format auto-detection failed: coverage report is empty; cannot detect format
coverage shard <path> has no executable lines (several --report, or any merge input)
4 A source marker is malformed (lint-markers, and diff for files in the report) src/m.rs:1: `patchcov: coverage ignore` needs a reason (write ...)
coverage marker lint failed
5 Config is bad could not parse coverage config ./.patchcov/config.yaml: ... (malformed YAML, wrong type, a misspelled path-mappings field)
coverage path-mappings destination must be repo-relative without '..': ...
invalid ignore-filename-regex pattern
invalid glob ... in --fail-on-unmeasured / diff.require-measured
6 Git cannot answer could not open git repository at ...
could not resolve base ref ...
could not resolve a default base ref (tried `refs/remotes/origin/HEAD`, `origin/main`, `main`, `origin/master`, `master`); pass --base-ref
could not compute merge-base of `<ref>` and HEAD
could not read `<path>` from the tree to scan for coverage markers (with --head-ref or a baseline)
7 A path mismatch (diff): a nonempty report has no path matching a tracked file. With --allow-path-mismatch or diff.allow-path-mismatch it is only a warning coverage report <path>: none of its N file path(s) matches a tracked file in the repository; unmatched normalized paths: p1, p2, p3[, and M more]; use --strip-prefix or diff.path-mappings to make paths repo-relative (or pass --allow-path-mismatch / set diff.allow-path-mismatch to warn instead)
8 Any other runtime error could not write merged report to ./out/merged.lcov: No such file or directory
could not read <path> to scan for coverage markers (a file in the working tree)

When one failure fits two rows, the most specific one wins: a config file that cannot be read is 5, not 8. A failure that no row names also exits 8. A process killed by a signal exits with the shell's 128 + signal, as usual.

Up to and including 0.3.0, every runtime error, gate or not, exited 1. A script that treated 1 as "a gate failed" keeps working. One that tested for 1 to mean "anything went wrong" should test for a non-zero status instead.

When upgrading from 0.3.0, a path mismatch also changes from a warning to an error by default: a nonempty head, shard or baseline report with no normalized path matching a tracked file now exits 7. A CI run that previously passed with exit 0 and a warning can therefore fail after upgrading. Pass --allow-path-mismatch or set diff.allow-path-mismatch: true in .patchcov/config.yaml to restore the warning-only behavior while fixing the report paths. Either option is enough; other errors and failed gates still fail the run.

patchcov diff --report head.lcov --fail-under-patch 80 > coverage-comment.md
case $? in
  0) ;;                                       # passed
  1) echo "coverage gate failed" ;;           # post the comment, then fail the job
  *) echo "patchcov could not run" >&2 ;;     # no usable report; do not post
esac

Error output

By default a failure ends stderr with one Error: ... line. A wrapper that wants the class and cause without parsing that line can ask for a JSON object instead, with --error-format json or PATCHCOV_ERROR_FORMAT=json. The flag wins over the variable, and an empty variable counts as unset. The values are text (the default) and json; a variable with any other value is ignored with a warning, so a typo cannot stop a run.

With json, a failing run prints one object on a single line, as the last line of stderr, instead of the Error: line. Stdout and the exit code are unchanged, and so is each warning's message. Lines printed earlier are JSON lines too, see Warnings and Findings and summary below.

{"level":"error","code":3,"kind":"report","message":"could not read coverage report ./missing.lcov","chain":["No such file or directory (os error 2)"]}
Field Type Meaning
level string Always "error"; a warning line has "warning", and the other lines have "error" (a finding) or "info"
code number The process exit code, from the table above
kind string The name of the class of failure, from the table below; stable like the code
message string The outermost error message
chain array of strings The causes beneath message, outermost first; empty when there are none
gates array of objects Only when kind is gate: the failed gates as data, described after the table of kind values

message and then chain, joined with : , is the text that follows Error: in the default format. A message can contain newlines (a regex parse error does), escaped as usual in JSON.

kind code
gate 1
usage 2
report 3
marker 4
config 5
git 6
path-mismatch 7
other 8

The argument parser's own errors (a missing required flag, an unknown subcommand) are usage with an empty chain, and message is the parser's error text, with any tips, without its usage block. Because parsing had failed, patchcov finds the format by looking for --error-format among the arguments (the last one wins, and -- ends the options) and in PATCHCOV_ERROR_FORMAT. --help and --version are not failures and print as usual. A bad value for --error-format itself is a parser error in the default format.

A failed gate is a gate object. Its message names every failed gate, with the threshold and the measured value, as in the text. It also has a gates field with the same facts as data, so a wrapper can show which gate failed, or compare the measured value with the threshold, without parsing the message. gates is present only when kind is gate. It has one entry per failed gate, in the order below, and each entry's gate names the gate and decides its other fields:

{"level":"error","code":1,"kind":"gate","message":"patch coverage 61.11% is below the --fail-under-patch threshold of 80.00%","chain":[],"gates":[{"gate":"fail-under-patch","threshold":80.0,"measured":61.11111111111111}]}
gate Fields Meaning
fail-under-patch threshold, measured (numbers) Patch coverage measured is below --fail-under-patch
fail-under-lines threshold (number), measured (number or null) Overall line coverage measured is below --fail-under-lines. measured is null when the report has no executable lines, which fails the gate because nothing can be measured
fail-on-unmeasured files (array of strings) These touched files match --fail-on-unmeasured or diff.require-measured and are absent from every report

threshold is the value you gave. measured is a percentage on a 0 to 100 scale, not rounded (the message rounds it to two decimal places), so measured < threshold is the comparison the gate made. Round it yourself for display. A gate that passed is not listed.

Consumers should ignore keys they do not know: new fields, and new gate values, may be added without a change to the exit codes or to the existing fields.

Warnings

With --error-format json, each warning is printed as one JSON line on stderr instead of a warning: ... line. The text of the message is the same as in the default format.

{"level":"warning","kind":"path-mismatch","message":"coverage report head.lcov: none of its 1 file path(s) matches a tracked file in the repository; unmatched normalized paths: `nowhere/else.rs`; use --strip-prefix or diff.path-mappings to make paths repo-relative","report":"head.lcov","file_count":1,"unmatched":["nowhere/else.rs"]}

This is patchcov diff --report head.lcov --allow-path-mismatch: report is the argument head.lcov, including when -C is supplied (details).

Field Type Meaning
level string Always "warning"
kind string The class of warning, from the table below; stable like the error kind
message string The warning, as it follows warning: in the default format

Each kind adds fields after message, listed below.

kind When Fields besides level, kind and message
deprecated A deprecated flag was used (--format, --fail-on-path-mismatch) flag (string), the flag with its dashes; replacement (string or null), what to use instead, or null if nothing replaces it
path-mismatch diff: a report's paths match no tracked file, and --allow-path-mismatch or diff.allow-path-mismatch let the run continue report (string), the report as the message names it (a display string); file_count (number), how many file paths it has; unmatched (array of strings), the first three of its normalized paths (the ones the message samples). Every path in the report is unmatched, so the list is truncated exactly when it is shorter than file_count (more than three paths), and the message then ends the sample with , and N more
shard-root merge: a shard was measured under a different workspace root shard (string), the shard as the message names it (a display string); strip_prefix (string), the prefix it was expected under, without a trailing / (a display string too); absolute_paths (number), how many absolute file paths it has, none of them under the prefix
glob-no-match lint-markers: its globs matched no tracked file, so nothing was checked globs (array of strings), the globs; origin (string), where they came from: "--include" or "lint-markers.include" (the config key)

Another example, a shard under another root, from patchcov merge --strip-prefix /ci/workspace -o merged.lcov two.lcov (without -C, merge names the shard as typed):

{"level":"warning","kind":"shard-root","message":"coverage shard two.lcov: none of its 1 absolute file path(s) is under `/ci/workspace`, so ...","shard":"two.lcov","strip_prefix":"/ci/workspace","absolute_paths":1}

The fields follow message and are the data it is written from, so a wrapper can attach a warning to a file or a flag without parsing the message. Consumers should ignore keys they do not know: fields and kinds may be added without a change to the existing ones.

To tell the lines apart, read level: a warning is "warning", a finding or summary is "error" or "info", and the failure is "error" with a code. The failure is still the last line of stderr. The warning about an invalid PATCHCOV_ERROR_FORMAT is the one line that is not JSON, since the format it asks for was not accepted; parse only the lines that start with { and keep the objects that have a level.

Paths in warning fields

report, shard and strip_prefix are filesystem paths written as display strings: the text the message prints for them (strip_prefix without its trailing /), not path identifiers. JSON strings must be UTF-8, so in a path that is not valid UTF-8 each invalid sequence of bytes is replaced with one U+FFFD (the replacement character). The value may then name no file that exists, and two different paths can give the same value.

report and shard preserve the input argument as typed, including a leading ./, for both commands. This applies to head reports, baseline reports and shards. Wrappers can match these fields against their UTF-8 input arguments. -C affects where a relative file is read, but does not change its diagnostic label:

Run A relative head.lcov is named Example
diff without -C as typed head.lcov
diff -C <dir> as typed head.lcov
merge without -C as typed head.lcov
merge -C <dir> as typed head.lcov

An absolute input path is also kept as typed. Relative inputs are still read relative to -C (or the current directory when it is omitted). Path-mismatch errors use the same report label as warnings. strip_prefix describes the effective prefix, which can be inferred from the repository; it is not necessarily an argument as typed.

Earlier versions named diff reports joined to -C (or .) and merge shards joined to -C when supplied. Consumers that expected those anchored labels should match input arguments instead.

No lossless form of these paths is emitted today: non-UTF-8 report or shard paths are rare, and a field for them can be added later without changing the existing ones. unmatched is not affected: it holds the file paths read from inside the report, which are already strings.

Findings and summary

Two commands print more than warnings and a failure. With --error-format json each of these is a JSON line too, with the same text in message as the default format prints.

patchcov lint-markers prints one object per file with a malformed marker (the first one in the file), before the failure. A finding is level "error" because it makes the run fail, but its kind is "marker-finding"; the failure that follows it has kind "marker" and a code, and is the last line. To find the failure, take the last line, not the first "error".

{"level":"error","kind":"marker-finding","path":"src/a.rs","line":12,"message":"unterminated `reason=\"…\"` (missing closing quote)"}
Field Type Meaning
level string Always "error"
kind string Always "marker-finding"
path string The file, as the default format prints it: repo-relative, or as given on the command line
line number The 1-based line of the marker (of the opening marker, for an unterminated region)
message string What is wrong, without the path:line: that the default format starts the line with

patchcov merge prints its summary line as an info object, after any warnings:

{"level":"info","kind":"merge-summary","message":"merged 3 report(s) into merged.lcov: 12 file(s), 840 of 1000 lines covered (84.00%)","inputs":3,"output":"merged.lcov","files":12,"total_lines":1000,"covered_lines":840,"percent":84.0}
Field Type Meaning
level string Always "info"
kind string Always "merge-summary"
message string The summary line, as the default format prints it
inputs number The number of reports merged
output string The file written, as the default format prints it
files number The files in the merged report
total_lines number Executable lines in the merged report
covered_lines number Executable lines hit at least once
percent number or null Line coverage on a 0 to 100 scale, not rounded (message rounds it); null when there are no executable lines

A line stays a JSON object even if patchcov cannot serialize its full record (a bug, not something a command line can cause), so stderr never has a blank line where a diagnostic belonged. A warning or summary line then has only level, kind and message, the first two being the record's own. An error line keeps level, code, kind and message; message is the outermost message alone. Its chain and gates are serialized independently and kept when each succeeds; only a component that cannot serialize is omitted. As in a normal error line, gates is absent when there are no failed gates. A finding's message is then the default format's whole line, path:line: included.

Output schema

patchcov diff -o json and -o yaml emit the same structure. Percentages are on a 0 to 100 scale and rounded to two decimal places. null (~ in YAML) means "not measurable", for example a percentage over zero lines. Field order follows the table below.

The example is the output of docs/examples/sample.sh json, a small repository where a patch adds 18 executable lines and 7 are uncovered, trimmed to the interesting parts:

{
  "patch_coverage": {
    "percent": 61.11,
    "covered": 11,
    "total": 18,
    "files": [
      {
        "path": "src/cache.rs",
        "percent": 66.67,
        "covered": 4,
        "total": 6,
        "uncovered_lines": [5, 6]
      }
    ]
  },
  "uncovered_new_lines": ["src/cache.rs:5", "src/cache.rs:6"],
  "unmeasured_files": [],
  "project_delta": {
    "total_before": 100.0,
    "total_after": 85.42,
    "files": [
      { "path": "src/cache.rs", "before": null, "after": 66.67, "delta": null }
    ]
  },
  "indirect_changes": { "newly_covered": 0, "newly_uncovered": 0, "lines": [] }
}

(The real output lists both files and all seven uncovered lines, and spreads arrays over several lines.)

Top level

Field Type Present Meaning
explanation object by default; omitted by --no-explanation A description of each field, and whether it is populated in this document. See explanation
patch_coverage object always Coverage of the lines this diff added. See patch_coverage
uncovered_new_lines string[] when non-empty The added lines that are not covered, as path:line, in path then line order
unmeasured_files string[] always (may be empty) Sorted repo-relative paths of non-deleted files the diff touched that appear under neither name in any head or baseline report. Files excluded by --ignore-filename-regex are omitted. May be documentation or uninstrumented code; only --fail-on-unmeasured / diff.require-measured globs turn a match into a failure
project_delta object only with --baseline-report Project coverage before and after. See project_delta
indirect_changes object only with --baseline-report Lines whose coverage flipped without their content changing. See indirect_changes
markers object[] when a source marker applied The silenced regions. See markers
excluded_files object when --ignore-filename-regex removed a file What the filter removed. See excluded_files

patch_coverage

Field Type Meaning
percent number or null Covered over total added executable lines. null when total is 0 (the diff added no instrumented code)
covered integer Added executable lines that are covered
total integer Added executable lines: the patch-coverage denominator
files object[] One entry per file that added executable lines, in path order
files[].path string Repo-relative path
files[].percent / covered / total as above The same three figures for this file
files[].uncovered_lines integer[] Uncovered added line numbers; omitted when the file has none

project_delta

Field Type Meaning
total_before number or null Overall line coverage of the baseline
total_after number or null Overall line coverage of the head: the real, measured value. This is what --fail-under-lines gates on
total_after_effective number Head coverage with tolerate masking applied. Present only when masking changed the total
files object[] Touched files (all files with --all-files) whose coverage is listed
files[].path string Repo-relative path
files[].before number or null The file's baseline coverage; null for a new file
files[].after number or null The file's real head coverage
files[].after_effective number Masked head coverage; present only when masking changed it, in which case delta is after_effective - before
files[].delta number or null Change in percentage points; null for a new file
notable_unchanged object[] Files the diff did not touch that still moved by at least 10 covered lines, with the same fields as files[]. Not attributable to this diff. Omitted when empty

indirect_changes

Field Type Meaning
newly_covered integer Unchanged lines that went from uncovered to covered
newly_uncovered integer Unchanged lines that went from covered to uncovered
lines object[] One entry per flipped line
lines[].path string Repo-relative path (at head)
lines[].head_line integer The line number at head
lines[].base_line integer The same line's number at base
lines[].transition string uncovered_to_covered or covered_to_uncovered

markers

One object per region a patchcov: coverage marker silenced, so a reviewer can see what was silenced and why. See source markers.

Field Type Meaning
path string Repo-relative path of the marked file
kind string ignore (lines removed from both reports) or tolerate (lines kept, flips masked)
side string Where the region was observed: both, head or base
start, end integer First and last line of the region, 1-based and inclusive, as observed on that side
reason string The marker's mandatory reason="…" text

excluded_files

Field Type Meaning
count integer Files removed by --ignore-filename-regex / diff.ignore-filename-regex; only files that were in a head or baseline report count, once each
touched_count integer How many of them this diff touched
new_executable_lines integer Executable lines the diff added to excluded files: patch lines the filter took out of the denominator
paths string[] Every excluded path
touched string[] The subset of paths this diff touched

explanation

Field Type Meaning
text string A paragraph describing the document
fields object[] One entry per documented field
fields[].name string Path of the field, e.g. patch_coverage.files[].path
fields[].text string What it contains
fields[].present boolean Whether this document populates it

.patchcov/config.yaml

Repository settings live in .patchcov/config.yaml, in version control. There are no user-level or machine-level settings, so what a gate reports is visible to a reviewer.

Discovery, the same for every command, first match wins:

  1. --config-dir <PATH> (diff only).
  2. The PATCHCOV_CONFIG_DIR environment variable, when set and non-empty.
  3. The nearest .patchcov/ directory walking up from the repository root, never past the repository boundary (a .git entry).
  4. <repo root>/.patchcov, which need not exist: a missing directory or file is an empty config, and behaviour is unchanged.

A file that is present but malformed (bad YAML, a value of the wrong type) is a hard error rather than a silent default. Unknown keys are ignored, so a newer config stays readable by an older binary, with one exception: a misspelled field inside a path-mappings entry fails.

Key Type Default Used by Combines with the CLI flag
diff.ignore-filename-regex list of regex strings [] diff Union with --ignore-filename-regex: the flag only adds
diff.path-mappings list of {from, to} [] diff No flag; config only. merge does not read it
diff.require-measured list of glob strings [] diff Union with --fail-on-unmeasured
diff.allow-path-mismatch boolean false diff Either one enables it: set here or pass --allow-path-mismatch
lint-markers.include list of glob strings [] (every tracked text file) lint-markers Replaced by --include when the flag is given
# .patchcov/config.yaml
diff:
  ignore-filename-regex:
    - 'src/bits/popcount\.rs'
  path-mappings:
    - from: com/example
      to: services/api/src/main/java/com/example
  require-measured:
    - 'src/**/*.rs'
  allow-path-mismatch: false
lint-markers:
  include:
    - '**/*.rs'

diff.ignore-filename-regex

Regexes (Rust regex syntax) matched against the repo-relative path, unanchored (a partial match is a match), after --strip-prefix. A matching file is removed from both the head and baseline reports. Empty patterns are dropped, because an empty regex would match every path. An invalid regex is an error. See excluding files.

diff.path-mappings

Each entry has exactly two string fields, from and to; any other field is an error.

Field Meaning
from A report path prefix. Matches whole directory components (src does not match src2). '' matches every relative path
to The repo-relative replacement. '' removes the matched prefix. Must not start with /, contain :, or contain ..

The longest matching from wins, each path is mapped once (no chaining), and two entries with the same normalised from are an error. Backslashes become / and a leading ./ and trailing / are dropped before comparison. Aliases that map to one path combine by maximum line hits. Mappings run before --strip-prefix. See package-relative paths and the path pipeline.

diff.require-measured

Globs matched against whole repo-relative paths: * stays within one directory, ** crosses directories (src/**/*.rs also matches src/a.rs). A touched file that matches and is absent from every report fails the run. An empty or invalid glob is an error. See requiring touched files to be measured.

diff.allow-path-mismatch

A boolean, false by default. By default diff fails when a nonempty head, shard or baseline report has no path matching a tracked file, because such a report cannot be joined to the diff and a gate over it would pass without measuring anything. true turns that error into the same message as a warning on stderr, exactly as --allow-path-mismatch does; either one is enough. Set it only for a repository where a report legitimately matches nothing, since a gate cannot see a patch it cannot join. A report with at least one tracked path never triggers the check. See absolute paths from another runner.

lint-markers.include

Globs with the same syntax, selecting which tracked files patchcov lint-markers scans when given no paths. A file is scanned when it matches any glob. A glob list that matches no tracked file scans nothing and prints a warning. See checking marker syntax.

Environment variables

Variable Used by Meaning
PATCHCOV_ERROR_FORMAT every command Fallback for --error-format: text or json. Empty is ignored. See error output
PATCHCOV_CONFIG_DIR every command that reads config Directory holding config.yaml; overrides discovery, overridden by --config-dir. Empty is ignored
COVERAGE_ARTIFACT_URL diff Fallback for --artifact-url
COVERAGE_RUN_URL diff Fallback for --run-url
COVERAGE_COMMIT_URL diff Fallback for --commit-url
COVERAGE_BASE_SHA diff Fallback for --base-sha
COVERAGE_HEAD_SHA diff Fallback for --head-sha

A flag wins over its variable, and an empty variable counts as unset. These only change the links and SHAs in the markdown footer.