name: releasing-software description: "Release prep and tagging with pre-flight verification. Use when user says release, tag, ship it, push to production, create release, or bump version."
Releasing Software
Iron Law
NO TAG WITHOUT GREEN CI
Run full verification locally → Fix everything → THEN tag. Never tag before CI passes.
Pre-Release Checklist
| Check | Items | Why |
|---|---|---|
| Build Paths | goreleaser.yml main:, workflows, Makefile, Dockerfile | Wrong path = build failure |
| Test Coverage | Every package has ≥1 test file | Go 1.23+ covdata fails without tests |
| Local CI | make test && make lint && make build | Catch failures before push |
| Docs | README.md, CHANGELOG.md, version refs | Professional releases |
| Release Config | goreleaser description, homepage URL, .gitignore | Proper artifact generation |
| Git State | git status, git diff --stat, git log | Clean history |
Release Procedure
Only after ALL checks pass:
- •Commit:
git add -A && git commit -m "release: prepare vX.Y.Z" - •Wait for pre-commit hooks
- •Push and WAIT:
git push origin main - •Check CI:
gh run list --limit 2 - •Only after green:
git tag -a vX.Y.Z -m "vX.Y.Z" && git push origin vX.Y.Z - •Verify release workflow triggered
Red Flags - STOP IMMEDIATELY
- •Tagging before CI completes
- •"CI will probably pass"
- •Deleting/recreating tags
- •Force-pushing tags
Common Failures
| Symptom | Root Cause | Fix |
|---|---|---|
| "couldn't find main file" | Wrong goreleaser path | Set main: . if main.go at root |
| "no such tool 'covdata'" | Package without tests | Add _test.go with placeholder |
| Had to retag | Tagged before CI passed | WAIT FOR GREEN CI |
| Build fails but tests pass | Wrong build path | Check Makefile/goreleaser match |
Semver Quick Ref
- •Patch (0.0.X): Bug fixes only
- •Minor (0.X.0): New features, backwards compatible
- •Major (X.0.0): Breaking changes
Troubleshooting
bash
# Verify goreleaser config
goreleaser check
# Dry run release
goreleaser release --snapshot --clean
# Check for packages without tests
find . -type d -not -path "*/.*" -exec sh -c 'ls {}/*_test.go 2>/dev/null || echo "No tests: {}"' \;
Remember
Every retag erodes trust. Fix problems before tagging, not after.