From f060bad9e054a5a5877a10a908d9c874f0229437 Mon Sep 17 00:00:00 2001 From: Miha Lunar Date: Sat, 20 Jun 2026 14:22:21 +0200 Subject: [PATCH 1/5] Add release skill for agents --- .agents/skills/release.md | 236 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 .agents/skills/release.md diff --git a/.agents/skills/release.md b/.agents/skills/release.md new file mode 100644 index 0000000..b990278 --- /dev/null +++ b/.agents/skills/release.md @@ -0,0 +1,236 @@ +--- +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. This is a superset of +[`RELEASE_CHECKLIST.md`](./RELEASE_CHECKLIST.md) — use it as the primary +source of truth for release automation. + +## 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" +``` + +```bash +# CI must be passing on current HEAD +curl -s "https://api.github.com/repos/SmilyOrg/photofield/commits/$(git rev-parse HEAD)/check-runs" | grep -oP '"conclusion":"[^"]*"' | grep -v '"success"' && echo "CI FAILING" || echo "CI 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 + 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 +# Returns "true" if any entry is minor-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 + +```bash +git tag -d "$NEXT" +git push origin :refs/tags/$NEXT +git reset --hard HEAD~1 +git push -f 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. From 4cbb2555196d60e26ac358644ece40d39693168d Mon Sep 17 00:00:00 2001 From: Miha Lunar Date: Sat, 20 Jun 2026 14:35:46 +0200 Subject: [PATCH 2/5] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .agents/skills/release.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.agents/skills/release.md b/.agents/skills/release.md index b990278..8164451 100644 --- a/.agents/skills/release.md +++ b/.agents/skills/release.md @@ -28,7 +28,7 @@ git diff-index --quiet HEAD -- || echo "NOT CLEAN" ```bash # CI must be passing on current HEAD -curl -s "https://api.github.com/repos/SmilyOrg/photofield/commits/$(git rev-parse HEAD)/check-runs" | grep -oP '"conclusion":"[^"]*"' | grep -v '"success"' && echo "CI FAILING" || echo "CI PASSING" +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. @@ -45,7 +45,7 @@ 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 +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" @@ -77,8 +77,8 @@ PATCH=$(echo "$CURRENT" | cut -d. -f3) Check if any entry is a minor-bump kind: ```bash -# Returns "true" if any entry is minor-bump -grep -l -E '^kind: (Breaking Changes|Added|Removed|Deprecated)' .changes/unreleased/*.yaml 2>/dev/null | grep -qv '^$' && echo "MINOR" || echo "PATCH" +# 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 From 31faf37340167b38f7ace0c68a77246c88154abb Mon Sep 17 00:00:00 2001 From: Miha Lunar Date: Sat, 20 Jun 2026 14:36:36 +0200 Subject: [PATCH 3/5] Remove reference to RELEASE_CHECKLIST.md --- .agents/skills/release.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.agents/skills/release.md b/.agents/skills/release.md index 8164451..4e3ff9b 100644 --- a/.agents/skills/release.md +++ b/.agents/skills/release.md @@ -8,9 +8,7 @@ description: >- # Photofield Release Process -Follow these steps to create a new Photofield release. This is a superset of -[`RELEASE_CHECKLIST.md`](./RELEASE_CHECKLIST.md) — use it as the primary -source of truth for release automation. +Follow these steps to create a new Photofield release. ## 1. Prerequisites From e6d81e0d372d45239bc32fdbc933950aacf5a3d0 Mon Sep 17 00:00:00 2001 From: Miha Lunar Date: Sat, 20 Jun 2026 14:37:02 +0200 Subject: [PATCH 4/5] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .agents/skills/release.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.agents/skills/release.md b/.agents/skills/release.md index 4e3ff9b..5a51332 100644 --- a/.agents/skills/release.md +++ b/.agents/skills/release.md @@ -21,7 +21,7 @@ git branch --show-current | grep -q '^main$' ```bash # Working directory must be clean -git diff-index --quiet HEAD -- || echo "NOT CLEAN" +git diff-index --quiet HEAD -- || { echo "NOT CLEAN"; exit 1; } ``` ```bash From 2166b5258204b4b43471f6de8173ce2a12526e98 Mon Sep 17 00:00:00 2001 From: Miha Lunar Date: Sat, 20 Jun 2026 14:55:03 +0200 Subject: [PATCH 5/5] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .agents/skills/release.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.agents/skills/release.md b/.agents/skills/release.md index 5a51332..3673dae 100644 --- a/.agents/skills/release.md +++ b/.agents/skills/release.md @@ -192,13 +192,13 @@ git tag -d "$NEXT" git reset --hard HEAD~1 ``` -### After push +### After push (Only With Explicit Approval) ```bash git tag -d "$NEXT" git push origin :refs/tags/$NEXT git reset --hard HEAD~1 -git push -f origin main +git push --force-with-lease origin main ``` Then fix the issue and restart from §6.