Skip to content

Commit fe593c4

Browse files
graycreateclaude
andauthored
feat: include past 3 versions in Google Play release notes (#181)
- Add feedback header at the top of release notes - Collect commits from current version and past 2 tagged versions - Combine with version separators (--- vX.Y.Z ---) - Respect Google Play's 500 character limit per language - Automatically truncate if content exceeds limit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent a76ca34 commit fe593c4

File tree

1 file changed

+143
-192
lines changed

1 file changed

+143
-192
lines changed

.github/workflows/release.yml

Lines changed: 143 additions & 192 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,10 @@ jobs:
612612
run: |
613613
mkdir -p whatsnew
614614
615-
# Define shared functions (duplicated from release job since jobs run in isolation)
615+
# Google Play whatsnew character limit
616+
MAX_CHARS=500
617+
618+
# Define shared functions
616619
cat > /tmp/release_functions.sh << 'FUNCTIONS_EOF'
617620
# Function to categorize commit message
618621
categorize_commit() {
@@ -652,221 +655,169 @@ jobs:
652655
echo "$category:$cleaned_msg"
653656
}
654657
655-
# Function to get GitHub username from commit
656-
get_github_username() {
657-
local commit_sha="$1"
658-
local github_repo="${GITHUB_REPOSITORY}"
659-
# Try to get the GitHub username from the commit using gh api
660-
local username=$(gh api "repos/${github_repo}/commits/${commit_sha}" --jq '.author.login // empty' 2>/dev/null || echo "")
661-
if [ -n "$username" ]; then
662-
echo "@$username"
663-
else
664-
# Fallback: try to get committer login if author login is not available
665-
local committer=$(gh api "repos/${github_repo}/commits/${commit_sha}" --jq '.committer.login // empty' 2>/dev/null || echo "")
666-
if [ -n "$committer" ]; then
667-
echo "@$committer"
668-
else
669-
# Last resort: use hardcoded mapping for known authors
670-
local git_author=$(git show -s --format='%an' $commit_sha)
671-
case "$git_author" in
672-
"Gray Zhang" | "gray" | "Gray")
673-
echo "@graycreate"
674-
;;
675-
"github-actions[bot]")
676-
echo "@github-actions[bot]"
677-
;;
678-
*)
679-
# If no mapping found, use git author name without @
680-
echo "$git_author"
681-
;;
682-
esac
683-
fi
684-
fi
685-
}
686-
FUNCTIONS_EOF
658+
# Function to collect commits for a version range
659+
collect_version_commits() {
660+
local range="$1"
661+
local -n feat_ref=$2
662+
local -n bug_ref=$3
663+
local -n improve_ref=$4
664+
local -n perf_ref=$5
687665
688-
# Source the shared functions
689-
source /tmp/release_functions.sh
666+
while IFS= read -r line; do
667+
[ -z "$line" ] && continue
668+
sha=$(echo "$line" | cut -d' ' -f1)
669+
msg=$(echo "$line" | cut -d' ' -f2-)
690670
691-
# Get commits since last tag for categorization
692-
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
671+
# Skip version bump and merge commits
672+
if [[ "$msg" =~ "bump version" ]] || [[ "$msg" =~ "Merge pull request" ]] || [[ "$msg" =~ "Merge branch" ]]; then
673+
continue
674+
fi
693675
694-
# Collect and categorize commits
695-
declare -A features
696-
declare -A bugs
697-
declare -A improvements
698-
declare -A performance
699-
declare -A contributors
676+
categorized=$(categorize_commit "$msg")
677+
category=$(echo "$categorized" | cut -d':' -f1)
678+
clean_msg=$(echo "$categorized" | cut -d':' -f2-)
700679
701-
if [ -n "$LAST_TAG" ]; then
702-
RANGE="$LAST_TAG..HEAD"
703-
else
704-
RANGE="HEAD~5..HEAD"
705-
fi
680+
case "$category" in
681+
feature) feat_ref["$clean_msg"]=1 ;;
682+
bug) bug_ref["$clean_msg"]=1 ;;
683+
improvement) improve_ref["$clean_msg"]=1 ;;
684+
performance) perf_ref["$clean_msg"]=1 ;;
685+
esac
686+
done < <(git log --oneline --no-merges $range 2>/dev/null)
687+
}
706688
707-
# Process commits
708-
while IFS= read -r line; do
709-
sha=$(echo "$line" | cut -d' ' -f1)
710-
msg=$(echo "$line" | cut -d' ' -f2-)
689+
# Function to generate version notes (compact format for Google Play)
690+
generate_version_notes() {
691+
local -n feat=$1
692+
local -n bugs=$2
693+
local -n improve=$3
694+
local -n perf=$4
695+
local output=""
711696
712-
# Skip version bump and merge commits
713-
if [[ "$msg" =~ "bump version" ]] || [[ "$msg" =~ "Merge pull request" ]] || [[ "$msg" =~ "Merge branch" ]]; then
714-
continue
697+
if [ ${#feat[@]} -gt 0 ]; then
698+
for msg in "${!feat[@]}"; do
699+
output+="• $msg"$'\n'
700+
done
715701
fi
716-
717-
categorized=$(categorize_commit "$msg")
718-
category=$(echo "$categorized" | cut -d':' -f1)
719-
clean_msg=$(echo "$categorized" | cut -d':' -f2-)
720-
721-
# Get author for this commit
722-
author=$(get_github_username "$sha")
723-
if [ -n "$author" ]; then
724-
contributors["$author"]="1"
702+
if [ ${#bugs[@]} -gt 0 ]; then
703+
for msg in "${!bugs[@]}"; do
704+
output+="• $msg"$'\n'
705+
done
706+
fi
707+
if [ ${#improve[@]} -gt 0 ]; then
708+
for msg in "${!improve[@]}"; do
709+
output+="• $msg"$'\n'
710+
done
725711
fi
712+
if [ ${#perf[@]} -gt 0 ]; then
713+
for msg in "${!perf[@]}"; do
714+
output+="• $msg"$'\n'
715+
done
716+
fi
717+
echo "$output"
718+
}
719+
FUNCTIONS_EOF
726720
727-
case "$category" in
728-
feature)
729-
features["$clean_msg"]="$author"
730-
;;
731-
bug)
732-
bugs["$clean_msg"]="$author"
733-
;;
734-
improvement)
735-
improvements["$clean_msg"]="$author"
736-
;;
737-
performance)
738-
performance["$clean_msg"]="$author"
739-
;;
740-
esac
741-
done < <(git log --oneline --no-merges $RANGE)
721+
# Source the shared functions
722+
source /tmp/release_functions.sh
742723
743-
# Generate English release notes
744-
echo "V2er ${{ needs.prepare.outputs.version }}" > whatsnew/whatsnew-en-US
745-
echo "" >> whatsnew/whatsnew-en-US
724+
# Get last 3 tags for multi-version release notes
725+
TAGS=($(git tag --sort=-v:refname | head -3))
726+
CURRENT_VERSION="${{ needs.prepare.outputs.version }}"
746727
747-
if [ ${#features[@]} -gt 0 ]; then
748-
echo "🚀 New Features:" >> whatsnew/whatsnew-en-US
749-
for msg in "${!features[@]}"; do
750-
author="${features[$msg]}"
751-
if [ -n "$author" ]; then
752-
echo "• $msg (by $author)" >> whatsnew/whatsnew-en-US
753-
else
754-
echo "• $msg" >> whatsnew/whatsnew-en-US
755-
fi
756-
done
757-
echo "" >> whatsnew/whatsnew-en-US
758-
fi
728+
echo "Found tags: ${TAGS[*]}"
729+
echo "Current version: $CURRENT_VERSION"
759730
760-
if [ ${#bugs[@]} -gt 0 ]; then
761-
echo "🐛 Bug Fixes:" >> whatsnew/whatsnew-en-US
762-
for msg in "${!bugs[@]}"; do
763-
author="${bugs[$msg]}"
764-
if [ -n "$author" ]; then
765-
echo "• $msg (by $author)" >> whatsnew/whatsnew-en-US
766-
else
767-
echo "• $msg" >> whatsnew/whatsnew-en-US
768-
fi
769-
done
770-
echo "" >> whatsnew/whatsnew-en-US
771-
fi
731+
# Feedback header
732+
FEEDBACK_HEADER_EN="Feedback: https://v2er.app/help"
733+
FEEDBACK_HEADER_ZH="唯一问题反馈渠道:https://v2er.app/help"
772734
773-
if [ ${#improvements[@]} -gt 0 ]; then
774-
echo "💪 Improvements:" >> whatsnew/whatsnew-en-US
775-
for msg in "${!improvements[@]}"; do
776-
author="${improvements[$msg]}"
777-
if [ -n "$author" ]; then
778-
echo "• $msg (by $author)" >> whatsnew/whatsnew-en-US
779-
else
780-
echo "• $msg" >> whatsnew/whatsnew-en-US
781-
fi
782-
done
783-
echo "" >> whatsnew/whatsnew-en-US
784-
fi
735+
# Build release notes for each version
736+
declare -a version_notes_en
737+
declare -a version_notes_zh
785738
786-
if [ ${#performance[@]} -gt 0 ]; then
787-
echo "⚡ Performance:" >> whatsnew/whatsnew-en-US
788-
for msg in "${!performance[@]}"; do
789-
author="${performance[$msg]}"
790-
if [ -n "$author" ]; then
791-
echo "• $msg (by $author)" >> whatsnew/whatsnew-en-US
792-
else
793-
echo "• $msg" >> whatsnew/whatsnew-en-US
794-
fi
795-
done
796-
echo "" >> whatsnew/whatsnew-en-US
739+
# Current version (HEAD to last tag or all commits if no tags)
740+
declare -A curr_features curr_bugs curr_improvements curr_performance
741+
if [ ${#TAGS[@]} -gt 0 ]; then
742+
collect_version_commits "${TAGS[0]}..HEAD" curr_features curr_bugs curr_improvements curr_performance
743+
else
744+
collect_version_commits "HEAD~10..HEAD" curr_features curr_bugs curr_improvements curr_performance
797745
fi
798746
799-
# Add contributors section if there are any
800-
if [ ${#contributors[@]} -gt 0 ]; then
801-
echo "👥 Contributors: ${!contributors[@]}" >> whatsnew/whatsnew-en-US
802-
echo "" >> whatsnew/whatsnew-en-US
747+
CURR_NOTES=$(generate_version_notes curr_features curr_bugs curr_improvements curr_performance)
748+
if [ -n "$CURR_NOTES" ]; then
749+
version_notes_en+=("$CURR_NOTES")
750+
version_notes_zh+=("$CURR_NOTES")
803751
fi
804752
805-
echo "Thank you for using V2er! Please report any issues on GitHub." >> whatsnew/whatsnew-en-US
806-
807-
# Generate Chinese release notes
808-
echo "V2er ${{ needs.prepare.outputs.version }}" > whatsnew/whatsnew-zh-CN
809-
echo "" >> whatsnew/whatsnew-zh-CN
810-
811-
if [ ${#features[@]} -gt 0 ]; then
812-
echo "🚀 新功能:" >> whatsnew/whatsnew-zh-CN
813-
for msg in "${!features[@]}"; do
814-
author="${features[$msg]}"
815-
if [ -n "$author" ]; then
816-
echo "• $msg (贡献者 $author)" >> whatsnew/whatsnew-zh-CN
817-
else
818-
echo "• $msg" >> whatsnew/whatsnew-zh-CN
753+
# Previous versions (from tags)
754+
for i in 0 1; do
755+
if [ $i -lt ${#TAGS[@]} ] && [ $((i+1)) -lt ${#TAGS[@]} ]; then
756+
declare -A prev_features prev_bugs prev_improvements prev_performance
757+
collect_version_commits "${TAGS[$((i+1))]}..${TAGS[$i]}" prev_features prev_bugs prev_improvements prev_performance
758+
PREV_NOTES=$(generate_version_notes prev_features prev_bugs prev_improvements prev_performance)
759+
if [ -n "$PREV_NOTES" ]; then
760+
version_notes_en+=("--- ${TAGS[$i]} ---"$'\n'"$PREV_NOTES")
761+
version_notes_zh+=("--- ${TAGS[$i]} ---"$'\n'"$PREV_NOTES")
819762
fi
820-
done
821-
echo "" >> whatsnew/whatsnew-zh-CN
822-
fi
823-
824-
if [ ${#bugs[@]} -gt 0 ]; then
825-
echo "🐛 问题修复:" >> whatsnew/whatsnew-zh-CN
826-
for msg in "${!bugs[@]}"; do
827-
author="${bugs[$msg]}"
828-
if [ -n "$author" ]; then
829-
echo "• $msg (贡献者 $author)" >> whatsnew/whatsnew-zh-CN
830-
else
831-
echo "• $msg" >> whatsnew/whatsnew-zh-CN
763+
unset prev_features prev_bugs prev_improvements prev_performance
764+
elif [ $i -lt ${#TAGS[@]} ] && [ $((i+1)) -ge ${#TAGS[@]} ]; then
765+
# Last tag - get commits before it
766+
declare -A prev_features prev_bugs prev_improvements prev_performance
767+
collect_version_commits "${TAGS[$i]}~5..${TAGS[$i]}" prev_features prev_bugs prev_improvements prev_performance
768+
PREV_NOTES=$(generate_version_notes prev_features prev_bugs prev_improvements prev_performance)
769+
if [ -n "$PREV_NOTES" ]; then
770+
version_notes_en+=("--- ${TAGS[$i]} ---"$'\n'"$PREV_NOTES")
771+
version_notes_zh+=("--- ${TAGS[$i]} ---"$'\n'"$PREV_NOTES")
832772
fi
833-
done
834-
echo "" >> whatsnew/whatsnew-zh-CN
835-
fi
773+
unset prev_features prev_bugs prev_improvements prev_performance
774+
fi
775+
done
836776
837-
if [ ${#improvements[@]} -gt 0 ]; then
838-
echo "💪 改进优化:" >> whatsnew/whatsnew-zh-CN
839-
for msg in "${!improvements[@]}"; do
840-
author="${improvements[$msg]}"
841-
if [ -n "$author" ]; then
842-
echo "• $msg (贡献者 $author)" >> whatsnew/whatsnew-zh-CN
843-
else
844-
echo "• $msg" >> whatsnew/whatsnew-zh-CN
845-
fi
846-
done
847-
echo "" >> whatsnew/whatsnew-zh-CN
848-
fi
777+
# Generate English release notes with character limit
778+
{
779+
echo "$FEEDBACK_HEADER_EN"
780+
echo ""
781+
echo "V2er $CURRENT_VERSION"
782+
echo ""
783+
} > whatsnew/whatsnew-en-US
849784
850-
if [ ${#performance[@]} -gt 0 ]; then
851-
echo "⚡ 性能优化:" >> whatsnew/whatsnew-zh-CN
852-
for msg in "${!performance[@]}"; do
853-
author="${performance[$msg]}"
854-
if [ -n "$author" ]; then
855-
echo "• $msg (贡献者 $author)" >> whatsnew/whatsnew-zh-CN
856-
else
857-
echo "• $msg" >> whatsnew/whatsnew-zh-CN
858-
fi
859-
done
860-
echo "" >> whatsnew/whatsnew-zh-CN
861-
fi
785+
CURRENT_LEN=$(wc -c < whatsnew/whatsnew-en-US)
786+
for notes in "${version_notes_en[@]}"; do
787+
NOTES_LEN=${#notes}
788+
if [ $((CURRENT_LEN + NOTES_LEN + 2)) -lt $MAX_CHARS ]; then
789+
echo "$notes" >> whatsnew/whatsnew-en-US
790+
CURRENT_LEN=$((CURRENT_LEN + NOTES_LEN + 2))
791+
else
792+
break
793+
fi
794+
done
862795
863-
# Add contributors section if there are any
864-
if [ ${#contributors[@]} -gt 0 ]; then
865-
echo "👥 贡献者:${!contributors[@]}" >> whatsnew/whatsnew-zh-CN
866-
echo "" >> whatsnew/whatsnew-zh-CN
867-
fi
796+
# Generate Chinese release notes with character limit
797+
{
798+
echo "$FEEDBACK_HEADER_ZH"
799+
echo ""
800+
echo "V2er $CURRENT_VERSION"
801+
echo ""
802+
} > whatsnew/whatsnew-zh-CN
803+
804+
CURRENT_LEN=$(wc -c < whatsnew/whatsnew-zh-CN)
805+
for notes in "${version_notes_zh[@]}"; do
806+
NOTES_LEN=${#notes}
807+
if [ $((CURRENT_LEN + NOTES_LEN + 2)) -lt $MAX_CHARS ]; then
808+
echo "$notes" >> whatsnew/whatsnew-zh-CN
809+
CURRENT_LEN=$((CURRENT_LEN + NOTES_LEN + 2))
810+
else
811+
break
812+
fi
813+
done
868814
869-
echo "感谢您使用 V2er!如遇问题请在 GitHub 上反馈。" >> whatsnew/whatsnew-zh-CN
815+
# Show generated content
816+
echo "=== English whatsnew ($(wc -c < whatsnew/whatsnew-en-US) chars) ==="
817+
cat whatsnew/whatsnew-en-US
818+
echo ""
819+
echo "=== Chinese whatsnew ($(wc -c < whatsnew/whatsnew-zh-CN) chars) ==="
820+
cat whatsnew/whatsnew-zh-CN
870821
871822
- name: Upload to Play Store (with debug symbols)
872823
if: steps.find-files.outputs.symbols_path != ''

0 commit comments

Comments
 (0)