Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions bin/gstack-pr-title-rewrite.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@
# Output: corrected title on stdout.
#
# Rule: PR titles MUST start with v<NEW_VERSION>. Three cases:
# 1. Already starts with "v<NEW_VERSION> " -> no change.
# 2. Starts with a different "v<digits and dots> " prefix -> replace prefix.
# 1. Already starts with "v<NEW_VERSION>" -> no change.
# 2. Starts with a different "v<digits and dots>" prefix -> replace prefix.
# 3. No version prefix -> prepend "v<NEW_VERSION> ".
#
# Each version prefix may be followed by a space (then a description) OR sit at
# the end of the title as a bare version with no description (e.g. "v1.2.3", the
# format ship/CHANGELOG uses for version-only bumps). Both forms must be handled
# in cases 1 and 2, otherwise a bare version falls through to case 3 and gets a
# second prefix prepended, e.g. "v1.2.3" -> "v1.2.3.4 v1.2.3". The CI workflow
# .github/workflows/pr-title-sync.yml feeds real PR titles through this and then
# `gh pr edit`s the result, so the duplicated title would be written back.
#
# The version-prefix regex matches two or more dot-separated digit segments
# (covers v1.2, v1.2.3, v1.2.3.4) so the rule is portable across repos that
# use 3-part or 4-part versions, but does NOT strip plain words like
Expand All @@ -33,12 +41,20 @@ fi

# Literal prefix match (case statement is glob-quoted by bash, but our
# regex-validated NEW_VERSION has no glob metacharacters so this is safe).
# Match both "v<NEW_VERSION> <description>" and a bare "v<NEW_VERSION>" title.
case "$TITLE" in
"v$NEW_VERSION "*)
"v$NEW_VERSION "*|"v$NEW_VERSION")
printf '%s\n' "$TITLE"
exit 0
;;
esac

REST=$(printf '%s' "$TITLE" | sed -E 's/^v[0-9]+(\.[0-9]+)+ //')
printf 'v%s %s\n' "$NEW_VERSION" "$REST"
# Strip an existing different version prefix whether it is followed by a space
# (then a description) or sits at the end of the title (bare version).
REST=$(printf '%s' "$TITLE" | sed -E 's/^v[0-9]+(\.[0-9]+)+( |$)//')
if [ -n "$REST" ]; then
printf 'v%s %s\n' "$NEW_VERSION" "$REST"
else
# Title was nothing but a (different) version prefix; emit the bare new one.
printf 'v%s\n' "$NEW_VERSION"
fi
17 changes: 17 additions & 0 deletions test/pr-title-rewrite.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,23 @@ describe('gstack-pr-title-rewrite', () => {
expect(rewrite('1.2.3.4', 'v1.2.3 feat: foo').stdout).toBe('v1.2.3.4 feat: foo');
});

test('bare correct version (no description): no change, not duplicated', () => {
// CHANGELOG/ship uses a version-only title for branch-ahead bumps. It must
// stay as-is, not become "v1.2.3.4 v1.2.3.4".
expect(rewrite('1.2.3.4', 'v1.2.3.4').stdout).toBe('v1.2.3.4');
});

test('bare different version (no description): replaces, not duplicates', () => {
// Must strip the stale prefix even with nothing after it, otherwise CI
// writes back "v1.2.3.4 v1.2.3".
expect(rewrite('1.2.3.4', 'v1.2.3').stdout).toBe('v1.2.3.4');
});

test('idempotent on a bare version title', () => {
const once = rewrite('1.2.3.4', 'v1.2.3').stdout;
expect(rewrite('1.2.3.4', once).stdout).toBe(once);
});

test('no version prefix: prepends', () => {
expect(rewrite('1.2.3.4', 'feat: foo').stdout).toBe('v1.2.3.4 feat: foo');
});
Expand Down
Loading