golangci-lint init source
Superseded. These jobs now live in
aioz-ci-templateand arrive throughinclude:, pinned to a tag - seeconventional/ci-cd.md. New repositories should include thelibraryprofile rather than paste this file.This template is kept only as a reference for a repository not yet migrated. Two reasons it is not the shape to copy:
- It ends in
<<: *on_code_change, a YAML alias. Anchors are resolved by the YAML parser before GitLab merges anything, so an alias cannot see an anchor in another file - the moment this file isinclude:d, that key silently goes missing. The shared jobs useextends:and!reference, which are resolved after the merge.- It installs golangci-lint with the upstream
install.sh, whose non-anchored asset match downloads...tar.gz.sbom.jsoninstead of...tar.gzand dies on a checksum mismatch. The shared job usesgo install, which verifies through the Go checksum database. It also pins v2.11.4, against v2.12.2 in the template repository.
Copy-paste-ready golangci-lint setup for aioz-map Go service repos (backend, crawler-service, parser-service, and future services). Built from aioz-map/backend's working config, adjusted to actually enforce what team-playbook requires instead of just reporting it.
Contents
| File | What it is |
|---|---|
.golangci.yml | golangci-lint v2 config, the linter set + settings |
lint.gitlab-ci.yml | Blocking GitLab CI lint job |
Makefile.snippet | make lint / lint-fix / fmt targets |
What is still current here
aioz-ci-template runs golangci-lint, but it does not ship a .golangci.yml - the linter set is the repository's own call, and the shared job only requires that the file exists and uses the v2 schema. So one file in this folder is still the thing to copy:
| File | Status |
|---|---|
.golangci.yml | Current. Copy it to the repo root as a starting point |
lint.gitlab-ci.yml | Superseded by the shared lint job. Reference only |
Makefile.snippet | Optional. Handy for running the linter locally; CI does not need it |
Adopting in a repo
Copy
.golangci.ymlto the repo root. Update thedepguardexcluded path (internal/utils/log) to this repo's actual logging-wrapper package if it differs. Keepversion: "2"on the first line - a v2 config in a v1 binary fails withcan't load config: the format is required.Run it locally and fix what it finds, before CI does:
shgo run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2 run ./...Get the
lintjob from the shared template, not from this folder - seeconventional/ci-cd.md.
Why blocking, not report-only
aioz-map/backend's current CI lint job runs with allow_failure: true and --issues-exit-code=0: it never fails the pipeline, only feeds a checkstyle report to Sonar. team-playbook's Definition of Done requires "linter passes with zero warnings" as a Universal gate (conventional/definition-of-done.md), and the README's Code Standards section lists "linter passes before merge" as non-negotiable. lint.gitlab-ci.yml here fixes that gap: it fails the job (and blocks merge) on any finding, while still writing the checkstyle report for Sonar via artifacts: when: always.
Requirement → config traceability
| team-playbook requirement | Source | Enforced by |
|---|---|---|
| "Linter passes before merge" | README.md §6 | lint.gitlab-ci.yml (blocking job, no allow_failure) |
| "Auto-format on save and in CI" | README.md §6 | .golangci.yml formatters: (gofmt, goimports) |
| "No commented-out code" (Universal DoD) | definition-of-done.md | .golangci.yml gocritic (commentedOutCode check) |
| Linter passes with zero warnings (Universal DoD) | definition-of-done.md | lint.gitlab-ci.yml blocking job + make lint locally |
| Package naming: lowercase, snake_case, not plural | conventional/naming.md | .golangci.yml revive (package-naming rule) |
| Variable naming: camelCase unexported, PascalCase exported | conventional/naming.md | .golangci.yml revive (var-naming rule) |
File naming: snake_case, _test.go, main.go entrypoints | conventional/naming.md | .golangci.yml revive (filename-format rule) |
| No swallowed errors ("return errors with context") | README.md §6 | .golangci.yml default errcheck (with narrow Close() exclusions) |
Resource leaks (HTTP bodies, sql.Rows/Stmt, missing rows.Err()) | carried over from aioz-map/backend | bodyclose, sqlclosecheck, rowserrcheck |
Logging via log/slog only | carried over from aioz-map/backend | .golangci.yml depguard (enforce-slog rule) |
Everything not listed above (SonarQube Quality Gate, commit message format, REST API conventions, PR size/review rules) is out of golangci-lint's scope and stays enforced elsewhere (Sonar CI job, commit-msg convention, code review) as described in the main README.md.