Skip to content

Commit a96ee38

Browse files
graycreateclaude
andcommitted
feat: improve release notes generation with categorization
- Categorize commits into Features, Bug Fixes, Improvements, and Performance - Clean commit messages by removing PR numbers and prefixes - Format release notes with emojis and proper sections - Apply same categorization to both GitHub and Google Play release notes - Capitalize first letter of each changelog entry for better readability 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 10942b0 commit a96ee38

File tree

1 file changed

+290
-34
lines changed

1 file changed

+290
-34
lines changed

.github/workflows/release.yml

Lines changed: 290 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -348,13 +348,50 @@ jobs:
348348
id: changelog
349349
env:
350350
GH_TOKEN: ${{ github.token }}
351+
GITHUB_REPOSITORY: ${{ github.repository }}
351352
run: |
352-
echo "## What's Changed" > CHANGELOG.md
353-
echo "" >> CHANGELOG.md
354-
355353
# Get commits since last tag
356354
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
357-
355+
CURRENT_TAG="${{ needs.prepare.outputs.version }}"
356+
357+
# Function to categorize commit message
358+
categorize_commit() {
359+
local msg="$1"
360+
local category=""
361+
local cleaned_msg=""
362+
363+
if [[ "$msg" =~ ^fix(\(.*\))?:\ (.*)$ ]] || [[ "$msg" =~ ^fix\ (.*)$ ]]; then
364+
category="bug"
365+
cleaned_msg="${BASH_REMATCH[-1]}"
366+
elif [[ "$msg" =~ ^feat(\(.*\))?:\ (.*)$ ]] || [[ "$msg" =~ ^feat\ (.*)$ ]]; then
367+
category="feature"
368+
cleaned_msg="${BASH_REMATCH[-1]}"
369+
elif [[ "$msg" =~ ^perf(\(.*\))?:\ (.*)$ ]]; then
370+
category="performance"
371+
cleaned_msg="${BASH_REMATCH[2]}"
372+
elif [[ "$msg" =~ ^refactor(\(.*\))?:\ (.*)$ ]]; then
373+
category="improvement"
374+
cleaned_msg="${BASH_REMATCH[2]}"
375+
elif [[ "$msg" =~ ^chore(\(.*\))?:\ (.*)$ ]]; then
376+
category="maintenance"
377+
cleaned_msg="${BASH_REMATCH[2]}"
378+
elif [[ "$msg" =~ ^docs(\(.*\))?:\ (.*)$ ]]; then
379+
category="documentation"
380+
cleaned_msg="${BASH_REMATCH[2]}"
381+
else
382+
category="other"
383+
cleaned_msg="$msg"
384+
fi
385+
386+
# Remove PR numbers from the end
387+
cleaned_msg=$(echo "$cleaned_msg" | sed 's/ (#[0-9]*)//')
388+
389+
# Capitalize first letter
390+
cleaned_msg="$(echo "${cleaned_msg:0:1}" | tr '[:lower:]' '[:upper:]')${cleaned_msg:1}"
391+
392+
echo "$category:$cleaned_msg"
393+
}
394+
358395
# Function to get GitHub username from commit
359396
get_github_username() {
360397
local commit_sha="$1"
@@ -385,23 +422,111 @@ jobs:
385422
fi
386423
fi
387424
}
388-
389-
# Generate changelog with GitHub usernames
425+
426+
# Collect commits and categorize them
427+
declare -A features
428+
declare -A bugs
429+
declare -A improvements
430+
declare -A performance
431+
declare -A maintenance
432+
390433
if [ -n "$LAST_TAG" ]; then
391-
while IFS= read -r commit_sha; do
392-
commit_msg=$(git show -s --format='%s' $commit_sha)
393-
author=$(get_github_username $commit_sha)
394-
echo "* $commit_msg by $author" >> CHANGELOG.md
395-
done < <(git rev-list "$LAST_TAG"..HEAD)
434+
RANGE="$LAST_TAG..HEAD"
396435
else
397-
while IFS= read -r commit_sha; do
398-
commit_msg=$(git show -s --format='%s' $commit_sha)
399-
author=$(get_github_username $commit_sha)
400-
echo "* $commit_msg by $author" >> CHANGELOG.md
401-
done < <(git rev-list HEAD -10)
436+
RANGE="HEAD"
402437
fi
403-
438+
439+
# Process commits
440+
while IFS= read -r line; do
441+
sha=$(echo "$line" | cut -d' ' -f1)
442+
msg=$(echo "$line" | cut -d' ' -f2-)
443+
444+
# Skip version bump and merge commits
445+
if [[ "$msg" =~ "bump version" ]] || [[ "$msg" =~ "Merge pull request" ]] || [[ "$msg" =~ "Merge branch" ]]; then
446+
continue
447+
fi
448+
449+
categorized=$(categorize_commit "$msg")
450+
category=$(echo "$categorized" | cut -d':' -f1)
451+
clean_msg=$(echo "$categorized" | cut -d':' -f2-)
452+
author=$(get_github_username "$sha")
453+
454+
# Store in associative arrays
455+
case "$category" in
456+
feature)
457+
features["$clean_msg"]="$author"
458+
;;
459+
bug)
460+
bugs["$clean_msg"]="$author"
461+
;;
462+
improvement)
463+
improvements["$clean_msg"]="$author"
464+
;;
465+
performance)
466+
performance["$clean_msg"]="$author"
467+
;;
468+
maintenance)
469+
maintenance["$clean_msg"]="$author"
470+
;;
471+
esac
472+
done < <(git log --oneline --no-merges $RANGE)
473+
474+
# Generate GitHub Release Notes
475+
echo "## What's Changed" > CHANGELOG.md
404476
echo "" >> CHANGELOG.md
477+
478+
if [ ${#features[@]} -gt 0 ]; then
479+
echo "### 🚀 New Features" >> CHANGELOG.md
480+
for msg in "${!features[@]}"; do
481+
author="${features[$msg]}"
482+
if [ -n "$author" ]; then
483+
echo "* $msg by $author" >> CHANGELOG.md
484+
else
485+
echo "* $msg" >> CHANGELOG.md
486+
fi
487+
done
488+
echo "" >> CHANGELOG.md
489+
fi
490+
491+
if [ ${#bugs[@]} -gt 0 ]; then
492+
echo "### 🐛 Bug Fixes" >> CHANGELOG.md
493+
for msg in "${!bugs[@]}"; do
494+
author="${bugs[$msg]}"
495+
if [ -n "$author" ]; then
496+
echo "* $msg by $author" >> CHANGELOG.md
497+
else
498+
echo "* $msg" >> CHANGELOG.md
499+
fi
500+
done
501+
echo "" >> CHANGELOG.md
502+
fi
503+
504+
if [ ${#improvements[@]} -gt 0 ]; then
505+
echo "### 💪 Improvements" >> CHANGELOG.md
506+
for msg in "${!improvements[@]}"; do
507+
author="${improvements[$msg]}"
508+
if [ -n "$author" ]; then
509+
echo "* $msg by $author" >> CHANGELOG.md
510+
else
511+
echo "* $msg" >> CHANGELOG.md
512+
fi
513+
done
514+
echo "" >> CHANGELOG.md
515+
fi
516+
517+
if [ ${#performance[@]} -gt 0 ]; then
518+
echo "### ⚡ Performance" >> CHANGELOG.md
519+
for msg in "${!performance[@]}"; do
520+
author="${performance[$msg]}"
521+
if [ -n "$author" ]; then
522+
echo "* $msg by $author" >> CHANGELOG.md
523+
else
524+
echo "* $msg" >> CHANGELOG.md
525+
fi
526+
done
527+
echo "" >> CHANGELOG.md
528+
fi
529+
405530
echo "" >> CHANGELOG.md
406531
echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${LAST_TAG}...${{ needs.prepare.outputs.version }}" >> CHANGELOG.md
407532
@@ -477,27 +602,158 @@ jobs:
477602
run: |
478603
mkdir -p whatsnew
479604
480-
# Generate release notes for public test track
481-
echo "V2er Beta Release ${{ needs.prepare.outputs.version }}" > whatsnew/whatsnew-en-US
482-
echo "" >> whatsnew/whatsnew-en-US
483-
echo "What's new in this beta:" >> whatsnew/whatsnew-en-US
484-
echo "" >> whatsnew/whatsnew-en-US
605+
# Get commits since last tag for categorization
606+
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
485607
486-
# Get recent commits formatted for users
487-
git log --pretty=format:"• %s" -5 | sed 's/^• fix:/• Fixed:/g' | sed 's/^• feat:/• New:/g' | sed 's/^• chore:/• Updated:/g' >> whatsnew/whatsnew-en-US
488-
echo "" >> whatsnew/whatsnew-en-US
608+
# Function to categorize commit message (same as above)
609+
categorize_commit() {
610+
local msg="$1"
611+
local category=""
612+
local cleaned_msg=""
613+
614+
if [[ "$msg" =~ ^fix(\(.*\))?:\ (.*)$ ]] || [[ "$msg" =~ ^fix\ (.*)$ ]]; then
615+
category="bug"
616+
cleaned_msg="${BASH_REMATCH[-1]}"
617+
elif [[ "$msg" =~ ^feat(\(.*\))?:\ (.*)$ ]] || [[ "$msg" =~ ^feat\ (.*)$ ]]; then
618+
category="feature"
619+
cleaned_msg="${BASH_REMATCH[-1]}"
620+
elif [[ "$msg" =~ ^perf(\(.*\))?:\ (.*)$ ]]; then
621+
category="performance"
622+
cleaned_msg="${BASH_REMATCH[2]}"
623+
elif [[ "$msg" =~ ^refactor(\(.*\))?:\ (.*)$ ]]; then
624+
category="improvement"
625+
cleaned_msg="${BASH_REMATCH[2]}"
626+
else
627+
category="other"
628+
cleaned_msg="$msg"
629+
fi
630+
631+
# Remove PR numbers from the end
632+
cleaned_msg=$(echo "$cleaned_msg" | sed 's/ (#[0-9]*)//')
633+
634+
# Capitalize first letter
635+
cleaned_msg="$(echo "${cleaned_msg:0:1}" | tr '[:lower:]' '[:upper:]')${cleaned_msg:1}"
636+
637+
echo "$category:$cleaned_msg"
638+
}
639+
640+
# Collect and categorize commits
641+
declare -A features
642+
declare -A bugs
643+
declare -A improvements
644+
declare -A performance
645+
646+
if [ -n "$LAST_TAG" ]; then
647+
RANGE="$LAST_TAG..HEAD"
648+
else
649+
RANGE="HEAD~5..HEAD"
650+
fi
651+
652+
# Process commits
653+
while IFS= read -r line; do
654+
sha=$(echo "$line" | cut -d' ' -f1)
655+
msg=$(echo "$line" | cut -d' ' -f2-)
656+
657+
# Skip version bump and merge commits
658+
if [[ "$msg" =~ "bump version" ]] || [[ "$msg" =~ "Merge pull request" ]] || [[ "$msg" =~ "Merge branch" ]]; then
659+
continue
660+
fi
661+
662+
categorized=$(categorize_commit "$msg")
663+
category=$(echo "$categorized" | cut -d':' -f1)
664+
clean_msg=$(echo "$categorized" | cut -d':' -f2-)
665+
666+
case "$category" in
667+
feature)
668+
features["$clean_msg"]="1"
669+
;;
670+
bug)
671+
bugs["$clean_msg"]="1"
672+
;;
673+
improvement)
674+
improvements["$clean_msg"]="1"
675+
;;
676+
performance)
677+
performance["$clean_msg"]="1"
678+
;;
679+
esac
680+
done < <(git log --oneline --no-merges $RANGE)
681+
682+
# Generate English release notes
683+
echo "V2er ${{ needs.prepare.outputs.version }}" > whatsnew/whatsnew-en-US
489684
echo "" >> whatsnew/whatsnew-en-US
490-
echo "Thank you for testing! Please report any issues on GitHub." >> whatsnew/whatsnew-en-US
491685
492-
# Chinese version
493-
echo "V2er 测试版 ${{ needs.prepare.outputs.version }}" > whatsnew/whatsnew-zh-CN
494-
echo "" >> whatsnew/whatsnew-zh-CN
495-
echo "此测试版的新内容:" >> whatsnew/whatsnew-zh-CN
496-
echo "" >> whatsnew/whatsnew-zh-CN
497-
git log --pretty=format:"• %s" -5 | sed 's/^• fix:/• 修复:/g' | sed 's/^• feat:/• 新增:/g' | sed 's/^• chore:/• 更新:/g' >> whatsnew/whatsnew-zh-CN
498-
echo "" >> whatsnew/whatsnew-zh-CN
686+
if [ ${#features[@]} -gt 0 ]; then
687+
echo "🚀 New Features:" >> whatsnew/whatsnew-en-US
688+
for msg in "${!features[@]}"; do
689+
echo "• $msg" >> whatsnew/whatsnew-en-US
690+
done
691+
echo "" >> whatsnew/whatsnew-en-US
692+
fi
693+
694+
if [ ${#bugs[@]} -gt 0 ]; then
695+
echo "🐛 Bug Fixes:" >> whatsnew/whatsnew-en-US
696+
for msg in "${!bugs[@]}"; do
697+
echo "• $msg" >> whatsnew/whatsnew-en-US
698+
done
699+
echo "" >> whatsnew/whatsnew-en-US
700+
fi
701+
702+
if [ ${#improvements[@]} -gt 0 ]; then
703+
echo "💪 Improvements:" >> whatsnew/whatsnew-en-US
704+
for msg in "${!improvements[@]}"; do
705+
echo "• $msg" >> whatsnew/whatsnew-en-US
706+
done
707+
echo "" >> whatsnew/whatsnew-en-US
708+
fi
709+
710+
if [ ${#performance[@]} -gt 0 ]; then
711+
echo "⚡ Performance:" >> whatsnew/whatsnew-en-US
712+
for msg in "${!performance[@]}"; do
713+
echo "• $msg" >> whatsnew/whatsnew-en-US
714+
done
715+
echo "" >> whatsnew/whatsnew-en-US
716+
fi
717+
718+
echo "Thank you for using V2er! Please report any issues on GitHub." >> whatsnew/whatsnew-en-US
719+
720+
# Generate Chinese release notes
721+
echo "V2er ${{ needs.prepare.outputs.version }}" > whatsnew/whatsnew-zh-CN
499722
echo "" >> whatsnew/whatsnew-zh-CN
500-
echo "感谢您的测试!如遇问题请在GitHub上反馈。" >> whatsnew/whatsnew-zh-CN
723+
724+
if [ ${#features[@]} -gt 0 ]; then
725+
echo "🚀 新功能:" >> whatsnew/whatsnew-zh-CN
726+
for msg in "${!features[@]}"; do
727+
echo "• $msg" >> whatsnew/whatsnew-zh-CN
728+
done
729+
echo "" >> whatsnew/whatsnew-zh-CN
730+
fi
731+
732+
if [ ${#bugs[@]} -gt 0 ]; then
733+
echo "🐛 问题修复:" >> whatsnew/whatsnew-zh-CN
734+
for msg in "${!bugs[@]}"; do
735+
echo "• $msg" >> whatsnew/whatsnew-zh-CN
736+
done
737+
echo "" >> whatsnew/whatsnew-zh-CN
738+
fi
739+
740+
if [ ${#improvements[@]} -gt 0 ]; then
741+
echo "💪 改进优化:" >> whatsnew/whatsnew-zh-CN
742+
for msg in "${!improvements[@]}"; do
743+
echo "• $msg" >> whatsnew/whatsnew-zh-CN
744+
done
745+
echo "" >> whatsnew/whatsnew-zh-CN
746+
fi
747+
748+
if [ ${#performance[@]} -gt 0 ]; then
749+
echo "⚡ 性能优化:" >> whatsnew/whatsnew-zh-CN
750+
for msg in "${!performance[@]}"; do
751+
echo "• $msg" >> whatsnew/whatsnew-zh-CN
752+
done
753+
echo "" >> whatsnew/whatsnew-zh-CN
754+
fi
755+
756+
echo "感谢您使用 V2er!如遇问题请在 GitHub 上反馈。" >> whatsnew/whatsnew-zh-CN
501757
502758
- name: Upload to Play Store (with debug symbols)
503759
if: steps.find-files.outputs.symbols_path != ''

0 commit comments

Comments
 (0)