CLI reference
Every command, option and environment variable, with what it does, its default and an example. Run td --help for the short version.
td affected [options] Print the projects and tests a change affects
td test [options] [-- <args>] Run only the tests a change affects
td record [options] Run all tests with coverage and store the map
td license status [options] Check the license and show what it covers
td license install <license|file> Store a license in ~/.testdetta/license
Options for every analysis
These work with affected, test and record.
--base <ref>
The git ref to compare with. TestDetta compares your working tree with the merge base of HEAD and this ref, so commits that landed on the base branch after you branched off are not counted as your changes. Default: origin/main.
td test --base origin/develop
td affected --base HEAD~3 # the last three commits and anything uncommitted
--repo <path>
Any path inside the repository to analyse. Default: the current directory.
td affected --repo ../shop
-v, --verbose and --log-level <level>
Logs go to stderr, so stdout stays machine readable. -v turns on debug logs, which explain every decision: why a project is affected, which member a test class ran, which name a trace followed. --log-level picks any of trace, debug, information, warning (default), error or none; trace adds raw git output.
td affected -v 2> testdetta-debug.log
td test --log-level information
--max-map-age <n>
Use a coverage map recorded up to n first-parent commits before the merge base when there is none at the merge base itself. Changes made in between are bridged: classes that ran any member changed since the map and able to reach your change are selected too. 0 uses only a map recorded at the merge base. Default: 50. See How it decides.
td test --max-map-age 20
--drift-fallback <all|name>
What to do when the changes since an older map include something members cannot describe: a build file, configuration, a global using. all (default) runs the affected test projects completely; name decides them by name, which is faster but blind to calls wired by configuration or reflection.
td test --drift-fallback name
--maps-dir <dir>
Keep coverage maps outside the repository, one folder per commit. record saves to <dir>/<commit>/; affected and test restore the newest one within --max-map-age. Use it on CI systems other than GitHub Actions, with a shared disk or synced object storage. Default: maps live in .testdetta/coverage in the repository.
td record --maps-dir /srv/testdetta-maps/shop
td test --base origin/main --maps-dir /srv/testdetta-maps/shop
td affected
Prints what a change affects and why, without building or running anything.
--format <text|json|paths|commands>
| Format | Output | Use it for |
|---|---|---|
text (default) | Affected projects with the reason, then the test plan | Reading |
json | Every project and test class with its decision, evidence and time estimate | Scripts, dashboards |
paths | One affected test .csproj per line | Feeding another tool |
commands | One dotnet test command per test project, with its filter | Running the tests your own way |
td affected --format json > plan.json
td affected --format paths | xargs -n1 dotnet build
--tests-only
List only the affected test projects, not the production projects on the way.
td test
Builds and runs only the affected tests: a filter per test project when only some classes are affected, the whole project when all are or when a change cannot be narrowed, nothing when none is. Exit code 3 when any test fails.
--dry-run
Print the dotnet test commands instead of running them. A project whose global.json lives in a subfolder is printed as (cd src && dotnet test ...).
--summary-file <path>
Append a Markdown summary: each project's result, which classes ran and why, which were skipped, and the recorded test time saved. Point it at $GITHUB_STEP_SUMMARY in GitHub Actions; the action does this for you. See an example.
td test --summary-file "$GITHUB_STEP_SUMMARY"
-- <dotnet test arguments>
Everything after -- is passed to every dotnet test call.
td test -- -c Release --logger trx
td test -- --no-restore
td record
Runs every test with coverage and writes one map per test project to .testdetta/coverage (or --maps-dir). Run it on your default branch; it is also that branch's full test run. Exit code 3 when tests fail; the maps are still written, and the failing classes are always selected later.
-c, --configuration <name>
Build configuration. Default: Debug.
-f, --framework <tfm>
Target framework to record in a multi-targeted test project. Default: the project's first target framework.
td record -f net10.0
--project <path>
Record only this test project, relative to the repository root; repeat it for several. Leave out projects that cannot run in CI, such as integration tests that need a database; they are then decided by name.
td record --project tests/Shop.Tests/Shop.Tests.csproj --project tests/Api.Tests/Api.Tests.csproj
--parallel <n>
Spread each project's test classes over n test processes to record faster. Each process still runs its tests one at a time. Your suite must tolerate several test processes at once (no fixed ports or shared files). Default: 1.
--no-build
Record the output of an earlier build with the same configuration instead of building again.
dotnet build -c Release
td record -c Release --no-build
td license
td license status checks the license the way td test would and prints what it covers: licensee, seats, active committers over the last 30 days, the bot list, scopes, the end date. It sends no personal data anywhere. td license install <license|file> stores a license in ~/.testdetta/license, for machines where no CI secret can hold it. See License.
Environment variables
| Variable | What it does |
|---|---|
TESTDETTA_LICENSE | The license string, from a CI secret. |
TESTDETTA_LICENSE_FILE | A file holding the license string. |
TESTDETTA_LICENSE_REFRESH=off | Turns off the daily license refresh, for networks that cannot reach the license service. |
TESTDETTA_LICENSE_SCOPE | The repository the license must cover, when the origin remote does not name it (a local mirror, for example). |
HTTPS_PROXY | Proxy for the license refresh. |
Exit codes
| Code | Meaning |
|---|---|
0 | Success, including "no tests needed". |
1 | The analysis failed: git, the file system or a project file. |
2 | Invalid command line. |
3 | Tests failed (test and record). |