Skip to content

Commit b105e99

Browse files
feat: add automated release workflow (#1)
- GitHub Actions workflow automatically creates git tags and GitHub releases - Triggers on push to main when .claude-plugin/plugin.json changes - Extracts release notes from CHANGELOG.md [Unreleased] section - Automatically updates CHANGELOG.md (renames [Unreleased] to [version]) - Marks 0.x.x releases as pre-release - Updated CLAUDE.md release process documentation Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 8264c17 commit b105e99

3 files changed

Lines changed: 130 additions & 7 deletions

File tree

.github/workflows/auto-release.yml

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
name: Auto Release
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- '.claude-plugin/plugin.json'
9+
10+
jobs:
11+
create-release:
12+
runs-on: ubuntu-latest
13+
permissions:
14+
contents: write
15+
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 0 # Full history for tagging
21+
22+
- name: Extract version
23+
id: version
24+
run: |
25+
VERSION=$(jq -r '.version' .claude-plugin/plugin.json)
26+
echo "version=$VERSION" >> $GITHUB_OUTPUT
27+
echo "tag=v$VERSION" >> $GITHUB_OUTPUT
28+
echo "Detected version: $VERSION"
29+
30+
- name: Check if tag exists
31+
id: check_tag
32+
run: |
33+
if git rev-parse "v${{ steps.version.outputs.version }}" >/dev/null 2>&1; then
34+
echo "exists=true" >> $GITHUB_OUTPUT
35+
echo "Tag v${{ steps.version.outputs.version }} already exists, skipping release"
36+
else
37+
echo "exists=false" >> $GITHUB_OUTPUT
38+
echo "Tag v${{ steps.version.outputs.version }} does not exist, proceeding with release"
39+
fi
40+
41+
- name: Extract release notes from CHANGELOG
42+
id: changelog
43+
if: steps.check_tag.outputs.exists == 'false'
44+
run: |
45+
# Extract everything between [Unreleased] and the next ## heading
46+
NOTES=$(awk '/## \[Unreleased\]/,/^## \[/ {
47+
if (/^## \[Unreleased\]/) next
48+
if (/^## \[/) exit
49+
print
50+
}' CHANGELOG.md | sed '/^$/d' | head -c 65000)
51+
52+
# If empty, use default message
53+
if [ -z "$NOTES" ]; then
54+
NOTES="Release ${{ steps.version.outputs.version }}"
55+
fi
56+
57+
# Save to file to preserve formatting
58+
echo "$NOTES" > /tmp/release_notes.md
59+
echo "Release notes extracted"
60+
61+
- name: Create GitHub Release
62+
if: steps.check_tag.outputs.exists == 'false'
63+
env:
64+
GH_TOKEN: ${{ github.token }}
65+
run: |
66+
# Determine if pre-release (0.x.x versions)
67+
if [[ "${{ steps.version.outputs.version }}" =~ ^0\. ]]; then
68+
PRERELEASE="--prerelease"
69+
else
70+
PRERELEASE=""
71+
fi
72+
73+
gh release create \
74+
"${{ steps.version.outputs.tag }}" \
75+
--title "${{ steps.version.outputs.version }}" \
76+
--notes-file /tmp/release_notes.md \
77+
$PRERELEASE
78+
79+
- name: Update CHANGELOG
80+
if: steps.check_tag.outputs.exists == 'false'
81+
run: |
82+
VERSION="${{ steps.version.outputs.version }}"
83+
DATE=$(date +%Y-%m-%d)
84+
85+
python3 << 'PYTHON_SCRIPT'
86+
import os
87+
import re
88+
from datetime import date
89+
90+
version = os.environ['VERSION']
91+
release_date = os.environ['DATE']
92+
93+
with open('CHANGELOG.md', 'r') as f:
94+
content = f.read()
95+
96+
# Replace [Unreleased] with [X.Y.Z] - DATE
97+
content = content.replace('## [Unreleased]', f'## [{version}] - {release_date}')
98+
99+
# Add new [Unreleased] section
100+
new_section = "## [Unreleased]\n\n### Added\n\n### Changed\n\n### Fixed\n\n"
101+
# Insert new section before the versioned release
102+
content = content.replace(f'## [{version}] - {release_date}', new_section + f'## [{version}] - {release_date}')
103+
104+
with open('CHANGELOG.md', 'w') as f:
105+
f.write(content)
106+
107+
print("CHANGELOG.md updated")
108+
PYTHON_SCRIPT
109+
110+
- name: Commit CHANGELOG update
111+
if: steps.check_tag.outputs.exists == 'false'
112+
run: |
113+
git config user.name "github-actions[bot]"
114+
git config user.email "github-actions[bot]@users.noreply.github.com"
115+
git add CHANGELOG.md
116+
git commit -m "chore: update CHANGELOG for ${{ steps.version.outputs.version }} release [skip ci]"
117+
git push

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This project uses [Conventional Commits](https://conventionalcommits.org/) and [
77
## [Unreleased]
88

99
### Added
10+
- Automated release workflow - GitHub Actions automatically creates tags and releases when version files are updated on main
1011
- `/sheet-music-publisher` skill - Convert audio to sheet music, create KDP-ready songbooks
1112
- AnthemScore CLI integration for automated transcription
1213
- MuseScore integration for polishing and PDF export

CLAUDE.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,21 @@ This plugin uses [Semantic Versioning](https://semver.org/) with [Conventional C
3737
| `docs:` | `docs: update README` | None |
3838
| `chore:` | `chore: cleanup tests` | None |
3939

40-
**Manual release process:**
41-
1. Update version in `.claude-plugin/plugin.json`
42-
2. Update version in `marketplace.json` (must match plugin.json)
43-
3. Update `CHANGELOG.md` with changes
44-
4. Commit: `chore: release 0.x.0`
45-
5. Create GitHub Release with tag `v0.x.0`
40+
**Release process:**
41+
1. Update entries in `CHANGELOG.md` under `[Unreleased]` as you work
42+
2. When ready to release:
43+
- Update version in `.claude-plugin/plugin.json`
44+
- Update version in `.claude-plugin/marketplace.json` (must match plugin.json)
45+
3. Commit: `chore: release 0.x.0`
46+
4. Push to main → **Automated workflow**:
47+
- Creates git tag `v0.x.0`
48+
- Creates GitHub release with CHANGELOG notes
49+
- Updates CHANGELOG.md (renames [Unreleased][0.x.0] with date)
50+
- Commits CHANGELOG update back to main
4651

4752
**Version files (must stay in sync):**
4853
- `.claude-plugin/plugin.json` - Plugin manifest
49-
- `marketplace.json` - Marketplace listing
54+
- `.claude-plugin/marketplace.json` - Marketplace listing
5055

5156
**Pre-1.0 note:** While version is 0.x.x, the plugin is in early development.
5257

0 commit comments

Comments
 (0)