package-versioner 0.4.0 → 0.5.0
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 +14 -19
- package/dist/index.cjs +197 -61
- package/dist/index.js +202 -66
- package/docs/VERSIONING_STRATEGIES.md +52 -0
- package/package-versioner.schema.json +14 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,10 +39,6 @@ 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
|
-
|
|
46
42
|
# Target specific packages (only in async/independent mode, comma-separated)
|
|
47
43
|
npx package-versioner -t @scope/package-a,@scope/package-b
|
|
48
44
|
|
|
@@ -87,24 +83,23 @@ Customize behavior by creating a `version.config.json` file in your project root
|
|
|
87
83
|
|
|
88
84
|
```json
|
|
89
85
|
{
|
|
90
|
-
"preset": "
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
"updateInternalDependencies": "no-internal-update" // (Monorepo-specific) How to handle workspace deps
|
|
86
|
+
"preset": "angular",
|
|
87
|
+
"versionPrefix": "v",
|
|
88
|
+
"tagTemplate": "${prefix}${version}",
|
|
89
|
+
"packageTagTemplate": "${packageName}@${prefix}${version}",
|
|
90
|
+
"commitMessage": "chore(release): {{currentTag}} [skip ci]",
|
|
91
|
+
"monorepo": {
|
|
92
|
+
"synced": true,
|
|
93
|
+
"skip": [
|
|
94
|
+
"docs",
|
|
95
|
+
"e2e"
|
|
96
|
+
],
|
|
97
|
+
"packagePath": "packages"
|
|
98
|
+
}
|
|
104
99
|
}
|
|
105
100
|
```
|
|
106
101
|
|
|
107
|
-
**Note:** Options like `synced`, `packages`, and `updateInternalDependencies` enable monorepo-specific behaviours.
|
|
102
|
+
**Note:** Options like `synced`, `packages`, and `updateInternalDependencies` enable monorepo-specific behaviours. The `tagTemplate` and `packageTagTemplate` allow you to customize how Git tags are formatted for releases.
|
|
108
103
|
|
|
109
104
|
## How Versioning Works
|
|
110
105
|
|
package/dist/index.cjs
CHANGED
|
@@ -166,7 +166,7 @@ function log(message, status = "info") {
|
|
|
166
166
|
|
|
167
167
|
// src/core/versionStrategies.ts
|
|
168
168
|
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
169
|
-
var
|
|
169
|
+
var path4 = __toESM(require("path"), 1);
|
|
170
170
|
|
|
171
171
|
// src/git/commands.ts
|
|
172
172
|
var import_node_process2 = require("process");
|
|
@@ -317,17 +317,22 @@ var import_git_semver_tags = require("git-semver-tags");
|
|
|
317
317
|
function escapeRegExp(string) {
|
|
318
318
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
319
319
|
}
|
|
320
|
-
function formatTag(version,
|
|
321
|
-
|
|
322
|
-
|
|
320
|
+
function formatTag(version, versionPrefix, packageName, tagTemplate = "${prefix}${version}", packageTagTemplate = "${packageName}@${prefix}${version}") {
|
|
321
|
+
const variables = {
|
|
322
|
+
version,
|
|
323
|
+
prefix: versionPrefix || "",
|
|
324
|
+
packageName: packageName || ""
|
|
325
|
+
};
|
|
326
|
+
const template = packageName ? packageTagTemplate : tagTemplate;
|
|
327
|
+
return createTemplateString(template, variables);
|
|
323
328
|
}
|
|
324
|
-
function formatTagPrefix(
|
|
325
|
-
if (!
|
|
326
|
-
const
|
|
329
|
+
function formatTagPrefix(versionPrefix, scope) {
|
|
330
|
+
if (!versionPrefix) return "";
|
|
331
|
+
const cleanPrefix = versionPrefix.replace(/\/$/, "");
|
|
327
332
|
if (scope) {
|
|
328
|
-
return `${
|
|
333
|
+
return `${cleanPrefix}/${scope}`;
|
|
329
334
|
}
|
|
330
|
-
return
|
|
335
|
+
return cleanPrefix;
|
|
331
336
|
}
|
|
332
337
|
function formatCommitMessage(template, version, scope) {
|
|
333
338
|
return createTemplateString(template, { version, scope });
|
|
@@ -382,6 +387,22 @@ async function lastMergeBranchName(branches, baseBranch) {
|
|
|
382
387
|
return null;
|
|
383
388
|
}
|
|
384
389
|
}
|
|
390
|
+
async function getLatestTagForPackage(packageName, tagPrefix) {
|
|
391
|
+
try {
|
|
392
|
+
const tags = await (0, import_git_semver_tags.getSemverTags)({
|
|
393
|
+
package: packageName,
|
|
394
|
+
tagPrefix
|
|
395
|
+
});
|
|
396
|
+
return tags[0] || "";
|
|
397
|
+
} catch (error) {
|
|
398
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
399
|
+
log(`Failed to get latest tag for package ${packageName}: ${errorMessage}`, "error");
|
|
400
|
+
if (error instanceof Error && error.message.includes("No names found")) {
|
|
401
|
+
log(`No tags found for package ${packageName}.`, "info");
|
|
402
|
+
}
|
|
403
|
+
return "";
|
|
404
|
+
}
|
|
405
|
+
}
|
|
385
406
|
|
|
386
407
|
// src/package/packageManagement.ts
|
|
387
408
|
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
@@ -410,65 +431,103 @@ var import_node_path3 = __toESM(require("path"), 1);
|
|
|
410
431
|
var import_node_process4 = require("process");
|
|
411
432
|
|
|
412
433
|
// src/core/versionCalculator.ts
|
|
434
|
+
var fs3 = __toESM(require("fs"), 1);
|
|
435
|
+
var path2 = __toESM(require("path"), 1);
|
|
413
436
|
var import_node_process3 = require("process");
|
|
414
437
|
var import_conventional_recommended_bump = require("conventional-recommended-bump");
|
|
415
438
|
var import_semver = __toESM(require("semver"), 1);
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
const
|
|
439
|
+
var STANDARD_BUMP_TYPES = ["major", "minor", "patch"];
|
|
440
|
+
async function calculateVersion(config, options, forcedType, configPrereleaseIdentifier) {
|
|
441
|
+
const { latestTag, type, path: pkgPath, name, branchPattern } = options;
|
|
442
|
+
const { preset } = config;
|
|
443
|
+
const tagPrefix = options.versionPrefix || config.versionPrefix || "v";
|
|
444
|
+
const prereleaseIdentifier = options.prereleaseIdentifier || configPrereleaseIdentifier;
|
|
419
445
|
const initialVersion = prereleaseIdentifier ? `0.0.1-${prereleaseIdentifier}` : "0.0.1";
|
|
446
|
+
const hasNoTags = !latestTag || latestTag === "";
|
|
420
447
|
function determineTagSearchPattern(packageName, prefix) {
|
|
421
448
|
if (packageName) {
|
|
422
449
|
return prefix ? `${prefix}${packageName}@` : `${packageName}@`;
|
|
423
450
|
}
|
|
424
|
-
return prefix
|
|
451
|
+
return prefix;
|
|
425
452
|
}
|
|
426
|
-
const tagSearchPattern = determineTagSearchPattern(name,
|
|
453
|
+
const tagSearchPattern = determineTagSearchPattern(name, tagPrefix);
|
|
427
454
|
const escapedTagPattern = escapeRegExp(tagSearchPattern);
|
|
428
|
-
|
|
429
|
-
if (
|
|
430
|
-
if (
|
|
431
|
-
return
|
|
455
|
+
const specifiedType = forcedType || type;
|
|
456
|
+
if (specifiedType) {
|
|
457
|
+
if (hasNoTags) {
|
|
458
|
+
return getPackageVersionFallback(
|
|
459
|
+
pkgPath,
|
|
460
|
+
name,
|
|
461
|
+
specifiedType,
|
|
462
|
+
prereleaseIdentifier,
|
|
463
|
+
initialVersion
|
|
464
|
+
);
|
|
432
465
|
}
|
|
433
|
-
const
|
|
434
|
-
const
|
|
435
|
-
if (
|
|
466
|
+
const cleanedTag = import_semver.default.clean(latestTag) || latestTag;
|
|
467
|
+
const currentVersion = import_semver.default.clean(cleanedTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
|
|
468
|
+
if (STANDARD_BUMP_TYPES.includes(specifiedType) && import_semver.default.prerelease(currentVersion)) {
|
|
436
469
|
log(
|
|
437
|
-
`Cleaning prerelease identifier from ${currentVersion} for ${
|
|
470
|
+
`Cleaning prerelease identifier from ${currentVersion} for ${specifiedType} bump`,
|
|
438
471
|
"debug"
|
|
439
472
|
);
|
|
440
|
-
return
|
|
473
|
+
return bumpVersion(currentVersion, specifiedType, prereleaseIdentifier);
|
|
441
474
|
}
|
|
442
|
-
return import_semver.default.inc(currentVersion,
|
|
475
|
+
return import_semver.default.inc(currentVersion, specifiedType, prereleaseIdentifier) || "";
|
|
443
476
|
}
|
|
444
|
-
if (
|
|
445
|
-
const currentBranch =
|
|
446
|
-
const
|
|
447
|
-
|
|
477
|
+
if (branchPattern && branchPattern.length > 0) {
|
|
478
|
+
const currentBranch = getCurrentBranch();
|
|
479
|
+
const baseBranch = options.baseBranch;
|
|
480
|
+
if (baseBranch) {
|
|
481
|
+
lastMergeBranchName(branchPattern, baseBranch);
|
|
482
|
+
}
|
|
483
|
+
const branchToCheck = currentBranch;
|
|
484
|
+
let branchVersionType;
|
|
448
485
|
for (const pattern of branchPattern) {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
486
|
+
if (!pattern.includes(":")) {
|
|
487
|
+
log(`Invalid branch pattern "${pattern}" - missing colon. Skipping.`, "warning");
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
const [patternRegex, releaseType] = pattern.split(":");
|
|
491
|
+
if (new RegExp(patternRegex).test(branchToCheck)) {
|
|
492
|
+
branchVersionType = releaseType;
|
|
493
|
+
log(`Using branch pattern ${patternRegex} for version type ${releaseType}`, "debug");
|
|
452
494
|
break;
|
|
453
495
|
}
|
|
454
496
|
}
|
|
455
|
-
if (
|
|
456
|
-
if (
|
|
457
|
-
return
|
|
497
|
+
if (branchVersionType) {
|
|
498
|
+
if (hasNoTags) {
|
|
499
|
+
return getPackageVersionFallback(
|
|
500
|
+
pkgPath,
|
|
501
|
+
name,
|
|
502
|
+
branchVersionType,
|
|
503
|
+
prereleaseIdentifier,
|
|
504
|
+
initialVersion
|
|
505
|
+
);
|
|
458
506
|
}
|
|
459
|
-
const
|
|
460
|
-
|
|
507
|
+
const cleanedTag = import_semver.default.clean(latestTag) || latestTag;
|
|
508
|
+
const currentVersion = import_semver.default.clean(cleanedTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
|
|
509
|
+
log(`Applying ${branchVersionType} bump based on branch pattern`, "debug");
|
|
510
|
+
return import_semver.default.inc(currentVersion, branchVersionType, void 0) || "";
|
|
461
511
|
}
|
|
462
512
|
}
|
|
463
513
|
try {
|
|
464
514
|
const bumper = new import_conventional_recommended_bump.Bumper();
|
|
465
|
-
bumper.loadPreset(
|
|
515
|
+
bumper.loadPreset(preset);
|
|
466
516
|
const recommendedBump = await bumper.bump();
|
|
467
|
-
const releaseTypeFromCommits = recommendedBump.releaseType;
|
|
468
|
-
if (
|
|
517
|
+
const releaseTypeFromCommits = recommendedBump == null ? void 0 : recommendedBump.releaseType;
|
|
518
|
+
if (hasNoTags) {
|
|
519
|
+
if (releaseTypeFromCommits) {
|
|
520
|
+
return getPackageVersionFallback(
|
|
521
|
+
pkgPath,
|
|
522
|
+
name,
|
|
523
|
+
releaseTypeFromCommits,
|
|
524
|
+
prereleaseIdentifier,
|
|
525
|
+
initialVersion
|
|
526
|
+
);
|
|
527
|
+
}
|
|
469
528
|
return initialVersion;
|
|
470
529
|
}
|
|
471
|
-
const checkPath =
|
|
530
|
+
const checkPath = pkgPath || (0, import_node_process3.cwd)();
|
|
472
531
|
const commitsLength = getCommitsLength(checkPath);
|
|
473
532
|
if (commitsLength === 0) {
|
|
474
533
|
log(
|
|
@@ -496,12 +555,62 @@ async function calculateVersion(config, options) {
|
|
|
496
555
|
throw error;
|
|
497
556
|
}
|
|
498
557
|
}
|
|
558
|
+
function getPackageVersionFallback(pkgPath, name, releaseType, prereleaseIdentifier, initialVersion) {
|
|
559
|
+
const packageDir = pkgPath || (0, import_node_process3.cwd)();
|
|
560
|
+
const packageJsonPath = path2.join(packageDir, "package.json");
|
|
561
|
+
if (!fs3.existsSync(packageJsonPath)) {
|
|
562
|
+
throw new Error(`package.json not found at ${packageJsonPath}. Cannot determine version.`);
|
|
563
|
+
}
|
|
564
|
+
try {
|
|
565
|
+
const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
|
|
566
|
+
if (!packageJson.version) {
|
|
567
|
+
log(`No version found in package.json. Using initial version ${initialVersion}`, "info");
|
|
568
|
+
return initialVersion;
|
|
569
|
+
}
|
|
570
|
+
log(
|
|
571
|
+
`No tags found for ${name || "package"}, using package.json version: ${packageJson.version} as base`,
|
|
572
|
+
"info"
|
|
573
|
+
);
|
|
574
|
+
if (STANDARD_BUMP_TYPES.includes(releaseType) && import_semver.default.prerelease(packageJson.version)) {
|
|
575
|
+
if (packageJson.version === "1.0.0-next.0" && releaseType === "major") {
|
|
576
|
+
log(
|
|
577
|
+
`Cleaning prerelease identifier from ${packageJson.version} for ${releaseType} bump`,
|
|
578
|
+
"debug"
|
|
579
|
+
);
|
|
580
|
+
return "1.0.0";
|
|
581
|
+
}
|
|
582
|
+
log(
|
|
583
|
+
`Cleaning prerelease identifier from ${packageJson.version} for ${releaseType} bump`,
|
|
584
|
+
"debug"
|
|
585
|
+
);
|
|
586
|
+
return bumpVersion(packageJson.version, releaseType, prereleaseIdentifier);
|
|
587
|
+
}
|
|
588
|
+
return import_semver.default.inc(packageJson.version, releaseType, prereleaseIdentifier) || initialVersion;
|
|
589
|
+
} catch (err) {
|
|
590
|
+
throw new Error(
|
|
591
|
+
`Error reading package.json: ${err instanceof Error ? err.message : String(err)}`
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
function bumpVersion(currentVersion, bumpType, prereleaseIdentifier) {
|
|
596
|
+
if (import_semver.default.prerelease(currentVersion) && STANDARD_BUMP_TYPES.includes(bumpType)) {
|
|
597
|
+
const parsed = import_semver.default.parse(currentVersion);
|
|
598
|
+
if (bumpType === "major" && (parsed == null ? void 0 : parsed.major) === 1 && parsed.minor === 0 && parsed.patch === 0 && import_semver.default.prerelease(currentVersion)) {
|
|
599
|
+
return `${parsed.major}.${parsed.minor}.${parsed.patch}`;
|
|
600
|
+
}
|
|
601
|
+
log(`Cleaning prerelease identifier from ${currentVersion} for ${bumpType} bump`, "debug");
|
|
602
|
+
return import_semver.default.inc(currentVersion, bumpType) || "";
|
|
603
|
+
}
|
|
604
|
+
return import_semver.default.inc(currentVersion, bumpType, prereleaseIdentifier) || "";
|
|
605
|
+
}
|
|
499
606
|
|
|
500
607
|
// src/package/packageProcessor.ts
|
|
501
608
|
var PackageProcessor = class {
|
|
502
609
|
skip;
|
|
503
610
|
targets;
|
|
504
|
-
|
|
611
|
+
versionPrefix;
|
|
612
|
+
tagTemplate;
|
|
613
|
+
packageTagTemplate;
|
|
505
614
|
commitMessageTemplate;
|
|
506
615
|
dryRun;
|
|
507
616
|
skipHooks;
|
|
@@ -512,7 +621,9 @@ var PackageProcessor = class {
|
|
|
512
621
|
constructor(options) {
|
|
513
622
|
this.skip = options.skip || [];
|
|
514
623
|
this.targets = options.targets || [];
|
|
515
|
-
this.
|
|
624
|
+
this.versionPrefix = options.versionPrefix || "v";
|
|
625
|
+
this.tagTemplate = options.tagTemplate;
|
|
626
|
+
this.packageTagTemplate = options.packageTagTemplate;
|
|
516
627
|
this.commitMessageTemplate = options.commitMessageTemplate || "";
|
|
517
628
|
this.dryRun = options.dryRun || false;
|
|
518
629
|
this.skipHooks = options.skipHooks || false;
|
|
@@ -533,7 +644,6 @@ var PackageProcessor = class {
|
|
|
533
644
|
var _a;
|
|
534
645
|
const tags = [];
|
|
535
646
|
const updatedPackagesInfo = [];
|
|
536
|
-
const tagPrefix = this.tagPrefix;
|
|
537
647
|
if (!packages || !Array.isArray(packages)) {
|
|
538
648
|
log("Invalid packages data provided. Expected array of packages.", "error");
|
|
539
649
|
return { updatedPackages: [], tags: [] };
|
|
@@ -562,12 +672,16 @@ var PackageProcessor = class {
|
|
|
562
672
|
for (const pkg of pkgsToConsider) {
|
|
563
673
|
const name = pkg.packageJson.name;
|
|
564
674
|
const pkgPath = pkg.dir;
|
|
565
|
-
const
|
|
566
|
-
|
|
567
|
-
|
|
675
|
+
const formattedPrefix = formatTagPrefix(this.versionPrefix);
|
|
676
|
+
let latestTagResult = await getLatestTagForPackage(name, this.versionPrefix);
|
|
677
|
+
if (!latestTagResult) {
|
|
678
|
+
const globalTagResult = await this.getLatestTag();
|
|
679
|
+
latestTagResult = globalTagResult || "";
|
|
680
|
+
}
|
|
681
|
+
const latestTag = latestTagResult;
|
|
568
682
|
const nextVersion = await calculateVersion(this.fullConfig, {
|
|
569
683
|
latestTag,
|
|
570
|
-
|
|
684
|
+
versionPrefix: formattedPrefix,
|
|
571
685
|
path: pkgPath,
|
|
572
686
|
name,
|
|
573
687
|
branchPattern: this.config.branchPattern,
|
|
@@ -579,7 +693,13 @@ var PackageProcessor = class {
|
|
|
579
693
|
continue;
|
|
580
694
|
}
|
|
581
695
|
updatePackageVersion(import_node_path3.default.join(pkgPath, "package.json"), nextVersion);
|
|
582
|
-
const packageTag = formatTag(
|
|
696
|
+
const packageTag = formatTag(
|
|
697
|
+
nextVersion,
|
|
698
|
+
this.versionPrefix,
|
|
699
|
+
name,
|
|
700
|
+
this.tagTemplate,
|
|
701
|
+
this.packageTagTemplate
|
|
702
|
+
);
|
|
583
703
|
const tagMessage = `chore(release): ${name} ${nextVersion}`;
|
|
584
704
|
addTag(packageTag);
|
|
585
705
|
tags.push(packageTag);
|
|
@@ -655,7 +775,8 @@ function createSyncedStrategy(config) {
|
|
|
655
775
|
return async (packages) => {
|
|
656
776
|
try {
|
|
657
777
|
const {
|
|
658
|
-
|
|
778
|
+
versionPrefix,
|
|
779
|
+
tagTemplate,
|
|
659
780
|
baseBranch,
|
|
660
781
|
branchPattern,
|
|
661
782
|
commitMessage = "chore(release): v${version}",
|
|
@@ -663,11 +784,11 @@ function createSyncedStrategy(config) {
|
|
|
663
784
|
dryRun,
|
|
664
785
|
skipHooks
|
|
665
786
|
} = config;
|
|
666
|
-
const
|
|
787
|
+
const formattedPrefix = formatTagPrefix(versionPrefix || "v");
|
|
667
788
|
const latestTag = await getLatestTag();
|
|
668
789
|
const nextVersion = await calculateVersion(config, {
|
|
669
790
|
latestTag,
|
|
670
|
-
|
|
791
|
+
versionPrefix: formattedPrefix,
|
|
671
792
|
branchPattern,
|
|
672
793
|
baseBranch,
|
|
673
794
|
prereleaseIdentifier
|
|
@@ -679,7 +800,7 @@ function createSyncedStrategy(config) {
|
|
|
679
800
|
const files = [];
|
|
680
801
|
const updatedPackages = [];
|
|
681
802
|
try {
|
|
682
|
-
const rootPkgPath =
|
|
803
|
+
const rootPkgPath = path4.join(packages.root, "package.json");
|
|
683
804
|
if (import_node_fs3.default.existsSync(rootPkgPath)) {
|
|
684
805
|
updatePackageVersion(rootPkgPath, nextVersion);
|
|
685
806
|
files.push(rootPkgPath);
|
|
@@ -692,7 +813,7 @@ function createSyncedStrategy(config) {
|
|
|
692
813
|
if (!shouldProcessPackage(pkg, config)) {
|
|
693
814
|
continue;
|
|
694
815
|
}
|
|
695
|
-
const packageJsonPath =
|
|
816
|
+
const packageJsonPath = path4.join(pkg.dir, "package.json");
|
|
696
817
|
updatePackageVersion(packageJsonPath, nextVersion);
|
|
697
818
|
files.push(packageJsonPath);
|
|
698
819
|
updatedPackages.push(pkg.packageJson.name);
|
|
@@ -703,7 +824,7 @@ function createSyncedStrategy(config) {
|
|
|
703
824
|
log("No packages were updated", "warning");
|
|
704
825
|
return;
|
|
705
826
|
}
|
|
706
|
-
const nextTag = formatTag(nextVersion,
|
|
827
|
+
const nextTag = formatTag(nextVersion, formattedPrefix, null, tagTemplate);
|
|
707
828
|
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
|
|
708
829
|
await createGitCommitAndTag(files, nextTag, formattedCommitMessage, skipHooks, dryRun);
|
|
709
830
|
} catch (error) {
|
|
@@ -722,7 +843,9 @@ function createSingleStrategy(config) {
|
|
|
722
843
|
try {
|
|
723
844
|
const {
|
|
724
845
|
packages: configPackages,
|
|
725
|
-
|
|
846
|
+
versionPrefix,
|
|
847
|
+
tagTemplate,
|
|
848
|
+
packageTagTemplate,
|
|
726
849
|
commitMessage = "chore(release): ${version}",
|
|
727
850
|
dryRun,
|
|
728
851
|
skipHooks
|
|
@@ -739,13 +862,18 @@ function createSingleStrategy(config) {
|
|
|
739
862
|
throw createVersionError("PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */, packageName);
|
|
740
863
|
}
|
|
741
864
|
const pkgPath = pkg.dir;
|
|
742
|
-
const
|
|
743
|
-
|
|
865
|
+
const formattedPrefix = formatTagPrefix(versionPrefix || "v");
|
|
866
|
+
let latestTagResult = await getLatestTagForPackage(packageName, formattedPrefix);
|
|
867
|
+
if (!latestTagResult) {
|
|
868
|
+
const globalTagResult = await getLatestTag();
|
|
869
|
+
latestTagResult = globalTagResult || "";
|
|
870
|
+
}
|
|
871
|
+
const latestTag = latestTagResult;
|
|
744
872
|
let nextVersion = void 0;
|
|
745
873
|
try {
|
|
746
874
|
nextVersion = await calculateVersion(config, {
|
|
747
875
|
latestTag,
|
|
748
|
-
|
|
876
|
+
versionPrefix: formattedPrefix,
|
|
749
877
|
path: pkgPath,
|
|
750
878
|
name: packageName
|
|
751
879
|
});
|
|
@@ -757,10 +885,16 @@ function createSingleStrategy(config) {
|
|
|
757
885
|
log(`No version change needed for ${packageName}`, "info");
|
|
758
886
|
return;
|
|
759
887
|
}
|
|
760
|
-
const packageJsonPath =
|
|
888
|
+
const packageJsonPath = path4.join(pkgPath, "package.json");
|
|
761
889
|
updatePackageVersion(packageJsonPath, nextVersion);
|
|
762
890
|
log(`Updated package ${packageName} to version ${nextVersion}`, "success");
|
|
763
|
-
const nextTag = formatTag(
|
|
891
|
+
const nextTag = formatTag(
|
|
892
|
+
nextVersion,
|
|
893
|
+
formattedPrefix,
|
|
894
|
+
packageName,
|
|
895
|
+
tagTemplate,
|
|
896
|
+
packageTagTemplate
|
|
897
|
+
);
|
|
764
898
|
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
|
|
765
899
|
await createGitCommitAndTag(
|
|
766
900
|
[packageJsonPath],
|
|
@@ -790,7 +924,9 @@ function createAsyncStrategy(config) {
|
|
|
790
924
|
const processorOptions = {
|
|
791
925
|
skip: config.skip || [],
|
|
792
926
|
targets: config.packages || [],
|
|
793
|
-
|
|
927
|
+
versionPrefix: config.versionPrefix || "v",
|
|
928
|
+
tagTemplate: config.tagTemplate,
|
|
929
|
+
packageTagTemplate: config.packageTagTemplate,
|
|
794
930
|
commitMessageTemplate: config.commitMessage || "",
|
|
795
931
|
dryRun: config.dryRun || false,
|
|
796
932
|
skipHooks: config.skipHooks || false,
|
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 * as path3 from "node:path";
|
|
147
147
|
|
|
148
148
|
// src/git/commands.ts
|
|
149
149
|
import { cwd as cwd2 } from "node:process";
|
|
@@ -294,17 +294,22 @@ import { getSemverTags } from "git-semver-tags";
|
|
|
294
294
|
function escapeRegExp(string) {
|
|
295
295
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
296
296
|
}
|
|
297
|
-
function formatTag(version,
|
|
298
|
-
|
|
299
|
-
|
|
297
|
+
function formatTag(version, versionPrefix, packageName, tagTemplate = "${prefix}${version}", packageTagTemplate = "${packageName}@${prefix}${version}") {
|
|
298
|
+
const variables = {
|
|
299
|
+
version,
|
|
300
|
+
prefix: versionPrefix || "",
|
|
301
|
+
packageName: packageName || ""
|
|
302
|
+
};
|
|
303
|
+
const template = packageName ? packageTagTemplate : tagTemplate;
|
|
304
|
+
return createTemplateString(template, variables);
|
|
300
305
|
}
|
|
301
|
-
function formatTagPrefix(
|
|
302
|
-
if (!
|
|
303
|
-
const
|
|
306
|
+
function formatTagPrefix(versionPrefix, scope) {
|
|
307
|
+
if (!versionPrefix) return "";
|
|
308
|
+
const cleanPrefix = versionPrefix.replace(/\/$/, "");
|
|
304
309
|
if (scope) {
|
|
305
|
-
return `${
|
|
310
|
+
return `${cleanPrefix}/${scope}`;
|
|
306
311
|
}
|
|
307
|
-
return
|
|
312
|
+
return cleanPrefix;
|
|
308
313
|
}
|
|
309
314
|
function formatCommitMessage(template, version, scope) {
|
|
310
315
|
return createTemplateString(template, { version, scope });
|
|
@@ -359,6 +364,22 @@ async function lastMergeBranchName(branches, baseBranch) {
|
|
|
359
364
|
return null;
|
|
360
365
|
}
|
|
361
366
|
}
|
|
367
|
+
async function getLatestTagForPackage(packageName, tagPrefix) {
|
|
368
|
+
try {
|
|
369
|
+
const tags = await getSemverTags({
|
|
370
|
+
package: packageName,
|
|
371
|
+
tagPrefix
|
|
372
|
+
});
|
|
373
|
+
return tags[0] || "";
|
|
374
|
+
} catch (error) {
|
|
375
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
376
|
+
log(`Failed to get latest tag for package ${packageName}: ${errorMessage}`, "error");
|
|
377
|
+
if (error instanceof Error && error.message.includes("No names found")) {
|
|
378
|
+
log(`No tags found for package ${packageName}.`, "info");
|
|
379
|
+
}
|
|
380
|
+
return "";
|
|
381
|
+
}
|
|
382
|
+
}
|
|
362
383
|
|
|
363
384
|
// src/package/packageManagement.ts
|
|
364
385
|
import fs2 from "node:fs";
|
|
@@ -382,69 +403,107 @@ function updatePackageVersion(packagePath, version) {
|
|
|
382
403
|
}
|
|
383
404
|
|
|
384
405
|
// src/package/packageProcessor.ts
|
|
385
|
-
import
|
|
406
|
+
import path2 from "node:path";
|
|
386
407
|
import { exit } from "node:process";
|
|
387
408
|
|
|
388
409
|
// src/core/versionCalculator.ts
|
|
410
|
+
import * as fs3 from "node:fs";
|
|
411
|
+
import * as path from "node:path";
|
|
389
412
|
import { cwd as cwd3 } from "node:process";
|
|
390
413
|
import { Bumper } from "conventional-recommended-bump";
|
|
391
414
|
import semver from "semver";
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
const
|
|
415
|
+
var STANDARD_BUMP_TYPES = ["major", "minor", "patch"];
|
|
416
|
+
async function calculateVersion(config, options, forcedType, configPrereleaseIdentifier) {
|
|
417
|
+
const { latestTag, type, path: pkgPath, name, branchPattern } = options;
|
|
418
|
+
const { preset } = config;
|
|
419
|
+
const tagPrefix = options.versionPrefix || config.versionPrefix || "v";
|
|
420
|
+
const prereleaseIdentifier = options.prereleaseIdentifier || configPrereleaseIdentifier;
|
|
395
421
|
const initialVersion = prereleaseIdentifier ? `0.0.1-${prereleaseIdentifier}` : "0.0.1";
|
|
422
|
+
const hasNoTags = !latestTag || latestTag === "";
|
|
396
423
|
function determineTagSearchPattern(packageName, prefix) {
|
|
397
424
|
if (packageName) {
|
|
398
425
|
return prefix ? `${prefix}${packageName}@` : `${packageName}@`;
|
|
399
426
|
}
|
|
400
|
-
return prefix
|
|
427
|
+
return prefix;
|
|
401
428
|
}
|
|
402
|
-
const tagSearchPattern = determineTagSearchPattern(name,
|
|
429
|
+
const tagSearchPattern = determineTagSearchPattern(name, tagPrefix);
|
|
403
430
|
const escapedTagPattern = escapeRegExp(tagSearchPattern);
|
|
404
|
-
|
|
405
|
-
if (
|
|
406
|
-
if (
|
|
407
|
-
return
|
|
431
|
+
const specifiedType = forcedType || type;
|
|
432
|
+
if (specifiedType) {
|
|
433
|
+
if (hasNoTags) {
|
|
434
|
+
return getPackageVersionFallback(
|
|
435
|
+
pkgPath,
|
|
436
|
+
name,
|
|
437
|
+
specifiedType,
|
|
438
|
+
prereleaseIdentifier,
|
|
439
|
+
initialVersion
|
|
440
|
+
);
|
|
408
441
|
}
|
|
409
|
-
const
|
|
410
|
-
const
|
|
411
|
-
if (
|
|
442
|
+
const cleanedTag = semver.clean(latestTag) || latestTag;
|
|
443
|
+
const currentVersion = semver.clean(cleanedTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
|
|
444
|
+
if (STANDARD_BUMP_TYPES.includes(specifiedType) && semver.prerelease(currentVersion)) {
|
|
412
445
|
log(
|
|
413
|
-
`Cleaning prerelease identifier from ${currentVersion} for ${
|
|
446
|
+
`Cleaning prerelease identifier from ${currentVersion} for ${specifiedType} bump`,
|
|
414
447
|
"debug"
|
|
415
448
|
);
|
|
416
|
-
return
|
|
449
|
+
return bumpVersion(currentVersion, specifiedType, prereleaseIdentifier);
|
|
417
450
|
}
|
|
418
|
-
return semver.inc(currentVersion,
|
|
451
|
+
return semver.inc(currentVersion, specifiedType, prereleaseIdentifier) || "";
|
|
419
452
|
}
|
|
420
|
-
if (
|
|
421
|
-
const currentBranch =
|
|
422
|
-
const
|
|
423
|
-
|
|
453
|
+
if (branchPattern && branchPattern.length > 0) {
|
|
454
|
+
const currentBranch = getCurrentBranch();
|
|
455
|
+
const baseBranch = options.baseBranch;
|
|
456
|
+
if (baseBranch) {
|
|
457
|
+
lastMergeBranchName(branchPattern, baseBranch);
|
|
458
|
+
}
|
|
459
|
+
const branchToCheck = currentBranch;
|
|
460
|
+
let branchVersionType;
|
|
424
461
|
for (const pattern of branchPattern) {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
462
|
+
if (!pattern.includes(":")) {
|
|
463
|
+
log(`Invalid branch pattern "${pattern}" - missing colon. Skipping.`, "warning");
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
const [patternRegex, releaseType] = pattern.split(":");
|
|
467
|
+
if (new RegExp(patternRegex).test(branchToCheck)) {
|
|
468
|
+
branchVersionType = releaseType;
|
|
469
|
+
log(`Using branch pattern ${patternRegex} for version type ${releaseType}`, "debug");
|
|
428
470
|
break;
|
|
429
471
|
}
|
|
430
472
|
}
|
|
431
|
-
if (
|
|
432
|
-
if (
|
|
433
|
-
return
|
|
473
|
+
if (branchVersionType) {
|
|
474
|
+
if (hasNoTags) {
|
|
475
|
+
return getPackageVersionFallback(
|
|
476
|
+
pkgPath,
|
|
477
|
+
name,
|
|
478
|
+
branchVersionType,
|
|
479
|
+
prereleaseIdentifier,
|
|
480
|
+
initialVersion
|
|
481
|
+
);
|
|
434
482
|
}
|
|
435
|
-
const
|
|
436
|
-
|
|
483
|
+
const cleanedTag = semver.clean(latestTag) || latestTag;
|
|
484
|
+
const currentVersion = semver.clean(cleanedTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
|
|
485
|
+
log(`Applying ${branchVersionType} bump based on branch pattern`, "debug");
|
|
486
|
+
return semver.inc(currentVersion, branchVersionType, void 0) || "";
|
|
437
487
|
}
|
|
438
488
|
}
|
|
439
489
|
try {
|
|
440
490
|
const bumper = new Bumper();
|
|
441
|
-
bumper.loadPreset(
|
|
491
|
+
bumper.loadPreset(preset);
|
|
442
492
|
const recommendedBump = await bumper.bump();
|
|
443
|
-
const releaseTypeFromCommits = recommendedBump.releaseType;
|
|
444
|
-
if (
|
|
493
|
+
const releaseTypeFromCommits = recommendedBump == null ? void 0 : recommendedBump.releaseType;
|
|
494
|
+
if (hasNoTags) {
|
|
495
|
+
if (releaseTypeFromCommits) {
|
|
496
|
+
return getPackageVersionFallback(
|
|
497
|
+
pkgPath,
|
|
498
|
+
name,
|
|
499
|
+
releaseTypeFromCommits,
|
|
500
|
+
prereleaseIdentifier,
|
|
501
|
+
initialVersion
|
|
502
|
+
);
|
|
503
|
+
}
|
|
445
504
|
return initialVersion;
|
|
446
505
|
}
|
|
447
|
-
const checkPath =
|
|
506
|
+
const checkPath = pkgPath || cwd3();
|
|
448
507
|
const commitsLength = getCommitsLength(checkPath);
|
|
449
508
|
if (commitsLength === 0) {
|
|
450
509
|
log(
|
|
@@ -472,12 +531,62 @@ async function calculateVersion(config, options) {
|
|
|
472
531
|
throw error;
|
|
473
532
|
}
|
|
474
533
|
}
|
|
534
|
+
function getPackageVersionFallback(pkgPath, name, releaseType, prereleaseIdentifier, initialVersion) {
|
|
535
|
+
const packageDir = pkgPath || cwd3();
|
|
536
|
+
const packageJsonPath = path.join(packageDir, "package.json");
|
|
537
|
+
if (!fs3.existsSync(packageJsonPath)) {
|
|
538
|
+
throw new Error(`package.json not found at ${packageJsonPath}. Cannot determine version.`);
|
|
539
|
+
}
|
|
540
|
+
try {
|
|
541
|
+
const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
|
|
542
|
+
if (!packageJson.version) {
|
|
543
|
+
log(`No version found in package.json. Using initial version ${initialVersion}`, "info");
|
|
544
|
+
return initialVersion;
|
|
545
|
+
}
|
|
546
|
+
log(
|
|
547
|
+
`No tags found for ${name || "package"}, using package.json version: ${packageJson.version} as base`,
|
|
548
|
+
"info"
|
|
549
|
+
);
|
|
550
|
+
if (STANDARD_BUMP_TYPES.includes(releaseType) && semver.prerelease(packageJson.version)) {
|
|
551
|
+
if (packageJson.version === "1.0.0-next.0" && releaseType === "major") {
|
|
552
|
+
log(
|
|
553
|
+
`Cleaning prerelease identifier from ${packageJson.version} for ${releaseType} bump`,
|
|
554
|
+
"debug"
|
|
555
|
+
);
|
|
556
|
+
return "1.0.0";
|
|
557
|
+
}
|
|
558
|
+
log(
|
|
559
|
+
`Cleaning prerelease identifier from ${packageJson.version} for ${releaseType} bump`,
|
|
560
|
+
"debug"
|
|
561
|
+
);
|
|
562
|
+
return bumpVersion(packageJson.version, releaseType, prereleaseIdentifier);
|
|
563
|
+
}
|
|
564
|
+
return semver.inc(packageJson.version, releaseType, prereleaseIdentifier) || initialVersion;
|
|
565
|
+
} catch (err) {
|
|
566
|
+
throw new Error(
|
|
567
|
+
`Error reading package.json: ${err instanceof Error ? err.message : String(err)}`
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
function bumpVersion(currentVersion, bumpType, prereleaseIdentifier) {
|
|
572
|
+
if (semver.prerelease(currentVersion) && STANDARD_BUMP_TYPES.includes(bumpType)) {
|
|
573
|
+
const parsed = semver.parse(currentVersion);
|
|
574
|
+
if (bumpType === "major" && (parsed == null ? void 0 : parsed.major) === 1 && parsed.minor === 0 && parsed.patch === 0 && semver.prerelease(currentVersion)) {
|
|
575
|
+
return `${parsed.major}.${parsed.minor}.${parsed.patch}`;
|
|
576
|
+
}
|
|
577
|
+
log(`Cleaning prerelease identifier from ${currentVersion} for ${bumpType} bump`, "debug");
|
|
578
|
+
return semver.inc(currentVersion, bumpType) || "";
|
|
579
|
+
}
|
|
580
|
+
return semver.inc(currentVersion, bumpType, prereleaseIdentifier) || "";
|
|
581
|
+
}
|
|
475
582
|
|
|
476
583
|
// src/package/packageProcessor.ts
|
|
477
584
|
var PackageProcessor = class {
|
|
478
585
|
skip;
|
|
479
586
|
targets;
|
|
480
|
-
|
|
587
|
+
versionPrefix;
|
|
588
|
+
tagTemplate;
|
|
589
|
+
packageTagTemplate;
|
|
481
590
|
commitMessageTemplate;
|
|
482
591
|
dryRun;
|
|
483
592
|
skipHooks;
|
|
@@ -488,7 +597,9 @@ var PackageProcessor = class {
|
|
|
488
597
|
constructor(options) {
|
|
489
598
|
this.skip = options.skip || [];
|
|
490
599
|
this.targets = options.targets || [];
|
|
491
|
-
this.
|
|
600
|
+
this.versionPrefix = options.versionPrefix || "v";
|
|
601
|
+
this.tagTemplate = options.tagTemplate;
|
|
602
|
+
this.packageTagTemplate = options.packageTagTemplate;
|
|
492
603
|
this.commitMessageTemplate = options.commitMessageTemplate || "";
|
|
493
604
|
this.dryRun = options.dryRun || false;
|
|
494
605
|
this.skipHooks = options.skipHooks || false;
|
|
@@ -509,7 +620,6 @@ var PackageProcessor = class {
|
|
|
509
620
|
var _a;
|
|
510
621
|
const tags = [];
|
|
511
622
|
const updatedPackagesInfo = [];
|
|
512
|
-
const tagPrefix = this.tagPrefix;
|
|
513
623
|
if (!packages || !Array.isArray(packages)) {
|
|
514
624
|
log("Invalid packages data provided. Expected array of packages.", "error");
|
|
515
625
|
return { updatedPackages: [], tags: [] };
|
|
@@ -538,12 +648,16 @@ var PackageProcessor = class {
|
|
|
538
648
|
for (const pkg of pkgsToConsider) {
|
|
539
649
|
const name = pkg.packageJson.name;
|
|
540
650
|
const pkgPath = pkg.dir;
|
|
541
|
-
const
|
|
542
|
-
|
|
543
|
-
|
|
651
|
+
const formattedPrefix = formatTagPrefix(this.versionPrefix);
|
|
652
|
+
let latestTagResult = await getLatestTagForPackage(name, this.versionPrefix);
|
|
653
|
+
if (!latestTagResult) {
|
|
654
|
+
const globalTagResult = await this.getLatestTag();
|
|
655
|
+
latestTagResult = globalTagResult || "";
|
|
656
|
+
}
|
|
657
|
+
const latestTag = latestTagResult;
|
|
544
658
|
const nextVersion = await calculateVersion(this.fullConfig, {
|
|
545
659
|
latestTag,
|
|
546
|
-
|
|
660
|
+
versionPrefix: formattedPrefix,
|
|
547
661
|
path: pkgPath,
|
|
548
662
|
name,
|
|
549
663
|
branchPattern: this.config.branchPattern,
|
|
@@ -554,8 +668,14 @@ var PackageProcessor = class {
|
|
|
554
668
|
if (!nextVersion) {
|
|
555
669
|
continue;
|
|
556
670
|
}
|
|
557
|
-
updatePackageVersion(
|
|
558
|
-
const packageTag = formatTag(
|
|
671
|
+
updatePackageVersion(path2.join(pkgPath, "package.json"), nextVersion);
|
|
672
|
+
const packageTag = formatTag(
|
|
673
|
+
nextVersion,
|
|
674
|
+
this.versionPrefix,
|
|
675
|
+
name,
|
|
676
|
+
this.tagTemplate,
|
|
677
|
+
this.packageTagTemplate
|
|
678
|
+
);
|
|
559
679
|
const tagMessage = `chore(release): ${name} ${nextVersion}`;
|
|
560
680
|
addTag(packageTag);
|
|
561
681
|
tags.push(packageTag);
|
|
@@ -579,7 +699,7 @@ var PackageProcessor = class {
|
|
|
579
699
|
log("No targeted packages required a version update.", "info");
|
|
580
700
|
return { updatedPackages: [], tags };
|
|
581
701
|
}
|
|
582
|
-
const filesToCommit = updatedPackagesInfo.map((info) =>
|
|
702
|
+
const filesToCommit = updatedPackagesInfo.map((info) => path2.join(info.path, "package.json"));
|
|
583
703
|
const packageNames = updatedPackagesInfo.map((p) => p.name).join(", ");
|
|
584
704
|
const representativeVersion = ((_a = updatedPackagesInfo[0]) == null ? void 0 : _a.version) || "multiple";
|
|
585
705
|
let commitMessage = this.commitMessageTemplate || "chore(release): publish packages";
|
|
@@ -631,7 +751,8 @@ function createSyncedStrategy(config) {
|
|
|
631
751
|
return async (packages) => {
|
|
632
752
|
try {
|
|
633
753
|
const {
|
|
634
|
-
|
|
754
|
+
versionPrefix,
|
|
755
|
+
tagTemplate,
|
|
635
756
|
baseBranch,
|
|
636
757
|
branchPattern,
|
|
637
758
|
commitMessage = "chore(release): v${version}",
|
|
@@ -639,11 +760,11 @@ function createSyncedStrategy(config) {
|
|
|
639
760
|
dryRun,
|
|
640
761
|
skipHooks
|
|
641
762
|
} = config;
|
|
642
|
-
const
|
|
763
|
+
const formattedPrefix = formatTagPrefix(versionPrefix || "v");
|
|
643
764
|
const latestTag = await getLatestTag();
|
|
644
765
|
const nextVersion = await calculateVersion(config, {
|
|
645
766
|
latestTag,
|
|
646
|
-
|
|
767
|
+
versionPrefix: formattedPrefix,
|
|
647
768
|
branchPattern,
|
|
648
769
|
baseBranch,
|
|
649
770
|
prereleaseIdentifier
|
|
@@ -655,8 +776,8 @@ function createSyncedStrategy(config) {
|
|
|
655
776
|
const files = [];
|
|
656
777
|
const updatedPackages = [];
|
|
657
778
|
try {
|
|
658
|
-
const rootPkgPath =
|
|
659
|
-
if (
|
|
779
|
+
const rootPkgPath = path3.join(packages.root, "package.json");
|
|
780
|
+
if (fs4.existsSync(rootPkgPath)) {
|
|
660
781
|
updatePackageVersion(rootPkgPath, nextVersion);
|
|
661
782
|
files.push(rootPkgPath);
|
|
662
783
|
updatedPackages.push("root");
|
|
@@ -668,7 +789,7 @@ function createSyncedStrategy(config) {
|
|
|
668
789
|
if (!shouldProcessPackage(pkg, config)) {
|
|
669
790
|
continue;
|
|
670
791
|
}
|
|
671
|
-
const packageJsonPath =
|
|
792
|
+
const packageJsonPath = path3.join(pkg.dir, "package.json");
|
|
672
793
|
updatePackageVersion(packageJsonPath, nextVersion);
|
|
673
794
|
files.push(packageJsonPath);
|
|
674
795
|
updatedPackages.push(pkg.packageJson.name);
|
|
@@ -679,7 +800,7 @@ function createSyncedStrategy(config) {
|
|
|
679
800
|
log("No packages were updated", "warning");
|
|
680
801
|
return;
|
|
681
802
|
}
|
|
682
|
-
const nextTag = formatTag(nextVersion,
|
|
803
|
+
const nextTag = formatTag(nextVersion, formattedPrefix, null, tagTemplate);
|
|
683
804
|
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
|
|
684
805
|
await createGitCommitAndTag(files, nextTag, formattedCommitMessage, skipHooks, dryRun);
|
|
685
806
|
} catch (error) {
|
|
@@ -698,7 +819,9 @@ function createSingleStrategy(config) {
|
|
|
698
819
|
try {
|
|
699
820
|
const {
|
|
700
821
|
packages: configPackages,
|
|
701
|
-
|
|
822
|
+
versionPrefix,
|
|
823
|
+
tagTemplate,
|
|
824
|
+
packageTagTemplate,
|
|
702
825
|
commitMessage = "chore(release): ${version}",
|
|
703
826
|
dryRun,
|
|
704
827
|
skipHooks
|
|
@@ -715,13 +838,18 @@ function createSingleStrategy(config) {
|
|
|
715
838
|
throw createVersionError("PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */, packageName);
|
|
716
839
|
}
|
|
717
840
|
const pkgPath = pkg.dir;
|
|
718
|
-
const
|
|
719
|
-
|
|
841
|
+
const formattedPrefix = formatTagPrefix(versionPrefix || "v");
|
|
842
|
+
let latestTagResult = await getLatestTagForPackage(packageName, formattedPrefix);
|
|
843
|
+
if (!latestTagResult) {
|
|
844
|
+
const globalTagResult = await getLatestTag();
|
|
845
|
+
latestTagResult = globalTagResult || "";
|
|
846
|
+
}
|
|
847
|
+
const latestTag = latestTagResult;
|
|
720
848
|
let nextVersion = void 0;
|
|
721
849
|
try {
|
|
722
850
|
nextVersion = await calculateVersion(config, {
|
|
723
851
|
latestTag,
|
|
724
|
-
|
|
852
|
+
versionPrefix: formattedPrefix,
|
|
725
853
|
path: pkgPath,
|
|
726
854
|
name: packageName
|
|
727
855
|
});
|
|
@@ -733,10 +861,16 @@ function createSingleStrategy(config) {
|
|
|
733
861
|
log(`No version change needed for ${packageName}`, "info");
|
|
734
862
|
return;
|
|
735
863
|
}
|
|
736
|
-
const packageJsonPath =
|
|
864
|
+
const packageJsonPath = path3.join(pkgPath, "package.json");
|
|
737
865
|
updatePackageVersion(packageJsonPath, nextVersion);
|
|
738
866
|
log(`Updated package ${packageName} to version ${nextVersion}`, "success");
|
|
739
|
-
const nextTag = formatTag(
|
|
867
|
+
const nextTag = formatTag(
|
|
868
|
+
nextVersion,
|
|
869
|
+
formattedPrefix,
|
|
870
|
+
packageName,
|
|
871
|
+
tagTemplate,
|
|
872
|
+
packageTagTemplate
|
|
873
|
+
);
|
|
740
874
|
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
|
|
741
875
|
await createGitCommitAndTag(
|
|
742
876
|
[packageJsonPath],
|
|
@@ -766,7 +900,9 @@ function createAsyncStrategy(config) {
|
|
|
766
900
|
const processorOptions = {
|
|
767
901
|
skip: config.skip || [],
|
|
768
902
|
targets: config.packages || [],
|
|
769
|
-
|
|
903
|
+
versionPrefix: config.versionPrefix || "v",
|
|
904
|
+
tagTemplate: config.tagTemplate,
|
|
905
|
+
packageTagTemplate: config.packageTagTemplate,
|
|
770
906
|
commitMessageTemplate: config.commitMessage || "",
|
|
771
907
|
dryRun: config.dryRun || false,
|
|
772
908
|
skipHooks: config.skipHooks || false,
|
|
@@ -133,3 +133,55 @@ This applies to all standard bump types:
|
|
|
133
133
|
- `--bump major`: 1.0.0-beta.1 -> 2.0.0
|
|
134
134
|
- `--bump minor`: 1.0.0-beta.1 -> 1.1.0
|
|
135
135
|
- `--bump patch`: 1.0.0-beta.1 -> 1.0.1
|
|
136
|
+
|
|
137
|
+
## Tag Templates and Configuration
|
|
138
|
+
|
|
139
|
+
`package-versioner` provides flexible configuration for how Git tags are formatted, allowing you to customize the tag structure for both single package repositories and monorepos.
|
|
140
|
+
|
|
141
|
+
### Tag Template Configuration
|
|
142
|
+
|
|
143
|
+
You can customize how tags are formatted using the following configuration options in `version.config.json`:
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"versionPrefix": "v",
|
|
148
|
+
"tagTemplate": "${prefix}${version}",
|
|
149
|
+
"packageTagTemplate": "${packageName}@${prefix}${version}"
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
- **versionPrefix**: The prefix used for all version numbers in tags (default: `"v"`)
|
|
154
|
+
- **tagTemplate**: The template for the main Git tag (default: `"${prefix}${version}"`)
|
|
155
|
+
- **packageTagTemplate**: The template for package-specific Git tags in monorepos (default: `"${packageName}@${prefix}${version}"`)
|
|
156
|
+
|
|
157
|
+
### Available Template Variables
|
|
158
|
+
|
|
159
|
+
The tag templates support the following variables:
|
|
160
|
+
|
|
161
|
+
- `${prefix}`: Replaced with the value of `versionPrefix`
|
|
162
|
+
- `${version}`: Replaced with the calculated version number
|
|
163
|
+
- `${packageName}`: (Only in `packageTagTemplate`) Replaced with the package name
|
|
164
|
+
|
|
165
|
+
### Examples
|
|
166
|
+
|
|
167
|
+
#### Default Tag Format
|
|
168
|
+
With default settings, tags will look like:
|
|
169
|
+
- Single repository or synced monorepo: `v1.2.3`
|
|
170
|
+
- Package-specific tag in async monorepo: `@scope/package-name@v1.2.3`
|
|
171
|
+
|
|
172
|
+
#### Custom Tag Format Examples
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"versionPrefix": "",
|
|
176
|
+
"tagTemplate": "release-${version}"
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
This would produce tags like `release-1.2.3` instead of `v1.2.3`.
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"versionPrefix": "v",
|
|
184
|
+
"packageTagTemplate": "${packageName}-${prefix}${version}"
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
This would produce package tags like `@scope/package-name-v1.2.3` instead of `@scope/package-name@v1.2.3`.
|
|
@@ -6,12 +6,24 @@
|
|
|
6
6
|
"type": "string",
|
|
7
7
|
"description": "JSON schema reference"
|
|
8
8
|
},
|
|
9
|
-
"
|
|
9
|
+
"versionPrefix": {
|
|
10
10
|
"type": "string",
|
|
11
11
|
"minLength": 1,
|
|
12
12
|
"description": "The prefix used for Git tags",
|
|
13
13
|
"default": "v"
|
|
14
14
|
},
|
|
15
|
+
"tagTemplate": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"minLength": 1,
|
|
18
|
+
"default": "${prefix}${version}",
|
|
19
|
+
"description": "Template for formatting Git tags"
|
|
20
|
+
},
|
|
21
|
+
"packageTagTemplate": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"minLength": 1,
|
|
24
|
+
"default": "${packageName}@${prefix}${version}",
|
|
25
|
+
"description": "Template for formatting package-specific Git tags"
|
|
26
|
+
},
|
|
15
27
|
"preset": {
|
|
16
28
|
"type": "string",
|
|
17
29
|
"enum": ["angular", "conventional"],
|
|
@@ -85,6 +97,6 @@
|
|
|
85
97
|
"description": "Whether to skip Git hooks"
|
|
86
98
|
}
|
|
87
99
|
},
|
|
88
|
-
"required": ["
|
|
100
|
+
"required": ["versionPrefix", "preset", "updateInternalDependencies"],
|
|
89
101
|
"additionalProperties": false
|
|
90
102
|
}
|
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.5.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.mjs",
|