Skip to content

Commit 97c27cc

Browse files
authored
feat: derive release bump only from the title bang marker (#268)
The release workflow scanned the PR title and body for "BREAKING CHANGE(S)" and forced a major bump on any match. Prose that merely mentioned the phrase, including a sentence stating there was no breaking change, tripped it. This is the same footgun that mis-cut a major in getstream-ruby. Treat the `\!` marker in the conventional-commits title (e.g. `feat\!:`) as the sole breaking-change signal and stop reading the PR body entirely. Drop the now-unused --body / --body-file options and the body plumbing in release.yml.
1 parent 39b2317 commit 97c27cc

2 files changed

Lines changed: 5 additions & 19 deletions

File tree

.github/workflows/release.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,9 @@ jobs:
6464
if: github.event_name == 'pull_request' && steps.already_released.outputs.value != 'true'
6565
env:
6666
PR_TITLE: ${{ github.event.pull_request.title }}
67-
PR_BODY: ${{ github.event.pull_request.body }}
6867
run: |
69-
PR_BODY_FILE=$(mktemp)
70-
printf '%s' "$PR_BODY" > "$PR_BODY_FILE"
7168
python3 scripts/release/bump_version.py \
7269
--title "$PR_TITLE" \
73-
--body-file "$PR_BODY_FILE" \
7470
--output "$GITHUB_OUTPUT"
7571
7672
- name: Determine version bump (manual)

scripts/release/bump_version.py

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,11 @@ def find_latest_semver_tag() -> str:
6565
return "{}.{}.{}".format(*versions[-1])
6666

6767

68-
def determine_bump_type(title: str, body: str) -> str:
68+
def determine_bump_type(title: str) -> str:
69+
# Breaking changes are signalled only by the `!` marker in the title
70+
# (e.g. `feat!:`). Free-text body/title prose is not trusted: a PR that
71+
# merely mentions "BREAKING CHANGE" must not force a major bump.
6972
title = title.strip()
70-
body = body.strip()
71-
breaking_re = re.compile(r"BREAKING[ -]CHANGES?", re.IGNORECASE)
72-
if breaking_re.search(title) or breaking_re.search(body):
73-
return "major"
7473
match = re.match(r"^([a-zA-Z]+)(\([^)]+\))?(!)?:", title)
7574
if not match:
7675
return "none"
@@ -119,12 +118,6 @@ def parse_bool(value: str) -> bool:
119118
return value.strip().lower() == "true"
120119

121120

122-
def resolve_body(args: argparse.Namespace) -> str:
123-
if args.body_file:
124-
return Path(args.body_file).read_text(encoding="utf-8")
125-
return args.body or ""
126-
127-
128121
def write_outputs(output_path: str, entries: dict[str, str]) -> None:
129122
if not output_path:
130123
for key, value in entries.items():
@@ -138,8 +131,6 @@ def write_outputs(output_path: str, entries: dict[str, str]) -> None:
138131
def main() -> int:
139132
parser = argparse.ArgumentParser()
140133
parser.add_argument("--title", default="")
141-
parser.add_argument("--body", default="")
142-
parser.add_argument("--body-file", dest="body_file", default="")
143134
parser.add_argument("--output", default="")
144135
parser.add_argument("--manual-bump", dest="manual_bump", default="")
145136
parser.add_argument(
@@ -174,8 +165,7 @@ def main() -> int:
174165
)
175166
return 0
176167

177-
body = resolve_body(args)
178-
bump = determine_bump_type(args.title, body)
168+
bump = determine_bump_type(args.title)
179169
if bump == "none":
180170
write_outputs(
181171
args.output,

0 commit comments

Comments
 (0)