# Releasing Software

> Use when preparing a release, tagging a version, or when user says "release", "tag", "ship it", "push to production" - ensures all release artifacts are verified before tagging to avoid the retag-four-times failure pattern

- Skill: `majiayu000/releasing-software` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add majiayu000/releasing-software`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/releasing-software/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/releasing-software

---


# Releasing Software

## Overview

**Never tag until CI passes.** Every retag erodes trust and wastes time.

This skill prevents the "tag, watch CI fail, retag, repeat" anti-pattern by establishing a pre-flight checklist that catches issues BEFORE creating the tag.

## The Iron Law

```
NO TAG WITHOUT GREEN CI
```

Run the full verification locally. Fix everything. THEN tag. Not before.

## Pre-Release Checklist

**MANDATORY: Use TodoWrite to create todos for EACH item.**

### 1. Verify Build Paths

Check ALL places that reference your main package:

- [ ] `goreleaser.yml` - `main:` field (common: `./cmd/app` vs `.`)
- [ ] `.github/workflows/*.yml` - any `go build` commands
- [ ] `Makefile` - build targets
- [ ] `Dockerfile` - build commands

```bash
# Find all references to cmd/ or main package paths
grep -r "cmd/" . --include="*.yml" --include="*.yaml" --include="Makefile" --include="Dockerfile"
grep -r "go build" . --include="*.yml" --include="*.yaml" --include="Makefile"
```

### 2. Verify Tests Exist

Go 1.23+ coverage tool fails on packages without tests:

```bash
# Check for test files in each package
find . -name "*_test.go" | wc -l

# If zero, add placeholder tests to EVERY package
```

**Every package needs at least one test file** or CI coverage step fails with `no such tool "covdata"`.

### 3. Verify Local CI Passes

```bash
# Run what CI runs
make test          # or go test ./...
make lint          # or golangci-lint run
make build         # verify it compiles

# If using coverage
make test-coverage
```

### 4. Verify Documentation

- [ ] README.md exists and is current
- [ ] CHANGELOG.md updated (if maintained)
- [ ] Version references updated

### 5. Verify Release Config

- [ ] goreleaser description is correct (not template leftovers)
- [ ] goreleaser homepage URL is correct
- [ ] `.gitignore` includes build artifacts, coverage files

### 6. Verify Clean Git State

```bash
git status                    # Nothing unexpected staged
git diff --stat              # Review all changes
git log --oneline -5         # Verify recent history
```

## Release Procedure

**Only after ALL checks pass:**

```bash
# 1. Commit all changes
git add -A && git commit -m "release: prepare v0.0.X"

# 2. Wait for pre-commit hooks to pass
# If hooks fail, fix and re-commit

# 3. Push and wait for CI
git push origin main

# 4. WAIT FOR CI TO PASS - check status
gh run list --limit 2
# OR watch in browser

# 5. Only after CI is green, create tag
git tag -a v0.0.X -m "v0.0.X"
git push origin v0.0.X

# 6. Verify release workflow completes
gh run list --limit 2
```

## Red Flags - STOP

If you catch yourself doing any of these, STOP:

- Tagging before CI completes
- "CI will probably pass"
- "I'll fix it if it fails"
- Deleting and recreating tags
- Force-pushing tags
- "It's just a minor release"

**All of these mean: Wait for CI. Fix issues. Then tag.**

## Common Failures

| Symptom | Cause | Fix |
|---------|-------|-----|
| `couldn't find main file` | Wrong path in goreleaser | Set `main: .` if main.go at root |
| `no such tool "covdata"` | Package without tests | Add placeholder test to each package |
| Release succeeds but brew fails | Wrong description/homepage | Update goreleaser brews section |
| Had to retag | Tagged before CI passed | WAIT FOR GREEN CI |
| 504 errors in CI | GitHub infra issue | Retry workflow, not a code problem |

## Version Bumping

When incrementing version:

1. **Patch** (0.0.X): Bug fixes, no new features
2. **Minor** (0.X.0): New features, backwards compatible
3. **Major** (X.0.0): Breaking changes

Search codebase for version references:
```bash
grep -r "version" . --include="*.go" --include="*.yml" --include="*.json" | grep -v test | grep -v vendor
```

## Post-Release Verification

After tag is pushed:

```bash
# Watch release workflow
gh run watch

# Verify release assets
gh release view v0.0.X

# Test installation (if applicable)
go install github.com/user/repo@v0.0.X
```

## The Bottom Line

**Retagging is a symptom of rushing.**

The 5 minutes spent on pre-flight checks saves 30 minutes of retag cycles and preserves your release history integrity.

Every tag should be final. If you're deleting tags, you skipped the checklist.

