1818A pull-request-time gate that compares per-package line coverage produced
1919by [ ` cargo-llvm-cov ` ] [ __link0 ] against per-package thresholds carried in
2020` Cargo.toml ` . The accompanying ` cargo-coverage-gate ` binary reads the
21- coverage lcov tracefile, resolves each package’s threshold from a small
22- three-layer lookup, and emits a verdict table to stdout (and,
21+ coverage lcov tracefile, resolves each package’s base policy from a small
22+ three-layer lookup, applies any matching package target policy, and emits a
23+ verdict table to stdout (and,
2324optionally, to a Markdown summary file for CI step summaries). A failing
2425verdict includes actionable details without relying on a later
2526coverage-service upload. A coverable line is a distinct LCOV ` DA: ` record.
@@ -28,9 +29,27 @@ Numeric failures show exact covered/coverable counts and uncovered ranges;
2829and ` NO DATA ` explains that no records were attributed. Location lists are
2930bounded, with an exact count of omitted locations.
3031
31- ### Threshold resolution
32+ ### Configuration
3233
33- For each workspace member, the effective threshold is the first match
34+ #### Numeric thresholds
35+
36+ A workspace can define the default line-coverage threshold:
37+
38+ ``` toml
39+ # Illustrative workspace policy.
40+ [workspace .metadata .coverage-gate ]
41+ min-lines-percent = 80
42+ ```
43+
44+ Individual packages can override it:
45+
46+ ``` toml
47+ # Illustrative package policy, intentionally stricter than the workspace.
48+ [package .metadata .coverage-gate ]
49+ min-lines-percent = 95
50+ ```
51+
52+ For each workspace member, the base threshold is the first match
3453among:
3554
36551 . ` [package.metadata.coverage-gate] min-lines-percent = N ` in the package’s
@@ -40,13 +59,67 @@ among:
40591 . The built-in default of ` 100.0 ` — full coverage required.
4160
4261Setting ` min-lines-percent = 0.0 ` explicitly opts a package out of
43- gating (it always passes, regardless of attributed data). A package
44- that legitimately contains no coverable lines (pure re-exports, type
45- definitions, a thin binary shim) instead declares
46- ` expect-no-coverable-lines = true ` : the gate passes only while that
47- holds and fails — as a regression — if coverable lines later appear.
48- The two keys are mutually exclusive, and ` expect-no-coverable-lines `
49- is package-scoped only.
62+ gating: it always passes, regardless of attributed data. Thresholds must
63+ be in the inclusive range ` 0.0..=100.0 ` .
64+
65+ #### Packages with no coverable lines
66+
67+ A package that legitimately contains no coverable lines (pure re-exports,
68+ type definitions, or a thin binary shim) can make that invariant explicit:
69+
70+ ``` toml
71+ [package .metadata .coverage-gate ]
72+ expect-no-coverable-lines = true
73+ ```
74+
75+ The gate passes only while the package has no attributed coverable lines
76+ and fails as a regression if coverable code later appears. This differs
77+ from ` min-lines-percent = 0 ` , which keeps passing if the package grows
78+ coverable code. The two keys are mutually exclusive, and
79+ ` expect-no-coverable-lines ` is package-scoped only.
80+
81+ #### Target-specific policies
82+
83+ A package can replace its base policy for a Cargo-style target selector:
84+
85+ ``` toml
86+ [package .metadata .coverage-gate ]
87+ min-lines-percent = 100
88+
89+ [package .metadata .coverage-gate .target .'cfg(not(windows))' ]
90+ expect-no-coverable-lines = true
91+
92+ [package .metadata .coverage-gate .target .x86_64-unknown-linux-gnu ]
93+ min-lines-percent = 100
94+ ```
95+
96+ A target-specific no-coverable-lines assertion uses the same nesting:
97+
98+ ``` toml
99+ [package .metadata .coverage-gate .target .thumbv7em-none-eabihf ]
100+ expect-no-coverable-lines = true
101+ ```
102+
103+ Target tables are package-scoped; they are invalid in workspace metadata.
104+ Their keys accept exact Rust target triples or quoted ` cfg(...) ` expressions
105+ using the target-derived subset of Cargo’s target grammar. Target
106+ configuration options such as ` windows ` , ` unix ` , ` target_os ` , and
107+ ` target_arch ` are supported. Build-context options such as ` feature ` , ` test ` ,
108+ ` debug_assertions ` , and ` proc_macro ` are rejected because a standalone target
109+ query cannot evaluate them. A selected target table sets either
110+ ` min-lines-percent ` or ` expect-no-coverable-lines = true ` , completely
111+ replacing the package’s base policy to produce its effective policy. Exact
112+ triples take precedence over matching ` cfg(...) ` expressions. Multiple
113+ matching cfg policies are a configuration error rather than depending on
114+ declaration order.
115+
116+ A zero target-specific threshold disables gating on the matching target,
117+ but does not disable test execution or instrumentation. Those test binaries
118+ remain instrumented because they may contribute coverage to other packages.
119+ If cargo-llvm-cov reports that an instrumented run produced no coverage
120+ data, automation can supply an empty lcov tracefile: zero-threshold and
121+ ` expect-no-coverable-lines ` packages pass, while positively gated packages
122+ report ` NO DATA ` .
50123
51124### Why lcov, not the JSON?
52125
@@ -66,6 +139,7 @@ Codecov / ADO numbers confusing.
66139
67140``` text
68141cargo coverage-gate [--lcov <path>]... [-p|--package <spec>]...
142+ [--target <triple>]
69143 [--summary-file <path>] [--quiet]
70144```
71145
@@ -97,25 +171,29 @@ let code = report.verdict().as_exit_code();
97171
98172### Public API
99173
100- The library exposes [ ` evaluate ` ] [ __link1 ] , which returns an
101- [ ` EvaluatedReport ` ] [ __link2 ] . The report can be rendered as plain text via
102- [ ` EvaluatedReport::render_text ` ] [ __link3 ] or as GitHub-flavored Markdown
103- via [ ` EvaluatedReport::render_markdown ` ] [ __link4 ] , and reduced to a single
104- [ ` Verdict ` ] [ __link5 ] via [ ` EvaluatedReport::verdict ` ] [ __link6 ] . The accompanying
105- binary loads the lcov tracefile from disk and orchestrates rendering
106- plus the appropriate exit code.
174+ [ ` evaluate ` ] [ __link1 ] gates one lcov tracefile for the rustc host target, while
175+ [ ` evaluate_many ` ] [ __link2 ] merges multiple tracefiles at line level.
176+ [ ` evaluate_many_for_target ` ] [ __link3 ] evaluates a selected Rust target, which may be
177+ supplied explicitly or omitted to select the rustc host target.
178+ Evaluation returns an [ ` EvaluatedReport ` ] [ __link4 ] , which renders as plain
179+ text via [ ` EvaluatedReport::render_text ` ] [ __link5 ] or GitHub-flavored Markdown via
180+ [ ` EvaluatedReport::render_markdown ` ] [ __link6 ] and reduces to a [ ` Verdict ` ] [ __link7 ] via
181+ [ ` EvaluatedReport::verdict ` ] [ __link8 ] . The accompanying binary loads tracefiles from
182+ disk and orchestrates rendering plus the appropriate exit code.
107183
108184
109185<hr />
110186<sub >
111187This crate was developed as part of <a href =" ../.. " >The Oxidizer Project</a >. Browse this crate's <a href =" https://github.com/microsoft/ox-tools/tree/main/crates/cargo-coverage-gate " >source code</a >.
112188</sub >
113189
114- [ __cargo_doc2readme_dependencies_info ] : ggGmYW0CYXZlMC43LjNhdIQbFhzZ8rzWNNYbuRaDSGWynFgbH4PMdoT7GNcbVwNPtPjAhvFhYvRhcoQbSLvuLqYvzncbvkJE0ZCfihkbvLj44R1A234bYHxJKfzepgZhZIGDc2NhcmdvLWNvdmVyYWdlLWdhdGVlMC4zLjBzY2FyZ29fY292ZXJhZ2VfZ2F0ZQ
190+ [ __cargo_doc2readme_dependencies_info ] : ggGmYW0CYXZlMC43LjNhdIQbFhzZ8rzWNNYbuRaDSGWynFgbH4PMdoT7GNcbVwNPtPjAhvFhYvRhcoQb3wjNoVxGaCAbpkmpjr98NCcbw-HRsqJQXfkb8-afvWiSredhZIGDc2NhcmdvLWNvdmVyYWdlLWdhdGVlMC40LjBzY2FyZ29fY292ZXJhZ2VfZ2F0ZQ
115191 [ __link0 ] : https://github.com/taiki-e/cargo-llvm-cov
116- [ __link1 ] : https://docs.rs/cargo-coverage-gate/0.3.0/cargo_coverage_gate/fn.evaluate.html
117- [ __link2 ] : https://docs.rs/cargo-coverage-gate/0.3.0/cargo_coverage_gate/struct.EvaluatedReport.html
118- [ __link3 ] : https://docs.rs/cargo-coverage-gate/0.3.0/cargo_coverage_gate/?search=EvaluatedReport::render_text
119- [ __link4 ] : https://docs.rs/cargo-coverage-gate/0.3.0/cargo_coverage_gate/?search=EvaluatedReport::render_markdown
120- [ __link5 ] : https://docs.rs/cargo-coverage-gate/0.3.0/cargo_coverage_gate/enum.Verdict.html
121- [ __link6 ] : https://docs.rs/cargo-coverage-gate/0.3.0/cargo_coverage_gate/?search=EvaluatedReport::verdict
192+ [ __link1 ] : https://docs.rs/cargo-coverage-gate/0.4.0/cargo_coverage_gate/fn.evaluate.html
193+ [ __link2 ] : https://docs.rs/cargo-coverage-gate/0.4.0/cargo_coverage_gate/fn.evaluate_many.html
194+ [ __link3 ] : https://docs.rs/cargo-coverage-gate/0.4.0/cargo_coverage_gate/fn.evaluate_many_for_target.html
195+ [ __link4 ] : https://docs.rs/cargo-coverage-gate/0.4.0/cargo_coverage_gate/struct.EvaluatedReport.html
196+ [ __link5 ] : https://docs.rs/cargo-coverage-gate/0.4.0/cargo_coverage_gate/?search=EvaluatedReport::render_text
197+ [ __link6 ] : https://docs.rs/cargo-coverage-gate/0.4.0/cargo_coverage_gate/?search=EvaluatedReport::render_markdown
198+ [ __link7 ] : https://docs.rs/cargo-coverage-gate/0.4.0/cargo_coverage_gate/enum.Verdict.html
199+ [ __link8 ] : https://docs.rs/cargo-coverage-gate/0.4.0/cargo_coverage_gate/?search=EvaluatedReport::verdict
0 commit comments