No description
  • Go 97.2%
  • Shell 1.4%
  • Makefile 0.9%
  • Dockerfile 0.5%
Find a file
2026-10-27 17:25:27 +01:00
.github chore(deps): bump dawidd6/action-download-artifact from 25 to 27 (#365) 2026-10-05 10:24:17 +02:00
action/source chore(version): bump to v2.21.0 (#375) 2026-10-27 17:25:27 +01:00
docs chore(docs): add contributing page (#246) 2025-11-19 13:05:47 +01:00
pkg/testcoverage chore: scope package loading to coverage analysis (#374) 2026-10-27 17:08:26 +01:00
.gitignore make: add config for local coverage check 2024-11-19 13:16:36 +01:00
.golangci.yml chore: bump go to v1.27 and modernize lint (#362) 2026-10-03 11:28:28 +02:00
.testcoverage.example.yml feat: add option to exclude single return error checks from coverage (#367) 2026-10-27 14:44:31 +01:00
action.yml chore(version): bump to v2.21.0 (#375) 2026-10-27 17:25:27 +01:00
docker-entrypoint.sh feat(action): add diff threshold input (#330) 2026-07-28 14:28:28 +00:00
Dockerfile chore(deps): bump golang from 1.27.0 to 1.27.1 (#354) 2026-09-07 09:38:40 +00:00
go.mod feat: add option to exclude single return error checks from coverage (#367) 2026-10-27 14:44:31 +01:00
go.sum feat: add option to exclude single return error checks from coverage (#367) 2026-10-27 14:44:31 +01:00
LICENSE update license copyright entity 2024-07-02 14:05:33 +02:00
main.go chore(version): bump to v2.21.0 (#375) 2026-10-27 17:25:27 +01:00
main_config.go feat(action): add diff threshold input (#330) 2026-07-28 14:28:28 +00:00
main_config_test.go feat(action): add diff threshold input (#330) 2026-07-28 14:28:28 +00:00
Makefile chore: bump go to v1.27 and modernize lint (#362) 2026-10-03 11:28:28 +02:00
README.md feat: add option to exclude single return error checks from coverage (#367) 2026-10-27 14:44:31 +01:00

go-test-coverage

test action-test-docker action-test-source lint coverage

Release GHCR pulls

go-test-coverage cover image

go-test-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-test-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 (e.g., ~1 second on this repo).
  • Versatility: Can be used both locally and in CI pipelines.
  • Customizable: Extensive configuration options to fit any project's needs.
  • Stylish Badges: Generate beautiful coverage badges for your repository.
  • Coverage Diff: Detailed comparison of code coverage changes relative to the base branch.
  • Open Source: Free to use and contribute to!

Usage

You can use go-test-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

Here’s an example Makefile with a check-coverage command that runs go-test-coverage locally:

GOBIN ?= $$(go env GOPATH)/bin

.PHONY: install-go-test-coverage
install-go-test-coverage:
	go install github.com/vladopajic/go-test-coverage/v2@latest

.PHONY: check-coverage
check-coverage: install-go-test-coverage
	go test ./... -coverprofile=./cover.out -covermode=atomic -coverpkg=./...
	${GOBIN}/go-test-coverage --config=./.testcoverage.yml

GitHub Workflow

Here’s an example of how to integrate go-test-coverage into a GitHub Actions workflow:

name: Go test coverage check
runs-on: ubuntu-latest
steps:
  - uses: actions/checkout@v3
  - uses: actions/setup-go@v3
  
  - name: generate test coverage
    run: go test ./... -coverprofile=./cover.out -covermode=atomic -coverpkg=./...

  - name: check test coverage
    uses: vladopajic/go-test-coverage@v2
    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)
  # Exclude error checks with a single return statement referencing the error.
  # Only the body is excluded; the condition is still counted.
  # e.g. `if err != nil { return ..., err }`.
  # See "Exclude Single Return Error Checks" below.
  single-return-error-checks: false

# (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

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
...
}

Exclude Single Return Error Checks

Set exclude.single-return-error-checks: true to automatically exclude error checks whose condition is <err> != nil (or nil != <err>), where <err> is a variable implementing error, and whose body contains only a single return statement referencing that error.

Only the body of the if statement is excluded; the condition itself is still counted.

if err != nil {
	return err // excluded
}

if err := foo(); err != nil {
	return nil, fmt.Errorf("doing foo: %w", err) // excluded
}

if val == 0 {
	return errors.New("invalid value") // not excluded: not an error check
}

if err != nil {
	log.Print(err)
	return err // not excluded: body contains multiple statements
}

Generate Coverage Badge

You can easily generate a stylish coverage badge for your repository and embed it in your markdown files. Here’s an example badge: coverage

Instructions for badge creation are available here.

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

⭐ Love this project? Star it!

This tool is still not widely known, and giving the repository a ⭐️ is a simple, cost-free way to help it gain visibility. It’s a win-win for everyone: new users discover a useful tool they might have otherwise missed, and existing users benefit from a larger community where issues get identified sooner, improvements happen faster and new contributions help the project grow.

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 🌞