Skip to content

Commit ff4070d

Browse files
committed
Write the generated notes where the release can actually commit them
Two bugs, both fatal to the generate-notes path. write_changelog_section ran during preflight, so it dirtied a tracked file before the release-commit step, which refuses to run on an unclean tree. Every generated-notes release would have died there. And nothing staged CHANGELOG.md anyway, so the section would never have reached main. The write now happens in the release-commit step and is staged with the version bump, which also puts it in DOC_FILES before the binaries build. The insertion point matched the first `## [` of any kind, which is the live `## [Unreleased]` heading — the new release sorted above it and stranded its contents below every future release. It now targets the first versioned header, and warns when Unreleased still has content, since nothing renames it any more. previous_tag is gone. The script fetches with --no-tags and never refreshes tags, so deriving the previous tag locally would replay already-released pull requests from a stale clone. GitHub derives it from release history instead. That also removes a set -e trap: the pipeline returned 1 on a first release and only survived because command substitution under `||` suspends errexit. CL-7888
1 parent 9702ef0 commit ff4070d

1 file changed

Lines changed: 35 additions & 24 deletions

File tree

scripts/release.sh

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -307,33 +307,25 @@ changelog_section() {
307307
' CHANGELOG.md
308308
}
309309

310-
# Most recent vX.Y.Z tag before this one, so generated notes span the right
311-
# range. Empty output lets GitHub pick, which is right for a first release.
312-
previous_tag() {
313-
git tag --list 'v*' --sort=-v:refname \
314-
| grep -v "^${TAG}$" \
315-
| head -1
316-
}
317-
318310
# GitHub renders the merged-PR list, crediting each author. The tag does not
319311
# exist yet at this point in the run, so target_commitish anchors the range end
320312
# at the commit being released.
313+
# previous_tag_name is deliberately NOT passed. The script fetches with
314+
# --no-tags and never refreshes local tags, so deriving the previous tag
315+
# locally would silently widen the range on a stale clone and replay
316+
# already-released pull requests. GitHub derives it from actual release
317+
# history instead.
321318
generate_notes() {
322-
local prev
323-
prev=$(previous_tag)
324-
local args=(
325-
-X POST
326-
"repos/$MAIN_REPO/releases/generate-notes"
327-
-f "tag_name=$TAG"
328-
-f "target_commitish=$(git rev-parse HEAD)"
329-
)
330-
[ -n "$prev" ] && args+=(-f "previous_tag_name=$prev")
331-
gh api "${args[@]}" --jq '.body'
319+
gh api -X POST "repos/$MAIN_REPO/releases/generate-notes" \
320+
-f "tag_name=$TAG" \
321+
-f "target_commitish=$(git rev-parse HEAD)" \
322+
--jq '.body'
332323
}
333324

334-
# Insert a rendered section immediately before the first existing `## [`
335-
# header, so it lands after the file's title and preamble and ahead of every
336-
# older release. Appending at the top of the file would bury the preamble.
325+
# Insert a rendered section immediately before the first existing VERSIONED
326+
# header, so it lands after the title, the preamble, and any `## [Unreleased]`
327+
# section, and ahead of every older release. Matching the first `## [` of any
328+
# kind would sort the new release above a live `[Unreleased]` heading.
337329
write_changelog_section() {
338330
local body=$1 tmp first
339331
# Demote the generated body's own h2s ("## What's Changed", "## New
@@ -342,7 +334,7 @@ write_changelog_section() {
342334
# to its header and `/changelog` renders an empty release.
343335
body=$(printf '%s\n' "$body" | sed 's/^## /### /')
344336
tmp=$(mktemp)
345-
first=$(grep -n '^## \[' CHANGELOG.md | head -1 | cut -d: -f1)
337+
first=$(grep -n '^## \[[0-9]' CHANGELOG.md | head -1 | cut -d: -f1)
346338
if [ -z "$first" ]; then
347339
cp CHANGELOG.md "$tmp"
348340
printf '\n## [%s] - %s\n\n%s\n' "$VERSION" "$(date -u +%Y-%m-%d)" "$body" >> "$tmp"
@@ -392,8 +384,19 @@ else
392384
SECTION=$(generate_notes) || die "gh could not generate release notes for $TAG"
393385
[ -n "$(printf '%s' "$SECTION" | sed '/^[[:space:]]*$/d')" ] || \
394386
die "GitHub returned empty release notes for $TAG"
395-
write_changelog_section "$SECTION"
387+
# Deferred, not written here: the release commit step below refuses to run
388+
# on a dirty tree, so touching a tracked file during preflight would abort
389+
# every generated-notes release before it started.
390+
CHANGELOG_PENDING=$SECTION
396391
NOTES_SOURCE="generated from merged pull requests"
392+
# Nothing renames `## [Unreleased]` any more, so content left there is
393+
# invisible to /changelog (parseChangelogText skips non-semver headers)
394+
# and will never appear in a release. Say so rather than silently
395+
# stranding it below the new section.
396+
if awk '/^## \[Unreleased\]/ { u = 1; next } /^## \[/ { u = 0 } u && NF' \
397+
CHANGELOG.md | grep -q .; then
398+
info "WARNING: CHANGELOG.md has a non-empty ## [Unreleased] section; generated notes do not consume it. Fold it in or delete it."
399+
fi
397400
fi
398401
{
399402
printf '%s\n\n' "$SECTION"
@@ -421,6 +424,14 @@ else
421424
mv package.json.tmp package.json
422425
[ "$(jq -r .version package.json)" = "$VERSION" ] || die "package.json bump failed"
423426
git add package.json
427+
# Generated notes land in the release commit, so the section ships in
428+
# DOC_FILES with the binaries built in the next step and reaches main with
429+
# the version bump.
430+
if [ -n "${CHANGELOG_PENDING:-}" ]; then
431+
write_changelog_section "$CHANGELOG_PENDING"
432+
git add CHANGELOG.md
433+
info "wrote generated ## [$VERSION] section into CHANGELOG.md"
434+
fi
424435
git commit -q -m "Release $FORMULA $VERSION"
425436
info "committed release $VERSION (PR and tag deferred until after build)"
426437
fi
@@ -495,7 +506,7 @@ else
495506
if [ -z "$PR_NUM" ]; then
496507
gh pr create --repo "$MAIN_REPO" --head "$RELEASE_BRANCH" --base main \
497508
--title "Release $FORMULA $VERSION" \
498-
--body "Version bump to $VERSION. Release notes are the CHANGELOG.md \`## [$VERSION]\` section." >/dev/null
509+
--body "Version bump to $VERSION. Release notes are generated from the pull requests merged since the previous release." >/dev/null
499510
PR_NUM=$(gh pr list --repo "$MAIN_REPO" --head "$RELEASE_BRANCH" --state open \
500511
--json number --jq '.[0].number // empty')
501512
[ -n "$PR_NUM" ] || die "could not create or find the release PR for $RELEASE_BRANCH"

0 commit comments

Comments
 (0)