Skip to content

Commit 22583ab

Browse files
committed
Update generate-release-note.yml
1 parent 56226dd commit 22583ab

File tree

1 file changed

+156
-80
lines changed

1 file changed

+156
-80
lines changed

.github/workflows/generate-release-note.yml

Lines changed: 156 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -3,144 +3,220 @@ name: 'Generate Release Note'
33
on:
44
push:
55
tags:
6-
- 'v*' # Triggers for any tag starting with 'v' (e.g., v1.0, v2.1.3)
7-
- 'release-*' # Triggers for any tag starting with 'release-'
8-
- '1.*.*' # Triggers for any tag starting with '1.' (e.g., 1.0.0, 1.1.0)
9-
- '2.*.*' # Triggers for any tag starting with '2.' (e.g., 2.0.0, 2.1.0)
10-
- '3.*.*' # Triggers for any tag starting with '3.' (e.g., 3.0.0, 3.1.0)
6+
- '[0-9]+.[0-9]+.[0-9]+' # Triggers for tags like 1.0.0, 2.1.3, etc.
7+
- 'v[0-9]+.[0-9]+.[0-9]+' # Triggers for tags like v1.0.0, v2.1.3, etc.
118

129
permissions:
1310
contents: write
1411
pull-requests: read
1512

1613
jobs:
17-
check-for-release:
14+
check-release-needed:
1815
runs-on: ubuntu-latest
1916
outputs:
20-
should-release: ${{ steps.check.outputs.should-release }}
21-
version: ${{ steps.check.outputs.version }}
22-
tag: ${{ steps.check.outputs.tag }}
23-
latest_tag: ${{ steps.check.outputs.latest_tag }}
17+
should-create-release: ${{ steps.check.outputs.should-create-release }}
18+
current-tag: ${{ steps.check.outputs.current-tag }}
19+
latest-tag: ${{ steps.check.outputs.latest-tag }}
20+
clean-version: ${{ steps.check.outputs.clean-version }}
2421
steps:
2522
- name: Checkout code
26-
uses: actions/checkout@v5
23+
uses: actions/checkout@v4
2724
with:
2825
fetch-depth: 0
26+
token: ${{ secrets.GITHUB_TOKEN }}
2927

30-
- name: Check if release is needed
28+
- name: Check if release notes generation is needed
3129
id: check
30+
env:
31+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3232
run: |
33-
echo "Tag pushed: ${{ github.ref_name }}"
33+
CURRENT_TAG="${{ github.ref_name }}"
34+
echo "Current tag: $CURRENT_TAG"
35+
36+
# Remove 'v' prefix if present for version comparison
37+
CLEAN_VERSION="${CURRENT_TAG#v}"
38+
echo "Clean version: $CLEAN_VERSION"
39+
40+
# Check if any release (including draft) already exists for this tag
41+
EXISTING_RELEASE=$(gh release view "$CURRENT_TAG" --json isDraft,tagName 2>/dev/null || echo "")
3442
35-
if [[ -z "${{ github.ref_name }}" ]]; then
36-
echo "No tag name found in the event."
37-
echo "should-release=false" >> $GITHUB_OUTPUT
43+
if [[ -n "$EXISTING_RELEASE" ]]; then
44+
echo "Release (draft or published) already exists for tag: $CURRENT_TAG"
45+
echo "should-create-release=false" >> $GITHUB_OUTPUT
3846
exit 0
3947
fi
4048
41-
HAVE_RELEASE=$(gh release view ${{ github.ref_name }} --json tagName --jq '.tagName' 2>/dev/null || echo "")
42-
if [[ -n "$HAVE_RELEASE" ]]; then
43-
echo "Release already exists for tag: ${{ github.ref_name }}"
44-
echo "should-release=false" >> $GITHUB_OUTPUT
49+
# Parse version components
50+
IFS='.' read -r MAJOR MINOR PATCH <<< "$CLEAN_VERSION"
51+
52+
if [[ -z "$MAJOR" || -z "$MINOR" || -z "$PATCH" ]]; then
53+
echo "Invalid version format: $CLEAN_VERSION"
54+
echo "should-create-release=false" >> $GITHUB_OUTPUT
4555
exit 0
4656
fi
4757
48-
IFS='.' read -r MAJOR MINOR PATCH <<< "${{ github.ref_name }}"
58+
# Find the latest tag with same major.minor but lower patch version
59+
LATEST_TAG=""
4960
50-
if [[ -z "$MAJOR" || -z "$MINOR" || -z "$PATCH" ]]; then
51-
LATEST_TAG=null
52-
else
53-
LATEST_TAG=$(git tag --list "${MAJOR}.${MINOR}.*" | sort -V | tail -n 1)
61+
# Get all tags, filter by pattern, and find the latest one before current
62+
ALL_TAGS=$(git tag --list | grep -E "^v?${MAJOR}\.${MINOR}\.[0-9]+$" | sed 's/^v//' | sort -V)
63+
64+
for tag in $ALL_TAGS; do
65+
IFS='.' read -r tag_major tag_minor tag_patch <<< "$tag"
66+
if [[ "$tag_patch" -lt "$PATCH" ]]; then
67+
LATEST_TAG="$tag"
68+
fi
69+
done
70+
71+
# Add 'v' prefix back if original tag had it
72+
if [[ "$CURRENT_TAG" == v* ]] && [[ -n "$LATEST_TAG" ]]; then
73+
LATEST_TAG="v$LATEST_TAG"
5474
fi
5575
56-
echo "should-release=true" >> $GITHUB_OUTPUT
57-
echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT
58-
echo "version=${{ github.ref_name }}" >> $GITHUB_OUTPUT
59-
echo "tag=${{ github.ref_name }}" >> $GITHUB_OUTPUT
76+
echo "Latest tag found: $LATEST_TAG"
77+
78+
echo "should-create-release=true" >> $GITHUB_OUTPUT
79+
echo "current-tag=$CURRENT_TAG" >> $GITHUB_OUTPUT
80+
echo "latest-tag=$LATEST_TAG" >> $GITHUB_OUTPUT
81+
echo "clean-version=$CLEAN_VERSION" >> $GITHUB_OUTPUT
6082
61-
create-release:
62-
needs: check-for-release
63-
if: needs.check-for-release.outputs.should-release == 'true'
83+
generate-release-notes:
84+
needs: check-release-needed
85+
if: needs.check-release-needed.outputs.should-create-release == 'true'
6486
runs-on: ubuntu-latest
6587
steps:
6688
- name: Checkout code
67-
uses: actions/checkout@v5
89+
uses: actions/checkout@v4
6890
with:
6991
fetch-depth: 0
92+
token: ${{ secrets.GITHUB_TOKEN }}
7093

71-
- name: Generate Release Notes
72-
id: generate_notes
94+
- name: Generate release notes content
95+
id: generate-notes
96+
env:
97+
PACKAGE_NAME: 'solution-forest/filament-tree'
7398
run: |
74-
# Get the latest tag
75-
LATEST_TAG="${{ needs.check-for-release.outputs.latest_tag }}"
99+
CURRENT_TAG="${{ needs.check-release-needed.outputs.current-tag }}"
100+
LATEST_TAG="${{ needs.check-release-needed.outputs.latest-tag }}"
101+
CLEAN_VERSION="${{ needs.check-release-needed.outputs.clean-version }}"
76102
77-
if [ -z "$LATEST_TAG" ]; then
78-
# If no previous tag, get all commits
79-
COMMITS=$(git log --pretty=format:"- %s (%h)" --reverse)
103+
echo "Generating release notes for: $CURRENT_TAG"
104+
echo "Previous tag: $LATEST_TAG"
105+
106+
# Get commits between tags
107+
if [[ -z "$LATEST_TAG" ]]; then
108+
echo "No previous tag found, getting all commits"
109+
COMMITS=$(git log --pretty=format:"%s|||%H" --reverse)
80110
else
81-
# Get commits since last tag
82-
COMMITS=$(git log ${LATEST_TAG}..HEAD --pretty=format:"- %s (%h)" --reverse)
111+
echo "Getting commits since: $LATEST_TAG"
112+
COMMITS=$(git log ${LATEST_TAG}..HEAD --pretty=format:"%s|||%H" --reverse)
83113
fi
84114
85-
# Categorize commits
115+
# Initialize categories
86116
BREAKING_CHANGES=""
87-
FEATURES=""
88-
FIXES=""
89-
OTHER=""
90-
91-
while IFS= read -r commit; do
92-
if echo "$commit" | grep -qE "(BREAKING CHANGE|!:)"; then
93-
BREAKING_CHANGES="$BREAKING_CHANGES$commit"$'\n'
94-
elif echo "$commit" | grep -qE "^- feat"; then
95-
FEATURES="$FEATURES$commit"$'\n'
96-
elif echo "$commit" | grep -qE "^- fix"; then
97-
# Skip "Fix styling" commits
98-
if echo "$commit" | grep -qE "Fix styling"; then
99-
continue
117+
NEW_FEATURES=""
118+
DOCUMENTATION=""
119+
BUG_FIXES=""
120+
OTHER_CHANGES=""
121+
122+
# Process each commit
123+
while IFS= read -r commit_line; do
124+
if [[ -z "$commit_line" ]]; then
125+
continue
126+
fi
127+
128+
# Split commit message and hash
129+
COMMIT_MSG="${commit_line%|||*}"
130+
COMMIT_HASH="${commit_line#*|||}"
131+
SHORT_HASH="${COMMIT_HASH:0:7}"
132+
133+
# Skip excluded commit patterns
134+
if echo "$COMMIT_MSG" | grep -qiE "^(Create |Update |Fix styling|wip|Merge branch)"; then
135+
continue
136+
fi
137+
138+
# Skip dependabot merge requests
139+
if echo "$COMMIT_MSG" | grep -qiE "Merge pull request.*dependabot/github_actions"; then
140+
continue
141+
fi
142+
143+
# Handle merge pull request commits - get PR title
144+
if echo "$COMMIT_MSG" | grep -qiE "^Merge pull request #[0-9]+"; then
145+
PR_NUMBER=$(echo "$COMMIT_MSG" | grep -oE "#[0-9]+" | sed 's/#//')
146+
if [[ -n "$PR_NUMBER" ]]; then
147+
# Try to get PR title using GitHub CLI
148+
PR_TITLE=$(gh pr view "$PR_NUMBER" --json title --jq '.title' 2>/dev/null || echo "")
149+
if [[ -n "$PR_TITLE" ]]; then
150+
COMMIT_MSG="$PR_TITLE"
151+
fi
100152
fi
101-
FIXES="$FIXES$commit"$'\n'
153+
fi
154+
155+
# Format commit for release notes
156+
FORMATTED_COMMIT="- $COMMIT_MSG ($SHORT_HASH)"
157+
158+
# Categorize commits
159+
if echo "$COMMIT_MSG" | grep -qiE "(BREAKING CHANGE|breaking:|!:)"; then
160+
BREAKING_CHANGES="$BREAKING_CHANGES$FORMATTED_COMMIT"$'\n'
161+
elif echo "$COMMIT_MSG" | grep -qiE "^(feat|feature):|Merge.*feature/|Add.*feature"; then
162+
NEW_FEATURES="$NEW_FEATURES$FORMATTED_COMMIT"$'\n'
163+
elif echo "$COMMIT_MSG" | grep -qiE "^docs?:|documentation|readme|Update.*\.md"; then
164+
DOCUMENTATION="$DOCUMENTATION$FORMATTED_COMMIT"$'\n'
165+
elif echo "$COMMIT_MSG" | grep -qiE "^(fix|bugfix):|Fix "; then
166+
BUG_FIXES="$BUG_FIXES$FORMATTED_COMMIT"$'\n'
102167
else
103-
OTHER="$OTHER$commit"$'\n'
168+
OTHER_CHANGES="$OTHER_CHANGES$FORMATTED_COMMIT"$'\n'
104169
fi
105170
done <<< "$COMMITS"
106171
107172
# Build release notes
108-
RELEASE_NOTES="## What's Changed in ${{ needs.check-for-release.outputs.version }}"$'\n\n'
173+
RELEASE_NOTES="## What's Changed in $CURRENT_TAG"$'\n\n'
174+
175+
if [[ -n "$BREAKING_CHANGES" ]]; then
176+
RELEASE_NOTES="$RELEASE_NOTES### ⚠️ Breaking changes"$'\n'"$BREAKING_CHANGES"$'\n'
177+
fi
109178
110-
if [ -n "$BREAKING_CHANGES" ]; then
111-
RELEASE_NOTES="$RELEASE_NOTES### 💥 Breaking Changes"$'\n'"$BREAKING_CHANGES"$'\n'
179+
if [[ -n "$NEW_FEATURES" ]]; then
180+
RELEASE_NOTES="$RELEASE_NOTES### 🚀 New features"$'\n'"$NEW_FEATURES"$'\n'
112181
fi
113182
114-
if [ -n "$FEATURES" ]; then
115-
RELEASE_NOTES="$RELEASE_NOTES### ✨ New Features"$'\n'"$FEATURES"$'\n'
183+
if [[ -n "$DOCUMENTATION" ]]; then
184+
RELEASE_NOTES="$RELEASE_NOTES### 📘 Documentation updates"$'\n'"$DOCUMENTATION"$'\n'
116185
fi
117186
118-
if [ -n "$FIXES" ]; then
119-
RELEASE_NOTES="$RELEASE_NOTES### 🐛 Bug Fixes"$'\n'"$FIXES"$'\n'
187+
if [[ -n "$BUG_FIXES" ]]; then
188+
RELEASE_NOTES="$RELEASE_NOTES### 🐛 Bug fixes"$'\n'"$BUG_FIXES"$'\n'
120189
fi
121190
122-
if [ -n "$OTHER" ]; then
123-
RELEASE_NOTES="$RELEASE_NOTES### 🔧 Other Changes"$'\n'"$OTHER"$'\n'
191+
if [[ -n "$OTHER_CHANGES" ]]; then
192+
RELEASE_NOTES="$RELEASE_NOTES### 🔧 Other Changes"$'\n'"$OTHER_CHANGES"$'\n'
124193
fi
125194
126195
# Add installation instructions
127196
RELEASE_NOTES="$RELEASE_NOTES"$'\n'"## Installation"$'\n\n'
128197
RELEASE_NOTES="$RELEASE_NOTES\`\`\`bash"$'\n'
129-
RELEASE_NOTES="$RELEASE_NOTES""composer require solution-forest/filament-tree:^${{ needs.check-for-release.outputs.version }}"$'\n'
198+
RELEASE_NOTES="$RELEASE_NOTES""composer require $PACKAGE_NAME:^$CLEAN_VERSION"$'\n'
130199
RELEASE_NOTES="$RELEASE_NOTES\`\`\`"$'\n\n'
131200
132-
# Output for GitHub (escape newlines)
133-
echo "notes<<EOF" >> $GITHUB_OUTPUT
134-
echo "$RELEASE_NOTES" >> $GITHUB_OUTPUT
135-
echo "EOF" >> $GITHUB_OUTPUT
201+
RELEASE_NOTES="$RELEASE_NOTES""**Full Changelog**: https://github.com/${{ github.repository }}/compare/${LATEST_TAG}...${CURRENT_TAG}"$'\n'
202+
203+
# Save to output (properly escape for GitHub Actions)
204+
{
205+
echo "notes<<EOF"
206+
echo "$RELEASE_NOTES"
207+
echo "EOF"
208+
} >> $GITHUB_OUTPUT
136209
137-
- name: Create Release
138-
uses: actions/create-release@v1
210+
- name: Create draft release
139211
env:
140212
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
141-
with:
142-
tag_name: ${{ needs.check-for-release.outputs.tag }}
143-
release_name: '${{ needs.check-for-release.outputs.version }}'
144-
body: ${{ steps.generate_notes.outputs.notes }}
145-
draft: true
146-
prerelease: false
213+
run: |
214+
CURRENT_TAG="${{ needs.check-release-needed.outputs.current-tag }}"
215+
216+
gh release create "$CURRENT_TAG" \
217+
--title "$CURRENT_TAG" \
218+
--notes "${{ steps.generate-notes.outputs.notes }}" \
219+
--draft \
220+
--latest
221+
222+
echo "Draft release created successfully for $CURRENT_TAG"

0 commit comments

Comments
 (0)