GitHub Actions

Record a map for every commit on the default branch, and let pull requests run only the tests their changes affect. The action builds TestDetta itself and keeps the maps in the Actions cache.

Workflow

on:
  push:
    branches: [main]
  pull_request:

permissions:
  contents: read
  actions: read # lets pull requests find the newest coverage map in the Actions cache

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7 # pin to a commit SHA
        with:
          fetch-depth: 0 # TestDetta compares with the merge base
          persist-credentials: false

      - uses: actions/setup-dotnet@v6 # pin to a commit SHA
        with:
          global-json-file: global.json

      # Also the full test run of main. Leave out projects that cannot run here, such as
      # integration tests that need a database; they are then decided by name on pull requests.
      - if: github.event_name == 'push'
        uses: <owner>/testdetta@<sha>
        with:
          mode: record
          projects: |
            tests/Shop.Tests/Shop.Tests.csproj

      - if: github.event_name == 'pull_request'
        uses: <owner>/testdetta@<sha>
        with:
          mode: test
          dotnet-test-args: --logger trx
          license: ${{ secrets.TESTDETTA_LICENSE }}

Full history is required. The action stops with an error on a shallow clone. Check out with fetch-depth: 0.

How the maps get to pull requests

When tests fail while recording, the map is still saved before the job fails, so pull requests keep a map to work with.

Permissions

PermissionWhy
contents: readCheck out the repository.
actions: readList the Actions caches to find the newest map within max-map-age.

With persist-credentials: false a private repository cannot be fetched again later in the job; fetch-depth: 0 already brings every branch, so the base branch is there.

Inputs

InputDefaultDescription
modetest on pull requests (run affected tests), record on the default branch (record coverage maps). Required.
basethe PR's base branchBranch to compare with in test mode. Outside pull requests, set it.
configurationDebugBuild configuration for building and running the tests.
projectsall test projectsRecord mode: .csproj paths, one per line.
parallel1Record mode: test host processes per test project; each still runs its tests one at a time. The suite must tolerate several test processes at once.
no-buildfalseRecord mode: true to record the build an earlier step made with the same configuration.
dotnet-test-argsTest mode: extra dotnet test arguments, separated by spaces.
max-map-age50Test mode: commits a map may be behind the merge base; the changes in between are bridged. 0 uses only an exact map.
drift-fallbackallTest mode: when the changes since an older map include a build file, configuration or a global using, all runs the affected test projects completely; name decides them by name (faster, blind to calls made through configuration or reflection).
github-tokengithub.tokenTest mode: lists the Actions caches to find the newest map (needs actions: read).
licenseTest mode: the license string, from a repository or organization secret such as TESTDETTA_LICENSE. Public repositories need none. Without a valid license every test runs; the job never fails because of it.
working-directory.Any directory inside the repository to analyze.
setup-dotnettrueInstall the .NET 10 SDK TestDetta runs on. Set to false if the job already has it.

Job summary

In test mode, TestDetta writes its selection to the job summary: the changed files and the base it compared with, each test project with whether it ran filtered, completely or not at all and why, the test results, and the license state when it matters. Paths, class names and reasons from the repository are written as code, so file names in a pull request cannot inject links or mentions into the page.

Recording only part of the suite

Recording runs the whole suite once with coverage, which on the default branch is also your full test run. Leave out projects that cannot run on the runner, such as integration tests that need a database, with projects. Pull requests then decide those projects by name.

If an earlier step already built the solution with the same configuration, set no-build: true. For a suite that tolerates several test processes at once, parallel spreads each project's test classes over that many processes.