mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-06-16 15:13:31 -07:00
fix: scope prerelease note reuse by version
This commit is contained in:
@@ -2,3 +2,4 @@ type: fixed
|
||||
area: release
|
||||
|
||||
- Kept the GitHub release `What's Changed` and `New Contributors` attribution sections when CI regenerates release notes from the committed changelog.
|
||||
- Scoped prerelease note reuse to the same base version so a new beta line starts from current fragments instead of stale notes from older prereleases.
|
||||
|
||||
+4
-2
@@ -61,8 +61,10 @@
|
||||
committed file — so review it before committing. If you add more
|
||||
`changes/*.md` fragments for a later beta/RC, rerun
|
||||
`bun run changelog:prerelease-notes --version <version>`; the generator uses
|
||||
the existing prerelease notes as the baseline and asks Claude to merge only
|
||||
the new fragment material. Do not run `bun run changelog:build`.
|
||||
the existing prerelease notes as the baseline only when their hidden
|
||||
`prerelease-base-version` marker matches the current base version, and asks
|
||||
Claude to merge only the new fragment material. Do not run
|
||||
`bun run changelog:build`.
|
||||
6. Tag the commit: `git tag v<version>`.
|
||||
7. Push commit + tag.
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
> This is a prerelease build for testing. Stable changelog and docs-site updates remain pending until the final stable release.
|
||||
|
||||
<!-- prerelease-base-version: 0.17.0 -->
|
||||
|
||||
## Highlights
|
||||
### Changed
|
||||
|
||||
|
||||
@@ -605,6 +605,7 @@ test('writePrereleaseNotesForVersion writes cumulative beta notes without mutati
|
||||
|
||||
const prereleaseNotes = fs.readFileSync(outputPath, 'utf8');
|
||||
assert.match(prereleaseNotes, /^> This is a prerelease build for testing\./m);
|
||||
assert.match(prereleaseNotes, /<!-- prerelease-base-version: 0\.11\.3 -->/);
|
||||
assert.match(prereleaseNotes, /## Highlights\n### Added\n- Polished: added entry\./);
|
||||
assert.match(prereleaseNotes, /### Fixed\n- Polished: fixed entry\./);
|
||||
assert.match(prereleaseNotes, /## Installation\n\nSee the README and docs\/installation guide/);
|
||||
@@ -620,6 +621,8 @@ test('writePrereleaseNotesForVersion reuses existing prerelease notes when addin
|
||||
const existingNotes = [
|
||||
'> This is a prerelease build for testing. Stable changelog and docs-site updates remain pending until the final stable release.',
|
||||
'',
|
||||
'<!-- prerelease-base-version: 0.11.3 -->',
|
||||
'',
|
||||
'## Highlights',
|
||||
'### Added',
|
||||
'- Overlay: Previous beta entry.',
|
||||
@@ -679,6 +682,61 @@ test('writePrereleaseNotesForVersion reuses existing prerelease notes when addin
|
||||
}
|
||||
});
|
||||
|
||||
test('writePrereleaseNotesForVersion ignores unmarked prerelease notes from an older release line', async () => {
|
||||
const { writePrereleaseNotesForVersion } = await loadModule();
|
||||
const workspace = createWorkspace('prerelease-ignore-unmarked-old-notes');
|
||||
const projectRoot = path.join(workspace, 'SubMiner');
|
||||
const existingNotes = [
|
||||
'> This is a prerelease build for testing. Stable changelog and docs-site updates remain pending until the final stable release.',
|
||||
'',
|
||||
'## Highlights',
|
||||
'### Added',
|
||||
'- Settings Window: Previous release line entry.',
|
||||
'',
|
||||
'## Installation',
|
||||
'',
|
||||
'See the README and docs/installation guide for full setup steps.',
|
||||
'',
|
||||
].join('\n');
|
||||
|
||||
fs.mkdirSync(path.join(projectRoot, 'changes'), { recursive: true });
|
||||
fs.mkdirSync(path.join(projectRoot, 'release'), { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.join(projectRoot, 'package.json'),
|
||||
JSON.stringify({ name: 'subminer', version: '0.17.0-beta.1' }, null, 2),
|
||||
'utf8',
|
||||
);
|
||||
fs.writeFileSync(path.join(projectRoot, 'release', 'prerelease-notes.md'), existingNotes, 'utf8');
|
||||
fs.writeFileSync(
|
||||
path.join(projectRoot, 'changes', '001.md'),
|
||||
[
|
||||
'type: changed',
|
||||
'area: overlay',
|
||||
'',
|
||||
'- Replaced subtitle delay actions with native mpv keybindings.',
|
||||
].join('\n'),
|
||||
'utf8',
|
||||
);
|
||||
|
||||
try {
|
||||
const stub = defaultStubClaude();
|
||||
const outputPath = writePrereleaseNotesForVersion({
|
||||
cwd: projectRoot,
|
||||
version: '0.17.0-beta.1',
|
||||
deps: { runClaude: stub.runClaude },
|
||||
});
|
||||
|
||||
assert.equal(stub.calls.length, 1, 'prerelease should issue exactly one Claude call');
|
||||
assert.doesNotMatch(stub.calls[0]!.input, /EXISTING PRERELEASE NOTES/);
|
||||
assert.doesNotMatch(stub.calls[0]!.input, /Settings Window: Previous release line entry/);
|
||||
|
||||
const prereleaseNotes = fs.readFileSync(outputPath, 'utf8');
|
||||
assert.match(prereleaseNotes, /### Changed\n- Polished: changed entry\./);
|
||||
} finally {
|
||||
fs.rmSync(workspace, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('writePrereleaseNotesForVersion prompts Claude to revise stale prerelease bullets instead of appending fix churn', async () => {
|
||||
const { writePrereleaseNotesForVersion } = await loadModule();
|
||||
const workspace = createWorkspace('prerelease-net-outcome-prompt');
|
||||
@@ -686,6 +744,8 @@ test('writePrereleaseNotesForVersion prompts Claude to revise stale prerelease b
|
||||
const existingNotes = [
|
||||
'> This is a prerelease build for testing. Stable changelog and docs-site updates remain pending until the final stable release.',
|
||||
'',
|
||||
'<!-- prerelease-base-version: 0.12.0 -->',
|
||||
'',
|
||||
'## Highlights',
|
||||
'### Added',
|
||||
'- Config Window: Previous beta entry.',
|
||||
|
||||
@@ -93,6 +93,40 @@ function isSupportedPrereleaseVersion(version: string): boolean {
|
||||
return /^\d+\.\d+\.\d+-(beta|rc)\.\d+$/u.test(normalizeVersion(version));
|
||||
}
|
||||
|
||||
function resolvePrereleaseBaseVersion(version: string): string {
|
||||
const match = /^(\d+\.\d+\.\d+)-(?:beta|rc)\.\d+$/u.exec(normalizeVersion(version));
|
||||
if (!match) {
|
||||
throw new Error(
|
||||
`Unsupported prerelease version (${version}). Expected x.y.z-beta.N or x.y.z-rc.N.`,
|
||||
);
|
||||
}
|
||||
return match[1]!;
|
||||
}
|
||||
|
||||
function renderPrereleaseBaseVersionMarker(version: string): string {
|
||||
return `<!-- prerelease-base-version: ${resolvePrereleaseBaseVersion(version)} -->`;
|
||||
}
|
||||
|
||||
function extractPrereleaseBaseVersionMarker(notes: string): string | null {
|
||||
return (
|
||||
/<!--\s*prerelease-base-version:\s*(\d+\.\d+\.\d+)\s*-->/u.exec(notes)?.[1] ?? null
|
||||
);
|
||||
}
|
||||
|
||||
function stripPrereleaseMetadata(notes: string): string {
|
||||
return notes
|
||||
.replace(/<!--\s*prerelease-base-version:\s*\d+\.\d+\.\d+\s*-->\s*/u, '')
|
||||
.trim();
|
||||
}
|
||||
|
||||
function resolveReusablePrereleaseNotes(notes: string, version: string): string | undefined {
|
||||
const existingBaseVersion = extractPrereleaseBaseVersionMarker(notes);
|
||||
if (existingBaseVersion !== resolvePrereleaseBaseVersion(version)) {
|
||||
return undefined;
|
||||
}
|
||||
return stripPrereleaseMetadata(notes);
|
||||
}
|
||||
|
||||
function verifyRequestedVersionMatchesPackageVersion(
|
||||
options: Pick<ChangelogOptions, 'cwd' | 'version' | 'deps'>,
|
||||
): void {
|
||||
@@ -669,13 +703,16 @@ function renderReleaseNotes(
|
||||
disclaimer?: string;
|
||||
contributions?: Contribution[];
|
||||
contributorSections?: string[];
|
||||
metadata?: string[];
|
||||
},
|
||||
): string {
|
||||
const prefix = options?.disclaimer ? [options.disclaimer, ''] : [];
|
||||
const metadata = options?.metadata?.length ? [...options.metadata, ''] : [];
|
||||
const contributorSections =
|
||||
options?.contributorSections ?? renderContributorsSections(options?.contributions ?? []);
|
||||
return [
|
||||
...prefix,
|
||||
...metadata,
|
||||
'## Highlights',
|
||||
changes,
|
||||
'',
|
||||
@@ -705,6 +742,7 @@ function writeReleaseNotesFile(
|
||||
outputPath?: string;
|
||||
contributions?: Contribution[];
|
||||
contributorSections?: string[];
|
||||
metadata?: string[];
|
||||
},
|
||||
): string {
|
||||
const mkdirSync = deps?.mkdirSync ?? fs.mkdirSync;
|
||||
@@ -1038,7 +1076,7 @@ export function writePrereleaseNotesForVersion(options?: ChangelogOptions): stri
|
||||
|
||||
const prereleaseNotesPath = path.join(cwd, PRERELEASE_NOTES_PATH);
|
||||
const existingReleaseNotes = existsSync(prereleaseNotesPath)
|
||||
? readFileSync(prereleaseNotesPath, 'utf8')
|
||||
? resolveReusablePrereleaseNotes(readFileSync(prereleaseNotesPath, 'utf8'), version)
|
||||
: undefined;
|
||||
const changes = polishFragmentsWithClaude(fragments, {
|
||||
mode: 'release-notes',
|
||||
@@ -1052,6 +1090,7 @@ export function writePrereleaseNotesForVersion(options?: ChangelogOptions): stri
|
||||
'> This is a prerelease build for testing. Stable changelog and docs-site updates remain pending until the final stable release.',
|
||||
outputPath: PRERELEASE_NOTES_PATH,
|
||||
contributions,
|
||||
metadata: [renderPrereleaseBaseVersionMarker(version)],
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user