package-versioner 0.0.2 → 0.1.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 +10 -1
- package/dist/index.cjs +160 -116
- package/dist/index.d.cts +1 -0
- package/dist/index.js +163 -123
- 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.1.0",
|
|
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,18 +217,22 @@ async function gitProcess({ files, nextTag, commitMessage, skipHooks, dryRun })
|
|
|
213
217
|
message: commitMessage,
|
|
214
218
|
skipHooks
|
|
215
219
|
});
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
220
|
+
if (nextTag) {
|
|
221
|
+
const tagMessage = `New Version ${nextTag} generated at ${(/* @__PURE__ */ new Date()).toISOString()}`;
|
|
222
|
+
await createGitTag({
|
|
223
|
+
tag: nextTag,
|
|
224
|
+
message: tagMessage
|
|
225
|
+
});
|
|
226
|
+
}
|
|
221
227
|
} else {
|
|
222
228
|
log("info", "[DRY RUN] Would add files:");
|
|
223
229
|
for (const file of files) {
|
|
224
230
|
log("info", ` - ${file}`);
|
|
225
231
|
}
|
|
226
232
|
log("info", `[DRY RUN] Would commit with message: "${commitMessage}"`);
|
|
227
|
-
|
|
233
|
+
if (nextTag) {
|
|
234
|
+
log("info", `[DRY RUN] Would create tag: ${nextTag}`);
|
|
235
|
+
}
|
|
228
236
|
}
|
|
229
237
|
} catch (err) {
|
|
230
238
|
console.log(err);
|
|
@@ -252,6 +260,25 @@ function getCurrentBranch() {
|
|
|
252
260
|
}
|
|
253
261
|
|
|
254
262
|
// src/utils.ts
|
|
263
|
+
function printFiglet() {
|
|
264
|
+
const font = "Standard";
|
|
265
|
+
import_figlet.default.text(package_default.name, { font }, (err, data) => {
|
|
266
|
+
if (err) {
|
|
267
|
+
log("warning", "Could not print figlet banner: Figlet error");
|
|
268
|
+
console.error(err);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
if (data) {
|
|
272
|
+
const figletText = data;
|
|
273
|
+
const versionText = `v${package_default.version}`;
|
|
274
|
+
process.stdout.write(`${import_chalk.default.hex("#FF1F57")(figletText)}
|
|
275
|
+
`);
|
|
276
|
+
process.stdout.write(`${import_chalk.default.hex("#0096FF")(versionText)}
|
|
277
|
+
|
|
278
|
+
`);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
}
|
|
255
282
|
function log(status, message) {
|
|
256
283
|
const statusColors = {
|
|
257
284
|
info: import_chalk.default.blue("\u2139"),
|
|
@@ -276,10 +303,10 @@ async function getLatestTag() {
|
|
|
276
303
|
}
|
|
277
304
|
}
|
|
278
305
|
function formatTag(options, props) {
|
|
279
|
-
const { name
|
|
306
|
+
const { name, synced, tagPrefix } = options;
|
|
280
307
|
const { version } = props;
|
|
281
|
-
if (!synced &&
|
|
282
|
-
return `${tagPrefix ? tagPrefix : ""}${
|
|
308
|
+
if (!synced && name) {
|
|
309
|
+
return `${tagPrefix ? tagPrefix : ""}${name}@${version}`;
|
|
283
310
|
}
|
|
284
311
|
return `${tagPrefix ? tagPrefix : "v"}${version}`;
|
|
285
312
|
}
|
|
@@ -292,7 +319,7 @@ function createTemplateString(template, data) {
|
|
|
292
319
|
function formatCommitMessage(template, version) {
|
|
293
320
|
return createTemplateString(template, { version });
|
|
294
321
|
}
|
|
295
|
-
function updatePackageVersion({ path: path2, version, name
|
|
322
|
+
function updatePackageVersion({ path: path2, version, name, dryRun }) {
|
|
296
323
|
try {
|
|
297
324
|
const pkgPath = `${path2}/package.json`;
|
|
298
325
|
const pkg = JSON.parse(import_node_fs2.default.readFileSync(pkgPath, "utf8"));
|
|
@@ -300,12 +327,12 @@ function updatePackageVersion({ path: path2, version, name: name2, dryRun }) {
|
|
|
300
327
|
if (!dryRun) {
|
|
301
328
|
import_node_fs2.default.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
302
329
|
`);
|
|
303
|
-
log("success", `${
|
|
330
|
+
log("success", `${name}: ${version}`);
|
|
304
331
|
} else {
|
|
305
|
-
log("info", `[DRY RUN] Would update ${
|
|
332
|
+
log("info", `[DRY RUN] Would update ${name} package.json to version ${version}`);
|
|
306
333
|
}
|
|
307
334
|
} catch (error) {
|
|
308
|
-
log("error", `Failed to update ${
|
|
335
|
+
log("error", `Failed to update ${name} to version ${version}`);
|
|
309
336
|
console.error(error);
|
|
310
337
|
}
|
|
311
338
|
}
|
|
@@ -318,14 +345,18 @@ var import_get_packages = require("@manypkg/get-packages");
|
|
|
318
345
|
var import_conventional_recommended_bump = require("conventional-recommended-bump");
|
|
319
346
|
var import_semver = __toESM(require("semver"), 1);
|
|
320
347
|
var VersionEngine = class {
|
|
348
|
+
config;
|
|
321
349
|
constructor(config) {
|
|
322
350
|
this.config = config;
|
|
323
351
|
}
|
|
352
|
+
/**
|
|
353
|
+
* Calculate the next version based on options
|
|
354
|
+
*/
|
|
324
355
|
async calculateVersion(options) {
|
|
325
|
-
const { latestTag, type, path: path2, name
|
|
356
|
+
const { latestTag, type, path: path2, name, branchPattern, prereleaseIdentifier } = options;
|
|
326
357
|
const originalPrefix = this.config.tagPrefix || "";
|
|
327
358
|
const initialVersion = prereleaseIdentifier ? `0.0.1-${prereleaseIdentifier}` : "0.0.1";
|
|
328
|
-
const tagSearchPattern =
|
|
359
|
+
const tagSearchPattern = name ? originalPrefix ? `${originalPrefix}${name}@` : `${name}@` : originalPrefix ? `${originalPrefix}v` : "v";
|
|
329
360
|
let determinedReleaseType = type || null;
|
|
330
361
|
if (determinedReleaseType) {
|
|
331
362
|
if (!latestTag) {
|
|
@@ -366,21 +397,21 @@ var VersionEngine = class {
|
|
|
366
397
|
if (commitsLength === 0) {
|
|
367
398
|
log(
|
|
368
399
|
"info",
|
|
369
|
-
`No new commits found for ${
|
|
400
|
+
`No new commits found for ${name || "project"} since ${latestTag}, skipping version bump`
|
|
370
401
|
);
|
|
371
402
|
return "";
|
|
372
403
|
}
|
|
373
404
|
if (!releaseTypeFromCommits) {
|
|
374
405
|
log(
|
|
375
406
|
"info",
|
|
376
|
-
`No relevant commits found for ${
|
|
407
|
+
`No relevant commits found for ${name || "project"} since ${latestTag}, skipping version bump`
|
|
377
408
|
);
|
|
378
409
|
return "";
|
|
379
410
|
}
|
|
380
411
|
const currentVersion = import_semver.default.clean(latestTag.replace(tagSearchPattern, "")) || "0.0.0";
|
|
381
412
|
return import_semver.default.inc(currentVersion, releaseTypeFromCommits, prereleaseIdentifier) || "";
|
|
382
413
|
} catch (error) {
|
|
383
|
-
log("error", `Failed to calculate version for ${
|
|
414
|
+
log("error", `Failed to calculate version for ${name || "project"}`);
|
|
384
415
|
console.error(error);
|
|
385
416
|
if (error instanceof Error && error.message.includes("No names found")) {
|
|
386
417
|
log("info", "No tags found, proceeding with initial version calculation (if applicable).");
|
|
@@ -389,30 +420,44 @@ var VersionEngine = class {
|
|
|
389
420
|
return "";
|
|
390
421
|
}
|
|
391
422
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
423
|
+
/**
|
|
424
|
+
* Process packages based on discovery, skip list, and optional target list.
|
|
425
|
+
* Returns a list of package.json file paths that were updated (or would be in dry run).
|
|
426
|
+
*/
|
|
427
|
+
async processPackages(discoveredPackages = [], targets = []) {
|
|
428
|
+
const { tagPrefix, skip } = this.config;
|
|
395
429
|
const files = [];
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
|
|
430
|
+
const pkgsToConsider = discoveredPackages.filter((pkg) => {
|
|
431
|
+
if (skip == null ? void 0 : skip.includes(pkg.packageJson.name)) {
|
|
432
|
+
log("info", `Skipping package ${pkg.packageJson.name} based on config skip list.`);
|
|
399
433
|
return false;
|
|
400
434
|
}
|
|
401
|
-
|
|
435
|
+
if (targets.length > 0) {
|
|
436
|
+
const isTargeted = targets.includes(pkg.packageJson.name);
|
|
437
|
+
if (!isTargeted) {
|
|
438
|
+
}
|
|
439
|
+
return isTargeted;
|
|
440
|
+
}
|
|
441
|
+
return true;
|
|
402
442
|
});
|
|
403
|
-
|
|
404
|
-
|
|
443
|
+
log("info", `Found ${pkgsToConsider.length} package(s) to process after filtering.`);
|
|
444
|
+
for (const pkg of pkgsToConsider) {
|
|
445
|
+
const name = pkg.packageJson.name;
|
|
405
446
|
const pkgPath = pkg.dir;
|
|
406
447
|
const prefix = formatTagPrefix(tagPrefix);
|
|
407
448
|
const latestTag = await getLatestTag();
|
|
408
449
|
const nextVersion = await this.calculateVersion({
|
|
409
450
|
latestTag,
|
|
451
|
+
// This might need refinement for async based on package-specific tags
|
|
410
452
|
tagPrefix: prefix,
|
|
411
453
|
path: pkgPath,
|
|
412
|
-
name
|
|
454
|
+
name,
|
|
455
|
+
// Pass name for potential package-specific tag lookups
|
|
413
456
|
branchPattern: this.config.branchPattern,
|
|
414
457
|
baseBranch: this.config.baseBranch,
|
|
415
|
-
prereleaseIdentifier: this.config.prereleaseIdentifier
|
|
458
|
+
prereleaseIdentifier: this.config.prereleaseIdentifier,
|
|
459
|
+
type: this.config.forceType
|
|
460
|
+
// Pass forced type if provided
|
|
416
461
|
});
|
|
417
462
|
if (!nextVersion) {
|
|
418
463
|
continue;
|
|
@@ -420,13 +465,16 @@ var VersionEngine = class {
|
|
|
420
465
|
updatePackageVersion({
|
|
421
466
|
path: pkgPath,
|
|
422
467
|
version: nextVersion,
|
|
423
|
-
name
|
|
468
|
+
name,
|
|
424
469
|
dryRun: this.config.dryRun
|
|
425
470
|
});
|
|
426
471
|
files.push(import_node_path2.default.join(pkgPath, "package.json"));
|
|
427
472
|
}
|
|
428
473
|
return files;
|
|
429
474
|
}
|
|
475
|
+
/**
|
|
476
|
+
* Create git commit and tag
|
|
477
|
+
*/
|
|
430
478
|
async createGitCommitAndTag(files, nextTag, commitMessage, dryRun) {
|
|
431
479
|
try {
|
|
432
480
|
await gitProcess({
|
|
@@ -445,6 +493,9 @@ var VersionEngine = class {
|
|
|
445
493
|
(0, import_node_process3.exit)(1);
|
|
446
494
|
}
|
|
447
495
|
}
|
|
496
|
+
/**
|
|
497
|
+
* Synced versioning strategy (all packages get the same version)
|
|
498
|
+
*/
|
|
448
499
|
async syncedStrategy() {
|
|
449
500
|
var _a;
|
|
450
501
|
const {
|
|
@@ -513,6 +564,9 @@ var VersionEngine = class {
|
|
|
513
564
|
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
|
|
514
565
|
await this.createGitCommitAndTag(files, nextTag, formattedCommitMessage, this.config.dryRun);
|
|
515
566
|
}
|
|
567
|
+
/**
|
|
568
|
+
* Single package versioning strategy
|
|
569
|
+
*/
|
|
516
570
|
async singleStrategy() {
|
|
517
571
|
const {
|
|
518
572
|
packages: configPackages,
|
|
@@ -572,11 +626,15 @@ var VersionEngine = class {
|
|
|
572
626
|
this.config.dryRun
|
|
573
627
|
);
|
|
574
628
|
}
|
|
575
|
-
|
|
629
|
+
/**
|
|
630
|
+
* Async versioning strategy (each package gets its own version)
|
|
631
|
+
*/
|
|
632
|
+
async asyncStrategy(cliTargets = []) {
|
|
576
633
|
const {
|
|
577
|
-
packages: configPackages,
|
|
578
634
|
commitMessage = "chore(release): ${version}",
|
|
635
|
+
// Align with test expectations
|
|
579
636
|
skipHooks
|
|
637
|
+
// Add skipHooks here
|
|
580
638
|
} = this.config;
|
|
581
639
|
let pkgsResult;
|
|
582
640
|
try {
|
|
@@ -590,9 +648,9 @@ var VersionEngine = class {
|
|
|
590
648
|
(0, import_node_process3.exit)(1);
|
|
591
649
|
return;
|
|
592
650
|
}
|
|
593
|
-
const pkgsToProcess = await this.processPackages(pkgsResult.packages,
|
|
651
|
+
const pkgsToProcess = await this.processPackages(pkgsResult.packages, cliTargets);
|
|
594
652
|
if (pkgsToProcess.length === 0) {
|
|
595
|
-
log("info", "No packages to process");
|
|
653
|
+
log("info", "No packages to process based on changes and targets");
|
|
596
654
|
return;
|
|
597
655
|
}
|
|
598
656
|
const formattedCommitMessage = commitMessage;
|
|
@@ -605,7 +663,7 @@ var VersionEngine = class {
|
|
|
605
663
|
dryRun: this.config.dryRun
|
|
606
664
|
});
|
|
607
665
|
if (!this.config.dryRun) {
|
|
608
|
-
log("success",
|
|
666
|
+
log("success", `Created version commit for ${pkgsToProcess.length} package(s)`);
|
|
609
667
|
}
|
|
610
668
|
} catch (error) {
|
|
611
669
|
log("error", "Failed to create version commit");
|
|
@@ -616,63 +674,49 @@ var VersionEngine = class {
|
|
|
616
674
|
};
|
|
617
675
|
|
|
618
676
|
// 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
|
-
`);
|
|
677
|
+
async function run() {
|
|
678
|
+
printFiglet();
|
|
679
|
+
const program = new import_commander.Command();
|
|
680
|
+
program.name("package-versioner").description(
|
|
681
|
+
"Automated semantic versioning based on Git history and conventional commits. Supports monorepos with synchronized or independent package versioning strategies."
|
|
682
|
+
).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(
|
|
683
|
+
"--prerelease <identifier>",
|
|
684
|
+
"Create a prerelease version with the specified identifier"
|
|
685
|
+
).option(
|
|
686
|
+
"-t, --target <targets>",
|
|
687
|
+
"Comma-separated list of package names to target (only for async strategy)"
|
|
688
|
+
).parse(process.argv);
|
|
689
|
+
const options = program.opts();
|
|
650
690
|
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;
|
|
691
|
+
const config = await loadConfig(options.config);
|
|
692
|
+
log("info", `Loaded configuration from ${options.config || "version.config.json"}`);
|
|
693
|
+
if (options.dryRun) config.dryRun = true;
|
|
694
|
+
if (options.synced) config.synced = true;
|
|
695
|
+
if (options.bump) config.forceType = options.bump;
|
|
659
696
|
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;
|
|
697
|
+
config.prereleaseIdentifier = options.prerelease === true ? "rc" : options.prerelease;
|
|
698
|
+
const cliTargets = options.target ? options.target.split(",").map((t) => t.trim()) : [];
|
|
665
699
|
const engine = new VersionEngine(config);
|
|
666
700
|
if (config.synced) {
|
|
701
|
+
log("info", "Using synced versioning strategy.");
|
|
667
702
|
await engine.syncedStrategy();
|
|
668
|
-
} else if (
|
|
703
|
+
} else if (config.packages && config.packages.length === 1) {
|
|
704
|
+
log("info", "Using single package versioning strategy.");
|
|
705
|
+
if (cliTargets.length > 0) {
|
|
706
|
+
log("warning", "--target flag is ignored for single package strategy.");
|
|
707
|
+
}
|
|
669
708
|
await engine.singleStrategy();
|
|
670
709
|
} else {
|
|
671
|
-
|
|
710
|
+
log("info", "Using async versioning strategy.");
|
|
711
|
+
if (cliTargets.length > 0) {
|
|
712
|
+
log("info", `Targeting specific packages: ${cliTargets.join(", ")}`);
|
|
713
|
+
}
|
|
714
|
+
await engine.asyncStrategy(cliTargets);
|
|
672
715
|
}
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
(
|
|
716
|
+
log("success", "Versioning process completed.");
|
|
717
|
+
} catch (error) {
|
|
718
|
+
log("error", error instanceof Error ? error.message : String(error));
|
|
719
|
+
process.exit(1);
|
|
676
720
|
}
|
|
677
|
-
}
|
|
678
|
-
|
|
721
|
+
}
|
|
722
|
+
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.1.0",
|
|
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,18 +194,22 @@ async function gitProcess({ files, nextTag, commitMessage, skipHooks, dryRun })
|
|
|
194
194
|
message: commitMessage,
|
|
195
195
|
skipHooks
|
|
196
196
|
});
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
197
|
+
if (nextTag) {
|
|
198
|
+
const tagMessage = `New Version ${nextTag} generated at ${(/* @__PURE__ */ new Date()).toISOString()}`;
|
|
199
|
+
await createGitTag({
|
|
200
|
+
tag: nextTag,
|
|
201
|
+
message: tagMessage
|
|
202
|
+
});
|
|
203
|
+
}
|
|
202
204
|
} else {
|
|
203
205
|
log("info", "[DRY RUN] Would add files:");
|
|
204
206
|
for (const file of files) {
|
|
205
207
|
log("info", ` - ${file}`);
|
|
206
208
|
}
|
|
207
209
|
log("info", `[DRY RUN] Would commit with message: "${commitMessage}"`);
|
|
208
|
-
|
|
210
|
+
if (nextTag) {
|
|
211
|
+
log("info", `[DRY RUN] Would create tag: ${nextTag}`);
|
|
212
|
+
}
|
|
209
213
|
}
|
|
210
214
|
} catch (err) {
|
|
211
215
|
console.log(err);
|
|
@@ -233,6 +237,25 @@ function getCurrentBranch() {
|
|
|
233
237
|
}
|
|
234
238
|
|
|
235
239
|
// src/utils.ts
|
|
240
|
+
function printFiglet() {
|
|
241
|
+
const font = "Standard";
|
|
242
|
+
figlet.text(package_default.name, { font }, (err, data) => {
|
|
243
|
+
if (err) {
|
|
244
|
+
log("warning", "Could not print figlet banner: Figlet error");
|
|
245
|
+
console.error(err);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (data) {
|
|
249
|
+
const figletText = data;
|
|
250
|
+
const versionText = `v${package_default.version}`;
|
|
251
|
+
process.stdout.write(`${chalk.hex("#FF1F57")(figletText)}
|
|
252
|
+
`);
|
|
253
|
+
process.stdout.write(`${chalk.hex("#0096FF")(versionText)}
|
|
254
|
+
|
|
255
|
+
`);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
236
259
|
function log(status, message) {
|
|
237
260
|
const statusColors = {
|
|
238
261
|
info: chalk.blue("\u2139"),
|
|
@@ -257,10 +280,10 @@ async function getLatestTag() {
|
|
|
257
280
|
}
|
|
258
281
|
}
|
|
259
282
|
function formatTag(options, props) {
|
|
260
|
-
const { name
|
|
283
|
+
const { name, synced, tagPrefix } = options;
|
|
261
284
|
const { version } = props;
|
|
262
|
-
if (!synced &&
|
|
263
|
-
return `${tagPrefix ? tagPrefix : ""}${
|
|
285
|
+
if (!synced && name) {
|
|
286
|
+
return `${tagPrefix ? tagPrefix : ""}${name}@${version}`;
|
|
264
287
|
}
|
|
265
288
|
return `${tagPrefix ? tagPrefix : "v"}${version}`;
|
|
266
289
|
}
|
|
@@ -273,7 +296,7 @@ function createTemplateString(template, data) {
|
|
|
273
296
|
function formatCommitMessage(template, version) {
|
|
274
297
|
return createTemplateString(template, { version });
|
|
275
298
|
}
|
|
276
|
-
function updatePackageVersion({ path: path2, version, name
|
|
299
|
+
function updatePackageVersion({ path: path2, version, name, dryRun }) {
|
|
277
300
|
try {
|
|
278
301
|
const pkgPath = `${path2}/package.json`;
|
|
279
302
|
const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf8"));
|
|
@@ -281,32 +304,36 @@ function updatePackageVersion({ path: path2, version, name: name2, dryRun }) {
|
|
|
281
304
|
if (!dryRun) {
|
|
282
305
|
fs2.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
283
306
|
`);
|
|
284
|
-
log("success", `${
|
|
307
|
+
log("success", `${name}: ${version}`);
|
|
285
308
|
} else {
|
|
286
|
-
log("info", `[DRY RUN] Would update ${
|
|
309
|
+
log("info", `[DRY RUN] Would update ${name} package.json to version ${version}`);
|
|
287
310
|
}
|
|
288
311
|
} catch (error) {
|
|
289
|
-
log("error", `Failed to update ${
|
|
312
|
+
log("error", `Failed to update ${name} to version ${version}`);
|
|
290
313
|
console.error(error);
|
|
291
314
|
}
|
|
292
315
|
}
|
|
293
316
|
|
|
294
317
|
// src/versionEngine.ts
|
|
295
|
-
import fs3 from "fs";
|
|
296
|
-
import path from "path";
|
|
297
|
-
import { cwd as cwd3, exit } from "process";
|
|
318
|
+
import fs3 from "node:fs";
|
|
319
|
+
import path from "node:path";
|
|
320
|
+
import { cwd as cwd3, exit } from "node:process";
|
|
298
321
|
import { getPackagesSync } from "@manypkg/get-packages";
|
|
299
322
|
import { Bumper } from "conventional-recommended-bump";
|
|
300
323
|
import semver from "semver";
|
|
301
324
|
var VersionEngine = class {
|
|
325
|
+
config;
|
|
302
326
|
constructor(config) {
|
|
303
327
|
this.config = config;
|
|
304
328
|
}
|
|
329
|
+
/**
|
|
330
|
+
* Calculate the next version based on options
|
|
331
|
+
*/
|
|
305
332
|
async calculateVersion(options) {
|
|
306
|
-
const { latestTag, type, path: path2, name
|
|
333
|
+
const { latestTag, type, path: path2, name, branchPattern, prereleaseIdentifier } = options;
|
|
307
334
|
const originalPrefix = this.config.tagPrefix || "";
|
|
308
335
|
const initialVersion = prereleaseIdentifier ? `0.0.1-${prereleaseIdentifier}` : "0.0.1";
|
|
309
|
-
const tagSearchPattern =
|
|
336
|
+
const tagSearchPattern = name ? originalPrefix ? `${originalPrefix}${name}@` : `${name}@` : originalPrefix ? `${originalPrefix}v` : "v";
|
|
310
337
|
let determinedReleaseType = type || null;
|
|
311
338
|
if (determinedReleaseType) {
|
|
312
339
|
if (!latestTag) {
|
|
@@ -347,21 +374,21 @@ var VersionEngine = class {
|
|
|
347
374
|
if (commitsLength === 0) {
|
|
348
375
|
log(
|
|
349
376
|
"info",
|
|
350
|
-
`No new commits found for ${
|
|
377
|
+
`No new commits found for ${name || "project"} since ${latestTag}, skipping version bump`
|
|
351
378
|
);
|
|
352
379
|
return "";
|
|
353
380
|
}
|
|
354
381
|
if (!releaseTypeFromCommits) {
|
|
355
382
|
log(
|
|
356
383
|
"info",
|
|
357
|
-
`No relevant commits found for ${
|
|
384
|
+
`No relevant commits found for ${name || "project"} since ${latestTag}, skipping version bump`
|
|
358
385
|
);
|
|
359
386
|
return "";
|
|
360
387
|
}
|
|
361
388
|
const currentVersion = semver.clean(latestTag.replace(tagSearchPattern, "")) || "0.0.0";
|
|
362
389
|
return semver.inc(currentVersion, releaseTypeFromCommits, prereleaseIdentifier) || "";
|
|
363
390
|
} catch (error) {
|
|
364
|
-
log("error", `Failed to calculate version for ${
|
|
391
|
+
log("error", `Failed to calculate version for ${name || "project"}`);
|
|
365
392
|
console.error(error);
|
|
366
393
|
if (error instanceof Error && error.message.includes("No names found")) {
|
|
367
394
|
log("info", "No tags found, proceeding with initial version calculation (if applicable).");
|
|
@@ -370,30 +397,44 @@ var VersionEngine = class {
|
|
|
370
397
|
return "";
|
|
371
398
|
}
|
|
372
399
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
400
|
+
/**
|
|
401
|
+
* Process packages based on discovery, skip list, and optional target list.
|
|
402
|
+
* Returns a list of package.json file paths that were updated (or would be in dry run).
|
|
403
|
+
*/
|
|
404
|
+
async processPackages(discoveredPackages = [], targets = []) {
|
|
405
|
+
const { tagPrefix, skip } = this.config;
|
|
376
406
|
const files = [];
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
407
|
+
const pkgsToConsider = discoveredPackages.filter((pkg) => {
|
|
408
|
+
if (skip == null ? void 0 : skip.includes(pkg.packageJson.name)) {
|
|
409
|
+
log("info", `Skipping package ${pkg.packageJson.name} based on config skip list.`);
|
|
380
410
|
return false;
|
|
381
411
|
}
|
|
382
|
-
|
|
412
|
+
if (targets.length > 0) {
|
|
413
|
+
const isTargeted = targets.includes(pkg.packageJson.name);
|
|
414
|
+
if (!isTargeted) {
|
|
415
|
+
}
|
|
416
|
+
return isTargeted;
|
|
417
|
+
}
|
|
418
|
+
return true;
|
|
383
419
|
});
|
|
384
|
-
|
|
385
|
-
|
|
420
|
+
log("info", `Found ${pkgsToConsider.length} package(s) to process after filtering.`);
|
|
421
|
+
for (const pkg of pkgsToConsider) {
|
|
422
|
+
const name = pkg.packageJson.name;
|
|
386
423
|
const pkgPath = pkg.dir;
|
|
387
424
|
const prefix = formatTagPrefix(tagPrefix);
|
|
388
425
|
const latestTag = await getLatestTag();
|
|
389
426
|
const nextVersion = await this.calculateVersion({
|
|
390
427
|
latestTag,
|
|
428
|
+
// This might need refinement for async based on package-specific tags
|
|
391
429
|
tagPrefix: prefix,
|
|
392
430
|
path: pkgPath,
|
|
393
|
-
name
|
|
431
|
+
name,
|
|
432
|
+
// Pass name for potential package-specific tag lookups
|
|
394
433
|
branchPattern: this.config.branchPattern,
|
|
395
434
|
baseBranch: this.config.baseBranch,
|
|
396
|
-
prereleaseIdentifier: this.config.prereleaseIdentifier
|
|
435
|
+
prereleaseIdentifier: this.config.prereleaseIdentifier,
|
|
436
|
+
type: this.config.forceType
|
|
437
|
+
// Pass forced type if provided
|
|
397
438
|
});
|
|
398
439
|
if (!nextVersion) {
|
|
399
440
|
continue;
|
|
@@ -401,13 +442,16 @@ var VersionEngine = class {
|
|
|
401
442
|
updatePackageVersion({
|
|
402
443
|
path: pkgPath,
|
|
403
444
|
version: nextVersion,
|
|
404
|
-
name
|
|
445
|
+
name,
|
|
405
446
|
dryRun: this.config.dryRun
|
|
406
447
|
});
|
|
407
448
|
files.push(path.join(pkgPath, "package.json"));
|
|
408
449
|
}
|
|
409
450
|
return files;
|
|
410
451
|
}
|
|
452
|
+
/**
|
|
453
|
+
* Create git commit and tag
|
|
454
|
+
*/
|
|
411
455
|
async createGitCommitAndTag(files, nextTag, commitMessage, dryRun) {
|
|
412
456
|
try {
|
|
413
457
|
await gitProcess({
|
|
@@ -426,6 +470,9 @@ var VersionEngine = class {
|
|
|
426
470
|
exit(1);
|
|
427
471
|
}
|
|
428
472
|
}
|
|
473
|
+
/**
|
|
474
|
+
* Synced versioning strategy (all packages get the same version)
|
|
475
|
+
*/
|
|
429
476
|
async syncedStrategy() {
|
|
430
477
|
var _a;
|
|
431
478
|
const {
|
|
@@ -494,6 +541,9 @@ var VersionEngine = class {
|
|
|
494
541
|
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
|
|
495
542
|
await this.createGitCommitAndTag(files, nextTag, formattedCommitMessage, this.config.dryRun);
|
|
496
543
|
}
|
|
544
|
+
/**
|
|
545
|
+
* Single package versioning strategy
|
|
546
|
+
*/
|
|
497
547
|
async singleStrategy() {
|
|
498
548
|
const {
|
|
499
549
|
packages: configPackages,
|
|
@@ -553,11 +603,15 @@ var VersionEngine = class {
|
|
|
553
603
|
this.config.dryRun
|
|
554
604
|
);
|
|
555
605
|
}
|
|
556
|
-
|
|
606
|
+
/**
|
|
607
|
+
* Async versioning strategy (each package gets its own version)
|
|
608
|
+
*/
|
|
609
|
+
async asyncStrategy(cliTargets = []) {
|
|
557
610
|
const {
|
|
558
|
-
packages: configPackages,
|
|
559
611
|
commitMessage = "chore(release): ${version}",
|
|
612
|
+
// Align with test expectations
|
|
560
613
|
skipHooks
|
|
614
|
+
// Add skipHooks here
|
|
561
615
|
} = this.config;
|
|
562
616
|
let pkgsResult;
|
|
563
617
|
try {
|
|
@@ -571,9 +625,9 @@ var VersionEngine = class {
|
|
|
571
625
|
exit(1);
|
|
572
626
|
return;
|
|
573
627
|
}
|
|
574
|
-
const pkgsToProcess = await this.processPackages(pkgsResult.packages,
|
|
628
|
+
const pkgsToProcess = await this.processPackages(pkgsResult.packages, cliTargets);
|
|
575
629
|
if (pkgsToProcess.length === 0) {
|
|
576
|
-
log("info", "No packages to process");
|
|
630
|
+
log("info", "No packages to process based on changes and targets");
|
|
577
631
|
return;
|
|
578
632
|
}
|
|
579
633
|
const formattedCommitMessage = commitMessage;
|
|
@@ -586,7 +640,7 @@ var VersionEngine = class {
|
|
|
586
640
|
dryRun: this.config.dryRun
|
|
587
641
|
});
|
|
588
642
|
if (!this.config.dryRun) {
|
|
589
|
-
log("success",
|
|
643
|
+
log("success", `Created version commit for ${pkgsToProcess.length} package(s)`);
|
|
590
644
|
}
|
|
591
645
|
} catch (error) {
|
|
592
646
|
log("error", "Failed to create version commit");
|
|
@@ -597,63 +651,49 @@ var VersionEngine = class {
|
|
|
597
651
|
};
|
|
598
652
|
|
|
599
653
|
// 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
|
-
`);
|
|
654
|
+
async function run() {
|
|
655
|
+
printFiglet();
|
|
656
|
+
const program = new Command();
|
|
657
|
+
program.name("package-versioner").description(
|
|
658
|
+
"Automated semantic versioning based on Git history and conventional commits. Supports monorepos with synchronized or independent package versioning strategies."
|
|
659
|
+
).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(
|
|
660
|
+
"--prerelease <identifier>",
|
|
661
|
+
"Create a prerelease version with the specified identifier"
|
|
662
|
+
).option(
|
|
663
|
+
"-t, --target <targets>",
|
|
664
|
+
"Comma-separated list of package names to target (only for async strategy)"
|
|
665
|
+
).parse(process.argv);
|
|
666
|
+
const options = program.opts();
|
|
631
667
|
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;
|
|
668
|
+
const config = await loadConfig(options.config);
|
|
669
|
+
log("info", `Loaded configuration from ${options.config || "version.config.json"}`);
|
|
670
|
+
if (options.dryRun) config.dryRun = true;
|
|
671
|
+
if (options.synced) config.synced = true;
|
|
672
|
+
if (options.bump) config.forceType = options.bump;
|
|
640
673
|
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;
|
|
674
|
+
config.prereleaseIdentifier = options.prerelease === true ? "rc" : options.prerelease;
|
|
675
|
+
const cliTargets = options.target ? options.target.split(",").map((t) => t.trim()) : [];
|
|
646
676
|
const engine = new VersionEngine(config);
|
|
647
677
|
if (config.synced) {
|
|
678
|
+
log("info", "Using synced versioning strategy.");
|
|
648
679
|
await engine.syncedStrategy();
|
|
649
|
-
} else if (
|
|
680
|
+
} else if (config.packages && config.packages.length === 1) {
|
|
681
|
+
log("info", "Using single package versioning strategy.");
|
|
682
|
+
if (cliTargets.length > 0) {
|
|
683
|
+
log("warning", "--target flag is ignored for single package strategy.");
|
|
684
|
+
}
|
|
650
685
|
await engine.singleStrategy();
|
|
651
686
|
} else {
|
|
652
|
-
|
|
687
|
+
log("info", "Using async versioning strategy.");
|
|
688
|
+
if (cliTargets.length > 0) {
|
|
689
|
+
log("info", `Targeting specific packages: ${cliTargets.join(", ")}`);
|
|
690
|
+
}
|
|
691
|
+
await engine.asyncStrategy(cliTargets);
|
|
653
692
|
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
693
|
+
log("success", "Versioning process completed.");
|
|
694
|
+
} catch (error) {
|
|
695
|
+
log("error", error instanceof Error ? error.message : String(error));
|
|
696
|
+
process.exit(1);
|
|
657
697
|
}
|
|
658
|
-
}
|
|
659
|
-
|
|
698
|
+
}
|
|
699
|
+
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.
|
|
4
|
+
"version": "0.1.1",
|
|
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
|
},
|