DotCov.Tool 3.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet tool install --global DotCov.Tool --version 3.0.0
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local DotCov.Tool --version 3.0.0
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=DotCov.Tool&version=3.0.0
                    
nuke :add-package DotCov.Tool --version 3.0.0
                    

Build

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

There are no supported framework assets in this package.

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
Loading failed

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