package-versioner 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/index.cjs +71 -7
- package/dist/index.js +80 -16
- package/docs/VERSIONING_STRATEGIES.md +39 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,6 +39,10 @@ npx package-versioner --bump minor
|
|
|
39
39
|
# Create a prerelease (e.g., alpha)
|
|
40
40
|
npx package-versioner --bump patch --prerelease alpha
|
|
41
41
|
|
|
42
|
+
# Promote a prerelease to a stable release (automatic cleaning)
|
|
43
|
+
# For example, 1.0.0-beta.1 -> 2.0.0:
|
|
44
|
+
npx package-versioner --bump major
|
|
45
|
+
|
|
42
46
|
# Target specific packages (only in async/independent mode, comma-separated)
|
|
43
47
|
npx package-versioner -t @scope/package-a,@scope/package-b
|
|
44
48
|
|
|
@@ -70,7 +74,7 @@ When using the `--json` flag, normal console output is suppressed and the tool o
|
|
|
70
74
|
],
|
|
71
75
|
"commitMessage": "chore(release): v1.2.3",
|
|
72
76
|
"tags": [
|
|
73
|
-
"@scope/package-a@
|
|
77
|
+
"v@scope/package-a@1.2.3"
|
|
74
78
|
]
|
|
75
79
|
}
|
|
76
80
|
```
|
package/dist/index.cjs
CHANGED
|
@@ -410,13 +410,16 @@ var import_node_path3 = __toESM(require("path"), 1);
|
|
|
410
410
|
var import_node_process4 = require("process");
|
|
411
411
|
|
|
412
412
|
// src/core/versionCalculator.ts
|
|
413
|
+
var fs3 = __toESM(require("fs"), 1);
|
|
414
|
+
var path2 = __toESM(require("path"), 1);
|
|
413
415
|
var import_node_process3 = require("process");
|
|
414
416
|
var import_conventional_recommended_bump = require("conventional-recommended-bump");
|
|
415
417
|
var import_semver = __toESM(require("semver"), 1);
|
|
416
418
|
async function calculateVersion(config, options) {
|
|
417
|
-
const { latestTag, type, path:
|
|
419
|
+
const { latestTag, type, path: pkgPath, name, branchPattern, prereleaseIdentifier } = options;
|
|
418
420
|
const originalPrefix = config.tagPrefix || "v";
|
|
419
421
|
const initialVersion = prereleaseIdentifier ? `0.0.1-${prereleaseIdentifier}` : "0.0.1";
|
|
422
|
+
const hasNoTags = !latestTag || latestTag === "";
|
|
420
423
|
function determineTagSearchPattern(packageName, prefix) {
|
|
421
424
|
if (packageName) {
|
|
422
425
|
return prefix ? `${prefix}${packageName}@` : `${packageName}@`;
|
|
@@ -427,10 +430,24 @@ async function calculateVersion(config, options) {
|
|
|
427
430
|
const escapedTagPattern = escapeRegExp(tagSearchPattern);
|
|
428
431
|
let determinedReleaseType = type || null;
|
|
429
432
|
if (determinedReleaseType) {
|
|
430
|
-
if (
|
|
431
|
-
return
|
|
433
|
+
if (hasNoTags) {
|
|
434
|
+
return getPackageVersionFallback(
|
|
435
|
+
pkgPath,
|
|
436
|
+
name,
|
|
437
|
+
determinedReleaseType,
|
|
438
|
+
prereleaseIdentifier,
|
|
439
|
+
initialVersion
|
|
440
|
+
);
|
|
432
441
|
}
|
|
433
442
|
const currentVersion = import_semver.default.clean(latestTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
|
|
443
|
+
const standardBumpTypes = ["major", "minor", "patch"];
|
|
444
|
+
if (standardBumpTypes.includes(determinedReleaseType) && import_semver.default.prerelease(currentVersion)) {
|
|
445
|
+
log(
|
|
446
|
+
`Cleaning prerelease identifier from ${currentVersion} for ${determinedReleaseType} bump`,
|
|
447
|
+
"debug"
|
|
448
|
+
);
|
|
449
|
+
return import_semver.default.inc(currentVersion, determinedReleaseType) || "";
|
|
450
|
+
}
|
|
434
451
|
return import_semver.default.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
|
|
435
452
|
}
|
|
436
453
|
if (config.versionStrategy === "branchPattern" && (branchPattern == null ? void 0 : branchPattern.length)) {
|
|
@@ -445,8 +462,14 @@ async function calculateVersion(config, options) {
|
|
|
445
462
|
}
|
|
446
463
|
}
|
|
447
464
|
if (determinedReleaseType) {
|
|
448
|
-
if (
|
|
449
|
-
return
|
|
465
|
+
if (hasNoTags) {
|
|
466
|
+
return getPackageVersionFallback(
|
|
467
|
+
pkgPath,
|
|
468
|
+
name,
|
|
469
|
+
determinedReleaseType,
|
|
470
|
+
prereleaseIdentifier,
|
|
471
|
+
initialVersion
|
|
472
|
+
);
|
|
450
473
|
}
|
|
451
474
|
const currentVersion = import_semver.default.clean(latestTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
|
|
452
475
|
return import_semver.default.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
|
|
@@ -457,10 +480,19 @@ async function calculateVersion(config, options) {
|
|
|
457
480
|
bumper.loadPreset(config.preset);
|
|
458
481
|
const recommendedBump = await bumper.bump();
|
|
459
482
|
const releaseTypeFromCommits = recommendedBump.releaseType;
|
|
460
|
-
if (
|
|
483
|
+
if (hasNoTags) {
|
|
484
|
+
if (releaseTypeFromCommits) {
|
|
485
|
+
return getPackageVersionFallback(
|
|
486
|
+
pkgPath,
|
|
487
|
+
name,
|
|
488
|
+
releaseTypeFromCommits,
|
|
489
|
+
prereleaseIdentifier,
|
|
490
|
+
initialVersion
|
|
491
|
+
);
|
|
492
|
+
}
|
|
461
493
|
return initialVersion;
|
|
462
494
|
}
|
|
463
|
-
const checkPath =
|
|
495
|
+
const checkPath = pkgPath || (0, import_node_process3.cwd)();
|
|
464
496
|
const commitsLength = getCommitsLength(checkPath);
|
|
465
497
|
if (commitsLength === 0) {
|
|
466
498
|
log(
|
|
@@ -488,6 +520,38 @@ async function calculateVersion(config, options) {
|
|
|
488
520
|
throw error;
|
|
489
521
|
}
|
|
490
522
|
}
|
|
523
|
+
function getPackageVersionFallback(pkgPath, name, releaseType, prereleaseIdentifier, initialVersion) {
|
|
524
|
+
const packageDir = pkgPath || (0, import_node_process3.cwd)();
|
|
525
|
+
const packageJsonPath = path2.join(packageDir, "package.json");
|
|
526
|
+
if (!fs3.existsSync(packageJsonPath)) {
|
|
527
|
+
throw new Error(`package.json not found at ${packageJsonPath}. Cannot determine version.`);
|
|
528
|
+
}
|
|
529
|
+
try {
|
|
530
|
+
const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
|
|
531
|
+
if (!packageJson.version) {
|
|
532
|
+
log(`No version found in package.json. Using initial version ${initialVersion}`, "info");
|
|
533
|
+
return initialVersion;
|
|
534
|
+
}
|
|
535
|
+
log(
|
|
536
|
+
`No tags found for ${name || "package"}, using package.json version: ${packageJson.version} as base`,
|
|
537
|
+
"info"
|
|
538
|
+
);
|
|
539
|
+
const standardBumpTypes = ["major", "minor", "patch"];
|
|
540
|
+
if (standardBumpTypes.includes(releaseType) && import_semver.default.prerelease(packageJson.version)) {
|
|
541
|
+
log(
|
|
542
|
+
`Cleaning prerelease identifier from ${packageJson.version} for ${releaseType} bump`,
|
|
543
|
+
"debug"
|
|
544
|
+
);
|
|
545
|
+
const cleanVersion = import_semver.default.inc(packageJson.version, "patch") || packageJson.version;
|
|
546
|
+
return import_semver.default.inc(cleanVersion, releaseType) || initialVersion;
|
|
547
|
+
}
|
|
548
|
+
return import_semver.default.inc(packageJson.version, releaseType, prereleaseIdentifier) || initialVersion;
|
|
549
|
+
} catch (err) {
|
|
550
|
+
throw new Error(
|
|
551
|
+
`Error reading package.json: ${err instanceof Error ? err.message : String(err)}`
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
491
555
|
|
|
492
556
|
// src/package/packageProcessor.ts
|
|
493
557
|
var PackageProcessor = class {
|
package/dist/index.js
CHANGED
|
@@ -142,8 +142,8 @@ function log(message, status = "info") {
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
// src/core/versionStrategies.ts
|
|
145
|
-
import
|
|
146
|
-
import
|
|
145
|
+
import fs4 from "node:fs";
|
|
146
|
+
import path3 from "node:path";
|
|
147
147
|
|
|
148
148
|
// src/git/commands.ts
|
|
149
149
|
import { cwd as cwd2 } from "node:process";
|
|
@@ -382,17 +382,20 @@ function updatePackageVersion(packagePath, version) {
|
|
|
382
382
|
}
|
|
383
383
|
|
|
384
384
|
// src/package/packageProcessor.ts
|
|
385
|
-
import
|
|
385
|
+
import path2 from "node:path";
|
|
386
386
|
import { exit } from "node:process";
|
|
387
387
|
|
|
388
388
|
// src/core/versionCalculator.ts
|
|
389
|
+
import * as fs3 from "node:fs";
|
|
390
|
+
import * as path from "node:path";
|
|
389
391
|
import { cwd as cwd3 } from "node:process";
|
|
390
392
|
import { Bumper } from "conventional-recommended-bump";
|
|
391
393
|
import semver from "semver";
|
|
392
394
|
async function calculateVersion(config, options) {
|
|
393
|
-
const { latestTag, type, path:
|
|
395
|
+
const { latestTag, type, path: pkgPath, name, branchPattern, prereleaseIdentifier } = options;
|
|
394
396
|
const originalPrefix = config.tagPrefix || "v";
|
|
395
397
|
const initialVersion = prereleaseIdentifier ? `0.0.1-${prereleaseIdentifier}` : "0.0.1";
|
|
398
|
+
const hasNoTags = !latestTag || latestTag === "";
|
|
396
399
|
function determineTagSearchPattern(packageName, prefix) {
|
|
397
400
|
if (packageName) {
|
|
398
401
|
return prefix ? `${prefix}${packageName}@` : `${packageName}@`;
|
|
@@ -403,10 +406,24 @@ async function calculateVersion(config, options) {
|
|
|
403
406
|
const escapedTagPattern = escapeRegExp(tagSearchPattern);
|
|
404
407
|
let determinedReleaseType = type || null;
|
|
405
408
|
if (determinedReleaseType) {
|
|
406
|
-
if (
|
|
407
|
-
return
|
|
409
|
+
if (hasNoTags) {
|
|
410
|
+
return getPackageVersionFallback(
|
|
411
|
+
pkgPath,
|
|
412
|
+
name,
|
|
413
|
+
determinedReleaseType,
|
|
414
|
+
prereleaseIdentifier,
|
|
415
|
+
initialVersion
|
|
416
|
+
);
|
|
408
417
|
}
|
|
409
418
|
const currentVersion = semver.clean(latestTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
|
|
419
|
+
const standardBumpTypes = ["major", "minor", "patch"];
|
|
420
|
+
if (standardBumpTypes.includes(determinedReleaseType) && semver.prerelease(currentVersion)) {
|
|
421
|
+
log(
|
|
422
|
+
`Cleaning prerelease identifier from ${currentVersion} for ${determinedReleaseType} bump`,
|
|
423
|
+
"debug"
|
|
424
|
+
);
|
|
425
|
+
return semver.inc(currentVersion, determinedReleaseType) || "";
|
|
426
|
+
}
|
|
410
427
|
return semver.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
|
|
411
428
|
}
|
|
412
429
|
if (config.versionStrategy === "branchPattern" && (branchPattern == null ? void 0 : branchPattern.length)) {
|
|
@@ -421,8 +438,14 @@ async function calculateVersion(config, options) {
|
|
|
421
438
|
}
|
|
422
439
|
}
|
|
423
440
|
if (determinedReleaseType) {
|
|
424
|
-
if (
|
|
425
|
-
return
|
|
441
|
+
if (hasNoTags) {
|
|
442
|
+
return getPackageVersionFallback(
|
|
443
|
+
pkgPath,
|
|
444
|
+
name,
|
|
445
|
+
determinedReleaseType,
|
|
446
|
+
prereleaseIdentifier,
|
|
447
|
+
initialVersion
|
|
448
|
+
);
|
|
426
449
|
}
|
|
427
450
|
const currentVersion = semver.clean(latestTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
|
|
428
451
|
return semver.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
|
|
@@ -433,10 +456,19 @@ async function calculateVersion(config, options) {
|
|
|
433
456
|
bumper.loadPreset(config.preset);
|
|
434
457
|
const recommendedBump = await bumper.bump();
|
|
435
458
|
const releaseTypeFromCommits = recommendedBump.releaseType;
|
|
436
|
-
if (
|
|
459
|
+
if (hasNoTags) {
|
|
460
|
+
if (releaseTypeFromCommits) {
|
|
461
|
+
return getPackageVersionFallback(
|
|
462
|
+
pkgPath,
|
|
463
|
+
name,
|
|
464
|
+
releaseTypeFromCommits,
|
|
465
|
+
prereleaseIdentifier,
|
|
466
|
+
initialVersion
|
|
467
|
+
);
|
|
468
|
+
}
|
|
437
469
|
return initialVersion;
|
|
438
470
|
}
|
|
439
|
-
const checkPath =
|
|
471
|
+
const checkPath = pkgPath || cwd3();
|
|
440
472
|
const commitsLength = getCommitsLength(checkPath);
|
|
441
473
|
if (commitsLength === 0) {
|
|
442
474
|
log(
|
|
@@ -464,6 +496,38 @@ async function calculateVersion(config, options) {
|
|
|
464
496
|
throw error;
|
|
465
497
|
}
|
|
466
498
|
}
|
|
499
|
+
function getPackageVersionFallback(pkgPath, name, releaseType, prereleaseIdentifier, initialVersion) {
|
|
500
|
+
const packageDir = pkgPath || cwd3();
|
|
501
|
+
const packageJsonPath = path.join(packageDir, "package.json");
|
|
502
|
+
if (!fs3.existsSync(packageJsonPath)) {
|
|
503
|
+
throw new Error(`package.json not found at ${packageJsonPath}. Cannot determine version.`);
|
|
504
|
+
}
|
|
505
|
+
try {
|
|
506
|
+
const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
|
|
507
|
+
if (!packageJson.version) {
|
|
508
|
+
log(`No version found in package.json. Using initial version ${initialVersion}`, "info");
|
|
509
|
+
return initialVersion;
|
|
510
|
+
}
|
|
511
|
+
log(
|
|
512
|
+
`No tags found for ${name || "package"}, using package.json version: ${packageJson.version} as base`,
|
|
513
|
+
"info"
|
|
514
|
+
);
|
|
515
|
+
const standardBumpTypes = ["major", "minor", "patch"];
|
|
516
|
+
if (standardBumpTypes.includes(releaseType) && semver.prerelease(packageJson.version)) {
|
|
517
|
+
log(
|
|
518
|
+
`Cleaning prerelease identifier from ${packageJson.version} for ${releaseType} bump`,
|
|
519
|
+
"debug"
|
|
520
|
+
);
|
|
521
|
+
const cleanVersion = semver.inc(packageJson.version, "patch") || packageJson.version;
|
|
522
|
+
return semver.inc(cleanVersion, releaseType) || initialVersion;
|
|
523
|
+
}
|
|
524
|
+
return semver.inc(packageJson.version, releaseType, prereleaseIdentifier) || initialVersion;
|
|
525
|
+
} catch (err) {
|
|
526
|
+
throw new Error(
|
|
527
|
+
`Error reading package.json: ${err instanceof Error ? err.message : String(err)}`
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
467
531
|
|
|
468
532
|
// src/package/packageProcessor.ts
|
|
469
533
|
var PackageProcessor = class {
|
|
@@ -546,7 +610,7 @@ var PackageProcessor = class {
|
|
|
546
610
|
if (!nextVersion) {
|
|
547
611
|
continue;
|
|
548
612
|
}
|
|
549
|
-
updatePackageVersion(
|
|
613
|
+
updatePackageVersion(path2.join(pkgPath, "package.json"), nextVersion);
|
|
550
614
|
const packageTag = formatTag(nextVersion, tagPrefix);
|
|
551
615
|
const tagMessage = `chore(release): ${name} ${nextVersion}`;
|
|
552
616
|
addTag(packageTag);
|
|
@@ -571,7 +635,7 @@ var PackageProcessor = class {
|
|
|
571
635
|
log("No targeted packages required a version update.", "info");
|
|
572
636
|
return { updatedPackages: [], tags };
|
|
573
637
|
}
|
|
574
|
-
const filesToCommit = updatedPackagesInfo.map((info) =>
|
|
638
|
+
const filesToCommit = updatedPackagesInfo.map((info) => path2.join(info.path, "package.json"));
|
|
575
639
|
const packageNames = updatedPackagesInfo.map((p) => p.name).join(", ");
|
|
576
640
|
const representativeVersion = ((_a = updatedPackagesInfo[0]) == null ? void 0 : _a.version) || "multiple";
|
|
577
641
|
let commitMessage = this.commitMessageTemplate || "chore(release): publish packages";
|
|
@@ -647,8 +711,8 @@ function createSyncedStrategy(config) {
|
|
|
647
711
|
const files = [];
|
|
648
712
|
const updatedPackages = [];
|
|
649
713
|
try {
|
|
650
|
-
const rootPkgPath =
|
|
651
|
-
if (
|
|
714
|
+
const rootPkgPath = path3.join(packages.root, "package.json");
|
|
715
|
+
if (fs4.existsSync(rootPkgPath)) {
|
|
652
716
|
updatePackageVersion(rootPkgPath, nextVersion);
|
|
653
717
|
files.push(rootPkgPath);
|
|
654
718
|
updatedPackages.push("root");
|
|
@@ -660,7 +724,7 @@ function createSyncedStrategy(config) {
|
|
|
660
724
|
if (!shouldProcessPackage(pkg, config)) {
|
|
661
725
|
continue;
|
|
662
726
|
}
|
|
663
|
-
const packageJsonPath =
|
|
727
|
+
const packageJsonPath = path3.join(pkg.dir, "package.json");
|
|
664
728
|
updatePackageVersion(packageJsonPath, nextVersion);
|
|
665
729
|
files.push(packageJsonPath);
|
|
666
730
|
updatedPackages.push(pkg.packageJson.name);
|
|
@@ -725,7 +789,7 @@ function createSingleStrategy(config) {
|
|
|
725
789
|
log(`No version change needed for ${packageName}`, "info");
|
|
726
790
|
return;
|
|
727
791
|
}
|
|
728
|
-
const packageJsonPath =
|
|
792
|
+
const packageJsonPath = path3.join(pkgPath, "package.json");
|
|
729
793
|
updatePackageVersion(packageJsonPath, nextVersion);
|
|
730
794
|
log(`Updated package ${packageName} to version ${nextVersion}`, "success");
|
|
731
795
|
const nextTag = formatTag(nextVersion, tagPrefix || "v");
|
|
@@ -94,3 +94,42 @@ This is the default if the `synced` flag is present and true.
|
|
|
94
94
|
- Finally, a **single commit** is created including all the updated `package.json` files, using a summary commit message (e.g., `chore(release): pkg-a, pkg-b 1.2.3 [skip-ci]`).
|
|
95
95
|
- **Important:** Only package-specific tags are created. The global tag (e.g., `v1.2.3`) is **not** automatically generated in this mode. If your release process (like GitHub Releases) depends on a global tag, you'll need to create it manually in your CI/CD script *after* `package-versioner` completes.
|
|
96
96
|
- **Use Case:** Releasing specific packages independently while still tagging each released package individually.
|
|
97
|
+
|
|
98
|
+
## Prerelease Handling
|
|
99
|
+
|
|
100
|
+
`package-versioner` provides flexible handling for prerelease versions, allowing both creation of prereleases and promotion to stable releases.
|
|
101
|
+
|
|
102
|
+
### Creating Prereleases
|
|
103
|
+
|
|
104
|
+
Use the `--prerelease` flag with an identifier to create a prerelease version:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Create a beta prerelease
|
|
108
|
+
npx package-versioner --bump minor --prerelease beta
|
|
109
|
+
# Result: 1.0.0 -> 1.1.0-beta.0
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
You can also set a default prerelease identifier in your `version.config.json`:
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"prereleaseIdentifier": "beta"
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Promoting Prereleases to Stable Releases
|
|
121
|
+
|
|
122
|
+
When using standard bump types (`major`, `minor`, `patch`) with the `--bump` flag on a prerelease version, `package-versioner` will automatically clean the prerelease identifier:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Starting from version 1.0.0-beta.1
|
|
126
|
+
npx package-versioner --bump major
|
|
127
|
+
# Result: 1.0.0-beta.1 -> 2.0.0 (not 2.0.0-beta.0)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
This intuitive behavior means you don't need to use an empty prerelease identifier (`--prerelease ""`) to promote a prerelease to a stable version. Simply specify the standard bump type and the tool will automatically produce a clean version number.
|
|
131
|
+
|
|
132
|
+
This applies to all standard bump types:
|
|
133
|
+
- `--bump major`: 1.0.0-beta.1 -> 2.0.0
|
|
134
|
+
- `--bump minor`: 1.0.0-beta.1 -> 1.1.0
|
|
135
|
+
- `--bump patch`: 1.0.0-beta.1 -> 1.0.1
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "package-versioner",
|
|
3
3
|
"description": "A lightweight yet powerful CLI tool for automated semantic versioning based on Git history and conventional commits.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.mjs",
|