Files
pad/scripts/release-previous-tag.sh
T
xarmian 2d8aedc9a4 fix(release): the changelog starts at the previous stable release by version, and its exclude filters match GitHub's hash-prefixed entries (TASK-3268) (#1626)
* fix(release): the changelog starts at the previous stable release by version, and its exclude filters match GitHub's hash-prefixed entries (TASK-3268)

Two release-notes defects, measured with the pinned GoReleaser (v2.15.4) in a
changelog-only dry run whose output for v0.16.0 is byte-identical to the
published notes.

Base: GoReleaser took the previous tag from git describe on the new tag's
parent, which sees only tags on that ancestry. Releases are cut on
release-X.Y.x branches, so v0.16.0 was built from v0.15.0-rc.1, and a tag cut
from main now would describe back past v0.16.0: GitHub's compare reports 547
commits from there against 301 from v0.16.0, re-listing all of v0.16.0.
release.yml now pins GORELEASER_PREVIOUS_TAG through
scripts/release-previous-tag.sh (the highest stable tag below the current one
by version; an RC gets the previous stable) and fails the run if none exists.

Filters: with `use: github` every entry is "<sha>: <message>", so the
message-anchored excludes never matched and v0.16.0 shipped 30 docs, test, ci
and chore lines. The rule now allows the prefix, a scope, and a type list made
only of excluded types (`docs,test(store):`).

Dry run of v0.16.0 with both fixes: 230 entries become 200. Every one of the 30
removed is an excluded type, and nothing is added.

Claude-Session: https://claude.ai/code/session_016PXRzXhokr61CLbbu3Txj9

* fix(release): a breaking change stays in the notes whatever its type (TASK-3268 codex r1)

The exclude accepted `!` before the colon, so `chore!: ...` would have been
dropped. Codex round 1, P2. The v0.16.0 dry run is unchanged at 200 entries;
an RE2 matrix of 15 messages, each with and without the hash prefix, answers
as intended.

Claude-Session: https://claude.ai/code/session_016PXRzXhokr61CLbbu3Txj9
2026-09-27 19:10:20 -04:00

41 lines
1.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# Print the tag a release's changelog should start from: the highest STABLE
# tag (vX.Y.Z, no pre-release suffix) that sorts below the current tag's
# X.Y.Z, by version and regardless of branch.
#
# Why not GoReleaser's own default: it runs `git describe --tags --abbrev=0`
# on the current tag's parent, which only sees tags on the current tag's
# ancestry. Releases are cut on release-X.Y.x branches, so their tags are not
# on main, and a tag cut from main described back to v0.15.0 while v0.16.0
# already existed. Its notes would have re-listed the whole of v0.16.0.
# TASK-3268 has the measurement.
#
# v0.17.0 -> v0.16.0 (the previous stable release)
# v0.17.0-rc.1 -> v0.16.0 (an RC previews everything its stable will list)
# v0.16.1 -> v0.16.0
#
# Usage: release-previous-tag.sh <current-tag>
# Exits non-zero, printing nothing on stdout, when the current tag is not
# vX.Y.Z[-suffix] or when no stable tag sorts below it. A release must not
# silently fall back to the describe base this script exists to replace.
set -euo pipefail
current="${1:-}"
if [[ ! "$current" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
echo "release-previous-tag: '$current' is not a vX.Y.Z[-suffix] tag" >&2
exit 1
fi
base="${current%%-*}"
previous=""
while IFS= read -r tag; do
[[ "$tag" == "$base" ]] && break
previous="$tag"
done < <({ git tag --list 'v*' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | grep -vxF "$base" || true; echo "$base"; } | sort -V)
if [[ -z "$previous" ]]; then
echo "release-previous-tag: no stable tag sorts below $base" >&2
exit 1
fi
echo "$previous"