From a849556a33105f0e2d8d491d38c04a5db45c3f8d Mon Sep 17 00:00:00 2001 From: Jean-Pierre Martineau Date: Wed, 9 Sep 2026 02:43:07 -0400 Subject: [PATCH] A release with notes should not publish 'No changelog entry' for losing a race --- .claude/skills/release/SKILL.md | 16 +++++++++++++--- .github/workflows/github-release.yml | 27 ++++++++++++++++----------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/.claude/skills/release/SKILL.md b/.claude/skills/release/SKILL.md index 032d7f2..74733e1 100644 --- a/.claude/skills/release/SKILL.md +++ b/.claude/skills/release/SKILL.md @@ -121,9 +121,19 @@ gh run watch --exit-status gh release view vX.Y.Z ``` -Five platform builds plus the release job, so it takes a few minutes. Report the release -URL and whether the notes came out of the changelog or fell back to "No changelog entry". -If a build fails, the tag is already public: fix forward with a new patch version rather +Five platform builds plus the release job, so it takes a few minutes. **Check the notes +actually came out of the changelog** — a green run is not proof, because the fallback is a +successful step: + +``` +gh release view vX.Y.Z --json body --jq .body | head -3 +``` + +If that reads "No changelog entry for X.Y.Z.", the extraction failed rather than the +changelog being empty. Fix the workflow, then repair the published notes in place with +`gh release edit vX.Y.Z --notes-file` — the binaries are fine and the tag does not move. + +If a *build* fails, the tag is already public: fix forward with a new patch version rather than deleting and re-pushing a tag people may have fetched. ## At 0.9.0 the changelog resets diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 37f9c48..6c68ab6 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -74,17 +74,22 @@ jobs: run: | # The section for this version, between its own heading and the next one. If the # changelog has nothing for it, say so plainly rather than inventing notes. - if awk -v v="$VERSION" ' - $0 ~ "^## \\[" v "\\]" {found=1; next} - found && /^## \[/ {exit} - found {print} - ' CHANGELOG.md | sed '/^$/d' | head -1 | grep -q .; then - awk -v v="$VERSION" ' - $0 ~ "^## \\[" v "\\]" {found=1; next} - found && /^## \[/ {exit} - found {print} - ' CHANGELOG.md > notes.md - else + # + # Extracted once, into the file, and the *file* is what gets tested. It used to + # run twice — once down a `| sed | head -1 | grep -q .` pipeline to decide, then + # again for real — and this step runs under `bash -e -o pipefail`, where that + # pipeline is a race it can lose. `head -1` exits the moment it has its line and + # closes the pipe; if `sed` still has bytes to write it dies on SIGPIPE, pipefail + # promotes that to a failed condition, and a version with a perfectly good + # changelog section publishes "No changelog entry" instead. It only bites once a + # section outgrows one buffered write, which is why every entry under 4 KB was + # fine and 0.3.1 was not — while 0.3.0, the same size, happened to win. + awk -v v="$VERSION" ' + $0 ~ "^## \\[" v "\\]" {found=1; next} + found && /^## \[/ {exit} + found {print} + ' CHANGELOG.md > notes.md + if ! grep -q '[^[:space:]]' notes.md; then echo "No changelog entry for $VERSION." > notes.md fi echo "--- notes ---"; cat notes.md