README
¶
go-coverage
go-coverage is a tool designed to report issues when test coverage falls below a specified threshold, ensuring higher code quality and preventing regressions in test coverage over time.
Why Use go-coverage?
Here are the key features and benefits:
- Quick Setup: Install and configure in just 5 minutes.
- Serverless Operation: No need for external servers, registration, or permissions.
- Eliminates connectivity or server-related failures.
- Data Privacy: All coverage checks are done locally, so no sensitive information leaks to third parties.
- Performance: Lightning-fast execution.
- Versatility: Can be used both locally and in CI pipelines.
- Customizable: Extensive configuration options to fit any project's needs.
- Coverage Diff: Detailed comparison of code coverage changes relative to the base branch.
- Open Source: Free to use and contribute to!
Subcommands
go-coverage provides four focused subcommands:
| Subcommand | Purpose | Exit Code |
|---|---|---|
check |
Check coverage against thresholds | 0 = pass, 1 = thresholds not met, 2 = error |
report |
Generate coverage report | Always 0 (informational) |
diff |
Compare coverage against a baseline | 0 = pass, 1 = threshold not met (if set) |
breakdown |
Save coverage snapshot for later diff | Always 0 |
All subcommands share global flags: --profile, --config, --debug, --source-dir, --log-format, --no-color.
Usage
You can use go-coverage in two ways:
- Locally as part of your development process.
- As a step in your GitHub Workflow.
It's recommended to utilize both options for Go projects.
Local Usage
First, generate a coverage profile:
go test ./... -coverprofile=./cover.out -covermode=atomic -coverpkg=./...
Check coverage thresholds
go-coverage check --config=./.testcoverage.yml
Uses the config file for thresholds. Exits with code 1 if any threshold is not met (suitable for CI gates and pre-commit hooks).
Thresholds can also be specified via flags:
go-coverage check -p cover.out -s . --threshold-file=80 --threshold-total=95
Generate a report
# Text report to stdout
go-coverage report -p cover.out -s .
# Markdown report saved to file
go-coverage report -p cover.out -s . --output-format=markdown --output-file-name=report.md
The report subcommand always exits with code 0, making it useful for informational output without blocking workflows.
Compare coverage (diff)
Save a baseline snapshot, make changes, then compare:
# Step 1: Save current coverage as baseline
go-coverage breakdown -p cover.out -s . -o baseline.json
# ... make changes, re-run tests ...
# Step 2: Compare against baseline
go-coverage diff -p cover.out -s . --base=baseline.json
# With a threshold (exit 1 if coverage dropped by more than 0.5%)
go-coverage diff -p cover.out -s . --base=baseline.json --threshold=-0.5
Makefile
Here's an example Makefile with a check-coverage command that runs go-coverage locally:
GOBIN ?= $$(go env GOPATH)/bin
.PHONY: install-go-coverage
install-go-coverage:
go install github.com/chelout/go-coverage@latest
.PHONY: check-coverage
check-coverage: install-go-coverage
go test ./... -coverprofile=./cover.out -covermode=atomic -coverpkg=./...
${GOBIN}/go-coverage check --config=./.testcoverage.yml
Taskfile
If you use go-task, here's a Taskfile.yml equivalent:
version: "3"
vars:
COVER_PROFILE: cover.out
tasks:
test:
desc: Run tests with coverage
cmds:
- go test ./... -coverprofile={{.COVER_PROFILE}} -covermode=atomic -coverpkg=./...
coverage:check:
desc: Check coverage thresholds
deps: [test]
cmds:
- go run ./cmd/go-coverage/ check --config=./.testcoverage.yml
coverage:report:
desc: Generate coverage report
deps: [test]
cmds:
- go run ./cmd/go-coverage/ report -p {{.COVER_PROFILE}} -s . --output-format=markdown
GitHub Workflow
Here's an example of how to integrate go-coverage into a GitHub Actions workflow:
name: Go test coverage check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- name: generate test coverage
run: go test ./... -coverprofile=./cover.out -covermode=atomic -coverpkg=./...
- name: check test coverage
uses: chelout/go-coverage@v1
with:
config: ./.testcoverage.yml
For detailed information about the GitHub Action, check out this page.
Configuration
Here's an example .testcoverage.yml configuration file:
# (mandatory)
# Path to coverage profile file (output of `go test -coverprofile` command).
#
# For cases where there are many coverage profiles, such as when running
# unit tests and integration tests separately, you can combine all those
# profiles into one. In this case, the profile should have a comma-separated list
# of profile files, e.g., 'cover_unit.out,cover_integration.out'.
profile: cover.out
# Holds coverage thresholds percentages, values should be in range [0-100].
threshold:
# (optional; default 0)
# Minimum coverage percentage required for individual files.
file: 70
# (optional; default 0)
# Minimum coverage percentage required for each package.
package: 80
# (optional; default 0)
# Minimum overall project coverage percentage required.
total: 95
# Holds regexp rules which will override thresholds for matched files or packages
# using their paths.
#
# First rule from this list that matches file or package is going to apply
# new threshold to it. If project has multiple rules that match same path,
# override rules should be listed in order from specific to more general rules.
override:
# Increase coverage threshold to 100% for `foo` package
# (default is 80, as configured above in this example).
- path: ^pkg/lib/foo$
threshold: 100
# Holds regexp rules which will exclude matched files or packages
# from coverage statistics.
exclude:
# Exclude files or packages matching their paths
paths:
- \.pb\.go$ # excludes all protobuf generated files
- ^pkg/bar # exclude package `pkg/bar`
# (optional; default false)
# When true, requires all coverage-ignore annotations to include explanatory comments
force-annotation-comment: false
# If specified, saves the current test coverage breakdown to this file.
#
# Typically, this breakdown is generated only for main (base) branches and
# stored as an artifact. Later, this file can be used in feature branches
# to compare test coverage against the base branch.
breakdown-file-name: ''
diff:
# Path to the test coverage breakdown file from the base branch.
#
# This file is usually generated and stored in the main (base) branch,
# controled via `breakdown-file-name` property.
# When set in a feature branch, it allows the tool to compute and report
# the coverage difference between the current (feature) branch and the base.
base-breakdown-file-name: ''
# Allowed threshold for the test coverage difference (in percentage)
# between the feature branch and the base branch.
#
# By default, this is disabled (set to null). Valid values range from
# -100.0 to +100.0.
#
# Example:
# If set to 0.5, an error will be reported if the feature branch has
# less than 0.5% more coverage than the base.
#
# If set to -0.5, the check allows up to 0.5% less coverage than the base.
threshold: null
# Output configuration.
# Controls the output format and which report sections are visible.
output:
# Output format to use.
# Available formats: text, markdown, json
format: text
# Save report to this file (empty = stdout).
file-name: ''
# Controls visibility of individual report sections.
# Available modes vary by section:
# threshold: show when threshold > 0 or overrides exist
# on-fail: show only when coverage check fails
# auto: show when relevant data is present
# always: always show
# never: never show
show-file-coverage: threshold
show-package-coverage: threshold
show-uncovered-lines: on-fail
show-diff: auto
show-annotations: auto
Exclude Code from Coverage
For cases where there is a code block that does not need to be tested, it can be ignored from coverage statistics by adding the comment // coverage-ignore at the start line of the statement body (right after {).
...
result, err := foo()
if err != nil { // coverage-ignore
return err
}
...
Similarly, the entire function can be excluded from coverage statistics when a comment is found at the start line of the function body (right after {).
func bar() { // coverage-ignore
...
}
CLI Reference
Global Flags
-c, --config string path to config file (.testcoverage.yml)
-p, --profile string path to coverage profile
-d, --debug enable debug output
-s, --source-dir string relative path to source files
--log-format string log output format: auto, console, json (default "auto")
--no-color disable colored log output
check
Check test coverage against thresholds. Exit code 1 if any threshold is not met.
go-coverage check [flags]
Flags:
-f, --threshold-file int file coverage threshold [0-100]
-k, --threshold-package int package coverage threshold [0-100]
-t, --threshold-total int total coverage threshold [0-100]
-o, --github-action-output enable GitHub Action output
--breakdown-file-name save coverage breakdown to file
--diff-base-breakdown-file-name base branch breakdown file for diff
--output-format output format: text, markdown, json
--output-file-name save report to file
report
Generate coverage report without threshold checking. Always exits with code 0.
go-coverage report [flags]
Flags:
--breakdown-file-name save coverage breakdown to file
--diff-base-breakdown-file-name base branch breakdown file for diff
--output-format output format: text, markdown, json
--output-file-name save report to file
diff
Compare current coverage against a baseline breakdown file.
go-coverage diff [flags]
Flags:
--base string path to base branch breakdown file (required)
--threshold float coverage diff threshold (exit 1 if not met)
--output-format output format: text, markdown, json
--output-file-name save report to file
breakdown
Generate a coverage breakdown file (snapshot for later diff).
go-coverage breakdown [flags]
Flags:
-o, --output string output file path (required)
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success (all thresholds met, or informational subcommand) |
| 1 | Coverage check failed (one or more thresholds not met) |
| 2 | Runtime error (invalid config, missing files, etc.) |
Visualise Coverage
Go includes a built-in tool for visualizing coverage profiles, allowing you to see which parts of the code are not covered by tests.
Following command will generate cover.html page with visualized coverage profile:
go tool cover -html=cover.out -o=cover.html
Support the Project
go-coverage is freely available for all users.
Love this project? Give the repository a star to help it gain visibility!
Contribution
All contributions are welcome - whether you're fixing a typo, adding a new feature, or reporting an issue. Feel free to open a pull request or create an issue to contribute!
See the contributing page for more details before opening a PR.
Happy coding