Skip to content

Commit e4587b0

Browse files
Copilotelenafuengar
andcommitted
Improve release notes workflow with unreleased section and documentation
Co-authored-by: elenafuengar <[email protected]>
1 parent 7715bc0 commit e4587b0

File tree

2 files changed

+188
-63
lines changed

2 files changed

+188
-63
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Automated Release Notes Workflow
2+
3+
This document explains how the automated release notes generation workflow works.
4+
5+
## Overview
6+
7+
The `update_release_notes.yml` workflow automatically updates the `release.md` file whenever:
8+
- Commits are pushed to the `main` branch
9+
- Pull requests are opened, synchronized, or reopened targeting the `main` branch
10+
11+
## How It Works
12+
13+
### Commit Range Detection
14+
15+
- **For Pull Requests**: Analyzes commits between the PR base and head
16+
- **For Push Events**: Analyzes commits since the last tag, or last 50 commits if no tags exist
17+
18+
### Categorization
19+
20+
The workflow categorizes commits based on conventional commit prefixes:
21+
22+
- **🚀 Features**: Commits starting with `feature:` or `feat:`
23+
- **🧪 Tests**: Commits starting with `test:`
24+
- **📚 Documentation**: Commits starting with `docs:`
25+
- **⚙️ Build & Compatibility**: Commits starting with `build:` or `ci:`
26+
- **🐛 Bugfixes**: Commits starting with `fix:` or `bugfix:`
27+
- **🎨 Style**: Commits starting with `style:`
28+
29+
### Release Notes Structure
30+
31+
The workflow generates an "Unreleased" section at the top of `release.md` with:
32+
33+
1. **New Features**: List of feature commits
34+
2. **Other Tag Highlights**: Organized by category (Tests, Docs, Build)
35+
3. **Bugfixes**: List of bugfix commits
36+
4. **Full Changelog**: Statistics table showing commit distribution and complete commit list
37+
38+
### Workflow Behavior
39+
40+
1. **On Push to Main**: The workflow commits and pushes the updated `release.md` directly to the main branch
41+
2. **On Pull Request**: The workflow commits the updated `release.md` to the PR branch
42+
43+
The commit message includes `[skip ci]` for push events to prevent triggering the workflow recursively.
44+
45+
## Using Conventional Commit Messages
46+
47+
To take full advantage of automatic categorization, use conventional commit prefixes:
48+
49+
```bash
50+
# Examples
51+
git commit -m "feat: add new GPU acceleration support"
52+
git commit -m "fix: resolve memory leak in solver"
53+
git commit -m "docs: update installation guide"
54+
git commit -m "test: add unit tests for geometry module"
55+
git commit -m "style: format code with black"
56+
git commit -m "build: update numpy dependency"
57+
```
58+
59+
## Manual Release Process
60+
61+
When you're ready to publish a new release:
62+
63+
1. Review the "Unreleased" section in `release.md`
64+
2. Manually edit it to:
65+
- Change "# Unreleased" to "# v{version}"
66+
- Add a descriptive summary of the release
67+
- Organize and expand the automatically generated content
68+
- Add any additional sections (e.g., "New Contributors")
69+
3. Commit the changes
70+
4. Tag the release using `release.sh` or manually
71+
72+
The next time the workflow runs, it will create a new "Unreleased" section above your versioned release.
73+
74+
## Disabling the Workflow
75+
76+
If you need to temporarily disable automatic release notes:
77+
78+
1. Rename the workflow file or move it to a different directory
79+
2. Or add a condition to skip the workflow in certain cases
80+
81+
## Troubleshooting
82+
83+
- **No changes detected**: The workflow only commits if there are actual changes to `release.md`
84+
- **Permission errors**: Ensure the workflow has `contents: write` permission
85+
- **Commit range issues**: For repositories with shallow clones, increase fetch-depth in checkout action

.github/workflows/update_release_notes.yml

Lines changed: 103 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -39,86 +39,109 @@ jobs:
3939
HEAD_REF="${{ github.event.pull_request.head.sha }}"
4040
COMMIT_RANGE="${BASE_REF}..${HEAD_REF}"
4141
else
42-
# For push events, use the last 20 commits
43-
COMMIT_RANGE="HEAD~20..HEAD"
42+
# For push events, get the last tag and use commits since then
43+
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
44+
if [ -n "$LAST_TAG" ]; then
45+
COMMIT_RANGE="${LAST_TAG}..HEAD"
46+
else
47+
# If no tags, use last 50 commits
48+
COMMIT_RANGE="HEAD~50..HEAD" 2>/dev/null || COMMIT_RANGE="HEAD"
49+
fi
4450
fi
4551
46-
# Create a temporary file for the new release notes
47-
cat > /tmp/new_release_section.md << 'EOF'
48-
# v${VERSION}
52+
echo "Processing commits in range: ${COMMIT_RANGE}"
53+
54+
# Count total commits in range
55+
TOTAL_COMMITS=$(git log ${COMMIT_RANGE} --oneline 2>/dev/null | wc -l || echo 0)
56+
57+
if [ ${TOTAL_COMMITS} -eq 0 ]; then
58+
echo "No new commits to process"
59+
exit 0
60+
fi
61+
62+
# Create a temporary file for the unreleased section
63+
cat > /tmp/unreleased_section.md << 'EOF'
64+
# Unreleased
4965
50-
This release includes updates from recent commits.
66+
This section contains updates that will be included in the next release.
5167
5268
---
5369
5470
## 🚀 New Features
5571
5672
EOF
5773
58-
# Process commits and categorize them
59-
echo "Processing commits in range: ${COMMIT_RANGE}"
60-
6174
# Extract feature commits
62-
git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" --grep="^feature:" --grep="^feat:" -i > /tmp/features.txt || true
75+
git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" --grep="^feature:" --grep="^feat:" -i 2>/dev/null > /tmp/features.txt || true
6376
if [ -s /tmp/features.txt ]; then
64-
cat /tmp/features.txt >> /tmp/new_release_section.md
77+
cat /tmp/features.txt >> /tmp/unreleased_section.md
6578
else
66-
echo "* No new features in this update" >> /tmp/new_release_section.md
79+
echo "* No new features yet" >> /tmp/unreleased_section.md
6780
fi
6881
69-
echo "" >> /tmp/new_release_section.md
70-
echo "---" >> /tmp/new_release_section.md
71-
echo "" >> /tmp/new_release_section.md
72-
echo "## 💗 Other Tag Highlights" >> /tmp/new_release_section.md
73-
echo "" >> /tmp/new_release_section.md
74-
echo "* 🔁 **Tests**" >> /tmp/new_release_section.md
82+
echo "" >> /tmp/unreleased_section.md
83+
echo "---" >> /tmp/unreleased_section.md
84+
echo "" >> /tmp/unreleased_section.md
85+
echo "## 💗 Other Tag Highlights" >> /tmp/unreleased_section.md
86+
echo "" >> /tmp/unreleased_section.md
87+
echo "* 🔁 **Tests**" >> /tmp/unreleased_section.md
7588
7689
# Extract test commits
77-
git log ${COMMIT_RANGE} --date=short --pretty=format:" * %ad %s (%aN)" --grep="^test:" -i > /tmp/tests.txt || true
90+
git log ${COMMIT_RANGE} --date=short --pretty=format:" * %ad %s (%aN)" --grep="^test:" -i 2>/dev/null > /tmp/tests.txt || true
7891
if [ -s /tmp/tests.txt ]; then
79-
cat /tmp/tests.txt >> /tmp/new_release_section.md
92+
cat /tmp/tests.txt >> /tmp/unreleased_section.md
8093
else
81-
echo " * No test updates" >> /tmp/new_release_section.md
94+
echo " * No test updates" >> /tmp/unreleased_section.md
8295
fi
8396
84-
echo "" >> /tmp/new_release_section.md
85-
echo "* 📚 **Documentation**" >> /tmp/new_release_section.md
97+
echo "" >> /tmp/unreleased_section.md
98+
echo "* 📚 **Documentation**" >> /tmp/unreleased_section.md
8699
87100
# Extract doc commits
88-
git log ${COMMIT_RANGE} --date=short --pretty=format:" * %ad %s (%aN)" --grep="^docs:" -i > /tmp/docs.txt || true
101+
git log ${COMMIT_RANGE} --date=short --pretty=format:" * %ad %s (%aN)" --grep="^docs:" -i 2>/dev/null > /tmp/docs.txt || true
89102
if [ -s /tmp/docs.txt ]; then
90-
cat /tmp/docs.txt >> /tmp/new_release_section.md
103+
cat /tmp/docs.txt >> /tmp/unreleased_section.md
104+
else
105+
echo " * No documentation updates" >> /tmp/unreleased_section.md
106+
fi
107+
108+
echo "" >> /tmp/unreleased_section.md
109+
echo "* ⚙️ **Build & Compatibility**" >> /tmp/unreleased_section.md
110+
111+
# Extract build commits
112+
git log ${COMMIT_RANGE} --date=short --pretty=format:" * %ad %s (%aN)" --grep="^build:" --grep="^ci:" -i 2>/dev/null > /tmp/build.txt || true
113+
if [ -s /tmp/build.txt ]; then
114+
cat /tmp/build.txt >> /tmp/unreleased_section.md
91115
else
92-
echo " * No documentation updates" >> /tmp/new_release_section.md
116+
echo " * No build updates" >> /tmp/unreleased_section.md
93117
fi
94118
95-
echo "" >> /tmp/new_release_section.md
96-
echo "---" >> /tmp/new_release_section.md
97-
echo "" >> /tmp/new_release_section.md
98-
echo "## 🐛 **Bugfixes**" >> /tmp/new_release_section.md
99-
echo "" >> /tmp/new_release_section.md
119+
echo "" >> /tmp/unreleased_section.md
120+
echo "---" >> /tmp/unreleased_section.md
121+
echo "" >> /tmp/unreleased_section.md
122+
echo "## 🐛 **Bugfixes**" >> /tmp/unreleased_section.md
123+
echo "" >> /tmp/unreleased_section.md
100124
101125
# Extract bugfix commits
102-
git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" --grep="^fix:" --grep="^bugfix:" -i > /tmp/fixes.txt || true
126+
git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" --grep="^fix:" --grep="^bugfix:" -i 2>/dev/null > /tmp/fixes.txt || true
103127
if [ -s /tmp/fixes.txt ]; then
104-
cat /tmp/fixes.txt >> /tmp/new_release_section.md
128+
cat /tmp/fixes.txt >> /tmp/unreleased_section.md
105129
else
106-
echo "* No bugfixes in this update" >> /tmp/new_release_section.md
130+
echo "* No bugfixes yet" >> /tmp/unreleased_section.md
107131
fi
108132
109-
echo "" >> /tmp/new_release_section.md
110-
echo "---" >> /tmp/new_release_section.md
111-
echo "" >> /tmp/new_release_section.md
112-
echo "## 📝 **Full changelog**" >> /tmp/new_release_section.md
113-
echo "" >> /tmp/new_release_section.md
133+
echo "" >> /tmp/unreleased_section.md
134+
echo "---" >> /tmp/unreleased_section.md
135+
echo "" >> /tmp/unreleased_section.md
136+
echo "## 📝 **Full changelog**" >> /tmp/unreleased_section.md
137+
echo "" >> /tmp/unreleased_section.md
114138
115139
# Count commits by category
116-
TOTAL_COMMITS=$(git log ${COMMIT_RANGE} --oneline | wc -l)
117-
FEAT_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^feature:" --grep="^feat:" -i | wc -l || echo 0)
118-
TEST_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^test:" -i | wc -l || echo 0)
119-
DOCS_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^docs:" -i | wc -l || echo 0)
120-
FIX_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^fix:" --grep="^bugfix:" -i | wc -l || echo 0)
121-
STYLE_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^style:" -i | wc -l || echo 0)
140+
FEAT_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^feature:" --grep="^feat:" -i 2>/dev/null | wc -l || echo 0)
141+
TEST_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^test:" -i 2>/dev/null | wc -l || echo 0)
142+
DOCS_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^docs:" -i 2>/dev/null | wc -l || echo 0)
143+
FIX_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^fix:" --grep="^bugfix:" -i 2>/dev/null | wc -l || echo 0)
144+
STYLE_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^style:" -i 2>/dev/null | wc -l || echo 0)
122145
123146
if [ ${TOTAL_COMMITS} -gt 0 ]; then
124147
FEAT_PCT=$(awk "BEGIN {printf \"%.1f\", (${FEAT_COUNT}/${TOTAL_COMMITS})*100}")
@@ -137,37 +160,54 @@ jobs:
137160
OTHER_PCT=0
138161
fi
139162
140-
cat >> /tmp/new_release_section.md << EOF
163+
cat >> /tmp/unreleased_section.md << EOF
141164
| **${TOTAL_COMMITS} commits** | 📚 Docs | 🧪 Tests | 🐛 Fixes | 🎨 Style | ✨ Features | Other |
142165
|-----------------|---------|----------|-----------|------------|--------------|-------|
143166
| % of Commits | ${DOCS_PCT}% | ${TEST_PCT}% | ${FIX_PCT}% | ${STYLE_PCT}% | ${FEAT_PCT}% | ${OTHER_PCT}% |
144167
145168
EOF
146169
147-
echo "" >> /tmp/new_release_section.md
148-
echo '`git log --date=short --pretty=format:"* %ad %s (%aN)"`' >> /tmp/new_release_section.md
149-
echo "" >> /tmp/new_release_section.md
150-
echo "" >> /tmp/new_release_section.md
170+
echo "" >> /tmp/unreleased_section.md
171+
echo '`git log --date=short --pretty=format:"* %ad %s (%aN)"`' >> /tmp/unreleased_section.md
172+
echo "" >> /tmp/unreleased_section.md
173+
echo "" >> /tmp/unreleased_section.md
151174
152175
# Add all commits
153-
git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" >> /tmp/new_release_section.md
176+
git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" 2>/dev/null >> /tmp/unreleased_section.md || true
154177
155-
echo "" >> /tmp/new_release_section.md
156-
echo "" >> /tmp/new_release_section.md
178+
echo "" >> /tmp/unreleased_section.md
179+
echo "" >> /tmp/unreleased_section.md
157180
158-
# Prepend the new section to the existing release.md
181+
# Update release.md
159182
if [ -f release.md ]; then
160-
cat /tmp/new_release_section.md > /tmp/updated_release.md
161-
echo "---" >> /tmp/updated_release.md
162-
echo "" >> /tmp/updated_release.md
163-
cat release.md >> /tmp/updated_release.md
164-
mv /tmp/updated_release.md release.md
183+
# Check if there's already an Unreleased section and remove it
184+
if grep -q "^# Unreleased" release.md; then
185+
# Find the line number of the first released version (starts with # v)
186+
FIRST_VERSION_LINE=$(grep -n "^# v[0-9]" release.md | head -1 | cut -d: -f1)
187+
if [ -n "$FIRST_VERSION_LINE" ]; then
188+
# Keep everything from the first version onwards
189+
tail -n +${FIRST_VERSION_LINE} release.md > /tmp/existing_releases.md
190+
# Prepend new unreleased section
191+
cat /tmp/unreleased_section.md > release.md
192+
echo "---" >> release.md
193+
echo "" >> release.md
194+
cat /tmp/existing_releases.md >> release.md
195+
else
196+
# No versioned releases found, just replace with unreleased
197+
mv /tmp/unreleased_section.md release.md
198+
fi
199+
else
200+
# No unreleased section exists, prepend to existing content
201+
cat /tmp/unreleased_section.md > /tmp/updated_release.md
202+
echo "---" >> /tmp/updated_release.md
203+
echo "" >> /tmp/updated_release.md
204+
cat release.md >> /tmp/updated_release.md
205+
mv /tmp/updated_release.md release.md
206+
fi
165207
else
166-
mv /tmp/new_release_section.md release.md
208+
# No release.md exists, create it
209+
mv /tmp/unreleased_section.md release.md
167210
fi
168-
169-
# Replace ${VERSION} placeholder
170-
sed -i "s/\${VERSION}/${VERSION}/g" release.md
171211
172212
- name: Check for changes
173213
id: check_changes

0 commit comments

Comments
 (0)