77
88jobs :
99 assemble :
10+ # RC tags are pre-release; only assemble notes for final releases.
11+ if : ${{ !contains(github.ref_name, '-rc') }}
1012 runs-on : ubuntu-latest
1113 permissions :
1214 contents : read
3133 # Check out the tagged commit (not main HEAD) so a fragment merged
3234 # into main between the tag push and this workflow's run is not
3335 # accidentally rolled into the wrong release.
34- uses : actions/checkout@v6
36+ uses : actions/checkout@v7
3537 with :
3638 ref : ${{ github.sha }}
3739 token : ${{ steps.app-token.outputs.token }}
4547 run : |
4648 set -euo pipefail
4749
50+ # ── Phase 1: read fragments from the tagged commit ──────────
51+ # The checkout step landed us on the tagged commit so that
52+ # fragments merged into main *after* the tag are excluded.
4853 shopt -s nullglob
4954 fragments=( release-notes.d/unreleased/*.md )
5055 if [[ ${#fragments[@]} -eq 0 ]]; then
5459
5560 tmp=$(mktemp)
5661 for f in "${fragments[@]}"; do
57- # Extract frontmatter values: strip "key: " prefix, take first match.
58- # Plain field-split breaks on URLs because they contain colons.
5962 pr=$(sed -n 's/^pr: *//p' "$f" | head -1)
6063 url=$(sed -n 's/^url: *//p' "$f" | head -1)
6164 date=$(sed -n 's/^date: *//p' "$f" | head -1)
62- # Print everything after the second `---` line verbatim — once
63- # we're past the closing frontmatter marker, a body line that
64- # happens to be `---` (Markdown horizontal rule) must be kept,
65- # not counted as a third delimiter.
6665 note=$(awk 'p {print; next} /^---$/ {if (++c == 2) p = 1}' "$f" | sed '/^[[:space:]]*$/d' | tr '\n' ' ' | sed 's/[[:space:]]*$//')
6766 if [[ -z "$pr" || -z "$url" || -z "$date" || -z "$note" ]]; then
6867 echo "Malformed fragment: $f" >&2
@@ -81,17 +80,30 @@ jobs:
8180 done < "$tmp"
8281 printf '\n' >> "$new_section"
8382
83+ # ── Phase 2: branch from main so the PR contains only
84+ # release-notes changes, not unrelated diffs between
85+ # the tagged commit and main HEAD ─────────────────────
86+ git fetch origin main
87+ BRANCH="release-notes/assemble-${TAG}"
88+ git config user.name "${APP_SLUG}[bot]"
89+ git config user.email "${APP_USER_ID}+${APP_SLUG}[bot]@users.noreply.github.com"
90+ git checkout -b "$BRANCH" origin/main
91+
92+ # ── Phase 3: apply release-notes changes on top of main ─
8493 touch RELEASE-NOTES.md
8594 cat "$new_section" RELEASE-NOTES.md > RELEASE-NOTES.md.new
8695 mv RELEASE-NOTES.md.new RELEASE-NOTES.md
96+ git add RELEASE-NOTES.md
8797
88- git rm -- release-notes.d/unreleased/*.md
98+ # Remove only the fragments captured from the tagged commit,
99+ # not the current main glob which may include post-tag fragments.
100+ # The -f guard skips fragments already absent from main.
101+ for f in "${fragments[@]}"; do
102+ if [[ -f "$f" ]]; then
103+ git rm -- "$f"
104+ fi
105+ done
89106
90- BRANCH="release-notes/assemble-${TAG}"
91- git config user.name "${APP_SLUG}[bot]"
92- git config user.email "${APP_USER_ID}+${APP_SLUG}[bot]@users.noreply.github.com"
93- git checkout -b "$BRANCH"
94- git add RELEASE-NOTES.md
95107 git commit -s -m "docs: assemble release notes for ${TAG}"
96108 # Force-push so a re-run (re-tag, manual workflow re-run) overwrites
97109 # the prior branch rather than failing non-fast-forward.
0 commit comments