Skip to content

Advanced Configuration

This page covers advanced configuration options for complex workflows.

For projects with separate integration tests, coverctl can build test binaries and run them with GOCOVERDIR:

integration:
enabled: true
packages: ["./internal/integration/..."]
run_args: ["-test.run", "TestIntegration"]
cover_dir: ".cover/integration"
profile: ".cover/integration.out"
FieldDescriptionDefault
enabledEnable integration test coveragefalse
packagesPackage patterns to build["./..."]
run_argsArguments passed to test binary[]
cover_dirDirectory for raw coverage data.cover/integration
profileOutput profile path.cover/integration.out
  1. Builds test binaries with go test -c -covermode=atomic
  2. Runs binaries with GOCOVERDIR environment variable
  3. Converts raw data to profile with go tool covdata
  4. Merges with unit test coverage
integration:
enabled: true
packages:
- "./test/integration/..."
- "./test/e2e/..."
run_args:
- "-test.run"
- "TestIntegration"
- "-test.v"
cover_dir: ".cover/integration-data"
profile: ".cover/integration.out"

Only check coverage for files changed since a git ref:

diff:
enabled: true
base: origin/main
FieldDescriptionDefault
enabledEnable diff-based filteringfalse
baseGit ref to compare againstorigin/main
  • Pull requests: Only check files in the PR
  • Feature branches: Focus on changed code
  • Incremental improvement: Don’t fail on legacy code
Terminal window
# Override config diff setting
coverctl report --diff origin/develop
.coverctl.yaml
diff:
enabled: false # Disabled by default
base: origin/main
# CI for PRs enables diff mode
# coverctl check --diff origin/main

Combine multiple coverage profiles into a single analysis:

merge:
profiles:
- ".cover/unit.out"
- ".cover/integration.out"
- ".cover/e2e.out"
Terminal window
coverctl report \
-p unit.out \
--merge integration.out \
--merge e2e.out
  • Profiles are merged by file and line
  • Higher coverage wins (if both profiles cover a line, it’s counted as covered)
  • All profiles must use the same coverage mode (atomic or set)

Enable in-code annotations to override coverage behavior:

annotations:
enabled: true

Exclude a file from coverage:

// coverctl:ignore
package generated
// This entire file is excluded from coverage analysis

Assign a file to a specific domain:

// coverctl:domain=critical
package validator
// This file is assigned to the "critical" domain
// regardless of its path

Annotations must be at the package level (before the package declaration):

// coverctl:ignore
// coverctl:domain=core
package mypackage
import "fmt"

version: 1
policy:
default:
min: 75
domains:
- name: core
match: ["./internal/core/..."]
min: 85
- name: api
match: ["./internal/api/..."]
min: 80
files:
- match: ["internal/core/payments/*.go"]
min: 95
exclude:
- "**/generated/**"
- "**/mocks/**"
# Diff-based coverage for PRs
diff:
enabled: false
base: origin/main
# Integration test coverage
integration:
enabled: true
packages: ["./test/integration/..."]
run_args: ["-test.v"]
cover_dir: ".cover/integration"
profile: ".cover/integration.out"
# Merge unit and integration profiles
merge:
profiles:
- ".cover/integration.out"
# Enable code annotations
annotations:
enabled: true

Use different configs for different environments:

Terminal window
# Development: lenient
coverctl check -c .coverctl.dev.yaml
# CI: strict
coverctl check -c .coverctl.ci.yaml
.coverctl.dev.yaml
version: 1
policy:
default:
min: 50
domains:
- name: core
match: ["./internal/core/..."]
min: 70
.coverctl.ci.yaml
version: 1
policy:
default:
min: 75
domains:
- name: core
match: ["./internal/core/..."]
min: 85
diff:
enabled: true
base: origin/main