Skip to content

Commit 94fcdfe

Browse files
committed
fix(bump): auto-increment unnamed prerelease when tag already exists
1 parent d0bba81 commit 94fcdfe

File tree

2 files changed

+49
-10
lines changed

2 files changed

+49
-10
lines changed

lib/lifecycles/bump.js

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -290,9 +290,17 @@ async function resolveUniquePrereleaseVersion(
290290
const base = `${parsed.major}.${parsed.minor}.${parsed.patch}`;
291291
const build = parsed.build; // preserve build metadata if present
292292

293-
// Current numeric index if present, otherwise default to 0
294-
const currentNum =
295-
typeof parsed.prerelease[1] === 'number' ? parsed.prerelease[1] : 0;
293+
// Determine current numeric index depending on named vs unnamed prerelease
294+
let currentNum = 0;
295+
if (Array.isArray(parsed.prerelease) && parsed.prerelease.length) {
296+
if (prereleaseId === '' && typeof parsed.prerelease[0] === 'number') {
297+
// unnamed prerelease like 1.2.3-0
298+
currentNum = parsed.prerelease[0];
299+
} else if (typeof parsed.prerelease[1] === 'number') {
300+
// named prerelease like 1.2.3-alpha.0
301+
currentNum = parsed.prerelease[1];
302+
}
303+
}
296304

297305
const tags = await new Promise((resolve, reject) => {
298306
gitSemverTags({ tagPrefix }, (err, t) =>
@@ -306,22 +314,29 @@ async function resolveUniquePrereleaseVersion(
306314
.map((t) => (semver.valid(t) ? semver.clean(t) : null))
307315
.filter(Boolean);
308316

309-
// collect numeric suffix for same base and prerelease id
317+
// collect numeric suffix for same base and prerelease id (or unnamed prerelease)
310318
const nums = cleaned
311319
.filter((t) => {
312320
const v = new semver.SemVer(t);
313321
if (!Array.isArray(v.prerelease) || v.prerelease.length === 0)
314322
return false;
315-
// same base version and same prerelease id
316-
return (
323+
const sameBase =
317324
v.major === parsed.major &&
318325
v.minor === parsed.minor &&
319-
v.patch === parsed.patch &&
320-
String(v.prerelease[0]) === String(prereleaseId)
321-
);
326+
v.patch === parsed.patch;
327+
if (!sameBase) return false;
328+
if (prereleaseId === '') {
329+
// unnamed prerelease: include tags where first prerelease token is numeric
330+
return typeof v.prerelease[0] === 'number';
331+
}
332+
// named prerelease: match by identifier
333+
return String(v.prerelease[0]) === String(prereleaseId);
322334
})
323335
.map((t) => {
324336
const v = new semver.SemVer(t);
337+
if (prereleaseId === '') {
338+
return typeof v.prerelease[0] === 'number' ? v.prerelease[0] : 0;
339+
}
325340
return typeof v.prerelease[1] === 'number' ? v.prerelease[1] : 0;
326341
});
327342

@@ -333,7 +348,10 @@ async function resolveUniquePrereleaseVersion(
333348
const maxExisting = Math.max(...nums);
334349
// If our proposed numeric index is already used or below max, bump to max + 1
335350
if (currentNum <= maxExisting) {
336-
let candidate = `${base}-${prereleaseId}.${maxExisting + 1}`;
351+
let candidate =
352+
prereleaseId === ''
353+
? `${base}-${maxExisting + 1}`
354+
: `${base}-${prereleaseId}.${maxExisting + 1}`;
337355
// re-append build metadata if any
338356
if (build && build.length) {
339357
candidate = semvarToVersionStr(candidate, build);

test/git.integration-test.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,27 @@ describe('git', function () {
248248
expect(getPackageVersion()).toEqual('1.1.0-0');
249249
});
250250

251+
it('increments unnamed prerelease number when unnamed prerelease tag already exists', async function () {
252+
writePackageJson('1.2.3');
253+
// Existing unnamed prerelease tag 1.2.3-0 exists
254+
mock({ bump: 'patch', tags: ['v1.2.3-0'] });
255+
await exec('--prerelease');
256+
expect(getPackageVersion()).toEqual('1.2.4-0');
257+
// Now start from a prerelease of same base to trigger unnamed collision
258+
writePackageJson('1.2.3-0');
259+
mock({ bump: 'patch', tags: ['v1.2.3-0'] });
260+
await exec('--prerelease');
261+
expect(getPackageVersion()).toEqual('1.2.3-1');
262+
});
263+
264+
it('increments unnamed prerelease number with gitTagFallback when unnamed prerelease tag already exists', async function () {
265+
shell.rm('package.json');
266+
mock({ bump: 'patch', tags: ['v1.2.3-0'] });
267+
await exec({ packageFiles: [], gitTagFallback: true, prerelease: '' });
268+
const output = shell.exec('git tag').stdout;
269+
expect(output).toMatch(/v1\.2\.3-1/);
270+
});
271+
251272
it('increments prerelease number when same prerelease tag already exists', async function () {
252273
writePackageJson('1.4.3-abc.0');
253274
// Simulate existing tags where v1.4.3-xyz.0 already exists from git history

0 commit comments

Comments
 (0)