CI Quality Gates: Lint, Test, Race, Vuln
Production Go services need a CI pipeline template that blocks merge until format, static analysis, tests, race detection, and vulnerability scans pass.
Busque em todas as páginas da documentação
Production Go services need a CI pipeline template that blocks merge until format, static analysis, tests, race detection, and vulnerability scans pass.
This page is a copy-paste starting point teams can adapt for GitHub Actions, GitLab CI, or Buildkite.
Quick-reference recipe card - copy-paste ready.
# .github/workflows/go-quality.yml
name: go-quality
on: [pull_request]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.26.x'
cache: true
- run: test -z "$(gofmt -l .)"
- run: go vet ./...
- run: go test -race -count=1 ./...
- uses: golangci/golangci-lint-action@v6
with:
version: v2.1.6
- run: go install golang.org/x/vuln/cmd/govulncheck@latest
- run: govulncheck ./...When to reach for this:
Full GitHub Actions workflow with module tidy check:
name: go-quality
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
gate:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache-dependency-path: go.sum
- name: Verify module tidy
run: |
go mod tidy
git diff --exit-code go.mod go.sum
- name: Format
run: test -z "$(gofmt -l .)"
- name: Vet
run: go vet ./...
- name: Test with race detector
run: go test -race -count=1 -timeout=10m ./...
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: v2.1.6
args: --timeout=5m ./...
- name: govulncheck
run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...Branch protection (document for admins):
go-quality / gate status before merge.What this demonstrates:
go.mod automatically.go test -race instruments memory accesses; failures include goroutine stacks..golangci.yml from the repo root. +--> format + vet (fast)
|
PR ----+--> go test -race
|
+--> golangci-lint
|
+--> govulncheckRun independent jobs in parallel matrix for monorepos:
strategy:
matrix:
module: [services/api, services/worker, libs/auth]
steps:
- run: cd ${{ matrix.module }} && go test -race ./...| Gate | Command | Fails on | Typical duration |
|---|---|---|---|
| Format | gofmt -l . | Unformatted .go | seconds |
| Vet | go vet ./... | Suspicious constructs | seconds-minutes |
| Test | go test ./... | Assertion failures | minutes |
| Race | go test -race ./... | Data races | minutes (slower) |
| Lint | golangci-lint run | Linter findings | minutes |
| Vuln | govulncheck ./... | Reachable CVEs | minutes |
| Tidy | go mod tidy + diff | Drift in go.mod/sum | seconds |
# Shard tests in large repos
go test -race -count=1 $(go list ./... | head -20)
# Cache modules in CI (setup-go handles on GitHub)
GOMODCACHE=$RUNNER_TEMP/gomodcache go test ./...Set GOTOOLCHAIN=local or pin go-version explicitly for reproducibility.
-race on every PR job.--timeout=5m and module sharding.integration job with services; still block merge.tools.go.| Alternative | Use When | Don't Use When |
|---|---|---|
| Nightly full scan + PR diff lint | Huge monorepo cost pressure | Security-critical services without nightly |
| Trunk-based without branch protection | Solo maintainer | Teams with multiple merge paths |
| Self-hosted runners with cache | Massive private modules | You cannot secure runner supply chain |
| SonarQube / external SAST | Org mandates central dashboard | Replacing go-native tools entirely |
Yes for merge gates that protect main.
Optional jobs (benchmarks, fuzz) can be informational with separate status.
Fix or quarantine with owner and deadline.
Do not disable race globally for flakes.
Team policy choice.
Many fail only on reachable symbols; others warn on all module hits.
Match go directive in go.mod or use go-version-file.
Matrix test N and N-1 for published libraries.
Target under 10 minutes for developer flow.
Shard modules or use remote cache if longer.
Yes.
Pull requests from forks may not have secrets; use pull_request_target carefully or limit to public checks.
Informational job or coverage gate on critical packages.
Not a substitute for race or lint.
Run on upgrade branches, commit results.
Not on every feature PR unless modernizers are the PR goal.
Check out repo root; run go test ./... from workspace root or matrix per go.mod.
Configure severity in .golangci.yml.
Keep security linters as errors.
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026