Skip to content

Add automated release notes generation workflow #1

Add automated release notes generation workflow

Add automated release notes generation workflow #1

name: Update Release Notes
on:
push:
branches:
- main
pull_request:
branches:
- main
types: [opened, synchronize, reopened]
jobs:
update-release-notes:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for proper changelog generation
ref: ${{ github.head_ref || github.ref_name }}
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Generate release notes
run: |
# Get the version from setup.py
VERSION=$(python setup.py --version 2>/dev/null || echo "dev")
# Determine the commit range
if [ "${{ github.event_name }}" = "pull_request" ]; then
BASE_REF="${{ github.event.pull_request.base.sha }}"
HEAD_REF="${{ github.event.pull_request.head.sha }}"
COMMIT_RANGE="${BASE_REF}..${HEAD_REF}"
else
# For push events, use the last 20 commits
COMMIT_RANGE="HEAD~20..HEAD"
fi
# Create a temporary file for the new release notes
cat > /tmp/new_release_section.md << 'EOF'
# v${VERSION}
This release includes updates from recent commits.
---
## 🚀 New Features
EOF
# Process commits and categorize them
echo "Processing commits in range: ${COMMIT_RANGE}"
# Extract feature commits
git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" --grep="^feature:" --grep="^feat:" -i > /tmp/features.txt || true
if [ -s /tmp/features.txt ]; then
cat /tmp/features.txt >> /tmp/new_release_section.md
else
echo "* No new features in this update" >> /tmp/new_release_section.md
fi
echo "" >> /tmp/new_release_section.md
echo "---" >> /tmp/new_release_section.md
echo "" >> /tmp/new_release_section.md
echo "## 💗 Other Tag Highlights" >> /tmp/new_release_section.md
echo "" >> /tmp/new_release_section.md
echo "* 🔁 **Tests**" >> /tmp/new_release_section.md
# Extract test commits
git log ${COMMIT_RANGE} --date=short --pretty=format:" * %ad %s (%aN)" --grep="^test:" -i > /tmp/tests.txt || true
if [ -s /tmp/tests.txt ]; then
cat /tmp/tests.txt >> /tmp/new_release_section.md
else
echo " * No test updates" >> /tmp/new_release_section.md
fi
echo "" >> /tmp/new_release_section.md
echo "* 📚 **Documentation**" >> /tmp/new_release_section.md
# Extract doc commits
git log ${COMMIT_RANGE} --date=short --pretty=format:" * %ad %s (%aN)" --grep="^docs:" -i > /tmp/docs.txt || true
if [ -s /tmp/docs.txt ]; then
cat /tmp/docs.txt >> /tmp/new_release_section.md
else
echo " * No documentation updates" >> /tmp/new_release_section.md
fi
echo "" >> /tmp/new_release_section.md
echo "---" >> /tmp/new_release_section.md
echo "" >> /tmp/new_release_section.md
echo "## 🐛 **Bugfixes**" >> /tmp/new_release_section.md
echo "" >> /tmp/new_release_section.md
# Extract bugfix commits
git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" --grep="^fix:" --grep="^bugfix:" -i > /tmp/fixes.txt || true
if [ -s /tmp/fixes.txt ]; then
cat /tmp/fixes.txt >> /tmp/new_release_section.md
else
echo "* No bugfixes in this update" >> /tmp/new_release_section.md
fi
echo "" >> /tmp/new_release_section.md
echo "---" >> /tmp/new_release_section.md
echo "" >> /tmp/new_release_section.md
echo "## 📝 **Full changelog**" >> /tmp/new_release_section.md
echo "" >> /tmp/new_release_section.md
# Count commits by category
TOTAL_COMMITS=$(git log ${COMMIT_RANGE} --oneline | wc -l)
FEAT_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^feature:" --grep="^feat:" -i | wc -l || echo 0)
TEST_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^test:" -i | wc -l || echo 0)
DOCS_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^docs:" -i | wc -l || echo 0)
FIX_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^fix:" --grep="^bugfix:" -i | wc -l || echo 0)
STYLE_COUNT=$(git log ${COMMIT_RANGE} --oneline --grep="^style:" -i | wc -l || echo 0)
if [ ${TOTAL_COMMITS} -gt 0 ]; then
FEAT_PCT=$(awk "BEGIN {printf \"%.1f\", (${FEAT_COUNT}/${TOTAL_COMMITS})*100}")
TEST_PCT=$(awk "BEGIN {printf \"%.1f\", (${TEST_COUNT}/${TOTAL_COMMITS})*100}")
DOCS_PCT=$(awk "BEGIN {printf \"%.1f\", (${DOCS_COUNT}/${TOTAL_COMMITS})*100}")
FIX_PCT=$(awk "BEGIN {printf \"%.1f\", (${FIX_COUNT}/${TOTAL_COMMITS})*100}")
STYLE_PCT=$(awk "BEGIN {printf \"%.1f\", (${STYLE_COUNT}/${TOTAL_COMMITS})*100}")
OTHER_COUNT=$((TOTAL_COMMITS - FEAT_COUNT - TEST_COUNT - DOCS_COUNT - FIX_COUNT - STYLE_COUNT))
OTHER_PCT=$(awk "BEGIN {printf \"%.1f\", (${OTHER_COUNT}/${TOTAL_COMMITS})*100}")
else
FEAT_PCT=0
TEST_PCT=0
DOCS_PCT=0
FIX_PCT=0
STYLE_PCT=0
OTHER_PCT=0
fi
cat >> /tmp/new_release_section.md << EOF
| **${TOTAL_COMMITS} commits** | 📚 Docs | 🧪 Tests | 🐛 Fixes | 🎨 Style | ✨ Features | Other |
|-----------------|---------|----------|-----------|------------|--------------|-------|
| % of Commits | ${DOCS_PCT}% | ${TEST_PCT}% | ${FIX_PCT}% | ${STYLE_PCT}% | ${FEAT_PCT}% | ${OTHER_PCT}% |
EOF
echo "" >> /tmp/new_release_section.md
echo '`git log --date=short --pretty=format:"* %ad %s (%aN)"`' >> /tmp/new_release_section.md
echo "" >> /tmp/new_release_section.md
echo "" >> /tmp/new_release_section.md
# Add all commits
git log ${COMMIT_RANGE} --date=short --pretty=format:"* %ad %s (%aN)" >> /tmp/new_release_section.md
echo "" >> /tmp/new_release_section.md
echo "" >> /tmp/new_release_section.md
# Prepend the new section to the existing release.md
if [ -f release.md ]; then
cat /tmp/new_release_section.md > /tmp/updated_release.md
echo "---" >> /tmp/updated_release.md
echo "" >> /tmp/updated_release.md
cat release.md >> /tmp/updated_release.md
mv /tmp/updated_release.md release.md
else
mv /tmp/new_release_section.md release.md
fi
# Replace ${VERSION} placeholder
sed -i "s/\${VERSION}/${VERSION}/g" release.md
- name: Check for changes
id: check_changes
run: |
if git diff --quiet release.md; then
echo "has_changes=false" >> $GITHUB_OUTPUT
echo "No changes to release.md"
else
echo "has_changes=true" >> $GITHUB_OUTPUT
echo "Changes detected in release.md"
fi
- name: Commit and push changes
if: steps.check_changes.outputs.has_changes == 'true' && github.event_name == 'push'
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add release.md
git commit -m "chore: auto-update release.md [skip ci]"
git push
- name: Commit changes to PR
if: steps.check_changes.outputs.has_changes == 'true' && github.event_name == 'pull_request'
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add release.md
git commit -m "chore: auto-update release.md for PR #${{ github.event.pull_request.number }}"
git push origin HEAD:${{ github.head_ref }}