Skip to content

Commit e63379c

Browse files
gregghclaude
andcommitted
Enhance: Automate release workflow with tag-based trigger
This commit: - Adds tag-based trigger to the release workflow - Adds automatic version extraction from tags - Implements smart changelog generation based on CHANGELOG.md or git log - Adds prerelease detection for tagged releases - Maintains backward compatibility with manual workflow dispatch 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 9feed06 commit e63379c

1 file changed

Lines changed: 67 additions & 11 deletions

File tree

.github/workflows/release.yml

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
name: Release
22

33
on:
4+
push:
5+
tags:
6+
- 'v*'
47
workflow_dispatch:
58
inputs:
69
version:
@@ -14,48 +17,101 @@ on:
1417
jobs:
1518
create-release:
1619
runs-on: ubuntu-latest
20+
permissions:
21+
contents: write
1722
steps:
1823
- uses: actions/checkout@v4
1924
with:
2025
fetch-depth: 0
26+
27+
- name: Get version from tag or input
28+
id: get_version
29+
run: |
30+
if [[ "${{ github.event_name }}" == "push" && "${{ github.ref_type }}" == "tag" ]]; then
31+
# Extract version from the tag (remove 'v' prefix)
32+
VERSION="${GITHUB_REF#refs/tags/v}"
33+
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
34+
echo "Using version from tag: ${VERSION}"
35+
else
36+
# For manual workflow dispatch
37+
VERSION="${{ github.event.inputs.version }}"
38+
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
39+
echo "Using provided version: ${VERSION}"
40+
fi
2141
2242
- name: Validate version format
43+
if: github.event_name == 'workflow_dispatch'
2344
run: |
24-
echo "Validating version format: ${{ github.event.inputs.version }}"
25-
if ! [[ ${{ github.event.inputs.version }} =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
45+
echo "Validating version format: ${{ steps.get_version.outputs.VERSION }}"
46+
if ! [[ ${{ steps.get_version.outputs.VERSION }} =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
2647
echo "::error::Version must be in the format X.Y.Z"
2748
exit 1
2849
fi
2950
3051
- name: Check tag doesn't already exist
52+
if: github.event_name == 'workflow_dispatch'
3153
run: |
32-
if git rev-parse "v${{ github.event.inputs.version }}" >/dev/null 2>&1; then
33-
echo "::error::Tag v${{ github.event.inputs.version }} already exists"
54+
if git rev-parse "v${{ steps.get_version.outputs.VERSION }}" >/dev/null 2>&1; then
55+
echo "::error::Tag v${{ steps.get_version.outputs.VERSION }} already exists"
3456
exit 1
3557
fi
3658
3759
- name: Generate changelog
3860
id: changelog
3961
run: |
40-
# Generate changelog from git history
41-
CHANGELOG=$(git log --pretty=format:"* %s (%an)" $(git describe --tags --abbrev=0 2>/dev/null || echo HEAD~50)..HEAD)
62+
if [[ "${{ github.event_name }}" == "push" && "${{ github.ref_type }}" == "tag" ]]; then
63+
# For tag pushes, extract from CHANGELOG.md if it exists
64+
VERSION="${{ steps.get_version.outputs.VERSION }}"
65+
if grep -q "## \[${VERSION}\]" CHANGELOG.md; then
66+
echo "Extracting changelog for v${VERSION} from CHANGELOG.md"
67+
CHANGELOG_CONTENT=$(awk -v ver="## [${VERSION}]" '
68+
BEGIN { printing = 0; content = ""; }
69+
$0 ~ ver { printing = 1; next; }
70+
/^## \[/ { if (printing == 1) { printing = 0; } }
71+
{ if (printing == 1) content = content $0 "\n"; }
72+
END { print content; }
73+
' CHANGELOG.md)
74+
else
75+
# Fallback to git log if not in CHANGELOG.md
76+
echo "No entry found in CHANGELOG.md, generating from git log"
77+
CHANGELOG_CONTENT=$(git log --pretty=format:"* %s (%an)" $(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo HEAD~50)..HEAD)
78+
fi
79+
else
80+
# For manual workflow, use git log from previous tag to HEAD
81+
echo "Generating changelog from git log"
82+
CHANGELOG_CONTENT=$(git log --pretty=format:"* %s (%an)" $(git describe --tags --abbrev=0 2>/dev/null || echo HEAD~50)..HEAD)
83+
fi
4284
4385
# Format for GitHub Actions output
4486
echo "changelog<<EOF" >> $GITHUB_OUTPUT
45-
echo "$CHANGELOG" >> $GITHUB_OUTPUT
87+
echo "$CHANGELOG_CONTENT" >> $GITHUB_OUTPUT
4688
echo "EOF" >> $GITHUB_OUTPUT
4789
4890
- name: Create changelog file
4991
run: |
50-
echo "# Changelog for v${{ github.event.inputs.version }}" > CHANGELOG.md
92+
echo "# Changelog for v${{ steps.get_version.outputs.VERSION }}" > CHANGELOG.md
5193
echo "" >> CHANGELOG.md
5294
echo "${{ steps.changelog.outputs.changelog }}" >> CHANGELOG.md
5395
96+
- name: Determine if prerelease
97+
id: prerelease
98+
run: |
99+
if [[ "${{ github.event_name }}" == "push" && "${{ github.ref_type }}" == "tag" ]]; then
100+
# Check if tag contains 'alpha', 'beta', 'rc', etc.
101+
if [[ "${{ github.ref_name }}" =~ -alpha|-beta|-rc|dev|test ]]; then
102+
echo "IS_PRERELEASE=true" >> $GITHUB_OUTPUT
103+
else
104+
echo "IS_PRERELEASE=false" >> $GITHUB_OUTPUT
105+
fi
106+
else
107+
echo "IS_PRERELEASE=${{ github.event.inputs.prerelease }}" >> $GITHUB_OUTPUT
108+
fi
109+
54110
- name: Create Release
55111
uses: softprops/action-gh-release@v1
56112
with:
57-
tag_name: v${{ github.event.inputs.version }}
58-
name: v${{ github.event.inputs.version }}
113+
tag_name: ${{ github.event_name == 'push' && github.ref_type == 'tag' && github.ref_name || format('v{0}', steps.get_version.outputs.VERSION) }}
114+
name: v${{ steps.get_version.outputs.VERSION }}
59115
body_path: CHANGELOG.md
60-
prerelease: ${{ github.event.inputs.prerelease }}
116+
prerelease: ${{ steps.prerelease.outputs.IS_PRERELEASE }}
61117
token: ${{ secrets.GITHUB_TOKEN }}

0 commit comments

Comments
 (0)