diff --git a/.agents/skills/release.md b/.agents/skills/release.md new file mode 100644 index 0000000..3673dae --- /dev/null +++ b/.agents/skills/release.md @@ -0,0 +1,234 @@ +--- +name: photofield-release +description: >- + Follow the Photofield release process: batch changelog entries, create the + release commit and tag, and push. Use when the user says "release", "cut a + release", "create a release", or "prepare vX.Y.Z". Always ask before pushing. +--- + +# Photofield Release Process + +Follow these steps to create a new Photofield release. + +## 1. Prerequisites + +Before starting, verify all of these: + +```bash +# Must be on main +git branch --show-current | grep -q '^main$' +``` + +```bash +# Working directory must be clean +git diff-index --quiet HEAD -- || { echo "NOT CLEAN"; exit 1; } +``` + +```bash +# CI must be passing on current HEAD +curl -s "https://api.github.com/repos/SmilyOrg/photofield/commits/$(git rev-parse HEAD)/status" | grep -q '"state":"success"' && echo "CI PASSING" || echo "CI NOT PASSING" +``` + +If any check fails, stop and report the issue to the user. Do not proceed. + +## 2. Check for Unreleased Changes + +```bash +ls -la .changes/unreleased/ +``` + +If the directory contains only `.gitkeep`, there are no unreleased entries. +Tell the user: *"No unreleased changelog entries found. Nothing to release."* + +List each entry for the user (read the YAML files): + +```bash +for f in .changes/unreleased/*.yaml; do [ -e "$f" ] || continue + kind=$(grep '^kind:' "$f" | sed 's/kind: //') + body=$(grep '^body:' "$f" | sed 's/body: //') + echo "- [$kind] $body" +done +``` + +## 3. Determine Next Version + +Changie's auto-bump rules (from `.changie.yaml`): + +| Kind | Bump type | Semantic meaning (at 0.x) | +|--------------------|-----------|---------------------------| +| `Breaking Changes` | minor | `0.X.0 → 0.(X+1).0` | +| `Added` | minor | `0.X.0 → 0.(X+1).0` | +| `Removed` | minor | `0.X.0 → 0.(X+1).0` | +| `Deprecated` | minor | `0.X.0 → 0.(X+1).0` | +| `Fixed` | patch | `0.X.Y → 0.X.(Y+1)` | +| `Security` | patch | `0.X.Y → 0.X.(Y+1)` | + +**Rule:** If *any* entry is a minor-bump kind, bump **minor**. Otherwise bump **patch**. + +```bash +CURRENT=$(changie latest | sed 's/^v//') +MAJOR=$(echo "$CURRENT" | cut -d. -f1) +MINOR=$(echo "$CURRENT" | cut -d. -f2) +PATCH=$(echo "$CURRENT" | cut -d. -f3) +``` + +Check if any entry is a minor-bump kind: + +```bash +# Sets BUMP to "MINOR" if any entry is a minor-bump kind, otherwise "PATCH" +BUMP=$(grep -l -E '^kind: (Breaking Changes|Added|Removed|Deprecated)' .changes/unreleased/*.yaml 2>/dev/null | grep -qv '^$' && echo "MINOR" || echo "PATCH") +``` + +```bash +if [ "$BUMP" = "MINOR" ]; then + NEXT="v${MAJOR}.$((MINOR+1)).0" +else + NEXT="v${MAJOR}.${MINOR}.$((PATCH+1))" +fi +``` + +## 4. Ask the User + +Show the user: + +- Current version (`$CURRENT`) +- Unreleased entries (list each kind + body) +- Suggested next version (`$NEXT`) +- Suggested release title (see §5) + +**Do not proceed until the user confirms.** + +## 5. Set Release Title + +Replace the default date-based title with a descriptive one: + +| Release type | Title convention | +|---|---| +| Patch | `"Security patches"`, `"Bug fixes and dependency updates"`, `"Stability improvements"` | +| Minor | Short phrase summarizing the main feature(s) | + +Example edit for `.changes/$NEXT.md`: + +```yaml +oldText: "## [$NEXT] - 2026-06-16" +newText: "## [$NEXT] - Security patches" +``` + +## 6. Batch and Merge + +```bash +# Merge unreleased fragments into version file +changie batch "$NEXT" + +# Review the generated file +cat .changes/$NEXT.md + +# Set a descriptive title (see §5) +# Use edit to replace the title line in .changes/$NEXT.md + +# Merge into CHANGELOG.md +changie merge +``` + +## 7. Commit and Tag + +⚠️ The `task release` target has `changie batch` and `changie merge` +**commented out** — it expects the agent to run them first. Do **not** run +`task release` (it will fail on a dirty tree). + +```bash +git add CHANGELOG.md .changes/$NEXT.md +git commit -m "Release $NEXT" +git tag -a "$NEXT" -m "Release $NEXT" +``` + +## 8. Review + +```bash +git show HEAD +task release:changelog +``` + +Verify: +- Changelog looks correct and well-formatted +- Tag message matches +- Commit only contains expected files (CHANGELOG.md + .changes/$NEXT.md) + +Show the review output to the user. + +## 9. Push (Only With Approval) + +**Always ask before pushing.** Show: + +``` +Release ready to push: +- Commit: — Release $NEXT +- Tag: $NEXT +- Changelog: + +Push? (yes/no) +``` + +Once confirmed: + +```bash +git push +git push --tags +``` + +Then report: + +> Release pushed ✓ +> - Commit: `` → `main` +> - Tag: `$NEXT` +> - CI running: https://github.com/SmilyOrg/photofield/actions + +## 10. Undo Procedures + +### Before push + +```bash +git tag -d "$NEXT" +git reset --hard HEAD~1 +``` + +### After push (Only With Explicit Approval) + +```bash +git tag -d "$NEXT" +git push origin :refs/tags/$NEXT +git reset --hard HEAD~1 +git push --force-with-lease origin main +``` + +Then fix the issue and restart from §6. + +## Quick Reference + +| Command | Purpose | +|---------|---------| +| `changie latest` | Get current latest version | +| `ls .changes/unreleased/` | List unreleased entries | +| `changie batch ` | Batch entries into version file | +| `changie merge` | Merge into CHANGELOG.md | +| `changie new -k -b ` | Create a changelog entry inline | +| `git add CHANGELOG.md .changes/.md` | Stage for commit | +| `git commit -m "Release "` | Create release commit | +| `git tag -a -m "Release "` | Create annotated tag | +| `git push && git push --tags` | Push release | +| `task release:changelog` | Preview changelog | +| `task release:undo` | Undo last release (only if not pushed) | + +## Common Pitfalls + +1. **Dirty working directory** — `task release` will fail. Stage and commit + changie outputs first. +2. **Wrong version bump** — If you have *any* minor-bump entries but only bump + patch, the version is wrong. Always check all entry kinds. +3. **Missing `.changes/.md`** — This file must be committed alongside + `CHANGELOG.md`. +4. **Changie `-e` flag** — `changie new -e` opens an editor. Use `-b` to set + body inline: `changie new -k Fixed -b "Fix description"`. +5. **`git push` bypasses branch rules** — The repo requires PRs for non-release + commits. The release commit is exempted (remote logs "Bypassed rule + violations for refs/heads/main"). This is expected.