Skip to content

Fix styling

Fix styling #10

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@v5
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@v5
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Generate release notes content
id: generate-notes
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
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"