Skip to content

Commit 04be56e

Browse files
ThomasK33claude
andauthored
fix: drop the component suffix from the release branch name (#147)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Thomas Kosiewski <tk@coder.com>
1 parent fc0680d commit 04be56e

3 files changed

Lines changed: 54 additions & 1 deletion

File tree

docs/RELEASE-PROCESS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Three workflows cooperate:
2525

2626
1. **Release Please** ([`.github/workflows/release-please.yml`](../.github/workflows/release-please.yml)) runs on every push to `main`. It executes [`src/tools/release-please-runner.ts`](../src/tools/release-please-runner.ts), which runs release-please as a library with Communique registered as the changelog generator (`"changelog-type": "communique"` in [`release-please-config.json`](../release-please-config.json)). Each run:
2727
- tags and creates the GitHub Release for any release PR that merged since the last run, then dispatches the **Release** workflow for that tag;
28-
- opens or updates the single release PR (title `chore(release): <version>`, head branch `release-please--branches--main--components--agent-tty`), carrying the `package.json` version bump plus a new `CHANGELOG.md` section written by Communique (`communique generate HEAD <last-tag> --concise`);
28+
- opens or updates the single release PR (title `chore(release): <version>`, head branch `release-please--branches--main`), carrying the `package.json` version bump plus a new `CHANGELOG.md` section written by Communique (`communique generate HEAD <last-tag> --concise`);
2929
- dispatches **CI** and **Validate skills** onto the release branch (pushes made with the workflow token never trigger `pull_request` workflows on their own).
3030
2. **Release** ([`.github/workflows/release.yml`](../.github/workflows/release.yml)) is the publish pipeline (see below). It is dispatched by Release Please after the tag exists, and still also triggers on manually pushed `v*` tags.
3131
3. **CI** runs on the release PR like on any other PR and gates the merge.

src/tools/release-please-runner.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,23 @@ function joinSections(head: string, entry: string, rest: string): string {
329329
* `release-please-config.json` keeps the standard `"release-type": "node"`.
330330
*/
331331
export class CommuniqueNodeStrategy extends Node {
332+
/**
333+
* The stock strategy always embeds the package name in the release branch
334+
* (`release-please--branches--main--components--agent-tty`), even when
335+
* `include-component-in-tag` is false. Follow the tag setting instead so
336+
* this single-package repo gets the plain `release-please--branches--main`.
337+
*
338+
* Migration note: buildRelease() skips release creation when a merged PR's
339+
* branch component does not match this value, so a release PR opened on
340+
* the old component-suffixed branch must be closed — never merged — once
341+
* this is live; the next push to main recreates it on the new branch.
342+
*/
343+
override async getBranchComponent(): Promise<string | undefined> {
344+
return this.includeComponentInTag
345+
? await super.getBranchComponent()
346+
: undefined;
347+
}
348+
332349
protected override async buildUpdates(
333350
options: BuildUpdatesOptions,
334351
): Promise<Update[]> {

test/unit/tools/release-please-runner.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { describe, expect, it } from 'vitest';
44
// compatibility contract the runner depends on but release-please does not
55
// document — the merged release PR body must parse back into a version +
66
// notes, otherwise no GitHub Release is created on merge.
7+
import { BranchName } from 'release-please/build/src/util/branch-name.js';
78
import { PullRequestBody } from 'release-please/build/src/util/pull-request-body.js';
89
import {
910
PullRequestTitle,
@@ -12,6 +13,7 @@ import {
1213
import { Version } from 'release-please/build/src/version.js';
1314

1415
import {
16+
CommuniqueNodeStrategy,
1517
UnreleasedAwareChangelog,
1618
assertLlmCredentials,
1719
buildCommuniqueArgs,
@@ -358,6 +360,40 @@ describe('createCommuniqueChangelogNotes', () => {
358360
});
359361
});
360362

363+
describe('CommuniqueNodeStrategy branch component', () => {
364+
// The branch component follows include-component-in-tag (the stock strategy
365+
// always embeds the package name in the branch). The fake `this` works
366+
// because the override only touches that flag and, on the true path, the
367+
// stock implementation's `component` field.
368+
it('drops the component when tags do not carry one', async () => {
369+
await expect(
370+
CommuniqueNodeStrategy.prototype.getBranchComponent.call({
371+
includeComponentInTag: false,
372+
} as unknown as CommuniqueNodeStrategy),
373+
).resolves.toBeUndefined();
374+
});
375+
376+
it('keeps the stock component when tags carry one', async () => {
377+
await expect(
378+
CommuniqueNodeStrategy.prototype.getBranchComponent.call({
379+
includeComponentInTag: true,
380+
component: 'agent-tty',
381+
} as unknown as CommuniqueNodeStrategy),
382+
).resolves.toBe('agent-tty');
383+
});
384+
385+
it('round-trips the short branch name (release-time contract)', () => {
386+
// buildRelease() parses the merged PR's branch and skips the release on a
387+
// component mismatch, so the componentless name must parse back cleanly.
388+
expect(BranchName.ofTargetBranch('main').toString()).toBe(
389+
'release-please--branches--main',
390+
);
391+
const parsed = BranchName.parse('release-please--branches--main');
392+
expect(parsed?.getTargetBranch()).toBe('main');
393+
expect(parsed?.getComponent()).toBeUndefined();
394+
});
395+
});
396+
361397
describe('workflow outputs', () => {
362398
it('maps releases and pull requests into workflow outputs', () => {
363399
expect(

0 commit comments

Comments
 (0)