@@ -25,13 +25,104 @@ jobs:
2525 tag-name : ${{ steps.release.outputs.tag_name }}
2626 version : ${{ steps.release.outputs.version }}
2727 major-version : ${{ steps.release.outputs.major }}
28+ pr-number : ${{ steps.release.outputs.pr }}
2829 steps :
2930 - name : Create Release PR or Release
3031 id : release
3132 uses : googleapis/release-please-action@c2a5a2bd6a758a0937f1ddb1e8950609867ed15c # v4.3.0
3233 with :
3334 token : ${{ secrets.GITHUB_TOKEN }}
3435 release-type : node
36+ config-file : release-please-config.json
37+
38+ enhance-release-pr :
39+ name : Enhance Release PR with Authors
40+ runs-on : ubuntu-latest
41+ needs : release-please
42+ if : needs.release-please.outputs.pr-number != ''
43+ steps :
44+ - name : Checkout code
45+ uses : actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
46+ with :
47+ fetch-depth : 0
48+ fetch-tags : true
49+
50+ - name : Configure git identity
51+ run : |
52+ git config --global user.name "github-actions[bot]"
53+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
54+
55+ - name : Enhance PR body with commit authors
56+ env :
57+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
58+ run : |
59+ PR_NUMBER="${{ needs.release-please.outputs.pr-number }}"
60+ echo "Enhancing PR #$PR_NUMBER with author information"
61+
62+ # Get the current PR body
63+ PR_BODY=$(gh pr view "$PR_NUMBER" --json body -q .body)
64+
65+ # Get the last release tag
66+ PREVIOUS_TAG=$(git tag --sort=-version:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1 || echo "")
67+
68+ if [[ -n "$PREVIOUS_TAG" ]]; then
69+ echo "Found previous tag: $PREVIOUS_TAG"
70+
71+ # Generate author credits section
72+ AUTHOR_CREDITS=""
73+ AUTHOR_CREDITS="${AUTHOR_CREDITS}"$'\n\n'"## 👥 Contributors"$'\n\n'
74+
75+ # Get unique contributors since last release
76+ CONTRIBUTORS=$(git log "$PREVIOUS_TAG..HEAD" --format='%an' --no-merges | sort -u)
77+
78+ while IFS= read -r contributor; do
79+ AUTHOR_CREDITS="${AUTHOR_CREDITS}• **${contributor}**"$'\n'
80+ done <<< "$CONTRIBUTORS"
81+
82+ # Add commit details with authors
83+ AUTHOR_CREDITS="${AUTHOR_CREDITS}"$'\n'"## 📝 Commits by Author"$'\n\n'
84+
85+ # Group commits by type with authors
86+ for type in feat fix docs perf deps ci refactor test chore build; do
87+ case $type in
88+ feat) section="### Features" ;;
89+ fix) section="### Bug Fixes" ;;
90+ docs) section="### Documentation" ;;
91+ perf) section="### Performance" ;;
92+ deps) section="### Dependencies" ;;
93+ ci) section="### CI/CD" ;;
94+ refactor) section="### Refactoring" ;;
95+ test) section="### Testing" ;;
96+ chore) section="### Maintenance" ;;
97+ build) section="### Build System" ;;
98+ esac
99+
100+ # Filter commits for this type - simplified pattern to avoid shellcheck issues
101+ COMMITS=""
102+ while IFS= read -r line; do
103+ if echo "$line" | grep -q "^${type}"; then
104+ # Remove type prefix and add bullet point
105+ cleaned="• ${line#"${type}"*: }"
106+ COMMITS="${COMMITS}${cleaned}"$'\n'
107+ fi
108+ done < <(git log "$PREVIOUS_TAG..HEAD" --pretty=format:"%s (@%an)" --no-merges)
109+
110+ if [[ -n "$COMMITS" ]]; then
111+ AUTHOR_CREDITS="${AUTHOR_CREDITS}${section}"$'\n'"${COMMITS}"
112+ fi
113+ done
114+
115+ # Update PR body with author information
116+ NEW_BODY="${PR_BODY}"$'\n\n'"---"$'\n'"${AUTHOR_CREDITS}"
117+
118+ # Escape the body for gh pr edit
119+ echo "$NEW_BODY" > /tmp/pr_body.txt
120+ gh pr edit "$PR_NUMBER" --body-file /tmp/pr_body.txt
121+
122+ echo "PR #$PR_NUMBER has been enhanced with author information"
123+ else
124+ echo "No previous release tag found, skipping author enhancement"
125+ fi
35126
36127 validate-tag :
37128 name : Validate Release Tag
@@ -144,6 +235,7 @@ jobs:
144235 uses : actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
145236 with :
146237 fetch-depth : 0
238+ fetch-tags : true
147239
148240 - name : Download release artifacts (Node 22)
149241 uses : actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
@@ -175,6 +267,15 @@ jobs:
175267
176268 printf "Generating changelog from %s to %s\n" "$PREVIOUS_TAG" "$CURRENT_TAG"
177269
270+ # Debug: Show available tags and commits
271+ echo "Available tags:"
272+ git tag --sort=-version:refname | head -5
273+
274+ if [[ -n "$PREVIOUS_TAG" ]]; then
275+ echo "Commits between $PREVIOUS_TAG and $CURRENT_TAG:"
276+ git log "$PREVIOUS_TAG..$CURRENT_TAG" --oneline --no-merges | head -10
277+ fi
278+
178279 # Generate conventional changelog
179280 if [[ -n "$PREVIOUS_TAG" ]]; then
180281 conventional-changelog -p conventionalcommits -r 2 > temp_changelog.md
@@ -189,33 +290,96 @@ jobs:
189290
190291 # Extract changes from conventional changelog
191292 if [[ -n "$PREVIOUS_TAG" ]]; then
192- # Parse git log for conventional commits and categorize
293+ # Parse git log for conventional commits and categorize with authors
193294 {
194295 echo "### ✨ Features"
195- git log "$PREVIOUS_TAG..$CURRENT_TAG" --pretty=format:"%s" --no-merges | grep -E "^feat(\(.+\))?:" | sed 's/^feat\(([^)]*)\)\?:\s*/* /' || echo "No new features"
296+ FEATURES=$(git log "$PREVIOUS_TAG..$CURRENT_TAG" --pretty=format:"%s (@%an)" --no-merges | { grep -E "^feat(\\([^)]+\\))?:" || true; } | sed -E 's/^feat(\\([^)]+\\))?:\\s*/- /')
297+ if [[ -n "$FEATURES" ]]; then
298+ echo "$FEATURES"
299+ else
300+ echo "- No new features in this release"
301+ fi
196302 echo ""
303+
197304 echo "### 🐛 Bug Fixes"
198- git log "$PREVIOUS_TAG..$CURRENT_TAG" --pretty=format:"%s" --no-merges | grep -E "^fix(\(.+\))?:" | sed 's/^fix\(([^)]*)\)\?:\s*/* /' || echo "No bug fixes"
305+ FIXES=$(git log "$PREVIOUS_TAG..$CURRENT_TAG" --pretty=format:"%s (@%an)" --no-merges | { grep -E "^fix(\\([^)]+\\))?:" || true; } | sed -E 's/^fix(\\([^)]+\\))?:\\s*/- /')
306+ if [[ -n "$FIXES" ]]; then
307+ echo "$FIXES"
308+ else
309+ echo "- No bug fixes in this release"
310+ fi
199311 echo ""
312+
200313 echo "### 📚 Documentation"
201- git log "$PREVIOUS_TAG..$CURRENT_TAG" --pretty=format:"%s" --no-merges | grep -E "^docs(\(.+\))?:" | sed 's/^docs\(([^)]*)\)\?:\s*/* /' || echo "No documentation changes"
314+ DOCS=$(git log "$PREVIOUS_TAG..$CURRENT_TAG" --pretty=format:"%s (@%an)" --no-merges | { grep -E "^docs(\\([^)]+\\))?:" || true; } | sed -E 's/^docs(\\([^)]+\\))?:\\s*/- /')
315+ if [[ -n "$DOCS" ]]; then
316+ echo "$DOCS"
317+ else
318+ echo "- No documentation changes in this release"
319+ fi
202320 echo ""
321+
203322 echo "### ⚡ Performance"
204- git log "$PREVIOUS_TAG..$CURRENT_TAG" --pretty=format:"%s" --no-merges | grep -E "^perf(\(.+\))?:" | sed 's/^perf\(([^)]*)\)\?:\s*/* /' || echo "No performance improvements"
323+ PERF=$(git log "$PREVIOUS_TAG..$CURRENT_TAG" --pretty=format:"%s (@%an)" --no-merges | { grep -E "^perf(\\([^)]+\\))?:" || true; } | sed -E 's/^perf(\\([^)]+\\))?:\\s*/- /')
324+ if [[ -n "$PERF" ]]; then
325+ echo "$PERF"
326+ else
327+ echo "- No performance improvements in this release"
328+ fi
205329 echo ""
330+
206331 echo "### 🔧 Maintenance"
207- git log "$PREVIOUS_TAG..$CURRENT_TAG" --pretty=format:"%s" --no-merges | grep -E "^(chore|ci|build|refactor)(\(.+\))?:" | sed 's/^[^:]*:\s*/* /' || echo "No maintenance changes"
332+ MAINT=$(git log "$PREVIOUS_TAG..$CURRENT_TAG" --pretty=format:"%s (@%an)" --no-merges | { grep -E "^(chore|ci|build|refactor)(\\([^)]+\\))?:" || true; } | sed -E 's/^[^:]+:\\s*/- /')
333+ if [[ -n "$MAINT" ]]; then
334+ echo "$MAINT"
335+ else
336+ echo "- No maintenance changes in this release"
337+ fi
208338 echo ""
209339 } >> release_notes.md
210340
211341 # Add commit count and contributors
212342 COMMIT_COUNT=$(git rev-list --count "$PREVIOUS_TAG..$CURRENT_TAG")
213- CONTRIBUTORS=$(git log "$PREVIOUS_TAG..$CURRENT_TAG" --format='%an' --no-merges | sort -u | wc -l | tr -d ' ')
343+ CONTRIBUTOR_LIST=$(git log "$PREVIOUS_TAG..$CURRENT_TAG" --format='%an' --no-merges | sort -u)
344+ CONTRIBUTOR_COUNT=$(echo "$CONTRIBUTOR_LIST" | wc -l | tr -d ' ')
214345
215346 {
216347 echo "### 📊 Release Statistics"
217348 echo "- **$COMMIT_COUNT** commits since $PREVIOUS_TAG"
218- echo "- **$CONTRIBUTORS** contributor(s) to this release"
349+ echo "- **$CONTRIBUTOR_COUNT** contributor(s) to this release"
350+ echo ""
351+ echo "### 👥 Contributors"
352+ echo "Thanks to the following contributors for this release:"
353+ echo ""
354+ while IFS= read -r contributor; do
355+ # Try to extract GitHub username from git config or use name as-is
356+ # Common patterns: "Name", "username", "Name (username)"
357+ if echo "$contributor" | grep -q '(.*)'; then
358+ # Extract username from parentheses if present
359+ # Extract username using parameter expansion
360+ temp="${contributor#*(}"
361+ username="${temp%)}"
362+ echo "- [@$username](https://github.com/$username) ($contributor)"
363+ else
364+ # Use the name as-is, attempting to link it
365+ echo "- **$contributor**"
366+ fi
367+ done <<< "$CONTRIBUTOR_LIST"
368+ echo ""
369+ echo "### 📝 Full Changelog"
370+ echo "<details>"
371+ echo "<summary>View all commits</summary>"
372+ echo ""
373+ echo "| Commit | Author | Message |"
374+ echo "|--------|--------|---------|"
375+ # Use a while loop to properly escape commit messages
376+ git log "$PREVIOUS_TAG..$CURRENT_TAG" --pretty=format:"%h|%an|%s" --no-merges | while IFS='|' read -r hash author message; do
377+ # Escape pipe characters in the message
378+ escaped_message="${message//|/\\|}"
379+ echo "| [\`$hash\`](https://github.com/${{ github.repository }}/commit/$hash) | **$author** | $escaped_message |"
380+ done
381+ echo ""
382+ echo "</details>"
219383 echo ""
220384 } >> release_notes.md
221385 else
@@ -300,15 +464,25 @@ jobs:
300464 token : ${{ secrets.GITHUB_TOKEN }}
301465 fetch-depth : 0
302466
467+ - name : Configure git identity
468+ run : |
469+ git config --global user.name "github-actions[bot]"
470+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
471+
303472 - name : Update major version tag
304473 run : |
305474 major_tag="${{ needs.validate-tag.outputs.major-version }}"
306475 current_tag="${{ needs.release-please.outputs.tag-name }}"
307476
308477 echo "Updating $major_tag to point to $current_tag"
309478
310- # Delete the major tag if it exists
311- git push origin --delete "$major_tag" || true
479+ # Check if the major tag exists remotely
480+ if git ls-remote --tags origin | grep -q "refs/tags/$major_tag"; then
481+ echo "Tag $major_tag exists remotely, deleting it first"
482+ git push origin --delete "$major_tag"
483+ else
484+ echo "Tag $major_tag does not exist remotely, will create it"
485+ fi
312486
313487 # Create new major tag pointing to current release
314488 git tag -fa "$major_tag" -m "Update $major_tag to $current_tag"
@@ -332,6 +506,7 @@ jobs:
332506 uses : actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
333507 with :
334508 repository : actions/checkout
509+ ref : main
335510 path : test-repo
336511
337512 - name : Test released action
0 commit comments