package-versioner 0.0.2 → 0.1.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 +10 -1
- package/dist/index.cjs +151 -111
- package/dist/index.d.cts +1 -0
- package/dist/index.js +154 -118
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# package-versioner
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
<a href="https://www.npmjs.com/package/package-versioner" alt="NPM Version">
|
|
5
|
+
<img src="https://img.shields.io/npm/v/package-versioner" /></a>
|
|
6
|
+
<a href="https://www.npmjs.com/package/package-versioner" alt="NPM Downloads">
|
|
7
|
+
<img src="https://img.shields.io/npm/dw/package-versioner" /></a>
|
|
8
|
+
|
|
3
9
|
A powerful CLI tool for automated semantic versioning based on Git history and conventional commits. Simplifies version management in JavaScript/TypeScript projects.
|
|
4
10
|
|
|
5
11
|
## Features
|
|
@@ -32,6 +38,9 @@ npx package-versioner --bump minor
|
|
|
32
38
|
# Create a prerelease (e.g., alpha)
|
|
33
39
|
npx package-versioner --bump patch --prerelease alpha
|
|
34
40
|
|
|
41
|
+
# Target specific packages (only in async/independent mode, comma-separated)
|
|
42
|
+
npx package-versioner -t @scope/package-a,@scope/package-b
|
|
43
|
+
|
|
35
44
|
# Perform a dry run: calculates version, logs actions, but makes no file changes or Git commits/tags
|
|
36
45
|
npx package-versioner --dry-run
|
|
37
46
|
```
|
|
@@ -82,7 +91,7 @@ npx package-versioner --help
|
|
|
82
91
|
|
|
83
92
|
## Acknowledgements
|
|
84
93
|
|
|
85
|
-
This project was originally forked from and inspired by `jucian0/turbo-version`
|
|
94
|
+
This project was originally forked from and inspired by [`jucian0/turbo-version`](https://github.com/jucian0/turbo-version). We appreciate the foundational work done by the original authors.
|
|
86
95
|
|
|
87
96
|
## License
|
|
88
97
|
|
package/dist/index.cjs
CHANGED
|
@@ -15,21 +15,50 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
15
|
return to;
|
|
16
16
|
};
|
|
17
17
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
18
22
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
19
23
|
mod
|
|
20
24
|
));
|
|
21
25
|
|
|
22
26
|
// src/index.ts
|
|
23
|
-
var import_node_process4 = require("process");
|
|
24
|
-
var import_chalk2 = __toESM(require("chalk"), 1);
|
|
25
27
|
var import_commander = require("commander");
|
|
28
|
+
|
|
29
|
+
// src/config.ts
|
|
30
|
+
var fs = __toESM(require("fs"), 1);
|
|
31
|
+
var import_node_process = require("process");
|
|
32
|
+
function loadConfig(configPath) {
|
|
33
|
+
const localProcess = (0, import_node_process.cwd)();
|
|
34
|
+
const filePath = configPath || `${localProcess}/version.config.json`;
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
fs.readFile(filePath, "utf-8", (err, data) => {
|
|
37
|
+
if (err) {
|
|
38
|
+
reject(new Error(`Could not locate the config file at ${filePath}: ${err.message}`));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const config = JSON.parse(data);
|
|
43
|
+
resolve(config);
|
|
44
|
+
} catch (err2) {
|
|
45
|
+
const errorMessage = err2 instanceof Error ? err2.message : String(err2);
|
|
46
|
+
reject(new Error(`Failed to parse config file ${filePath}: ${errorMessage}`));
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/utils.ts
|
|
53
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
54
|
+
var import_chalk = __toESM(require("chalk"), 1);
|
|
26
55
|
var import_figlet = __toESM(require("figlet"), 1);
|
|
27
56
|
|
|
28
57
|
// package.json
|
|
29
58
|
var package_default = {
|
|
30
59
|
name: "package-versioner",
|
|
31
60
|
description: "A powerful CLI tool for automated semantic versioning based on Git history and conventional commits. Supports monorepos with synchronized or independent package versioning strategies.",
|
|
32
|
-
version: "0.0.
|
|
61
|
+
version: "0.0.2",
|
|
33
62
|
type: "module",
|
|
34
63
|
main: "./dist/index.js",
|
|
35
64
|
module: "./dist/index.mjs",
|
|
@@ -79,12 +108,12 @@ var package_default = {
|
|
|
79
108
|
devDependencies: {
|
|
80
109
|
"@biomejs/biome": "^1.9.4",
|
|
81
110
|
"@types/figlet": "^1.5.5",
|
|
82
|
-
"@types/node": "^
|
|
111
|
+
"@types/node": "^22.14.0",
|
|
83
112
|
"@types/semver": "^7.3.13",
|
|
84
113
|
"@vitest/coverage-v8": "^3.1.1",
|
|
85
114
|
husky: "^9.1.7",
|
|
86
115
|
"lint-staged": "^15.5.0",
|
|
87
|
-
tsup: "^
|
|
116
|
+
tsup: "^8.4.0",
|
|
88
117
|
typescript: "^5.8.3",
|
|
89
118
|
vitest: "^3.1.1"
|
|
90
119
|
},
|
|
@@ -101,32 +130,7 @@ var package_default = {
|
|
|
101
130
|
packageManager: "pnpm@10.8.0+sha512.0e82714d1b5b43c74610193cb20734897c1d00de89d0e18420aebc5977fa13d780a9cb05734624e81ebd81cc876cd464794850641c48b9544326b5622ca29971"
|
|
102
131
|
};
|
|
103
132
|
|
|
104
|
-
// src/config.ts
|
|
105
|
-
var fs = __toESM(require("fs"), 1);
|
|
106
|
-
var import_node_process = require("process");
|
|
107
|
-
function loadConfig(configPath) {
|
|
108
|
-
const localProcess = (0, import_node_process.cwd)();
|
|
109
|
-
const filePath = configPath || `${localProcess}/version.config.json`;
|
|
110
|
-
return new Promise((resolve, reject) => {
|
|
111
|
-
fs.readFile(filePath, "utf-8", (err, data) => {
|
|
112
|
-
if (err) {
|
|
113
|
-
reject(new Error(`Could not locate the config file at ${filePath}: ${err.message}`));
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
try {
|
|
117
|
-
const config = JSON.parse(data);
|
|
118
|
-
resolve(config);
|
|
119
|
-
} catch (err2) {
|
|
120
|
-
const errorMessage = err2 instanceof Error ? err2.message : String(err2);
|
|
121
|
-
reject(new Error(`Failed to parse config file ${filePath}: ${errorMessage}`));
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
133
|
// src/utils.ts
|
|
128
|
-
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
129
|
-
var import_chalk = __toESM(require("chalk"), 1);
|
|
130
134
|
var import_git_semver_tags = require("git-semver-tags");
|
|
131
135
|
|
|
132
136
|
// src/git.ts
|
|
@@ -213,7 +217,7 @@ async function gitProcess({ files, nextTag, commitMessage, skipHooks, dryRun })
|
|
|
213
217
|
message: commitMessage,
|
|
214
218
|
skipHooks
|
|
215
219
|
});
|
|
216
|
-
const tagMessage = `New Version ${nextTag} generated at ${new Date().toISOString()}`;
|
|
220
|
+
const tagMessage = `New Version ${nextTag} generated at ${(/* @__PURE__ */ new Date()).toISOString()}`;
|
|
217
221
|
await createGitTag({
|
|
218
222
|
tag: nextTag,
|
|
219
223
|
message: tagMessage
|
|
@@ -252,6 +256,25 @@ function getCurrentBranch() {
|
|
|
252
256
|
}
|
|
253
257
|
|
|
254
258
|
// src/utils.ts
|
|
259
|
+
function printFiglet() {
|
|
260
|
+
const font = "Standard";
|
|
261
|
+
import_figlet.default.text(package_default.name, { font }, (err, data) => {
|
|
262
|
+
if (err) {
|
|
263
|
+
log("warning", "Could not print figlet banner: Figlet error");
|
|
264
|
+
console.error(err);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (data) {
|
|
268
|
+
const figletText = data;
|
|
269
|
+
const versionText = `v${package_default.version}`;
|
|
270
|
+
process.stdout.write(`${import_chalk.default.hex("#FF1F57")(figletText)}
|
|
271
|
+
`);
|
|
272
|
+
process.stdout.write(`${import_chalk.default.hex("#0096FF")(versionText)}
|
|
273
|
+
|
|
274
|
+
`);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
}
|
|
255
278
|
function log(status, message) {
|
|
256
279
|
const statusColors = {
|
|
257
280
|
info: import_chalk.default.blue("\u2139"),
|
|
@@ -276,10 +299,10 @@ async function getLatestTag() {
|
|
|
276
299
|
}
|
|
277
300
|
}
|
|
278
301
|
function formatTag(options, props) {
|
|
279
|
-
const { name
|
|
302
|
+
const { name, synced, tagPrefix } = options;
|
|
280
303
|
const { version } = props;
|
|
281
|
-
if (!synced &&
|
|
282
|
-
return `${tagPrefix ? tagPrefix : ""}${
|
|
304
|
+
if (!synced && name) {
|
|
305
|
+
return `${tagPrefix ? tagPrefix : ""}${name}@${version}`;
|
|
283
306
|
}
|
|
284
307
|
return `${tagPrefix ? tagPrefix : "v"}${version}`;
|
|
285
308
|
}
|
|
@@ -292,7 +315,7 @@ function createTemplateString(template, data) {
|
|
|
292
315
|
function formatCommitMessage(template, version) {
|
|
293
316
|
return createTemplateString(template, { version });
|
|
294
317
|
}
|
|
295
|
-
function updatePackageVersion({ path: path2, version, name
|
|
318
|
+
function updatePackageVersion({ path: path2, version, name, dryRun }) {
|
|
296
319
|
try {
|
|
297
320
|
const pkgPath = `${path2}/package.json`;
|
|
298
321
|
const pkg = JSON.parse(import_node_fs2.default.readFileSync(pkgPath, "utf8"));
|
|
@@ -300,12 +323,12 @@ function updatePackageVersion({ path: path2, version, name: name2, dryRun }) {
|
|
|
300
323
|
if (!dryRun) {
|
|
301
324
|
import_node_fs2.default.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
302
325
|
`);
|
|
303
|
-
log("success", `${
|
|
326
|
+
log("success", `${name}: ${version}`);
|
|
304
327
|
} else {
|
|
305
|
-
log("info", `[DRY RUN] Would update ${
|
|
328
|
+
log("info", `[DRY RUN] Would update ${name} package.json to version ${version}`);
|
|
306
329
|
}
|
|
307
330
|
} catch (error) {
|
|
308
|
-
log("error", `Failed to update ${
|
|
331
|
+
log("error", `Failed to update ${name} to version ${version}`);
|
|
309
332
|
console.error(error);
|
|
310
333
|
}
|
|
311
334
|
}
|
|
@@ -318,14 +341,18 @@ var import_get_packages = require("@manypkg/get-packages");
|
|
|
318
341
|
var import_conventional_recommended_bump = require("conventional-recommended-bump");
|
|
319
342
|
var import_semver = __toESM(require("semver"), 1);
|
|
320
343
|
var VersionEngine = class {
|
|
344
|
+
config;
|
|
321
345
|
constructor(config) {
|
|
322
346
|
this.config = config;
|
|
323
347
|
}
|
|
348
|
+
/**
|
|
349
|
+
* Calculate the next version based on options
|
|
350
|
+
*/
|
|
324
351
|
async calculateVersion(options) {
|
|
325
|
-
const { latestTag, type, path: path2, name
|
|
352
|
+
const { latestTag, type, path: path2, name, branchPattern, prereleaseIdentifier } = options;
|
|
326
353
|
const originalPrefix = this.config.tagPrefix || "";
|
|
327
354
|
const initialVersion = prereleaseIdentifier ? `0.0.1-${prereleaseIdentifier}` : "0.0.1";
|
|
328
|
-
const tagSearchPattern =
|
|
355
|
+
const tagSearchPattern = name ? originalPrefix ? `${originalPrefix}${name}@` : `${name}@` : originalPrefix ? `${originalPrefix}v` : "v";
|
|
329
356
|
let determinedReleaseType = type || null;
|
|
330
357
|
if (determinedReleaseType) {
|
|
331
358
|
if (!latestTag) {
|
|
@@ -366,21 +393,21 @@ var VersionEngine = class {
|
|
|
366
393
|
if (commitsLength === 0) {
|
|
367
394
|
log(
|
|
368
395
|
"info",
|
|
369
|
-
`No new commits found for ${
|
|
396
|
+
`No new commits found for ${name || "project"} since ${latestTag}, skipping version bump`
|
|
370
397
|
);
|
|
371
398
|
return "";
|
|
372
399
|
}
|
|
373
400
|
if (!releaseTypeFromCommits) {
|
|
374
401
|
log(
|
|
375
402
|
"info",
|
|
376
|
-
`No relevant commits found for ${
|
|
403
|
+
`No relevant commits found for ${name || "project"} since ${latestTag}, skipping version bump`
|
|
377
404
|
);
|
|
378
405
|
return "";
|
|
379
406
|
}
|
|
380
407
|
const currentVersion = import_semver.default.clean(latestTag.replace(tagSearchPattern, "")) || "0.0.0";
|
|
381
408
|
return import_semver.default.inc(currentVersion, releaseTypeFromCommits, prereleaseIdentifier) || "";
|
|
382
409
|
} catch (error) {
|
|
383
|
-
log("error", `Failed to calculate version for ${
|
|
410
|
+
log("error", `Failed to calculate version for ${name || "project"}`);
|
|
384
411
|
console.error(error);
|
|
385
412
|
if (error instanceof Error && error.message.includes("No names found")) {
|
|
386
413
|
log("info", "No tags found, proceeding with initial version calculation (if applicable).");
|
|
@@ -389,30 +416,44 @@ var VersionEngine = class {
|
|
|
389
416
|
return "";
|
|
390
417
|
}
|
|
391
418
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
419
|
+
/**
|
|
420
|
+
* Process packages based on discovery, skip list, and optional target list.
|
|
421
|
+
* Returns a list of package.json file paths that were updated (or would be in dry run).
|
|
422
|
+
*/
|
|
423
|
+
async processPackages(discoveredPackages = [], targets = []) {
|
|
424
|
+
const { tagPrefix, skip } = this.config;
|
|
395
425
|
const files = [];
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
|
|
426
|
+
const pkgsToConsider = discoveredPackages.filter((pkg) => {
|
|
427
|
+
if (skip == null ? void 0 : skip.includes(pkg.packageJson.name)) {
|
|
428
|
+
log("info", `Skipping package ${pkg.packageJson.name} based on config skip list.`);
|
|
399
429
|
return false;
|
|
400
430
|
}
|
|
401
|
-
|
|
431
|
+
if (targets.length > 0) {
|
|
432
|
+
const isTargeted = targets.includes(pkg.packageJson.name);
|
|
433
|
+
if (!isTargeted) {
|
|
434
|
+
}
|
|
435
|
+
return isTargeted;
|
|
436
|
+
}
|
|
437
|
+
return true;
|
|
402
438
|
});
|
|
403
|
-
|
|
404
|
-
|
|
439
|
+
log("info", `Found ${pkgsToConsider.length} package(s) to process after filtering.`);
|
|
440
|
+
for (const pkg of pkgsToConsider) {
|
|
441
|
+
const name = pkg.packageJson.name;
|
|
405
442
|
const pkgPath = pkg.dir;
|
|
406
443
|
const prefix = formatTagPrefix(tagPrefix);
|
|
407
444
|
const latestTag = await getLatestTag();
|
|
408
445
|
const nextVersion = await this.calculateVersion({
|
|
409
446
|
latestTag,
|
|
447
|
+
// This might need refinement for async based on package-specific tags
|
|
410
448
|
tagPrefix: prefix,
|
|
411
449
|
path: pkgPath,
|
|
412
|
-
name
|
|
450
|
+
name,
|
|
451
|
+
// Pass name for potential package-specific tag lookups
|
|
413
452
|
branchPattern: this.config.branchPattern,
|
|
414
453
|
baseBranch: this.config.baseBranch,
|
|
415
|
-
prereleaseIdentifier: this.config.prereleaseIdentifier
|
|
454
|
+
prereleaseIdentifier: this.config.prereleaseIdentifier,
|
|
455
|
+
type: this.config.forceType
|
|
456
|
+
// Pass forced type if provided
|
|
416
457
|
});
|
|
417
458
|
if (!nextVersion) {
|
|
418
459
|
continue;
|
|
@@ -420,13 +461,16 @@ var VersionEngine = class {
|
|
|
420
461
|
updatePackageVersion({
|
|
421
462
|
path: pkgPath,
|
|
422
463
|
version: nextVersion,
|
|
423
|
-
name
|
|
464
|
+
name,
|
|
424
465
|
dryRun: this.config.dryRun
|
|
425
466
|
});
|
|
426
467
|
files.push(import_node_path2.default.join(pkgPath, "package.json"));
|
|
427
468
|
}
|
|
428
469
|
return files;
|
|
429
470
|
}
|
|
471
|
+
/**
|
|
472
|
+
* Create git commit and tag
|
|
473
|
+
*/
|
|
430
474
|
async createGitCommitAndTag(files, nextTag, commitMessage, dryRun) {
|
|
431
475
|
try {
|
|
432
476
|
await gitProcess({
|
|
@@ -445,6 +489,9 @@ var VersionEngine = class {
|
|
|
445
489
|
(0, import_node_process3.exit)(1);
|
|
446
490
|
}
|
|
447
491
|
}
|
|
492
|
+
/**
|
|
493
|
+
* Synced versioning strategy (all packages get the same version)
|
|
494
|
+
*/
|
|
448
495
|
async syncedStrategy() {
|
|
449
496
|
var _a;
|
|
450
497
|
const {
|
|
@@ -513,6 +560,9 @@ var VersionEngine = class {
|
|
|
513
560
|
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
|
|
514
561
|
await this.createGitCommitAndTag(files, nextTag, formattedCommitMessage, this.config.dryRun);
|
|
515
562
|
}
|
|
563
|
+
/**
|
|
564
|
+
* Single package versioning strategy
|
|
565
|
+
*/
|
|
516
566
|
async singleStrategy() {
|
|
517
567
|
const {
|
|
518
568
|
packages: configPackages,
|
|
@@ -572,11 +622,15 @@ var VersionEngine = class {
|
|
|
572
622
|
this.config.dryRun
|
|
573
623
|
);
|
|
574
624
|
}
|
|
575
|
-
|
|
625
|
+
/**
|
|
626
|
+
* Async versioning strategy (each package gets its own version)
|
|
627
|
+
*/
|
|
628
|
+
async asyncStrategy(cliTargets = []) {
|
|
576
629
|
const {
|
|
577
|
-
packages: configPackages,
|
|
578
630
|
commitMessage = "chore(release): ${version}",
|
|
631
|
+
// Align with test expectations
|
|
579
632
|
skipHooks
|
|
633
|
+
// Add skipHooks here
|
|
580
634
|
} = this.config;
|
|
581
635
|
let pkgsResult;
|
|
582
636
|
try {
|
|
@@ -590,9 +644,9 @@ var VersionEngine = class {
|
|
|
590
644
|
(0, import_node_process3.exit)(1);
|
|
591
645
|
return;
|
|
592
646
|
}
|
|
593
|
-
const pkgsToProcess = await this.processPackages(pkgsResult.packages,
|
|
647
|
+
const pkgsToProcess = await this.processPackages(pkgsResult.packages, cliTargets);
|
|
594
648
|
if (pkgsToProcess.length === 0) {
|
|
595
|
-
log("info", "No packages to process");
|
|
649
|
+
log("info", "No packages to process based on changes and targets");
|
|
596
650
|
return;
|
|
597
651
|
}
|
|
598
652
|
const formattedCommitMessage = commitMessage;
|
|
@@ -605,7 +659,7 @@ var VersionEngine = class {
|
|
|
605
659
|
dryRun: this.config.dryRun
|
|
606
660
|
});
|
|
607
661
|
if (!this.config.dryRun) {
|
|
608
|
-
log("success",
|
|
662
|
+
log("success", `Created version commit for ${pkgsToProcess.length} package(s)`);
|
|
609
663
|
}
|
|
610
664
|
} catch (error) {
|
|
611
665
|
log("error", "Failed to create version commit");
|
|
@@ -616,63 +670,49 @@ var VersionEngine = class {
|
|
|
616
670
|
};
|
|
617
671
|
|
|
618
672
|
// src/index.ts
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
program
|
|
622
|
-
program.
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
"
|
|
626
|
-
"
|
|
627
|
-
|
|
628
|
-
"
|
|
629
|
-
"
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
if (!validBumps.includes(value)) {
|
|
633
|
-
log("error", `Invalid bump type '${value}'. Valid options are: ${validBumps.join(", ")}`);
|
|
634
|
-
process.exit(1);
|
|
635
|
-
}
|
|
636
|
-
return value;
|
|
637
|
-
}).option("--base-branch <branch>", "override the base branch for this operation").option("--synced", "force synced versioning mode").option("--no-synced", "force async versioning mode").option(
|
|
638
|
-
"--skip <packages>",
|
|
639
|
-
"comma-separated list of packages to skip",
|
|
640
|
-
(value) => value.split(",")
|
|
641
|
-
).option("--prerelease <identifier>", "set prerelease identifier (e.g., alpha, beta)").option("--skip-hooks", "skip Git hooks for this operation").option("--config <path>", "specify a custom config file path").option("--dry-run", "Calculate version and log actions without changing files or Git state");
|
|
642
|
-
program.description("Version packages based on Git context and conventional commits").action(async (options) => {
|
|
643
|
-
const figletText = import_figlet.default.textSync(name);
|
|
644
|
-
const versionText = `v${package_default.version}`;
|
|
645
|
-
process.stdout.write(`${import_chalk2.default.hex("#FF1F57")(figletText)}
|
|
646
|
-
`);
|
|
647
|
-
process.stdout.write(`${import_chalk2.default.hex("#0096FF")(versionText)}
|
|
648
|
-
|
|
649
|
-
`);
|
|
673
|
+
async function run() {
|
|
674
|
+
printFiglet();
|
|
675
|
+
const program = new import_commander.Command();
|
|
676
|
+
program.name("package-versioner").description(
|
|
677
|
+
"Automated semantic versioning based on Git history and conventional commits. Supports monorepos with synchronized or independent package versioning strategies."
|
|
678
|
+
).version("0.0.2").option("--config <path>", "Path to the configuration file").option("--dry-run", "Simulate the versioning process without making changes").option("--synced", "Force synced versioning strategy (overrides config)").option("--bump <type>", "Force a specific release type (patch, minor, major)").option(
|
|
679
|
+
"--prerelease <identifier>",
|
|
680
|
+
"Create a prerelease version with the specified identifier"
|
|
681
|
+
).option(
|
|
682
|
+
"-t, --target <targets>",
|
|
683
|
+
"Comma-separated list of package names to target (only for async strategy)"
|
|
684
|
+
).parse(process.argv);
|
|
685
|
+
const options = program.opts();
|
|
650
686
|
try {
|
|
651
|
-
const
|
|
652
|
-
|
|
653
|
-
if (options.
|
|
654
|
-
|
|
655
|
-
if (options.
|
|
656
|
-
config.synced = options.synced;
|
|
657
|
-
if (options.skip)
|
|
658
|
-
config.skip = options.skip;
|
|
687
|
+
const config = await loadConfig(options.config);
|
|
688
|
+
log("info", `Loaded configuration from ${options.config || "version.config.json"}`);
|
|
689
|
+
if (options.dryRun) config.dryRun = true;
|
|
690
|
+
if (options.synced) config.synced = true;
|
|
691
|
+
if (options.bump) config.forceType = options.bump;
|
|
659
692
|
if (options.prerelease)
|
|
660
|
-
config.prereleaseIdentifier = options.prerelease;
|
|
661
|
-
|
|
662
|
-
config.skipHooks = options.skipHooks;
|
|
663
|
-
if (options.dryRun !== void 0)
|
|
664
|
-
config.dryRun = options.dryRun;
|
|
693
|
+
config.prereleaseIdentifier = options.prerelease === true ? "rc" : options.prerelease;
|
|
694
|
+
const cliTargets = options.target ? options.target.split(",").map((t) => t.trim()) : [];
|
|
665
695
|
const engine = new VersionEngine(config);
|
|
666
696
|
if (config.synced) {
|
|
697
|
+
log("info", "Using synced versioning strategy.");
|
|
667
698
|
await engine.syncedStrategy();
|
|
668
|
-
} else if (
|
|
699
|
+
} else if (config.packages && config.packages.length === 1) {
|
|
700
|
+
log("info", "Using single package versioning strategy.");
|
|
701
|
+
if (cliTargets.length > 0) {
|
|
702
|
+
log("warning", "--target flag is ignored for single package strategy.");
|
|
703
|
+
}
|
|
669
704
|
await engine.singleStrategy();
|
|
670
705
|
} else {
|
|
671
|
-
|
|
706
|
+
log("info", "Using async versioning strategy.");
|
|
707
|
+
if (cliTargets.length > 0) {
|
|
708
|
+
log("info", `Targeting specific packages: ${cliTargets.join(", ")}`);
|
|
709
|
+
}
|
|
710
|
+
await engine.asyncStrategy(cliTargets);
|
|
672
711
|
}
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
(
|
|
712
|
+
log("success", "Versioning process completed.");
|
|
713
|
+
} catch (error) {
|
|
714
|
+
log("error", error instanceof Error ? error.message : String(error));
|
|
715
|
+
process.exit(1);
|
|
676
716
|
}
|
|
677
|
-
}
|
|
678
|
-
|
|
717
|
+
}
|
|
718
|
+
run();
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
CHANGED
|
@@ -1,16 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { exit as exit2 } from "process";
|
|
5
|
-
import chalk2 from "chalk";
|
|
6
4
|
import { Command } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/config.ts
|
|
7
|
+
import * as fs from "node:fs";
|
|
8
|
+
import { cwd } from "node:process";
|
|
9
|
+
function loadConfig(configPath) {
|
|
10
|
+
const localProcess = cwd();
|
|
11
|
+
const filePath = configPath || `${localProcess}/version.config.json`;
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
fs.readFile(filePath, "utf-8", (err, data) => {
|
|
14
|
+
if (err) {
|
|
15
|
+
reject(new Error(`Could not locate the config file at ${filePath}: ${err.message}`));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const config = JSON.parse(data);
|
|
20
|
+
resolve(config);
|
|
21
|
+
} catch (err2) {
|
|
22
|
+
const errorMessage = err2 instanceof Error ? err2.message : String(err2);
|
|
23
|
+
reject(new Error(`Failed to parse config file ${filePath}: ${errorMessage}`));
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/utils.ts
|
|
30
|
+
import fs2 from "node:fs";
|
|
31
|
+
import chalk from "chalk";
|
|
7
32
|
import figlet from "figlet";
|
|
8
33
|
|
|
9
34
|
// package.json
|
|
10
35
|
var package_default = {
|
|
11
36
|
name: "package-versioner",
|
|
12
37
|
description: "A powerful CLI tool for automated semantic versioning based on Git history and conventional commits. Supports monorepos with synchronized or independent package versioning strategies.",
|
|
13
|
-
version: "0.0.
|
|
38
|
+
version: "0.0.2",
|
|
14
39
|
type: "module",
|
|
15
40
|
main: "./dist/index.js",
|
|
16
41
|
module: "./dist/index.mjs",
|
|
@@ -60,12 +85,12 @@ var package_default = {
|
|
|
60
85
|
devDependencies: {
|
|
61
86
|
"@biomejs/biome": "^1.9.4",
|
|
62
87
|
"@types/figlet": "^1.5.5",
|
|
63
|
-
"@types/node": "^
|
|
88
|
+
"@types/node": "^22.14.0",
|
|
64
89
|
"@types/semver": "^7.3.13",
|
|
65
90
|
"@vitest/coverage-v8": "^3.1.1",
|
|
66
91
|
husky: "^9.1.7",
|
|
67
92
|
"lint-staged": "^15.5.0",
|
|
68
|
-
tsup: "^
|
|
93
|
+
tsup: "^8.4.0",
|
|
69
94
|
typescript: "^5.8.3",
|
|
70
95
|
vitest: "^3.1.1"
|
|
71
96
|
},
|
|
@@ -82,39 +107,14 @@ var package_default = {
|
|
|
82
107
|
packageManager: "pnpm@10.8.0+sha512.0e82714d1b5b43c74610193cb20734897c1d00de89d0e18420aebc5977fa13d780a9cb05734624e81ebd81cc876cd464794850641c48b9544326b5622ca29971"
|
|
83
108
|
};
|
|
84
109
|
|
|
85
|
-
// src/config.ts
|
|
86
|
-
import * as fs from "fs";
|
|
87
|
-
import { cwd } from "process";
|
|
88
|
-
function loadConfig(configPath) {
|
|
89
|
-
const localProcess = cwd();
|
|
90
|
-
const filePath = configPath || `${localProcess}/version.config.json`;
|
|
91
|
-
return new Promise((resolve, reject) => {
|
|
92
|
-
fs.readFile(filePath, "utf-8", (err, data) => {
|
|
93
|
-
if (err) {
|
|
94
|
-
reject(new Error(`Could not locate the config file at ${filePath}: ${err.message}`));
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
try {
|
|
98
|
-
const config = JSON.parse(data);
|
|
99
|
-
resolve(config);
|
|
100
|
-
} catch (err2) {
|
|
101
|
-
const errorMessage = err2 instanceof Error ? err2.message : String(err2);
|
|
102
|
-
reject(new Error(`Failed to parse config file ${filePath}: ${errorMessage}`));
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
110
|
// src/utils.ts
|
|
109
|
-
import fs2 from "fs";
|
|
110
|
-
import chalk from "chalk";
|
|
111
111
|
import { getSemverTags } from "git-semver-tags";
|
|
112
112
|
|
|
113
113
|
// src/git.ts
|
|
114
|
-
import { exec, execSync as syncExec } from "child_process";
|
|
115
|
-
import { existsSync, statSync } from "fs";
|
|
116
|
-
import { join } from "path";
|
|
117
|
-
import { cwd as cwd2 } from "process";
|
|
114
|
+
import { exec, execSync as syncExec } from "node:child_process";
|
|
115
|
+
import { existsSync, statSync } from "node:fs";
|
|
116
|
+
import { join } from "node:path";
|
|
117
|
+
import { cwd as cwd2 } from "node:process";
|
|
118
118
|
var execAsync = (command) => {
|
|
119
119
|
return new Promise((resolve, reject) => {
|
|
120
120
|
const options = { maxBuffer: 1024 * 1024 * 10 };
|
|
@@ -194,7 +194,7 @@ async function gitProcess({ files, nextTag, commitMessage, skipHooks, dryRun })
|
|
|
194
194
|
message: commitMessage,
|
|
195
195
|
skipHooks
|
|
196
196
|
});
|
|
197
|
-
const tagMessage = `New Version ${nextTag} generated at ${new Date().toISOString()}`;
|
|
197
|
+
const tagMessage = `New Version ${nextTag} generated at ${(/* @__PURE__ */ new Date()).toISOString()}`;
|
|
198
198
|
await createGitTag({
|
|
199
199
|
tag: nextTag,
|
|
200
200
|
message: tagMessage
|
|
@@ -233,6 +233,25 @@ function getCurrentBranch() {
|
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
// src/utils.ts
|
|
236
|
+
function printFiglet() {
|
|
237
|
+
const font = "Standard";
|
|
238
|
+
figlet.text(package_default.name, { font }, (err, data) => {
|
|
239
|
+
if (err) {
|
|
240
|
+
log("warning", "Could not print figlet banner: Figlet error");
|
|
241
|
+
console.error(err);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (data) {
|
|
245
|
+
const figletText = data;
|
|
246
|
+
const versionText = `v${package_default.version}`;
|
|
247
|
+
process.stdout.write(`${chalk.hex("#FF1F57")(figletText)}
|
|
248
|
+
`);
|
|
249
|
+
process.stdout.write(`${chalk.hex("#0096FF")(versionText)}
|
|
250
|
+
|
|
251
|
+
`);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
}
|
|
236
255
|
function log(status, message) {
|
|
237
256
|
const statusColors = {
|
|
238
257
|
info: chalk.blue("\u2139"),
|
|
@@ -257,10 +276,10 @@ async function getLatestTag() {
|
|
|
257
276
|
}
|
|
258
277
|
}
|
|
259
278
|
function formatTag(options, props) {
|
|
260
|
-
const { name
|
|
279
|
+
const { name, synced, tagPrefix } = options;
|
|
261
280
|
const { version } = props;
|
|
262
|
-
if (!synced &&
|
|
263
|
-
return `${tagPrefix ? tagPrefix : ""}${
|
|
281
|
+
if (!synced && name) {
|
|
282
|
+
return `${tagPrefix ? tagPrefix : ""}${name}@${version}`;
|
|
264
283
|
}
|
|
265
284
|
return `${tagPrefix ? tagPrefix : "v"}${version}`;
|
|
266
285
|
}
|
|
@@ -273,7 +292,7 @@ function createTemplateString(template, data) {
|
|
|
273
292
|
function formatCommitMessage(template, version) {
|
|
274
293
|
return createTemplateString(template, { version });
|
|
275
294
|
}
|
|
276
|
-
function updatePackageVersion({ path: path2, version, name
|
|
295
|
+
function updatePackageVersion({ path: path2, version, name, dryRun }) {
|
|
277
296
|
try {
|
|
278
297
|
const pkgPath = `${path2}/package.json`;
|
|
279
298
|
const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf8"));
|
|
@@ -281,32 +300,36 @@ function updatePackageVersion({ path: path2, version, name: name2, dryRun }) {
|
|
|
281
300
|
if (!dryRun) {
|
|
282
301
|
fs2.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
283
302
|
`);
|
|
284
|
-
log("success", `${
|
|
303
|
+
log("success", `${name}: ${version}`);
|
|
285
304
|
} else {
|
|
286
|
-
log("info", `[DRY RUN] Would update ${
|
|
305
|
+
log("info", `[DRY RUN] Would update ${name} package.json to version ${version}`);
|
|
287
306
|
}
|
|
288
307
|
} catch (error) {
|
|
289
|
-
log("error", `Failed to update ${
|
|
308
|
+
log("error", `Failed to update ${name} to version ${version}`);
|
|
290
309
|
console.error(error);
|
|
291
310
|
}
|
|
292
311
|
}
|
|
293
312
|
|
|
294
313
|
// src/versionEngine.ts
|
|
295
|
-
import fs3 from "fs";
|
|
296
|
-
import path from "path";
|
|
297
|
-
import { cwd as cwd3, exit } from "process";
|
|
314
|
+
import fs3 from "node:fs";
|
|
315
|
+
import path from "node:path";
|
|
316
|
+
import { cwd as cwd3, exit } from "node:process";
|
|
298
317
|
import { getPackagesSync } from "@manypkg/get-packages";
|
|
299
318
|
import { Bumper } from "conventional-recommended-bump";
|
|
300
319
|
import semver from "semver";
|
|
301
320
|
var VersionEngine = class {
|
|
321
|
+
config;
|
|
302
322
|
constructor(config) {
|
|
303
323
|
this.config = config;
|
|
304
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* Calculate the next version based on options
|
|
327
|
+
*/
|
|
305
328
|
async calculateVersion(options) {
|
|
306
|
-
const { latestTag, type, path: path2, name
|
|
329
|
+
const { latestTag, type, path: path2, name, branchPattern, prereleaseIdentifier } = options;
|
|
307
330
|
const originalPrefix = this.config.tagPrefix || "";
|
|
308
331
|
const initialVersion = prereleaseIdentifier ? `0.0.1-${prereleaseIdentifier}` : "0.0.1";
|
|
309
|
-
const tagSearchPattern =
|
|
332
|
+
const tagSearchPattern = name ? originalPrefix ? `${originalPrefix}${name}@` : `${name}@` : originalPrefix ? `${originalPrefix}v` : "v";
|
|
310
333
|
let determinedReleaseType = type || null;
|
|
311
334
|
if (determinedReleaseType) {
|
|
312
335
|
if (!latestTag) {
|
|
@@ -347,21 +370,21 @@ var VersionEngine = class {
|
|
|
347
370
|
if (commitsLength === 0) {
|
|
348
371
|
log(
|
|
349
372
|
"info",
|
|
350
|
-
`No new commits found for ${
|
|
373
|
+
`No new commits found for ${name || "project"} since ${latestTag}, skipping version bump`
|
|
351
374
|
);
|
|
352
375
|
return "";
|
|
353
376
|
}
|
|
354
377
|
if (!releaseTypeFromCommits) {
|
|
355
378
|
log(
|
|
356
379
|
"info",
|
|
357
|
-
`No relevant commits found for ${
|
|
380
|
+
`No relevant commits found for ${name || "project"} since ${latestTag}, skipping version bump`
|
|
358
381
|
);
|
|
359
382
|
return "";
|
|
360
383
|
}
|
|
361
384
|
const currentVersion = semver.clean(latestTag.replace(tagSearchPattern, "")) || "0.0.0";
|
|
362
385
|
return semver.inc(currentVersion, releaseTypeFromCommits, prereleaseIdentifier) || "";
|
|
363
386
|
} catch (error) {
|
|
364
|
-
log("error", `Failed to calculate version for ${
|
|
387
|
+
log("error", `Failed to calculate version for ${name || "project"}`);
|
|
365
388
|
console.error(error);
|
|
366
389
|
if (error instanceof Error && error.message.includes("No names found")) {
|
|
367
390
|
log("info", "No tags found, proceeding with initial version calculation (if applicable).");
|
|
@@ -370,30 +393,44 @@ var VersionEngine = class {
|
|
|
370
393
|
return "";
|
|
371
394
|
}
|
|
372
395
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
396
|
+
/**
|
|
397
|
+
* Process packages based on discovery, skip list, and optional target list.
|
|
398
|
+
* Returns a list of package.json file paths that were updated (or would be in dry run).
|
|
399
|
+
*/
|
|
400
|
+
async processPackages(discoveredPackages = [], targets = []) {
|
|
401
|
+
const { tagPrefix, skip } = this.config;
|
|
376
402
|
const files = [];
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
403
|
+
const pkgsToConsider = discoveredPackages.filter((pkg) => {
|
|
404
|
+
if (skip == null ? void 0 : skip.includes(pkg.packageJson.name)) {
|
|
405
|
+
log("info", `Skipping package ${pkg.packageJson.name} based on config skip list.`);
|
|
380
406
|
return false;
|
|
381
407
|
}
|
|
382
|
-
|
|
408
|
+
if (targets.length > 0) {
|
|
409
|
+
const isTargeted = targets.includes(pkg.packageJson.name);
|
|
410
|
+
if (!isTargeted) {
|
|
411
|
+
}
|
|
412
|
+
return isTargeted;
|
|
413
|
+
}
|
|
414
|
+
return true;
|
|
383
415
|
});
|
|
384
|
-
|
|
385
|
-
|
|
416
|
+
log("info", `Found ${pkgsToConsider.length} package(s) to process after filtering.`);
|
|
417
|
+
for (const pkg of pkgsToConsider) {
|
|
418
|
+
const name = pkg.packageJson.name;
|
|
386
419
|
const pkgPath = pkg.dir;
|
|
387
420
|
const prefix = formatTagPrefix(tagPrefix);
|
|
388
421
|
const latestTag = await getLatestTag();
|
|
389
422
|
const nextVersion = await this.calculateVersion({
|
|
390
423
|
latestTag,
|
|
424
|
+
// This might need refinement for async based on package-specific tags
|
|
391
425
|
tagPrefix: prefix,
|
|
392
426
|
path: pkgPath,
|
|
393
|
-
name
|
|
427
|
+
name,
|
|
428
|
+
// Pass name for potential package-specific tag lookups
|
|
394
429
|
branchPattern: this.config.branchPattern,
|
|
395
430
|
baseBranch: this.config.baseBranch,
|
|
396
|
-
prereleaseIdentifier: this.config.prereleaseIdentifier
|
|
431
|
+
prereleaseIdentifier: this.config.prereleaseIdentifier,
|
|
432
|
+
type: this.config.forceType
|
|
433
|
+
// Pass forced type if provided
|
|
397
434
|
});
|
|
398
435
|
if (!nextVersion) {
|
|
399
436
|
continue;
|
|
@@ -401,13 +438,16 @@ var VersionEngine = class {
|
|
|
401
438
|
updatePackageVersion({
|
|
402
439
|
path: pkgPath,
|
|
403
440
|
version: nextVersion,
|
|
404
|
-
name
|
|
441
|
+
name,
|
|
405
442
|
dryRun: this.config.dryRun
|
|
406
443
|
});
|
|
407
444
|
files.push(path.join(pkgPath, "package.json"));
|
|
408
445
|
}
|
|
409
446
|
return files;
|
|
410
447
|
}
|
|
448
|
+
/**
|
|
449
|
+
* Create git commit and tag
|
|
450
|
+
*/
|
|
411
451
|
async createGitCommitAndTag(files, nextTag, commitMessage, dryRun) {
|
|
412
452
|
try {
|
|
413
453
|
await gitProcess({
|
|
@@ -426,6 +466,9 @@ var VersionEngine = class {
|
|
|
426
466
|
exit(1);
|
|
427
467
|
}
|
|
428
468
|
}
|
|
469
|
+
/**
|
|
470
|
+
* Synced versioning strategy (all packages get the same version)
|
|
471
|
+
*/
|
|
429
472
|
async syncedStrategy() {
|
|
430
473
|
var _a;
|
|
431
474
|
const {
|
|
@@ -494,6 +537,9 @@ var VersionEngine = class {
|
|
|
494
537
|
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
|
|
495
538
|
await this.createGitCommitAndTag(files, nextTag, formattedCommitMessage, this.config.dryRun);
|
|
496
539
|
}
|
|
540
|
+
/**
|
|
541
|
+
* Single package versioning strategy
|
|
542
|
+
*/
|
|
497
543
|
async singleStrategy() {
|
|
498
544
|
const {
|
|
499
545
|
packages: configPackages,
|
|
@@ -553,11 +599,15 @@ var VersionEngine = class {
|
|
|
553
599
|
this.config.dryRun
|
|
554
600
|
);
|
|
555
601
|
}
|
|
556
|
-
|
|
602
|
+
/**
|
|
603
|
+
* Async versioning strategy (each package gets its own version)
|
|
604
|
+
*/
|
|
605
|
+
async asyncStrategy(cliTargets = []) {
|
|
557
606
|
const {
|
|
558
|
-
packages: configPackages,
|
|
559
607
|
commitMessage = "chore(release): ${version}",
|
|
608
|
+
// Align with test expectations
|
|
560
609
|
skipHooks
|
|
610
|
+
// Add skipHooks here
|
|
561
611
|
} = this.config;
|
|
562
612
|
let pkgsResult;
|
|
563
613
|
try {
|
|
@@ -571,9 +621,9 @@ var VersionEngine = class {
|
|
|
571
621
|
exit(1);
|
|
572
622
|
return;
|
|
573
623
|
}
|
|
574
|
-
const pkgsToProcess = await this.processPackages(pkgsResult.packages,
|
|
624
|
+
const pkgsToProcess = await this.processPackages(pkgsResult.packages, cliTargets);
|
|
575
625
|
if (pkgsToProcess.length === 0) {
|
|
576
|
-
log("info", "No packages to process");
|
|
626
|
+
log("info", "No packages to process based on changes and targets");
|
|
577
627
|
return;
|
|
578
628
|
}
|
|
579
629
|
const formattedCommitMessage = commitMessage;
|
|
@@ -586,7 +636,7 @@ var VersionEngine = class {
|
|
|
586
636
|
dryRun: this.config.dryRun
|
|
587
637
|
});
|
|
588
638
|
if (!this.config.dryRun) {
|
|
589
|
-
log("success",
|
|
639
|
+
log("success", `Created version commit for ${pkgsToProcess.length} package(s)`);
|
|
590
640
|
}
|
|
591
641
|
} catch (error) {
|
|
592
642
|
log("error", "Failed to create version commit");
|
|
@@ -597,63 +647,49 @@ var VersionEngine = class {
|
|
|
597
647
|
};
|
|
598
648
|
|
|
599
649
|
// src/index.ts
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
program
|
|
603
|
-
program.
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
"
|
|
607
|
-
"
|
|
608
|
-
|
|
609
|
-
"
|
|
610
|
-
"
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
if (!validBumps.includes(value)) {
|
|
614
|
-
log("error", `Invalid bump type '${value}'. Valid options are: ${validBumps.join(", ")}`);
|
|
615
|
-
process.exit(1);
|
|
616
|
-
}
|
|
617
|
-
return value;
|
|
618
|
-
}).option("--base-branch <branch>", "override the base branch for this operation").option("--synced", "force synced versioning mode").option("--no-synced", "force async versioning mode").option(
|
|
619
|
-
"--skip <packages>",
|
|
620
|
-
"comma-separated list of packages to skip",
|
|
621
|
-
(value) => value.split(",")
|
|
622
|
-
).option("--prerelease <identifier>", "set prerelease identifier (e.g., alpha, beta)").option("--skip-hooks", "skip Git hooks for this operation").option("--config <path>", "specify a custom config file path").option("--dry-run", "Calculate version and log actions without changing files or Git state");
|
|
623
|
-
program.description("Version packages based on Git context and conventional commits").action(async (options) => {
|
|
624
|
-
const figletText = figlet.textSync(name);
|
|
625
|
-
const versionText = `v${package_default.version}`;
|
|
626
|
-
process.stdout.write(`${chalk2.hex("#FF1F57")(figletText)}
|
|
627
|
-
`);
|
|
628
|
-
process.stdout.write(`${chalk2.hex("#0096FF")(versionText)}
|
|
629
|
-
|
|
630
|
-
`);
|
|
650
|
+
async function run() {
|
|
651
|
+
printFiglet();
|
|
652
|
+
const program = new Command();
|
|
653
|
+
program.name("package-versioner").description(
|
|
654
|
+
"Automated semantic versioning based on Git history and conventional commits. Supports monorepos with synchronized or independent package versioning strategies."
|
|
655
|
+
).version("0.0.2").option("--config <path>", "Path to the configuration file").option("--dry-run", "Simulate the versioning process without making changes").option("--synced", "Force synced versioning strategy (overrides config)").option("--bump <type>", "Force a specific release type (patch, minor, major)").option(
|
|
656
|
+
"--prerelease <identifier>",
|
|
657
|
+
"Create a prerelease version with the specified identifier"
|
|
658
|
+
).option(
|
|
659
|
+
"-t, --target <targets>",
|
|
660
|
+
"Comma-separated list of package names to target (only for async strategy)"
|
|
661
|
+
).parse(process.argv);
|
|
662
|
+
const options = program.opts();
|
|
631
663
|
try {
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
if (options.
|
|
635
|
-
|
|
636
|
-
if (options.
|
|
637
|
-
config.synced = options.synced;
|
|
638
|
-
if (options.skip)
|
|
639
|
-
config.skip = options.skip;
|
|
664
|
+
const config = await loadConfig(options.config);
|
|
665
|
+
log("info", `Loaded configuration from ${options.config || "version.config.json"}`);
|
|
666
|
+
if (options.dryRun) config.dryRun = true;
|
|
667
|
+
if (options.synced) config.synced = true;
|
|
668
|
+
if (options.bump) config.forceType = options.bump;
|
|
640
669
|
if (options.prerelease)
|
|
641
|
-
config.prereleaseIdentifier = options.prerelease;
|
|
642
|
-
|
|
643
|
-
config.skipHooks = options.skipHooks;
|
|
644
|
-
if (options.dryRun !== void 0)
|
|
645
|
-
config.dryRun = options.dryRun;
|
|
670
|
+
config.prereleaseIdentifier = options.prerelease === true ? "rc" : options.prerelease;
|
|
671
|
+
const cliTargets = options.target ? options.target.split(",").map((t) => t.trim()) : [];
|
|
646
672
|
const engine = new VersionEngine(config);
|
|
647
673
|
if (config.synced) {
|
|
674
|
+
log("info", "Using synced versioning strategy.");
|
|
648
675
|
await engine.syncedStrategy();
|
|
649
|
-
} else if (
|
|
676
|
+
} else if (config.packages && config.packages.length === 1) {
|
|
677
|
+
log("info", "Using single package versioning strategy.");
|
|
678
|
+
if (cliTargets.length > 0) {
|
|
679
|
+
log("warning", "--target flag is ignored for single package strategy.");
|
|
680
|
+
}
|
|
650
681
|
await engine.singleStrategy();
|
|
651
682
|
} else {
|
|
652
|
-
|
|
683
|
+
log("info", "Using async versioning strategy.");
|
|
684
|
+
if (cliTargets.length > 0) {
|
|
685
|
+
log("info", `Targeting specific packages: ${cliTargets.join(", ")}`);
|
|
686
|
+
}
|
|
687
|
+
await engine.asyncStrategy(cliTargets);
|
|
653
688
|
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
689
|
+
log("success", "Versioning process completed.");
|
|
690
|
+
} catch (error) {
|
|
691
|
+
log("error", error instanceof Error ? error.message : String(error));
|
|
692
|
+
process.exit(1);
|
|
657
693
|
}
|
|
658
|
-
}
|
|
659
|
-
|
|
694
|
+
}
|
|
695
|
+
run();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "package-versioner",
|
|
3
3
|
"description": "A powerful CLI tool for automated semantic versioning based on Git history and conventional commits. Supports monorepos with synchronized or independent package versioning strategies.",
|
|
4
|
-
"version": "0.0
|
|
4
|
+
"version": "0.1.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.mjs",
|
|
@@ -38,12 +38,12 @@
|
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@biomejs/biome": "^1.9.4",
|
|
40
40
|
"@types/figlet": "^1.5.5",
|
|
41
|
-
"@types/node": "^
|
|
41
|
+
"@types/node": "^22.14.0",
|
|
42
42
|
"@types/semver": "^7.3.13",
|
|
43
43
|
"@vitest/coverage-v8": "^3.1.1",
|
|
44
44
|
"husky": "^9.1.7",
|
|
45
45
|
"lint-staged": "^15.5.0",
|
|
46
|
-
"tsup": "^
|
|
46
|
+
"tsup": "^8.4.0",
|
|
47
47
|
"typescript": "^5.8.3",
|
|
48
48
|
"vitest": "^3.1.1"
|
|
49
49
|
},
|