-
-
Notifications
You must be signed in to change notification settings - Fork 0
222 lines (183 loc) · 8.25 KB
/
generate-release-note.yml
File metadata and controls
222 lines (183 loc) · 8.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
name: 'Generate Release Note'
on:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+' # Triggers for tags like 1.0.0, 2.1.3, etc.
- 'v[0-9]+.[0-9]+.[0-9]+' # Triggers for tags like v1.0.0, v2.1.3, etc.
permissions:
contents: write
pull-requests: read
jobs:
check-release-needed:
runs-on: ubuntu-latest
outputs:
should-create-release: ${{ steps.check.outputs.should-create-release }}
current-tag: ${{ steps.check.outputs.current-tag }}
latest-tag: ${{ steps.check.outputs.latest-tag }}
clean-version: ${{ steps.check.outputs.clean-version }}
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Check if release notes generation is needed
id: check
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
CURRENT_TAG="${{ github.ref_name }}"
echo "Current tag: $CURRENT_TAG"
# Remove 'v' prefix if present for version comparison
CLEAN_VERSION="${CURRENT_TAG#v}"
echo "Clean version: $CLEAN_VERSION"
# Check if any release (including draft) already exists for this tag
EXISTING_RELEASE=$(gh release view "$CURRENT_TAG" --json isDraft,tagName 2>/dev/null || echo "")
if [[ -n "$EXISTING_RELEASE" ]]; then
echo "Release (draft or published) already exists for tag: $CURRENT_TAG"
echo "should-create-release=false" >> $GITHUB_OUTPUT
exit 0
fi
# Parse version components
IFS='.' read -r MAJOR MINOR PATCH <<< "$CLEAN_VERSION"
if [[ -z "$MAJOR" || -z "$MINOR" || -z "$PATCH" ]]; then
echo "Invalid version format: $CLEAN_VERSION"
echo "should-create-release=false" >> $GITHUB_OUTPUT
exit 0
fi
# Find the latest tag with same major.minor but lower patch version
LATEST_TAG=""
# Get all tags, filter by pattern, and find the latest one before current
ALL_TAGS=$(git tag --list | grep -E "^v?${MAJOR}\.${MINOR}\.[0-9]+$" | sed 's/^v//' | sort -V)
for tag in $ALL_TAGS; do
IFS='.' read -r tag_major tag_minor tag_patch <<< "$tag"
if [[ "$tag_patch" -lt "$PATCH" ]]; then
LATEST_TAG="$tag"
fi
done
# Add 'v' prefix back if original tag had it
if [[ "$CURRENT_TAG" == v* ]] && [[ -n "$LATEST_TAG" ]]; then
LATEST_TAG="v$LATEST_TAG"
fi
echo "Latest tag found: $LATEST_TAG"
echo "should-create-release=true" >> $GITHUB_OUTPUT
echo "current-tag=$CURRENT_TAG" >> $GITHUB_OUTPUT
echo "latest-tag=$LATEST_TAG" >> $GITHUB_OUTPUT
echo "clean-version=$CLEAN_VERSION" >> $GITHUB_OUTPUT
generate-release-notes:
needs: check-release-needed
if: needs.check-release-needed.outputs.should-create-release == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Generate release notes content
id: generate-notes
env:
PACKAGE_NAME: 'solution-forest/inspirecms-core'
run: |
CURRENT_TAG="${{ needs.check-release-needed.outputs.current-tag }}"
LATEST_TAG="${{ needs.check-release-needed.outputs.latest-tag }}"
CLEAN_VERSION="${{ needs.check-release-needed.outputs.clean-version }}"
echo "Generating release notes for: $CURRENT_TAG"
echo "Previous tag: $LATEST_TAG"
# Get commits between tags
if [[ -z "$LATEST_TAG" ]]; then
echo "No previous tag found, getting all commits"
COMMITS=$(git log --pretty=format:"%s|||%H" --reverse)
else
echo "Getting commits since: $LATEST_TAG"
COMMITS=$(git log ${LATEST_TAG}..HEAD --pretty=format:"%s|||%H" --reverse)
fi
# Initialize categories
BREAKING_CHANGES=""
NEW_FEATURES=""
DOCUMENTATION=""
BUG_FIXES=""
OTHER_CHANGES=""
# Process each commit
while IFS= read -r commit_line; do
if [[ -z "$commit_line" ]]; then
continue
fi
# Split commit message and hash
COMMIT_MSG="${commit_line%|||*}"
COMMIT_HASH="${commit_line#*|||}"
SHORT_HASH="${COMMIT_HASH:0:7}"
# Skip excluded commit patterns
if echo "$COMMIT_MSG" | grep -qiE "^(Create |Update |Fix styling|wip|Merge branch)"; then
continue
fi
# Skip dependabot merge requests
if echo "$COMMIT_MSG" | grep -qiE "Merge pull request.*dependabot/github_actions"; then
continue
fi
# Handle merge pull request commits - get PR title
if echo "$COMMIT_MSG" | grep -qiE "^Merge pull request #[0-9]+"; then
PR_NUMBER=$(echo "$COMMIT_MSG" | grep -oE "#[0-9]+" | sed 's/#//')
if [[ -n "$PR_NUMBER" ]]; then
# Try to get PR title using GitHub CLI
PR_TITLE=$(gh pr view "$PR_NUMBER" --json title --jq '.title' 2>/dev/null || echo "")
if [[ -n "$PR_TITLE" ]]; then
COMMIT_MSG="$PR_TITLE"
fi
fi
fi
# Format commit for release notes
FORMATTED_COMMIT="- $COMMIT_MSG ($SHORT_HASH)"
# Categorize commits
if echo "$COMMIT_MSG" | grep -qiE "(BREAKING CHANGE|breaking:|!:)"; then
BREAKING_CHANGES="$BREAKING_CHANGES$FORMATTED_COMMIT"$'\n'
elif echo "$COMMIT_MSG" | grep -qiE "^(feat|feature):|Merge.*feature/|Add.*feature"; then
NEW_FEATURES="$NEW_FEATURES$FORMATTED_COMMIT"$'\n'
elif echo "$COMMIT_MSG" | grep -qiE "^docs?:|documentation|readme|Update.*\.md"; then
DOCUMENTATION="$DOCUMENTATION$FORMATTED_COMMIT"$'\n'
elif echo "$COMMIT_MSG" | grep -qiE "^(fix|bugfix):|Fix "; then
BUG_FIXES="$BUG_FIXES$FORMATTED_COMMIT"$'\n'
else
OTHER_CHANGES="$OTHER_CHANGES$FORMATTED_COMMIT"$'\n'
fi
done <<< "$COMMITS"
# Build release notes
RELEASE_NOTES="## What's Changed in $CURRENT_TAG"$'\n\n'
if [[ -n "$BREAKING_CHANGES" ]]; then
RELEASE_NOTES="$RELEASE_NOTES### ⚠️ Breaking changes"$'\n'"$BREAKING_CHANGES"$'\n'
fi
if [[ -n "$NEW_FEATURES" ]]; then
RELEASE_NOTES="$RELEASE_NOTES### 🚀 New features"$'\n'"$NEW_FEATURES"$'\n'
fi
if [[ -n "$DOCUMENTATION" ]]; then
RELEASE_NOTES="$RELEASE_NOTES### 📘 Documentation updates"$'\n'"$DOCUMENTATION"$'\n'
fi
if [[ -n "$BUG_FIXES" ]]; then
RELEASE_NOTES="$RELEASE_NOTES### 🐛 Bug fixes"$'\n'"$BUG_FIXES"$'\n'
fi
if [[ -n "$OTHER_CHANGES" ]]; then
RELEASE_NOTES="$RELEASE_NOTES### 🔧 Other Changes"$'\n'"$OTHER_CHANGES"$'\n'
fi
# Add installation instructions
RELEASE_NOTES="$RELEASE_NOTES"$'\n'"## Installation"$'\n\n'
RELEASE_NOTES="$RELEASE_NOTES\`\`\`bash"$'\n'
RELEASE_NOTES="$RELEASE_NOTES""composer require $PACKAGE_NAME:^$CLEAN_VERSION"$'\n'
RELEASE_NOTES="$RELEASE_NOTES\`\`\`"$'\n\n'
RELEASE_NOTES="$RELEASE_NOTES""**Full Changelog**: https://github.com/${{ github.repository }}/compare/${LATEST_TAG}...${CURRENT_TAG}"$'\n'
# Save to output (properly escape for GitHub Actions)
{
echo "notes<<EOF"
echo "$RELEASE_NOTES"
echo "EOF"
} >> $GITHUB_OUTPUT
- name: Create draft release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
CURRENT_TAG="${{ needs.check-release-needed.outputs.current-tag }}"
gh release create "$CURRENT_TAG" \
--title "$CURRENT_TAG" \
--notes "${{ steps.generate-notes.outputs.notes }}" \
--draft \
--latest
echo "Draft release created successfully for $CURRENT_TAG"