| name | go-release |
| description | Release engineering for Go projects — GoReleaser v2 with version ldflags into an internal/version package, SBOMs and multi-arch container images, tag-triggered GitHub Actions releases, CI running build/vet/test -race/govulncheck with SHA-pinned actions, and Dependabot coverage for gomod, tools, npm, and Actions. Use when adding GitHub Actions CI for a Go repository; writing a release workflow that publishes Go binaries, SBOMs, and multi-arch container images; setting up GoReleaser for a Go project; stamping version metadata into a Go binary at build time; or adding Dependabot coverage to a Go repo. Not for scaffolding a new Go project or its Makefile. |
| license | MIT |
Go release engineering
Tag-driven releases: pushing a vX.Y.Z tag builds cross-platform archives, checksums, SBOMs, and
multi-arch container images via GoReleaser. CI gates every push; Dependabot keeps everything —
including the action pins — fresh. This layers on the layout and Makefile from the go-project
skill.
1. Stamp version metadata into internal/version
package version
var (
Version = "dev"
Commit = "none"
BuildDate = "unknown"
)
Both make build and GoReleaser inject the same vars at the same import path:
-ldflags "-s -w -X <module>/internal/version.Version={{ .Version }} ..."
Expose the metadata through --version output or a GET /version endpoint.
2. GoReleaser config
Copy templates/goreleaser.yaml to .goreleaser.yaml and replace the
myapp / OWNER/REPO placeholders. What it encodes:
- Static, reproducible binaries:
CGO_ENABLED=0, -trimpath, -s -w, for linux + darwin ×
amd64 + arm64.
tar.gz archives shipping the LICENSE, a checksums.txt, and an SBOM per archive —
generated by the syft pinned in tools/go.mod and invoked via go tool, so nothing needs to
be on PATH.
- A changelog that excludes
docs: / test: / chore: / ci: conventional-commit prefixes.
dockers_v2 multi-arch images (buildx) pushed to GHCR with OCI annotations.
Validate locally with make snapshot (goreleaser release --snapshot --clean) — full build, no
publish.
3. CI workflow
Copy templates/ci.yaml to .github/workflows/ci.yaml. Every push and pull
request runs go build, go vet, go test -race, and govulncheck. Conventions:
- The Go version comes from
go.mod (go-version-file), never hard-coded in the workflow.
- Every action is pinned to a full commit SHA with the tag in a trailing comment — a moved tag
can never change what runs. Dependabot keeps the pins fresh.
permissions: contents: read — the default token does nothing else.
4. Release workflow
Copy templates/release.yaml to .github/workflows/release.yaml. It
triggers on v* tags, checks out with fetch-depth: 0 (GoReleaser needs full history for the
changelog), sets up QEMU + buildx for multi-arch images, logs into GHCR with the built-in
GITHUB_TOKEN, and runs goreleaser release --clean — SBOMs come from the pinned syft via
go tool, so there is no separate syft install step. Cutting a release is exactly: push a semver
tag.
5. Dependabot
Copy templates/dependabot.yaml to .github/dependabot.yaml: daily
checks with a 7-day cooldown, minor + patch bumps grouped into one PR per ecosystem (majors arrive
as individual PRs). tools/go.mod gets its own gomod entry — Dependabot does not descend into
nested modules — so developer-tool bumps never ride along with application dependency PRs, and the
github-actions entry keeps the workflow SHA pins fresh. For the rationale behind each knob and
the full ecosystem matrix (docker, docker-compose, uv, …), see reference.md.