Files
boshu2__agentops/scripts/extract-release-notes.sh
T
Bo 2a2d14fe72 docs(release): correct extract-release-notes.sh header to match killed fallback (ag-d0f #fallback-comment) (#570)
## Summary
- The `ag-d0f` "kill the silent fallback" change made
`scripts/extract-release-notes.sh` hard-error when no curated
`docs/releases/*-notes.md` exists (lines 50–60), but the file header
still advertised *"Falls back to CHANGELOG.md extraction if no curated
notes exist."*
- That comment contradicted the implemented behavior and could mislead a
maintainer about release-pipeline behavior (the exact class of
silent-fallback confusion that shipped raw CHANGELOG dumps as the
3.0.0/3.0.1 release bodies).
- Rewrites the header docstring to state the no-fallback contract:
curated notes + matching CHANGELOG section are required; a missing file
is a hard error; structure is enforced by
`scripts/validate-release-notes.sh`.

Comment-only change — no behavior change.

## Test plan
- [x] `shellcheck scripts/extract-release-notes.sh` — clean
- [x] `bats tests/scripts/validate-release-notes.bats` — 14/14 green
- [x] `git diff --stat` — 7/-4, comment lines only

Closes-scenario: ag-d0f#fallback-comment
Bounded-context: BC5-Runtime
Evidence: scripts/extract-release-notes.sh; bats
tests/scripts/validate-release-notes.bats (14/14)
2026-05-28 05:01:18 -04:00

100 lines
3.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Assemble the GitHub Release body for a given version.
# Body = curated highlights + the version's CHANGELOG section embedded in <details>.
#
# Usage: scripts/extract-release-notes.sh v2.9.2 [v2.9.0]
# $1 = current tag (required)
# $2 = previous tag (optional, for footer link)
#
# Requires: docs/releases/YYYY-MM-DD-v<version>-notes.md curated highlights AND a
# matching CHANGELOG.md section. There is NO fallback to a raw CHANGELOG dump — a
# missing curated file or CHANGELOG entry is a hard error (3.0.0/3.0.1 shipped raw
# dumps precisely because this used to fall back). Structure is enforced by
# scripts/validate-release-notes.sh.
#
# Output: writes release-notes.md to repo root
set -euo pipefail
TAG="${1:?Usage: extract-release-notes.sh TAG [PREV_TAG]}"
PREV_TAG="${2:-}"
VERSION="${TAG#v}"
REPO="boshu2/agentops"
CHANGELOG="CHANGELOG.md"
if [[ ! -f "$CHANGELOG" ]]; then
echo "ERROR: $CHANGELOG not found" >&2
exit 1
fi
# Extract the section for this version from CHANGELOG.md.
# Matches from "## [VERSION]" to the next "## [" line (exclusive).
CHANGELOG_SECTION=$(awk -v ver="$VERSION" '
/^## \[/ {
if (found) exit
if (index($0, "[" ver "]")) { found=1; next }
}
found { print }
' "$CHANGELOG")
# Strip leading + trailing blank lines so the section doesn't introduce
# double-blanks when wrapped in `echo ""` boilerplate by the formatters below.
CHANGELOG_SECTION="$(printf '%s\n' "$CHANGELOG_SECTION" \
| awk 'NF { found = 1 } found' \
| awk 'NF { last = NR } { line[NR] = $0 } END { for (i = 1; i <= last; i++) print line[i] }')"
if [[ -z "$CHANGELOG_SECTION" ]]; then
echo "ERROR: No CHANGELOG entry for $VERSION — add entry before releasing" >&2
exit 1
fi
# Check for curated release notes (written by /release skill or manually).
# These are plain-English highlights, not the raw changelog.
# Curated notes are REQUIRED — no silent fallback to the raw CHANGELOG. A missing
# or non-conforming file is a hard error (3.0.0/3.0.1 shipped raw CHANGELOG dumps
# precisely because this used to fall back). Structure is enforced separately by
# scripts/validate-release-notes.sh; here we only require the file to exist.
NOTES_FILE=$(find docs/releases -name "*-v${VERSION}-notes.md" 2>/dev/null | head -1 || true)
if [[ -z "$NOTES_FILE" || ! -f "$NOTES_FILE" ]]; then
echo "ERROR: no curated release-notes file docs/releases/*-v${VERSION}-notes.md" >&2
echo " Write one per skills/release/references/release-notes.md before tagging." >&2
echo " The raw CHANGELOG is not an acceptable release body." >&2
exit 1
fi
CURATED_NOTES=$(cat "$NOTES_FILE")
CURATED_NOTES="$(printf '%s' "$CURATED_NOTES" \
| sed \
-e "s#(../../CHANGELOG.md)#(https://github.com/${REPO}/blob/main/CHANGELOG.md)#g" \
-e "s#(../CHANGELOG.md)#(https://github.com/${REPO}/blob/main/docs/CHANGELOG.md)#g")"
echo "Using curated release notes from $NOTES_FILE" >&2
# Build the release notes file
{
# Header
cat <<HEADER
\`brew update && brew upgrade agentops\` · \`bash <(curl -fsSL https://raw.githubusercontent.com/boshu2/agentops/main/scripts/install.sh)\` · [checksums](https://github.com/${REPO}/releases/download/${TAG}/checksums.txt) · [verify provenance](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds)
---
HEADER
# Curated highlights (required) + the full changelog tucked in a <details>.
echo "$CURATED_NOTES"
echo ""
echo "---"
echo ""
echo "<details>"
echo "<summary>Full changelog</summary>"
echo ""
echo "$CHANGELOG_SECTION"
echo ""
echo "</details>"
echo ""
echo "---"
echo ""
echo "**Full Changelog**: https://github.com/${REPO}/compare/${PREV_TAG:-v0.0.0}...${TAG}"
} > release-notes.md
echo "Release notes written to release-notes.md ($(wc -l < release-notes.md) lines)"