Skip to content

Commit be6a469

Browse files
authored
Update generate-release-note.yml
1 parent 0f22efb commit be6a469

File tree

1 file changed

+154
-77
lines changed

1 file changed

+154
-77
lines changed

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

Lines changed: 154 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -3,143 +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)
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.
108

119
permissions:
1210
contents: write
1311
pull-requests: read
1412

1513
jobs:
16-
check-for-release:
14+
check-release-needed:
1715
runs-on: ubuntu-latest
1816
outputs:
19-
should-release: ${{ steps.check.outputs.should-release }}
20-
version: ${{ steps.check.outputs.version }}
21-
tag: ${{ steps.check.outputs.tag }}
22-
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 }}
2321
steps:
2422
- name: Checkout code
2523
uses: actions/checkout@v4
2624
with:
2725
fetch-depth: 0
26+
token: ${{ secrets.GITHUB_TOKEN }}
2827

29-
- name: Check if release is needed
28+
- name: Check if release notes generation is needed
3029
id: check
30+
env:
31+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3132
run: |
32-
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 "")
3342
34-
if [[ -z "${{ github.ref_name }}" ]]; then
35-
echo "No tag name found in the event."
36-
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
3746
exit 0
3847
fi
3948
40-
HAVE_RELEASE=$(gh release view ${{ github.ref_name }} --json tagName --jq '.tagName' 2>/dev/null || echo "")
41-
if [[ -n "$HAVE_RELEASE" ]]; then
42-
echo "Release already exists for tag: ${{ github.ref_name }}"
43-
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
4455
exit 0
4556
fi
4657
47-
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=""
4860
49-
if [[ -z "$MAJOR" || -z "$MINOR" || -z "$PATCH" ]]; then
50-
LATEST_TAG=null
51-
else
52-
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"
5374
fi
5475
55-
echo "should-release=true" >> $GITHUB_OUTPUT
56-
echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT
57-
echo "version=${{ github.ref_name }}" >> $GITHUB_OUTPUT
58-
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
5982
60-
create-release:
61-
needs: check-for-release
62-
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'
6386
runs-on: ubuntu-latest
6487
steps:
6588
- name: Checkout code
6689
uses: actions/checkout@v4
6790
with:
6891
fetch-depth: 0
92+
token: ${{ secrets.GITHUB_TOKEN }}
6993

70-
- name: Generate Release Notes
71-
id: generate_notes
94+
- name: Generate release notes content
95+
id: generate-notes
96+
env:
97+
PACKAGE_NAME: 'solution-forest/inspirecms-core'
7298
run: |
73-
# Get the latest tag
74-
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 }}"
75102
76-
if [ -z "$LATEST_TAG" ]; then
77-
# If no previous tag, get all commits
78-
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)
79110
else
80-
# Get commits since last tag
81-
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)
82113
fi
83114
84-
# Categorize commits
115+
# Initialize categories
85116
BREAKING_CHANGES=""
86-
FEATURES=""
87-
FIXES=""
88-
OTHER=""
89-
90-
while IFS= read -r commit; do
91-
if echo "$commit" | grep -qE "(BREAKING CHANGE|!:)"; then
92-
BREAKING_CHANGES="$BREAKING_CHANGES$commit"$'\n'
93-
elif echo "$commit" | grep -qE "^- feat"; then
94-
FEATURES="$FEATURES$commit"$'\n'
95-
elif echo "$commit" | grep -qE "^- fix"; then
96-
# Skip "Fix styling" commits
97-
if echo "$commit" | grep -qE "Fix styling"; then
98-
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
99152
fi
100-
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'
101167
else
102-
OTHER="$OTHER$commit"$'\n'
168+
OTHER_CHANGES="$OTHER_CHANGES$FORMATTED_COMMIT"$'\n'
103169
fi
104170
done <<< "$COMMITS"
105171
106172
# Build release notes
107-
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
108178
109-
if [ -n "$BREAKING_CHANGES" ]; then
110-
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'
111181
fi
112182
113-
if [ -n "$FEATURES" ]; then
114-
RELEASE_NOTES="$RELEASE_NOTES### ✨ New Features"$'\n'"$FEATURES"$'\n'
183+
if [[ -n "$DOCUMENTATION" ]]; then
184+
RELEASE_NOTES="$RELEASE_NOTES### 📘 Documentation updates"$'\n'"$DOCUMENTATION"$'\n'
115185
fi
116186
117-
if [ -n "$FIXES" ]; then
118-
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'
119189
fi
120190
121-
if [ -n "$OTHER" ]; then
122-
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'
123193
fi
124194
125195
# Add installation instructions
126196
RELEASE_NOTES="$RELEASE_NOTES"$'\n'"## Installation"$'\n\n'
127197
RELEASE_NOTES="$RELEASE_NOTES\`\`\`bash"$'\n'
128-
RELEASE_NOTES="$RELEASE_NOTES""composer require solution-forest/inspirecms-core:^${{ needs.check-for-release.outputs.version }}"$'\n'
198+
RELEASE_NOTES="$RELEASE_NOTES""composer require $PACKAGE_NAME:^$CLEAN_VERSION"$'\n'
129199
RELEASE_NOTES="$RELEASE_NOTES\`\`\`"$'\n\n'
130200
131-
# Output for GitHub (escape newlines)
132-
echo "notes<<EOF" >> $GITHUB_OUTPUT
133-
echo "$RELEASE_NOTES" >> $GITHUB_OUTPUT
134-
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
135209
136-
- name: Create Release
137-
uses: actions/create-release@v1
210+
- name: Create draft release
138211
env:
139212
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
140-
with:
141-
tag_name: ${{ needs.check-for-release.outputs.tag }}
142-
release_name: '${{ needs.check-for-release.outputs.version }}'
143-
body: ${{ steps.generate_notes.outputs.notes }}
144-
draft: true
145-
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)