package-versioner 0.8.5 → 0.9.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 +6 -6
- package/dist/index.cjs +46 -27
- package/dist/index.js +46 -27
- package/docs/versioning.md +6 -6
- package/package-versioner.schema.json +1 -1
- package/package.json +12 -12
package/README.md
CHANGED
|
@@ -130,7 +130,7 @@ Customize behaviour by creating a `version.config.json` file in your project roo
|
|
|
130
130
|
"updateChangelog": true,
|
|
131
131
|
"changelogFormat": "keep-a-changelog",
|
|
132
132
|
"strictReachable": false,
|
|
133
|
-
"
|
|
133
|
+
"sync": true,
|
|
134
134
|
"skip": [
|
|
135
135
|
"docs",
|
|
136
136
|
"e2e"
|
|
@@ -160,7 +160,7 @@ Customize behaviour by creating a `version.config.json` file in your project roo
|
|
|
160
160
|
- `paths`: Directories to search for Cargo.toml files (optional)
|
|
161
161
|
|
|
162
162
|
#### Monorepo-Specific Options
|
|
163
|
-
- `
|
|
163
|
+
- `sync`: Whether all packages should be versioned together (default: true)
|
|
164
164
|
- `skip`: Array of package names or patterns to exclude from versioning. Supports exact names, scope wildcards, path patterns, and global wildcards (e.g., ["@scope/package-a", "@scope/*", "packages/**/*"])
|
|
165
165
|
- `packages`: Array of package names or patterns to target for versioning. Supports exact names, scope wildcards, path patterns and global wildcards (e.g., ["@scope/package-a", "@scope/*", "*"])
|
|
166
166
|
- `mainPackage`: Package name whose commit history should drive version determination
|
|
@@ -234,7 +234,7 @@ This option works in conjunction with `tagTemplate` to control tag formatting. T
|
|
|
234
234
|
|
|
235
235
|
**Examples:**
|
|
236
236
|
|
|
237
|
-
For single-package repositories or
|
|
237
|
+
For single-package repositories or sync monorepos:
|
|
238
238
|
```json
|
|
239
239
|
{
|
|
240
240
|
"packageSpecificTags": true,
|
|
@@ -253,8 +253,8 @@ For global versioning:
|
|
|
253
253
|
Creates tags like `v1.2.3`
|
|
254
254
|
|
|
255
255
|
**Important Notes:**
|
|
256
|
-
- In **
|
|
257
|
-
- In **
|
|
256
|
+
- In **sync mode** with a single package, `packageSpecificTags: true` will use the package name even though all packages are versioned together
|
|
257
|
+
- In **sync mode** with multiple packages, package names are not used regardless of the setting
|
|
258
258
|
- In **async mode**, each package gets its own tag when `packageSpecificTags` is enabled
|
|
259
259
|
|
|
260
260
|
With package-specific tagging enabled, the tool will:
|
|
@@ -269,7 +269,7 @@ With package-specific tagging enabled, the tool will:
|
|
|
269
269
|
1. **Conventional Commits:** Analyzes commit messages (like `feat:`, `fix:`, `BREAKING CHANGE:`) since the last tag.
|
|
270
270
|
2. **Branch Pattern:** Determines the bump based on the current or recently merged branch name matching predefined patterns.
|
|
271
271
|
|
|
272
|
-
For a detailed explanation of these concepts and monorepo modes (
|
|
272
|
+
For a detailed explanation of these concepts and monorepo modes (Sync vs. Async), see [Versioning Strategies and Concepts](./docs/versioning.md).
|
|
273
273
|
|
|
274
274
|
## Documentation
|
|
275
275
|
|
package/dist/index.cjs
CHANGED
|
@@ -472,7 +472,7 @@ function getAllVersionTags(since, versionPrefix = "v") {
|
|
|
472
472
|
const allTags = tagOutput.split("\n").filter((tag) => !!tag);
|
|
473
473
|
let filteredTags = allTags;
|
|
474
474
|
if (since) {
|
|
475
|
-
const sinceIndex = allTags.
|
|
475
|
+
const sinceIndex = allTags.indexOf(since);
|
|
476
476
|
if (sinceIndex >= 0) {
|
|
477
477
|
filteredTags = allTags.slice(sinceIndex);
|
|
478
478
|
} else {
|
|
@@ -556,7 +556,7 @@ async function regenerateChangelog(options) {
|
|
|
556
556
|
const allTagsCmd = `git tag --list "${versionPrefix}*" --sort=creatordate`;
|
|
557
557
|
const allTagsOutput = (0, import_node_child_process2.execSync)(allTagsCmd, { encoding: "utf8" }).trim();
|
|
558
558
|
const allTags = allTagsOutput.split("\n").filter((tag) => !!tag);
|
|
559
|
-
const sinceIndex = allTags.
|
|
559
|
+
const sinceIndex = allTags.indexOf(since);
|
|
560
560
|
const actualPreviousTag = sinceIndex > 0 ? allTags[sinceIndex - 1] : null;
|
|
561
561
|
if (actualPreviousTag) {
|
|
562
562
|
tagRange = `${actualPreviousTag}..${currentTag.tag}`;
|
|
@@ -694,8 +694,12 @@ function filterPackagesByConfig(packages, configTargets, workspaceRoot) {
|
|
|
694
694
|
for (const target of configTargets) {
|
|
695
695
|
const dirMatches = filterByDirectoryPattern(packages, target, workspaceRoot);
|
|
696
696
|
const nameMatches = filterByPackageNamePattern(packages, target);
|
|
697
|
-
|
|
698
|
-
|
|
697
|
+
for (const pkg of dirMatches) {
|
|
698
|
+
matchedPackages.add(pkg);
|
|
699
|
+
}
|
|
700
|
+
for (const pkg of nameMatches) {
|
|
701
|
+
matchedPackages.add(pkg);
|
|
702
|
+
}
|
|
699
703
|
}
|
|
700
704
|
return Array.from(matchedPackages);
|
|
701
705
|
}
|
|
@@ -1008,7 +1012,7 @@ function formatVersionPrefix(prefix) {
|
|
|
1008
1012
|
function formatTag(version, prefix, packageName, template, packageSpecificTags) {
|
|
1009
1013
|
if ((template == null ? void 0 : template.includes("${packageName}")) && !packageName) {
|
|
1010
1014
|
log(
|
|
1011
|
-
'Warning: Your tagTemplate contains ${packageName} but no package name is available.\nThis will result in an empty package name in the tag (e.g., "@v1.0.0" instead of "my-package@v1.0.0").\n\nTo fix this:\n\u2022 If using
|
|
1015
|
+
'Warning: Your tagTemplate contains ${packageName} but no package name is available.\nThis will result in an empty package name in the tag (e.g., "@v1.0.0" instead of "my-package@v1.0.0").\n\nTo fix this:\n\u2022 If using sync mode: Set "packageSpecificTags": true in your config to enable package names in tags\n\u2022 If you want global tags: Remove ${packageName} from your tagTemplate (e.g., use "${prefix}${version}")\n\u2022 If using single/async mode: Ensure your package.json has a valid "name" field',
|
|
1012
1016
|
"warning"
|
|
1013
1017
|
);
|
|
1014
1018
|
}
|
|
@@ -1023,7 +1027,7 @@ function formatTag(version, prefix, packageName, template, packageSpecificTags)
|
|
|
1023
1027
|
function formatCommitMessage(template, version, packageName, additionalContext) {
|
|
1024
1028
|
if (template.includes("${packageName}") && !packageName) {
|
|
1025
1029
|
log(
|
|
1026
|
-
'Warning: Your commitMessage template contains ${packageName} but no package name is available.\nThis will result in an empty package name in the commit message (e.g., "Release @v1.0.0").\n\nTo fix this:\n\u2022 If using
|
|
1030
|
+
'Warning: Your commitMessage template contains ${packageName} but no package name is available.\nThis will result in an empty package name in the commit message (e.g., "Release @v1.0.0").\n\nTo fix this:\n\u2022 If using sync mode: Set "packageSpecificTags": true to enable package names in commits\n\u2022 If you want generic commit messages: Remove ${packageName} from your commitMessage template\n\u2022 If using single/async mode: Ensure your package.json has a valid "name" field',
|
|
1027
1031
|
"warning"
|
|
1028
1032
|
);
|
|
1029
1033
|
}
|
|
@@ -1561,14 +1565,21 @@ async function calculateVersion(config, options) {
|
|
|
1561
1565
|
const specifiedType = type;
|
|
1562
1566
|
if (specifiedType) {
|
|
1563
1567
|
const currentVersion = getCurrentVersionFromSource2();
|
|
1564
|
-
|
|
1568
|
+
const isCurrentPrerelease = import_semver3.default.prerelease(currentVersion);
|
|
1569
|
+
const explicitlyRequestedPrerelease = config.isPrerelease;
|
|
1570
|
+
if (STANDARD_BUMP_TYPES.includes(specifiedType) && (isCurrentPrerelease || explicitlyRequestedPrerelease)) {
|
|
1571
|
+
const prereleaseId2 = explicitlyRequestedPrerelease || isCurrentPrerelease ? normalizedPrereleaseId : void 0;
|
|
1565
1572
|
log(
|
|
1566
|
-
|
|
1573
|
+
explicitlyRequestedPrerelease ? `Creating prerelease version with identifier '${prereleaseId2}' using ${specifiedType}` : `Cleaning prerelease identifier from ${currentVersion} for ${specifiedType} bump`,
|
|
1567
1574
|
"debug"
|
|
1568
1575
|
);
|
|
1569
|
-
return bumpVersion(currentVersion, specifiedType,
|
|
1576
|
+
return bumpVersion(currentVersion, specifiedType, prereleaseId2);
|
|
1570
1577
|
}
|
|
1571
|
-
|
|
1578
|
+
const isPrereleaseBumpType = ["prerelease", "premajor", "preminor", "prepatch"].includes(
|
|
1579
|
+
specifiedType
|
|
1580
|
+
);
|
|
1581
|
+
const prereleaseId = config.isPrerelease || isPrereleaseBumpType ? normalizedPrereleaseId : void 0;
|
|
1582
|
+
return bumpVersion(currentVersion, specifiedType, prereleaseId);
|
|
1572
1583
|
}
|
|
1573
1584
|
if (branchPattern && branchPattern.length > 0) {
|
|
1574
1585
|
const currentBranch = getCurrentBranch();
|
|
@@ -1592,7 +1603,11 @@ async function calculateVersion(config, options) {
|
|
|
1592
1603
|
if (branchVersionType) {
|
|
1593
1604
|
const currentVersion = getCurrentVersionFromSource2();
|
|
1594
1605
|
log(`Applying ${branchVersionType} bump based on branch pattern`, "debug");
|
|
1595
|
-
|
|
1606
|
+
const isPrereleaseBumpType = ["prerelease", "premajor", "preminor", "prepatch"].includes(
|
|
1607
|
+
branchVersionType
|
|
1608
|
+
);
|
|
1609
|
+
const prereleaseId = config.isPrerelease || isPrereleaseBumpType ? normalizedPrereleaseId : void 0;
|
|
1610
|
+
return bumpVersion(currentVersion, branchVersionType, prereleaseId);
|
|
1596
1611
|
}
|
|
1597
1612
|
}
|
|
1598
1613
|
try {
|
|
@@ -1628,7 +1643,11 @@ async function calculateVersion(config, options) {
|
|
|
1628
1643
|
}
|
|
1629
1644
|
return "";
|
|
1630
1645
|
}
|
|
1631
|
-
|
|
1646
|
+
const isPrereleaseBumpType = ["prerelease", "premajor", "preminor", "prepatch"].includes(
|
|
1647
|
+
releaseTypeFromCommits
|
|
1648
|
+
);
|
|
1649
|
+
const prereleaseId = config.isPrerelease || isPrereleaseBumpType ? normalizedPrereleaseId : void 0;
|
|
1650
|
+
return bumpVersion(currentVersion, releaseTypeFromCommits, prereleaseId);
|
|
1632
1651
|
} catch (error) {
|
|
1633
1652
|
log(`Failed to calculate version for ${name || "project"}`, "error");
|
|
1634
1653
|
console.error(error);
|
|
@@ -1978,7 +1997,7 @@ function shouldProcessPackage2(pkg, config) {
|
|
|
1978
1997
|
const pkgName = pkg.packageJson.name;
|
|
1979
1998
|
return shouldProcessPackage(pkgName, config.skip);
|
|
1980
1999
|
}
|
|
1981
|
-
function
|
|
2000
|
+
function createSyncStrategy(config) {
|
|
1982
2001
|
return async (packages) => {
|
|
1983
2002
|
try {
|
|
1984
2003
|
const {
|
|
@@ -2315,14 +2334,14 @@ function createAsyncStrategy(config) {
|
|
|
2315
2334
|
};
|
|
2316
2335
|
}
|
|
2317
2336
|
function createStrategy(config) {
|
|
2318
|
-
if (config.
|
|
2319
|
-
return
|
|
2337
|
+
if (config.sync) {
|
|
2338
|
+
return createSyncStrategy(config);
|
|
2320
2339
|
}
|
|
2321
2340
|
return createAsyncStrategy(config);
|
|
2322
2341
|
}
|
|
2323
2342
|
function createStrategyMap(config) {
|
|
2324
2343
|
return {
|
|
2325
|
-
|
|
2344
|
+
sync: createSyncStrategy(config),
|
|
2326
2345
|
single: createSingleStrategy(config),
|
|
2327
2346
|
async: createAsyncStrategy(config)
|
|
2328
2347
|
};
|
|
@@ -2331,11 +2350,10 @@ function createStrategyMap(config) {
|
|
|
2331
2350
|
// src/core/versionEngine.ts
|
|
2332
2351
|
var VersionEngine = class {
|
|
2333
2352
|
config;
|
|
2334
|
-
jsonMode;
|
|
2335
2353
|
workspaceCache = null;
|
|
2336
2354
|
strategies;
|
|
2337
2355
|
currentStrategy;
|
|
2338
|
-
constructor(config,
|
|
2356
|
+
constructor(config, _jsonMode = false) {
|
|
2339
2357
|
if (!config) {
|
|
2340
2358
|
throw createVersionError("CONFIG_REQUIRED" /* CONFIG_REQUIRED */);
|
|
2341
2359
|
}
|
|
@@ -2344,7 +2362,6 @@ var VersionEngine = class {
|
|
|
2344
2362
|
log("No preset specified, using default: conventional-commits", "warning");
|
|
2345
2363
|
}
|
|
2346
2364
|
this.config = config;
|
|
2347
|
-
this.jsonMode = jsonMode;
|
|
2348
2365
|
this.strategies = createStrategyMap(config);
|
|
2349
2366
|
this.currentStrategy = createStrategy(config);
|
|
2350
2367
|
}
|
|
@@ -2425,7 +2442,7 @@ var VersionEngine = class {
|
|
|
2425
2442
|
}
|
|
2426
2443
|
/**
|
|
2427
2444
|
* Change the current strategy
|
|
2428
|
-
* @param strategyType The strategy type to use: '
|
|
2445
|
+
* @param strategyType The strategy type to use: 'sync', 'single', or 'async'
|
|
2429
2446
|
*/
|
|
2430
2447
|
setStrategy(strategyType) {
|
|
2431
2448
|
this.currentStrategy = this.strategies[strategyType];
|
|
@@ -2460,7 +2477,7 @@ async function run() {
|
|
|
2460
2477
|
program.command("version", { isDefault: true }).description("Version a package or packages based on configuration").option(
|
|
2461
2478
|
"-c, --config <path>",
|
|
2462
2479
|
"Path to config file (defaults to version.config.json in current directory)"
|
|
2463
|
-
).option("-d, --dry-run", "Dry run (no changes made)", false).option("-b, --bump <type>", "Specify bump type (patch|minor|major)").option("-p, --prerelease [identifier]", "Create prerelease version").option("-s, --
|
|
2480
|
+
).option("-d, --dry-run", "Dry run (no changes made)", false).option("-b, --bump <type>", "Specify bump type (patch|minor|major)").option("-p, --prerelease [identifier]", "Create prerelease version").option("-s, --sync", "Use synchronized versioning across all packages").option("-j, --json", "Output results as JSON", false).option("-t, --target <packages>", "Comma-delimited list of package names to target").option("--project-dir <path>", "Project directory to run commands in", process.cwd()).action(async (options) => {
|
|
2464
2481
|
if (options.json) {
|
|
2465
2482
|
enableJsonOutput(options.dryRun);
|
|
2466
2483
|
}
|
|
@@ -2479,20 +2496,22 @@ async function run() {
|
|
|
2479
2496
|
const config = await loadConfig(options.config);
|
|
2480
2497
|
log(`Loaded configuration from ${options.config || "version.config.json"}`, "info");
|
|
2481
2498
|
if (options.dryRun) config.dryRun = true;
|
|
2482
|
-
if (options.
|
|
2499
|
+
if (options.sync) config.sync = true;
|
|
2483
2500
|
if (options.bump) config.type = options.bump;
|
|
2484
|
-
if (options.prerelease)
|
|
2501
|
+
if (options.prerelease) {
|
|
2485
2502
|
config.prereleaseIdentifier = options.prerelease === true ? "next" : options.prerelease;
|
|
2503
|
+
config.isPrerelease = true;
|
|
2504
|
+
}
|
|
2486
2505
|
const cliTargets = options.target ? options.target.split(",").map((t) => t.trim()) : [];
|
|
2487
2506
|
const engine = new VersionEngine(config, !!options.json);
|
|
2488
2507
|
const pkgsResult = await engine.getWorkspacePackages();
|
|
2489
2508
|
const resolvedCount = pkgsResult.packages.length;
|
|
2490
2509
|
log(`Resolved ${resolvedCount} packages from workspace`, "debug");
|
|
2491
2510
|
log(`Config packages: ${JSON.stringify(config.packages)}`, "debug");
|
|
2492
|
-
log(`Config
|
|
2493
|
-
if (config.
|
|
2494
|
-
log("Using
|
|
2495
|
-
engine.setStrategy("
|
|
2511
|
+
log(`Config sync: ${config.sync}`, "debug");
|
|
2512
|
+
if (config.sync) {
|
|
2513
|
+
log("Using sync versioning strategy.", "info");
|
|
2514
|
+
engine.setStrategy("sync");
|
|
2496
2515
|
await engine.run(pkgsResult);
|
|
2497
2516
|
} else if (resolvedCount === 1) {
|
|
2498
2517
|
log("Using single package versioning strategy.", "info");
|
package/dist/index.js
CHANGED
|
@@ -439,7 +439,7 @@ function getAllVersionTags(since, versionPrefix = "v") {
|
|
|
439
439
|
const allTags = tagOutput.split("\n").filter((tag) => !!tag);
|
|
440
440
|
let filteredTags = allTags;
|
|
441
441
|
if (since) {
|
|
442
|
-
const sinceIndex = allTags.
|
|
442
|
+
const sinceIndex = allTags.indexOf(since);
|
|
443
443
|
if (sinceIndex >= 0) {
|
|
444
444
|
filteredTags = allTags.slice(sinceIndex);
|
|
445
445
|
} else {
|
|
@@ -523,7 +523,7 @@ async function regenerateChangelog(options) {
|
|
|
523
523
|
const allTagsCmd = `git tag --list "${versionPrefix}*" --sort=creatordate`;
|
|
524
524
|
const allTagsOutput = execSync2(allTagsCmd, { encoding: "utf8" }).trim();
|
|
525
525
|
const allTags = allTagsOutput.split("\n").filter((tag) => !!tag);
|
|
526
|
-
const sinceIndex = allTags.
|
|
526
|
+
const sinceIndex = allTags.indexOf(since);
|
|
527
527
|
const actualPreviousTag = sinceIndex > 0 ? allTags[sinceIndex - 1] : null;
|
|
528
528
|
if (actualPreviousTag) {
|
|
529
529
|
tagRange = `${actualPreviousTag}..${currentTag.tag}`;
|
|
@@ -661,8 +661,12 @@ function filterPackagesByConfig(packages, configTargets, workspaceRoot) {
|
|
|
661
661
|
for (const target of configTargets) {
|
|
662
662
|
const dirMatches = filterByDirectoryPattern(packages, target, workspaceRoot);
|
|
663
663
|
const nameMatches = filterByPackageNamePattern(packages, target);
|
|
664
|
-
|
|
665
|
-
|
|
664
|
+
for (const pkg of dirMatches) {
|
|
665
|
+
matchedPackages.add(pkg);
|
|
666
|
+
}
|
|
667
|
+
for (const pkg of nameMatches) {
|
|
668
|
+
matchedPackages.add(pkg);
|
|
669
|
+
}
|
|
666
670
|
}
|
|
667
671
|
return Array.from(matchedPackages);
|
|
668
672
|
}
|
|
@@ -975,7 +979,7 @@ function formatVersionPrefix(prefix) {
|
|
|
975
979
|
function formatTag(version, prefix, packageName, template, packageSpecificTags) {
|
|
976
980
|
if ((template == null ? void 0 : template.includes("${packageName}")) && !packageName) {
|
|
977
981
|
log(
|
|
978
|
-
'Warning: Your tagTemplate contains ${packageName} but no package name is available.\nThis will result in an empty package name in the tag (e.g., "@v1.0.0" instead of "my-package@v1.0.0").\n\nTo fix this:\n\u2022 If using
|
|
982
|
+
'Warning: Your tagTemplate contains ${packageName} but no package name is available.\nThis will result in an empty package name in the tag (e.g., "@v1.0.0" instead of "my-package@v1.0.0").\n\nTo fix this:\n\u2022 If using sync mode: Set "packageSpecificTags": true in your config to enable package names in tags\n\u2022 If you want global tags: Remove ${packageName} from your tagTemplate (e.g., use "${prefix}${version}")\n\u2022 If using single/async mode: Ensure your package.json has a valid "name" field',
|
|
979
983
|
"warning"
|
|
980
984
|
);
|
|
981
985
|
}
|
|
@@ -990,7 +994,7 @@ function formatTag(version, prefix, packageName, template, packageSpecificTags)
|
|
|
990
994
|
function formatCommitMessage(template, version, packageName, additionalContext) {
|
|
991
995
|
if (template.includes("${packageName}") && !packageName) {
|
|
992
996
|
log(
|
|
993
|
-
'Warning: Your commitMessage template contains ${packageName} but no package name is available.\nThis will result in an empty package name in the commit message (e.g., "Release @v1.0.0").\n\nTo fix this:\n\u2022 If using
|
|
997
|
+
'Warning: Your commitMessage template contains ${packageName} but no package name is available.\nThis will result in an empty package name in the commit message (e.g., "Release @v1.0.0").\n\nTo fix this:\n\u2022 If using sync mode: Set "packageSpecificTags": true to enable package names in commits\n\u2022 If you want generic commit messages: Remove ${packageName} from your commitMessage template\n\u2022 If using single/async mode: Ensure your package.json has a valid "name" field',
|
|
994
998
|
"warning"
|
|
995
999
|
);
|
|
996
1000
|
}
|
|
@@ -1528,14 +1532,21 @@ async function calculateVersion(config, options) {
|
|
|
1528
1532
|
const specifiedType = type;
|
|
1529
1533
|
if (specifiedType) {
|
|
1530
1534
|
const currentVersion = getCurrentVersionFromSource2();
|
|
1531
|
-
|
|
1535
|
+
const isCurrentPrerelease = semver3.prerelease(currentVersion);
|
|
1536
|
+
const explicitlyRequestedPrerelease = config.isPrerelease;
|
|
1537
|
+
if (STANDARD_BUMP_TYPES.includes(specifiedType) && (isCurrentPrerelease || explicitlyRequestedPrerelease)) {
|
|
1538
|
+
const prereleaseId2 = explicitlyRequestedPrerelease || isCurrentPrerelease ? normalizedPrereleaseId : void 0;
|
|
1532
1539
|
log(
|
|
1533
|
-
|
|
1540
|
+
explicitlyRequestedPrerelease ? `Creating prerelease version with identifier '${prereleaseId2}' using ${specifiedType}` : `Cleaning prerelease identifier from ${currentVersion} for ${specifiedType} bump`,
|
|
1534
1541
|
"debug"
|
|
1535
1542
|
);
|
|
1536
|
-
return bumpVersion(currentVersion, specifiedType,
|
|
1543
|
+
return bumpVersion(currentVersion, specifiedType, prereleaseId2);
|
|
1537
1544
|
}
|
|
1538
|
-
|
|
1545
|
+
const isPrereleaseBumpType = ["prerelease", "premajor", "preminor", "prepatch"].includes(
|
|
1546
|
+
specifiedType
|
|
1547
|
+
);
|
|
1548
|
+
const prereleaseId = config.isPrerelease || isPrereleaseBumpType ? normalizedPrereleaseId : void 0;
|
|
1549
|
+
return bumpVersion(currentVersion, specifiedType, prereleaseId);
|
|
1539
1550
|
}
|
|
1540
1551
|
if (branchPattern && branchPattern.length > 0) {
|
|
1541
1552
|
const currentBranch = getCurrentBranch();
|
|
@@ -1559,7 +1570,11 @@ async function calculateVersion(config, options) {
|
|
|
1559
1570
|
if (branchVersionType) {
|
|
1560
1571
|
const currentVersion = getCurrentVersionFromSource2();
|
|
1561
1572
|
log(`Applying ${branchVersionType} bump based on branch pattern`, "debug");
|
|
1562
|
-
|
|
1573
|
+
const isPrereleaseBumpType = ["prerelease", "premajor", "preminor", "prepatch"].includes(
|
|
1574
|
+
branchVersionType
|
|
1575
|
+
);
|
|
1576
|
+
const prereleaseId = config.isPrerelease || isPrereleaseBumpType ? normalizedPrereleaseId : void 0;
|
|
1577
|
+
return bumpVersion(currentVersion, branchVersionType, prereleaseId);
|
|
1563
1578
|
}
|
|
1564
1579
|
}
|
|
1565
1580
|
try {
|
|
@@ -1595,7 +1610,11 @@ async function calculateVersion(config, options) {
|
|
|
1595
1610
|
}
|
|
1596
1611
|
return "";
|
|
1597
1612
|
}
|
|
1598
|
-
|
|
1613
|
+
const isPrereleaseBumpType = ["prerelease", "premajor", "preminor", "prepatch"].includes(
|
|
1614
|
+
releaseTypeFromCommits
|
|
1615
|
+
);
|
|
1616
|
+
const prereleaseId = config.isPrerelease || isPrereleaseBumpType ? normalizedPrereleaseId : void 0;
|
|
1617
|
+
return bumpVersion(currentVersion, releaseTypeFromCommits, prereleaseId);
|
|
1599
1618
|
} catch (error) {
|
|
1600
1619
|
log(`Failed to calculate version for ${name || "project"}`, "error");
|
|
1601
1620
|
console.error(error);
|
|
@@ -1945,7 +1964,7 @@ function shouldProcessPackage2(pkg, config) {
|
|
|
1945
1964
|
const pkgName = pkg.packageJson.name;
|
|
1946
1965
|
return shouldProcessPackage(pkgName, config.skip);
|
|
1947
1966
|
}
|
|
1948
|
-
function
|
|
1967
|
+
function createSyncStrategy(config) {
|
|
1949
1968
|
return async (packages) => {
|
|
1950
1969
|
try {
|
|
1951
1970
|
const {
|
|
@@ -2282,14 +2301,14 @@ function createAsyncStrategy(config) {
|
|
|
2282
2301
|
};
|
|
2283
2302
|
}
|
|
2284
2303
|
function createStrategy(config) {
|
|
2285
|
-
if (config.
|
|
2286
|
-
return
|
|
2304
|
+
if (config.sync) {
|
|
2305
|
+
return createSyncStrategy(config);
|
|
2287
2306
|
}
|
|
2288
2307
|
return createAsyncStrategy(config);
|
|
2289
2308
|
}
|
|
2290
2309
|
function createStrategyMap(config) {
|
|
2291
2310
|
return {
|
|
2292
|
-
|
|
2311
|
+
sync: createSyncStrategy(config),
|
|
2293
2312
|
single: createSingleStrategy(config),
|
|
2294
2313
|
async: createAsyncStrategy(config)
|
|
2295
2314
|
};
|
|
@@ -2298,11 +2317,10 @@ function createStrategyMap(config) {
|
|
|
2298
2317
|
// src/core/versionEngine.ts
|
|
2299
2318
|
var VersionEngine = class {
|
|
2300
2319
|
config;
|
|
2301
|
-
jsonMode;
|
|
2302
2320
|
workspaceCache = null;
|
|
2303
2321
|
strategies;
|
|
2304
2322
|
currentStrategy;
|
|
2305
|
-
constructor(config,
|
|
2323
|
+
constructor(config, _jsonMode = false) {
|
|
2306
2324
|
if (!config) {
|
|
2307
2325
|
throw createVersionError("CONFIG_REQUIRED" /* CONFIG_REQUIRED */);
|
|
2308
2326
|
}
|
|
@@ -2311,7 +2329,6 @@ var VersionEngine = class {
|
|
|
2311
2329
|
log("No preset specified, using default: conventional-commits", "warning");
|
|
2312
2330
|
}
|
|
2313
2331
|
this.config = config;
|
|
2314
|
-
this.jsonMode = jsonMode;
|
|
2315
2332
|
this.strategies = createStrategyMap(config);
|
|
2316
2333
|
this.currentStrategy = createStrategy(config);
|
|
2317
2334
|
}
|
|
@@ -2392,7 +2409,7 @@ var VersionEngine = class {
|
|
|
2392
2409
|
}
|
|
2393
2410
|
/**
|
|
2394
2411
|
* Change the current strategy
|
|
2395
|
-
* @param strategyType The strategy type to use: '
|
|
2412
|
+
* @param strategyType The strategy type to use: 'sync', 'single', or 'async'
|
|
2396
2413
|
*/
|
|
2397
2414
|
setStrategy(strategyType) {
|
|
2398
2415
|
this.currentStrategy = this.strategies[strategyType];
|
|
@@ -2426,7 +2443,7 @@ async function run() {
|
|
|
2426
2443
|
program.command("version", { isDefault: true }).description("Version a package or packages based on configuration").option(
|
|
2427
2444
|
"-c, --config <path>",
|
|
2428
2445
|
"Path to config file (defaults to version.config.json in current directory)"
|
|
2429
|
-
).option("-d, --dry-run", "Dry run (no changes made)", false).option("-b, --bump <type>", "Specify bump type (patch|minor|major)").option("-p, --prerelease [identifier]", "Create prerelease version").option("-s, --
|
|
2446
|
+
).option("-d, --dry-run", "Dry run (no changes made)", false).option("-b, --bump <type>", "Specify bump type (patch|minor|major)").option("-p, --prerelease [identifier]", "Create prerelease version").option("-s, --sync", "Use synchronized versioning across all packages").option("-j, --json", "Output results as JSON", false).option("-t, --target <packages>", "Comma-delimited list of package names to target").option("--project-dir <path>", "Project directory to run commands in", process.cwd()).action(async (options) => {
|
|
2430
2447
|
if (options.json) {
|
|
2431
2448
|
enableJsonOutput(options.dryRun);
|
|
2432
2449
|
}
|
|
@@ -2445,20 +2462,22 @@ async function run() {
|
|
|
2445
2462
|
const config = await loadConfig(options.config);
|
|
2446
2463
|
log(`Loaded configuration from ${options.config || "version.config.json"}`, "info");
|
|
2447
2464
|
if (options.dryRun) config.dryRun = true;
|
|
2448
|
-
if (options.
|
|
2465
|
+
if (options.sync) config.sync = true;
|
|
2449
2466
|
if (options.bump) config.type = options.bump;
|
|
2450
|
-
if (options.prerelease)
|
|
2467
|
+
if (options.prerelease) {
|
|
2451
2468
|
config.prereleaseIdentifier = options.prerelease === true ? "next" : options.prerelease;
|
|
2469
|
+
config.isPrerelease = true;
|
|
2470
|
+
}
|
|
2452
2471
|
const cliTargets = options.target ? options.target.split(",").map((t) => t.trim()) : [];
|
|
2453
2472
|
const engine = new VersionEngine(config, !!options.json);
|
|
2454
2473
|
const pkgsResult = await engine.getWorkspacePackages();
|
|
2455
2474
|
const resolvedCount = pkgsResult.packages.length;
|
|
2456
2475
|
log(`Resolved ${resolvedCount} packages from workspace`, "debug");
|
|
2457
2476
|
log(`Config packages: ${JSON.stringify(config.packages)}`, "debug");
|
|
2458
|
-
log(`Config
|
|
2459
|
-
if (config.
|
|
2460
|
-
log("Using
|
|
2461
|
-
engine.setStrategy("
|
|
2477
|
+
log(`Config sync: ${config.sync}`, "debug");
|
|
2478
|
+
if (config.sync) {
|
|
2479
|
+
log("Using sync versioning strategy.", "info");
|
|
2480
|
+
engine.setStrategy("sync");
|
|
2462
2481
|
await engine.run(pkgsResult);
|
|
2463
2482
|
} else if (resolvedCount === 1) {
|
|
2464
2483
|
log("Using single package versioning strategy.", "info");
|
package/docs/versioning.md
CHANGED
|
@@ -334,7 +334,7 @@ Warning: Your tagTemplate contains ${packageName} but no package name is availab
|
|
|
334
334
|
This will result in an empty package name in the tag (e.g., "@v1.0.0" instead of "my-package@v1.0.0").
|
|
335
335
|
|
|
336
336
|
To fix this:
|
|
337
|
-
• If using
|
|
337
|
+
• If using sync mode: Set "packageSpecificTags": true in your config to enable package names in tags
|
|
338
338
|
• If you want global tags: Remove ${packageName} from your tagTemplate (e.g., use "${prefix}${version}")
|
|
339
339
|
• If using single/async mode: Ensure your package.json has a valid "name" field
|
|
340
340
|
```
|
|
@@ -344,7 +344,7 @@ To fix this:
|
|
|
344
344
|
1. **For Synced Mode with Package Names**: Enable package-specific tags
|
|
345
345
|
```json
|
|
346
346
|
{
|
|
347
|
-
"
|
|
347
|
+
"sync": true,
|
|
348
348
|
"packageSpecificTags": true,
|
|
349
349
|
"tagTemplate": "${packageName}@${prefix}${version}"
|
|
350
350
|
}
|
|
@@ -397,11 +397,11 @@ For global commit messages, use templates without `${packageName}`:
|
|
|
397
397
|
|
|
398
398
|
## Monorepo Versioning Modes
|
|
399
399
|
|
|
400
|
-
While primarily used for single packages now, `package-versioner` retains options for monorepo workflows, controlled mainly by the `
|
|
400
|
+
While primarily used for single packages now, `package-versioner` retains options for monorepo workflows, controlled mainly by the `sync` flag in `version.config.json`.
|
|
401
401
|
|
|
402
|
-
###
|
|
402
|
+
### Sync Mode (`sync: true`)
|
|
403
403
|
|
|
404
|
-
This is the default if the `
|
|
404
|
+
This is the default if the `sync` flag is present and true.
|
|
405
405
|
|
|
406
406
|
- **Behaviour:** The tool calculates **one** version bump based on the overall history (or branch pattern). This single new version is applied to **all** packages within the repository (or just the root `package.json` if not a structured monorepo). A single Git tag is created.
|
|
407
407
|
- **Tag Behaviour:**
|
|
@@ -409,7 +409,7 @@ This is the default if the `synced` flag is present and true.
|
|
|
409
409
|
- In **single-package repositories**: Respects the `packageSpecificTags` setting - can create either `v1.2.3` or `package-name@v1.2.3`
|
|
410
410
|
- **Use Case:** Suitable for monorepos where all packages are tightly coupled and released together with the same version number. Also the effective mode for single-package repositories.
|
|
411
411
|
|
|
412
|
-
### Async Mode (`
|
|
412
|
+
### Async Mode (`sync: false`)
|
|
413
413
|
|
|
414
414
|
*(Note: This mode relies heavily on monorepo tooling and structure, like `pnpm workspaces` and correctly configured package dependencies.)*
|
|
415
415
|
|
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.9.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.mjs",
|
|
@@ -37,34 +37,34 @@
|
|
|
37
37
|
]
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@biomejs/biome": "^2.
|
|
40
|
+
"@biomejs/biome": "^2.2.2",
|
|
41
41
|
"@types/figlet": "^1.5.5",
|
|
42
|
-
"@types/node": "^24.0
|
|
42
|
+
"@types/node": "^24.3.0",
|
|
43
43
|
"@types/semver": "^7.3.13",
|
|
44
44
|
"@vitest/coverage-v8": "^3.2.4",
|
|
45
|
-
"cross-env": "^
|
|
45
|
+
"cross-env": "^10.0.0",
|
|
46
46
|
"husky": "^9.1.7",
|
|
47
|
-
"lint-staged": "^16.1.
|
|
47
|
+
"lint-staged": "^16.1.5",
|
|
48
48
|
"tsup": "^8.5.0",
|
|
49
|
-
"tsx": "^4.20.
|
|
50
|
-
"typescript": "^5.
|
|
49
|
+
"tsx": "^4.20.5",
|
|
50
|
+
"typescript": "^5.9.2",
|
|
51
51
|
"vitest": "^3.2.4"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@manypkg/get-packages": "^3.
|
|
54
|
+
"@manypkg/get-packages": "^3.1.0",
|
|
55
55
|
"@types/micromatch": "^4.0.9",
|
|
56
|
-
"chalk": "^5.
|
|
56
|
+
"chalk": "^5.6.0",
|
|
57
57
|
"commander": "^14.0.0",
|
|
58
58
|
"conventional-changelog-angular": "^8.0.0",
|
|
59
59
|
"conventional-changelog-conventional-commits": "npm:conventional-changelog-conventionalcommits@^9.0.0",
|
|
60
|
-
"conventional-changelog-conventionalcommits": "^9.
|
|
60
|
+
"conventional-changelog-conventionalcommits": "^9.1.0",
|
|
61
61
|
"conventional-commits-filter": "^5.0.0",
|
|
62
62
|
"conventional-recommended-bump": "^11.2.0",
|
|
63
|
-
"figlet": "^1.8.
|
|
63
|
+
"figlet": "^1.8.2",
|
|
64
64
|
"git-semver-tags": "^8.0.0",
|
|
65
65
|
"micromatch": "^4.0.8",
|
|
66
66
|
"semver": "^7.7.2",
|
|
67
|
-
"smol-toml": "^1.4.
|
|
67
|
+
"smol-toml": "^1.4.2"
|
|
68
68
|
},
|
|
69
69
|
"scripts": {
|
|
70
70
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|