DotCov.Tool
3.0.0
See the version list below for details.
dotnet tool install --global DotCov.Tool --version 3.0.0
dotnet new tool-manifest
dotnet tool install --local DotCov.Tool --version 3.0.0
#tool dotnet:?package=DotCov.Tool&version=3.0.0
nuke :add-package DotCov.Tool --version 3.0.0
DotCov.Tool
dotcov turns Cobertura XML into a build decision — a table, a markdown block, a JSON payload,
and an exit code your CI can act on. Local by default; uploads are opt-in.
Getting started
dotnet tool install -g DotCov.Tool
dotnet test --results-directory TestResults --coverlet --coverlet-output-format cobertura
dotcov check TestResults/ --min-line 80 --min-branch 60 --exclude-generated
PASS: line 96.5% (min 80%), branch 93.0% (min 60%) - thresholds met
Pass a file or fresh run directory. A directory search matches **/*cobertura*.xml beneath it
(hidden directories included) and merges every match, so a sharded test matrix needs no merge step.
Merged reports are listed on stderr. Use a fresh directory for each run to avoid stale reports.
Timestamped coverlet.MTP files match. For generic names such as gcovr's coverage.xml, select
the filename explicitly with --pattern.
Commands
dotcov report TestResults/ --format table # also json or md
dotcov check TestResults/ --min-line 80 --exclude-generated # CI gate, exit 1 if below
dotcov crap TestResults/ --max-crap 6 # per-method risk gate
dotcov diff before.xml after.xml --format md # compare two reports
dotcov snapshot TestResults/ --commit SHA --branch main --project MyApp
dotcov test tests/MyApp.Tests --min-line 80 -- -c Release # dotnet test, then report and gate
check and test have no default threshold: pass --min-line, --min-branch, or both, each a
percentage from 0 to 100. A dimension left out is not checked; without either flag the command
exits 2 before it reads a report or runs a test.
--github-summary writes the markdown table to $GITHUB_STEP_SUMMARY on pass and fail, so a
green build still shows its number. --badge-dir <dir> on check and test writes the verdict as
coverage-badge.svg and coverage-badge.json, coloured by the outcome; the
badge action publishes them in one CI step.
Testing and gating in one step
dotcov test runs dotnet test with Microsoft Code Coverage writing Cobertura into a fresh
TestResults/<run> directory, then prints the table and gates that run like check:
dotcov test tests/MyApp.Tests --min-line 80 --exclude-generated -- -c Release
It passes the coverage options of the runner dotnet test uses in the current directory:
DOTNET_TEST_RUNNER, else test.runner in the nearest global.json, else VSTest. On
Microsoft.Testing.Platform the test project needs Microsoft.Testing.Extensions.CodeCoverage
(TUnit includes it); on VSTest, Microsoft.NET.Test.Sdk brings the Code Coverage collector.
Arguments after -- go to dotnet test unchanged. Its output goes to stdout, so stderr still
starts with the verdict. A failed test run exits 5 with error: and no coverage verdict.
Exit codes
Since 1.7, usage errors exit 2 instead of 5; update scripts accordingly. A missing
path argument exits 2; a supplied nonexistent path exits 5. Invalid upload URLs
are usage errors; HTTP/connection failures remain execution errors. Since 3.0, check and test
without a threshold exit 2, and so does a --source-root no report declares.
check, crap, and test return 0 only for a measured pass:
| Token | Meaning | Exit |
|---|---|---|
PASS: |
met the threshold | 0 |
FAIL: |
below the threshold | 1 |
NODATA: |
the gate lacks the data needed to evaluate: nothing measured, a requested dimension missing, an unscored CRAP method, or a file whose <source> root is unresolved |
3 |
DISABLED: |
both check thresholds are 0, or crap --max-crap is infinite, so the gate cannot fail |
4 |
error: |
unreadable/nonexistent path, parse/size-cap error, upload or badge write failure, failed test run | 5 |
error: or unknown command |
usage: unknown command/flag, invalid value (a threshold outside 0 to 100 included), missing/extra argument, no threshold for check or test, a --source-root no report declares |
2 |
report, diff, and snapshot return 0 when rendering and any requested upload succeed.
A passing gate whose badge cannot be written returns 5; a non-passing gate keeps its code if an
upload or badge write also fails.
Reporting commands do not enforce thresholds. report --threshold affects
presentation, not the exit code. Use check when CI must require measured coverage.
An existing directory with no matching reports is valid empty input for reporting commands;
a supplied nonexistent path or malformed report exits 5. An empty report displays no data in
Markdown and - for percentages in the table. Its JSON has files: [], zero totals, and no
lineRate or branchRate fields. These represent missing measurements, not 0% coverage.
For that same empty directory, check --min-line 1 returns NODATA: and exits 3.
Deciding what to test next
crap scores every method comp² · (1 − cov)³ + comp and sorts worst-first:
$ dotcov crap TestResults/ --exclude-generated --top 5 --max-crap 6
Method Comp Cov % CRAP
----------------------------------------------------------------------------
DotCov.Formatters.MarkdownFormatter.Render 43 100.0% 43.0
DotCov.Tool.DotCovCli.RunAsync 40 100.0% 40.0
DotCov.Tool.DotCovCli.Diff 14 50.0% 38.5
DotCov.CoberturaParser.ConsumeClass 34 100.0% 34.0
DotCov.FileCoverage.MergeWith 32 100.0% 32.0
----------------------------------------------------------------------------
... 250 more methods below (--top 5)
FAIL: worst CRAP 43.0 (max 6) - 69 of 255 methods above threshold
Fully covered code scores its own complexity, fully uncovered code scores comp² + comp — so a
100%-covered 43-branch method still scores 43 and the formula is telling you to split it, not to
test it. The default --max-crap is 30, the original CRAP threshold; the 6 above also caps
complexity, failing any method above complexity 6 however well it is tested. Complexity comes
from coverlet's per-method attribute automatically; for emitters that write none, pass
--metrics from dotnet msbuild /t:Metrics
(Microsoft.CodeAnalysis.Metrics).
The gate needs every method scored. A method without complexity, or without lines, is listed as
unscored in every format, and one such method makes the verdict NODATA (exit 3): it may be
the method above the limit. Emitters without a usable complexity attribute (gcovr
placeholders, ReportGenerator merges, some converters) therefore need --metrics to pass at all.
Flags
| Flag | Effect |
|---|---|
--min-line <n>, --min-branch <n> |
check, test: thresholds from 0 to 100, no default; set one or both |
--exclude-generated |
Skip .g.cs, .designer.cs, /obj/, /bin/, /Migrations/, GlobalUsings.cs, Program.cs |
--exclude-test-code |
Skip test projects and fixtures: *.Tests/, TestSupport/, TestFixtures/. Test code counts unless you set it |
--keep <subs> |
Comma-separated substrings exempt from both exclusions; requires one of them |
--probe-sources |
Several <source> roots: resolve each relative file name against the root that holds it on this machine's disk |
--source-root <root> |
Several <source> roots: resolve relative file names against this declared root |
--pattern <glob> |
Filename to scan for. Default **/*cobertura*.xml, including timestamped MTP reports |
--max-chars <n> |
Per-file XML character cap. Default 50000000; 0 = uncapped |
--format |
table, json, md |
--github-summary |
Append markdown to $GITHUB_STEP_SUMMARY |
--upload <url> |
POST the JSON payload |
--badge-dir <dir> |
check, test: write coverage-badge.svg and coverage-badge.json for every outcome; created if missing |
Commands reject unused flags, --name=value, and extra paths; see dotcov --help.
An active exclusion is named once: stderr lists its rules and every excluded file for table and
markdown output, and JSON output (report --format json, crap --format json, snapshot)
carries excluded and exclusionRules instead.
A report with several <source> roots does not say which root a relative file name belongs to.
By default DotCov never reads the disk to guess: the file is keyed under the first root with a
FileIdentityAmbiguous warning, report prints as usual, and check, crap and test exit
3. --probe-sources restores 2.0's disk probe — its answer depends on the machine running it,
so run it where the sources are checked out — and --source-root names the root anywhere.
dotcov version and dotcov --version print the version. Percentages use 62.0% on every host.
Also in this family
DotCov — the parser as a library, zero dependencies · DotCov.Fallout — Fallout build component
Feedback
Documentation · Issues · MIT
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.7.1 | 33 | 10/19/2026 |
| 4.7.0 | 47 | 10/15/2026 |
| 4.6.0 | 41 | 10/15/2026 |
| 4.5.0 | 42 | 10/15/2026 |
| 4.4.0 | 48 | 10/15/2026 |
| 4.3.2 | 38 | 10/15/2026 |
| 4.3.1 | 52 | 10/15/2026 |
| 4.3.0 | 68 | 10/14/2026 |
| 4.2.0 | 62 | 10/14/2026 |
| 4.1.0 | 71 | 10/14/2026 |
| 4.0.0 | 70 | 10/14/2026 |
| 3.0.1 | 68 | 10/14/2026 |
| 3.0.0 | 81 | 10/13/2026 |
| 2.0.0 | 75 | 10/13/2026 |
| 1.7.1 | 91 | 10/11/2026 |
| 1.7.0 | 140 | 10/11/2026 |
| 1.6.1 | 78 | 10/11/2026 |
| 1.6.0 | 85 | 10/11/2026 |
| 1.5.0 | 80 | 10/11/2026 |
| 1.4.0 | 89 | 10/11/2026 |
DotCov 3.0.0 changes three gate contracts; every number a gate decides on may move.
1. Thresholds are explicit: check, test, the Fallout target and the badge action have no default --min-line 80. Pass --min-line, --min-branch, or both (0 to 100); without either the command exits 2 before reading a report.
2. The CRAP gate needs every method scored: one unscored method makes it NODATA (exit 3). Emitters without a usable complexity attribute need --metrics.
3. File identity is deterministic: several source roots no longer trigger a disk probe; unresolved files make check, crap and test NODATA until --probe-sources or --source-root.
Fixes: contradictory condition detail and empty class summaries no longer inflate branch and line rates; condition identity no longer depends on XML packaging; CRAP rows stay per file and per overload, raising diluted scores; ./src/C.cs and src/C.cs count once; ParseAsync finishes method-only classes.
New: --exclude-test-code. Full notes: https://github.com/ANcpLua/dotcov/blob/main/docs/releases/3.0.0.md