package-versioner 0.0.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/LICENCE.md +7 -0
- package/README.md +89 -0
- package/dist/index.cjs +667 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +648 -0
- package/package-versioner.schema.json +90 -0
- package/package.json +72 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
19
|
+
mod
|
|
20
|
+
));
|
|
21
|
+
|
|
22
|
+
// src/index.ts
|
|
23
|
+
var import_node_process4 = require("process");
|
|
24
|
+
var import_chalk2 = __toESM(require("chalk"), 1);
|
|
25
|
+
var import_commander = require("commander");
|
|
26
|
+
var import_figlet = __toESM(require("figlet"), 1);
|
|
27
|
+
|
|
28
|
+
// package.json
|
|
29
|
+
var package_default = {
|
|
30
|
+
name: "package-versioner",
|
|
31
|
+
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.1",
|
|
33
|
+
type: "module",
|
|
34
|
+
main: "./dist/index.js",
|
|
35
|
+
module: "./dist/index.mjs",
|
|
36
|
+
types: "./dist/index.d.ts",
|
|
37
|
+
author: {
|
|
38
|
+
name: "Sam Maister",
|
|
39
|
+
email: "goosewobbler@protonmail.com"
|
|
40
|
+
},
|
|
41
|
+
repository: {
|
|
42
|
+
type: "git",
|
|
43
|
+
url: "https://github.com/goosewobbler/package-versioner",
|
|
44
|
+
homepage: "https://github.com/goosewobbler/package-versioner"
|
|
45
|
+
},
|
|
46
|
+
keywords: ["version", "semver", "git", "package"],
|
|
47
|
+
license: "MIT",
|
|
48
|
+
files: ["dist/**", "package-versioner.schema.json"],
|
|
49
|
+
bin: {
|
|
50
|
+
"package-versioner": "./dist/index.js"
|
|
51
|
+
},
|
|
52
|
+
scripts: {
|
|
53
|
+
build: "tsup src/index.ts --format esm,cjs --dts",
|
|
54
|
+
dev: "tsup src/index.ts --format esm,cjs --watch --dts",
|
|
55
|
+
clean: "rm -rf node_modules && rm -rf dist",
|
|
56
|
+
test: "vitest run --coverage",
|
|
57
|
+
"test:watch": "vitest --coverage",
|
|
58
|
+
lint: "biome check .",
|
|
59
|
+
"lint:fix": "biome check --apply .",
|
|
60
|
+
format: "biome format --write .",
|
|
61
|
+
"format:check": "biome format .",
|
|
62
|
+
fix: "pnpm run lint:fix && pnpm run format",
|
|
63
|
+
prepare: "husky"
|
|
64
|
+
},
|
|
65
|
+
"lint-staged": {
|
|
66
|
+
"*.{js,ts,jsx,tsx}": ["biome check --apply", "biome format --write"]
|
|
67
|
+
},
|
|
68
|
+
devDependencies: {
|
|
69
|
+
"@biomejs/biome": "^1.9.4",
|
|
70
|
+
"@types/figlet": "^1.5.5",
|
|
71
|
+
"@types/node": "^18.14.0",
|
|
72
|
+
"@types/semver": "^7.3.13",
|
|
73
|
+
"@vitest/coverage-v8": "^3.1.1",
|
|
74
|
+
husky: "^9.1.7",
|
|
75
|
+
"lint-staged": "^15.5.0",
|
|
76
|
+
tsup: "^5.10.1",
|
|
77
|
+
typescript: "^5.8.3",
|
|
78
|
+
vitest: "^3.1.1"
|
|
79
|
+
},
|
|
80
|
+
dependencies: {
|
|
81
|
+
"@manypkg/get-packages": "^2.2.2",
|
|
82
|
+
chalk: "^5.4.1",
|
|
83
|
+
commander: "^13.1.0",
|
|
84
|
+
"conventional-changelog-angular": "^8.0.0",
|
|
85
|
+
"conventional-recommended-bump": "^11.0.0",
|
|
86
|
+
figlet: "^1.8.0",
|
|
87
|
+
"git-semver-tags": "^8.0.0",
|
|
88
|
+
semver: "^7.7.1"
|
|
89
|
+
},
|
|
90
|
+
packageManager: "pnpm@10.8.0+sha512.0e82714d1b5b43c74610193cb20734897c1d00de89d0e18420aebc5977fa13d780a9cb05734624e81ebd81cc876cd464794850641c48b9544326b5622ca29971"
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// src/config.ts
|
|
94
|
+
var fs = __toESM(require("fs"), 1);
|
|
95
|
+
var import_node_process = require("process");
|
|
96
|
+
function loadConfig(configPath) {
|
|
97
|
+
const localProcess = (0, import_node_process.cwd)();
|
|
98
|
+
const filePath = configPath || `${localProcess}/version.config.json`;
|
|
99
|
+
return new Promise((resolve, reject) => {
|
|
100
|
+
fs.readFile(filePath, "utf-8", (err, data) => {
|
|
101
|
+
if (err) {
|
|
102
|
+
reject(new Error(`Could not locate the config file at ${filePath}: ${err.message}`));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const config = JSON.parse(data);
|
|
107
|
+
resolve(config);
|
|
108
|
+
} catch (err2) {
|
|
109
|
+
const errorMessage = err2 instanceof Error ? err2.message : String(err2);
|
|
110
|
+
reject(new Error(`Failed to parse config file ${filePath}: ${errorMessage}`));
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/utils.ts
|
|
117
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
118
|
+
var import_chalk = __toESM(require("chalk"), 1);
|
|
119
|
+
var import_git_semver_tags = require("git-semver-tags");
|
|
120
|
+
|
|
121
|
+
// src/git.ts
|
|
122
|
+
var import_node_child_process = require("child_process");
|
|
123
|
+
var import_node_fs = require("fs");
|
|
124
|
+
var import_node_path = require("path");
|
|
125
|
+
var import_node_process2 = require("process");
|
|
126
|
+
var execAsync = (command) => {
|
|
127
|
+
return new Promise((resolve, reject) => {
|
|
128
|
+
const options = { maxBuffer: 1024 * 1024 * 10 };
|
|
129
|
+
(0, import_node_child_process.exec)(
|
|
130
|
+
command,
|
|
131
|
+
options,
|
|
132
|
+
(error, stdout, stderr) => {
|
|
133
|
+
if (error) {
|
|
134
|
+
reject(error);
|
|
135
|
+
} else {
|
|
136
|
+
resolve({ stdout: stdout.toString(), stderr: stderr.toString() });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
var execSync = (command, args) => (0, import_node_child_process.execSync)(command, { maxBuffer: 1024 * 1024 * 10, ...args });
|
|
143
|
+
async function gitAdd(files) {
|
|
144
|
+
const command = `git add ${files.join(" ")}`;
|
|
145
|
+
return execAsync(command);
|
|
146
|
+
}
|
|
147
|
+
async function gitCommit(options) {
|
|
148
|
+
const command = ["commit"];
|
|
149
|
+
if (options.amend) {
|
|
150
|
+
command.push("--amend");
|
|
151
|
+
}
|
|
152
|
+
if (options.author) {
|
|
153
|
+
command.push(`--author="${options.author}"`);
|
|
154
|
+
}
|
|
155
|
+
if (options.date) {
|
|
156
|
+
command.push(`--date="${options.date}"`);
|
|
157
|
+
}
|
|
158
|
+
if (options.skipHooks) {
|
|
159
|
+
command.push("--no-verify");
|
|
160
|
+
}
|
|
161
|
+
command.push(`-m "${options.message}"`);
|
|
162
|
+
return execAsync(`git ${command.join(" ")}`);
|
|
163
|
+
}
|
|
164
|
+
async function createGitTag(options) {
|
|
165
|
+
const { tag, message = "", args = "" } = options;
|
|
166
|
+
const command = `git tag -a -m "${message}" ${tag} ${args}`;
|
|
167
|
+
return execAsync(command);
|
|
168
|
+
}
|
|
169
|
+
function getCommitsLength(pkgRoot) {
|
|
170
|
+
try {
|
|
171
|
+
const gitCommand = `git rev-list --count HEAD ^$(git describe --tags --abbrev=0) ${pkgRoot}`;
|
|
172
|
+
const amount = execSync(gitCommand).toString().trim();
|
|
173
|
+
return Number(amount);
|
|
174
|
+
} catch {
|
|
175
|
+
return 0;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function isGitRepository(directory) {
|
|
179
|
+
const gitDir = (0, import_node_path.join)(directory, ".git");
|
|
180
|
+
if (!(0, import_node_fs.existsSync)(gitDir)) {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
const stats = (0, import_node_fs.statSync)(gitDir);
|
|
184
|
+
if (!stats.isDirectory()) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
execSync("git rev-parse --is-inside-work-tree", { cwd: directory });
|
|
189
|
+
return true;
|
|
190
|
+
} catch (_error) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async function gitProcess({ files, nextTag, commitMessage, skipHooks, dryRun }) {
|
|
195
|
+
try {
|
|
196
|
+
if (!isGitRepository((0, import_node_process2.cwd)())) {
|
|
197
|
+
throw new Error("Not a git repository (or any parent up to mount point /)");
|
|
198
|
+
}
|
|
199
|
+
if (!dryRun) {
|
|
200
|
+
await gitAdd(files);
|
|
201
|
+
await gitCommit({
|
|
202
|
+
message: commitMessage,
|
|
203
|
+
skipHooks
|
|
204
|
+
});
|
|
205
|
+
const tagMessage = `New Version ${nextTag} generated at ${new Date().toISOString()}`;
|
|
206
|
+
await createGitTag({
|
|
207
|
+
tag: nextTag,
|
|
208
|
+
message: tagMessage
|
|
209
|
+
});
|
|
210
|
+
} else {
|
|
211
|
+
log("info", "[DRY RUN] Would add files:");
|
|
212
|
+
for (const file of files) {
|
|
213
|
+
log("info", ` - ${file}`);
|
|
214
|
+
}
|
|
215
|
+
log("info", `[DRY RUN] Would commit with message: "${commitMessage}"`);
|
|
216
|
+
log("info", `[DRY RUN] Would create tag: ${nextTag}`);
|
|
217
|
+
}
|
|
218
|
+
} catch (err) {
|
|
219
|
+
console.log(err);
|
|
220
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
221
|
+
throw new Error(`Failed to create new version: ${errorMessage}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
async function lastMergeBranchName(branches, baseBranch) {
|
|
225
|
+
try {
|
|
226
|
+
const branchesRegex = `${branches.join("/(.*)|")}/(.*)`;
|
|
227
|
+
const command = `git for-each-ref --sort=-committerdate --format='%(refname:short)' refs/heads --merged ${baseBranch} | grep -o -i -E "${branchesRegex}" | awk -F'[ ]' '{print $1}' | head -n 1`;
|
|
228
|
+
const { stdout } = await execAsync(command);
|
|
229
|
+
return stdout.trim();
|
|
230
|
+
} catch (error) {
|
|
231
|
+
console.error(
|
|
232
|
+
"Error while getting the last branch name:",
|
|
233
|
+
error instanceof Error ? error.message : String(error)
|
|
234
|
+
);
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function getCurrentBranch() {
|
|
239
|
+
const result = execSync("git rev-parse --abbrev-ref HEAD");
|
|
240
|
+
return result.toString().trim();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// src/utils.ts
|
|
244
|
+
function log(status, message) {
|
|
245
|
+
const statusColors = {
|
|
246
|
+
info: import_chalk.default.blue("\u2139"),
|
|
247
|
+
success: import_chalk.default.green("\u2713"),
|
|
248
|
+
error: import_chalk.default.red("\u2717"),
|
|
249
|
+
warning: import_chalk.default.yellow("\u26A0")
|
|
250
|
+
};
|
|
251
|
+
process.stdout.write(`${statusColors[status]} ${message}
|
|
252
|
+
`);
|
|
253
|
+
}
|
|
254
|
+
async function getLatestTag() {
|
|
255
|
+
try {
|
|
256
|
+
const tags = await (0, import_git_semver_tags.getSemverTags)({});
|
|
257
|
+
return tags[0] || "";
|
|
258
|
+
} catch (error) {
|
|
259
|
+
log("error", "Failed to get latest tag");
|
|
260
|
+
console.error(error);
|
|
261
|
+
if (error instanceof Error && error.message.includes("No names found")) {
|
|
262
|
+
log("info", "No tags found in the repository.");
|
|
263
|
+
}
|
|
264
|
+
return "";
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
function formatTag(options, props) {
|
|
268
|
+
const { name: name2, synced, tagPrefix } = options;
|
|
269
|
+
const { version } = props;
|
|
270
|
+
if (!synced && name2) {
|
|
271
|
+
return `${tagPrefix ? tagPrefix : ""}${name2}@${version}`;
|
|
272
|
+
}
|
|
273
|
+
return `${tagPrefix ? tagPrefix : "v"}${version}`;
|
|
274
|
+
}
|
|
275
|
+
function formatTagPrefix(tagPrefix) {
|
|
276
|
+
return tagPrefix ? `${tagPrefix}@` : "";
|
|
277
|
+
}
|
|
278
|
+
function createTemplateString(template, data) {
|
|
279
|
+
return template.replace(/\$\{([^}]+)\}/g, (_, key) => data[key] || "");
|
|
280
|
+
}
|
|
281
|
+
function formatCommitMessage(template, version) {
|
|
282
|
+
return createTemplateString(template, { version });
|
|
283
|
+
}
|
|
284
|
+
function updatePackageVersion({ path: path2, version, name: name2, dryRun }) {
|
|
285
|
+
try {
|
|
286
|
+
const pkgPath = `${path2}/package.json`;
|
|
287
|
+
const pkg = JSON.parse(import_node_fs2.default.readFileSync(pkgPath, "utf8"));
|
|
288
|
+
pkg.version = version;
|
|
289
|
+
if (!dryRun) {
|
|
290
|
+
import_node_fs2.default.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
291
|
+
`);
|
|
292
|
+
log("success", `${name2}: ${version}`);
|
|
293
|
+
} else {
|
|
294
|
+
log("info", `[DRY RUN] Would update ${name2} package.json to version ${version}`);
|
|
295
|
+
}
|
|
296
|
+
} catch (error) {
|
|
297
|
+
log("error", `Failed to update ${name2} to version ${version}`);
|
|
298
|
+
console.error(error);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// src/versionEngine.ts
|
|
303
|
+
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
304
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
305
|
+
var import_node_process3 = require("process");
|
|
306
|
+
var import_get_packages = require("@manypkg/get-packages");
|
|
307
|
+
var import_conventional_recommended_bump = require("conventional-recommended-bump");
|
|
308
|
+
var import_semver = __toESM(require("semver"), 1);
|
|
309
|
+
var VersionEngine = class {
|
|
310
|
+
constructor(config) {
|
|
311
|
+
this.config = config;
|
|
312
|
+
}
|
|
313
|
+
async calculateVersion(options) {
|
|
314
|
+
const { latestTag, type, path: path2, name: name2, branchPattern, prereleaseIdentifier } = options;
|
|
315
|
+
const originalPrefix = this.config.tagPrefix || "";
|
|
316
|
+
const initialVersion = prereleaseIdentifier ? `0.0.1-${prereleaseIdentifier}` : "0.0.1";
|
|
317
|
+
const tagSearchPattern = name2 ? originalPrefix ? `${originalPrefix}${name2}@` : `${name2}@` : originalPrefix ? `${originalPrefix}v` : "v";
|
|
318
|
+
let determinedReleaseType = type || null;
|
|
319
|
+
if (determinedReleaseType) {
|
|
320
|
+
if (!latestTag) {
|
|
321
|
+
return initialVersion;
|
|
322
|
+
}
|
|
323
|
+
const currentVersion = import_semver.default.clean(latestTag.replace(tagSearchPattern, "")) || "0.0.0";
|
|
324
|
+
return import_semver.default.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
|
|
325
|
+
}
|
|
326
|
+
if (this.config.versionStrategy === "branchPattern" && (branchPattern == null ? void 0 : branchPattern.length)) {
|
|
327
|
+
const currentBranch = await getCurrentBranch();
|
|
328
|
+
const mergeBranch = await lastMergeBranchName(branchPattern, this.config.baseBranch);
|
|
329
|
+
const branch = mergeBranch || currentBranch;
|
|
330
|
+
for (const pattern of branchPattern) {
|
|
331
|
+
const [match, releaseType] = pattern.split(":");
|
|
332
|
+
if (branch.includes(match) && releaseType) {
|
|
333
|
+
determinedReleaseType = releaseType;
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (determinedReleaseType) {
|
|
338
|
+
if (!latestTag) {
|
|
339
|
+
return initialVersion;
|
|
340
|
+
}
|
|
341
|
+
const currentVersion = import_semver.default.clean(latestTag.replace(tagSearchPattern, "")) || "0.0.0";
|
|
342
|
+
return import_semver.default.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
try {
|
|
346
|
+
const bumper = new import_conventional_recommended_bump.Bumper();
|
|
347
|
+
bumper.loadPreset(this.config.preset);
|
|
348
|
+
const recommendedBump = await bumper.bump();
|
|
349
|
+
const releaseTypeFromCommits = recommendedBump.releaseType;
|
|
350
|
+
if (!latestTag) {
|
|
351
|
+
return initialVersion;
|
|
352
|
+
}
|
|
353
|
+
const checkPath = path2 || (0, import_node_process3.cwd)();
|
|
354
|
+
const commitsLength = await getCommitsLength(checkPath);
|
|
355
|
+
if (commitsLength === 0) {
|
|
356
|
+
log(
|
|
357
|
+
"info",
|
|
358
|
+
`No new commits found for ${name2 || "project"} since ${latestTag}, skipping version bump`
|
|
359
|
+
);
|
|
360
|
+
return "";
|
|
361
|
+
}
|
|
362
|
+
if (!releaseTypeFromCommits) {
|
|
363
|
+
log(
|
|
364
|
+
"info",
|
|
365
|
+
`No relevant commits found for ${name2 || "project"} since ${latestTag}, skipping version bump`
|
|
366
|
+
);
|
|
367
|
+
return "";
|
|
368
|
+
}
|
|
369
|
+
const currentVersion = import_semver.default.clean(latestTag.replace(tagSearchPattern, "")) || "0.0.0";
|
|
370
|
+
return import_semver.default.inc(currentVersion, releaseTypeFromCommits, prereleaseIdentifier) || "";
|
|
371
|
+
} catch (error) {
|
|
372
|
+
log("error", `Failed to calculate version for ${name2 || "project"}`);
|
|
373
|
+
console.error(error);
|
|
374
|
+
if (error instanceof Error && error.message.includes("No names found")) {
|
|
375
|
+
log("info", "No tags found, proceeding with initial version calculation (if applicable).");
|
|
376
|
+
return initialVersion;
|
|
377
|
+
}
|
|
378
|
+
return "";
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
async processPackages(packages = [], configPackages = []) {
|
|
382
|
+
const { tagPrefix } = this.config;
|
|
383
|
+
const pkgsResult = packages.length ? { packages } : (0, import_get_packages.getPackagesSync)((0, import_node_process3.cwd)());
|
|
384
|
+
const files = [];
|
|
385
|
+
const selectedPackages = pkgsResult.packages.filter((pkg) => {
|
|
386
|
+
var _a;
|
|
387
|
+
if ((_a = this.config.skip) == null ? void 0 : _a.includes(pkg.packageJson.name)) {
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
return configPackages.length === 0 || configPackages.includes(pkg.packageJson.name);
|
|
391
|
+
});
|
|
392
|
+
for (const pkg of selectedPackages) {
|
|
393
|
+
const name2 = pkg.packageJson.name;
|
|
394
|
+
const pkgPath = pkg.dir;
|
|
395
|
+
const prefix = formatTagPrefix(tagPrefix);
|
|
396
|
+
const latestTag = await getLatestTag();
|
|
397
|
+
const nextVersion = await this.calculateVersion({
|
|
398
|
+
latestTag,
|
|
399
|
+
tagPrefix: prefix,
|
|
400
|
+
path: pkgPath,
|
|
401
|
+
name: name2,
|
|
402
|
+
branchPattern: this.config.branchPattern,
|
|
403
|
+
baseBranch: this.config.baseBranch,
|
|
404
|
+
prereleaseIdentifier: this.config.prereleaseIdentifier
|
|
405
|
+
});
|
|
406
|
+
if (!nextVersion) {
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
updatePackageVersion({
|
|
410
|
+
path: pkgPath,
|
|
411
|
+
version: nextVersion,
|
|
412
|
+
name: name2,
|
|
413
|
+
dryRun: this.config.dryRun
|
|
414
|
+
});
|
|
415
|
+
files.push(import_node_path2.default.join(pkgPath, "package.json"));
|
|
416
|
+
}
|
|
417
|
+
return files;
|
|
418
|
+
}
|
|
419
|
+
async createGitCommitAndTag(files, nextTag, commitMessage, dryRun) {
|
|
420
|
+
try {
|
|
421
|
+
await gitProcess({
|
|
422
|
+
files,
|
|
423
|
+
nextTag,
|
|
424
|
+
commitMessage,
|
|
425
|
+
skipHooks: this.config.skipHooks,
|
|
426
|
+
dryRun
|
|
427
|
+
});
|
|
428
|
+
if (!dryRun) {
|
|
429
|
+
log("success", `Created tag: ${nextTag}`);
|
|
430
|
+
}
|
|
431
|
+
} catch (error) {
|
|
432
|
+
log("error", "Failed to create git commit and tag");
|
|
433
|
+
console.error(error);
|
|
434
|
+
(0, import_node_process3.exit)(1);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
async syncedStrategy() {
|
|
438
|
+
var _a;
|
|
439
|
+
const {
|
|
440
|
+
tagPrefix,
|
|
441
|
+
baseBranch,
|
|
442
|
+
branchPattern,
|
|
443
|
+
commitMessage = "chore(release): v${version}",
|
|
444
|
+
prereleaseIdentifier
|
|
445
|
+
} = this.config;
|
|
446
|
+
const prefix = formatTagPrefix(tagPrefix);
|
|
447
|
+
const latestTag = await getLatestTag();
|
|
448
|
+
const nextVersion = await this.calculateVersion({
|
|
449
|
+
latestTag,
|
|
450
|
+
tagPrefix: prefix,
|
|
451
|
+
branchPattern,
|
|
452
|
+
baseBranch,
|
|
453
|
+
prereleaseIdentifier
|
|
454
|
+
});
|
|
455
|
+
if (!nextVersion) {
|
|
456
|
+
log("info", "No version change needed");
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
let pkgsResult;
|
|
460
|
+
try {
|
|
461
|
+
pkgsResult = (0, import_get_packages.getPackagesSync)((0, import_node_process3.cwd)());
|
|
462
|
+
if (!pkgsResult || !pkgsResult.packages) {
|
|
463
|
+
throw new Error("Failed to get packages information");
|
|
464
|
+
}
|
|
465
|
+
} catch (error) {
|
|
466
|
+
log("error", "Failed to get packages information");
|
|
467
|
+
console.error(error);
|
|
468
|
+
(0, import_node_process3.exit)(1);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
const files = [];
|
|
472
|
+
try {
|
|
473
|
+
const rootPkgPath = import_node_path2.default.join(pkgsResult.root, "package.json");
|
|
474
|
+
if (import_node_fs3.default.existsSync(rootPkgPath)) {
|
|
475
|
+
updatePackageVersion({
|
|
476
|
+
path: pkgsResult.root,
|
|
477
|
+
version: nextVersion,
|
|
478
|
+
name: "root",
|
|
479
|
+
dryRun: this.config.dryRun
|
|
480
|
+
});
|
|
481
|
+
files.push(rootPkgPath);
|
|
482
|
+
}
|
|
483
|
+
} catch (_error) {
|
|
484
|
+
log("error", "Failed to update root package.json");
|
|
485
|
+
}
|
|
486
|
+
for (const pkg of pkgsResult.packages) {
|
|
487
|
+
if ((_a = this.config.skip) == null ? void 0 : _a.includes(pkg.packageJson.name)) {
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
updatePackageVersion({
|
|
491
|
+
path: pkg.dir,
|
|
492
|
+
version: nextVersion,
|
|
493
|
+
name: pkg.packageJson.name,
|
|
494
|
+
dryRun: this.config.dryRun
|
|
495
|
+
});
|
|
496
|
+
files.push(import_node_path2.default.join(pkg.dir, "package.json"));
|
|
497
|
+
}
|
|
498
|
+
const nextTag = formatTag(
|
|
499
|
+
{ synced: true, tagPrefix },
|
|
500
|
+
{ tagPrefix: prefix, version: nextVersion }
|
|
501
|
+
);
|
|
502
|
+
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
|
|
503
|
+
await this.createGitCommitAndTag(files, nextTag, formattedCommitMessage, this.config.dryRun);
|
|
504
|
+
}
|
|
505
|
+
async singleStrategy() {
|
|
506
|
+
const {
|
|
507
|
+
packages: configPackages,
|
|
508
|
+
tagPrefix,
|
|
509
|
+
commitMessage = "chore(release): ${version}"
|
|
510
|
+
} = this.config;
|
|
511
|
+
if (configPackages.length !== 1) {
|
|
512
|
+
log("error", "Single mode requires exactly one package name");
|
|
513
|
+
(0, import_node_process3.exit)(1);
|
|
514
|
+
}
|
|
515
|
+
const packageName = configPackages[0];
|
|
516
|
+
let pkgsResult;
|
|
517
|
+
try {
|
|
518
|
+
pkgsResult = (0, import_get_packages.getPackagesSync)((0, import_node_process3.cwd)());
|
|
519
|
+
if (!pkgsResult || !pkgsResult.packages) {
|
|
520
|
+
throw new Error("Failed to get packages information");
|
|
521
|
+
}
|
|
522
|
+
} catch (error) {
|
|
523
|
+
log("error", "Failed to get packages information");
|
|
524
|
+
console.error(error);
|
|
525
|
+
(0, import_node_process3.exit)(1);
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
const pkg = pkgsResult.packages.find((p) => p.packageJson.name === packageName);
|
|
529
|
+
if (!pkg) {
|
|
530
|
+
log("error", `Package ${packageName} not found`);
|
|
531
|
+
(0, import_node_process3.exit)(1);
|
|
532
|
+
}
|
|
533
|
+
const pkgPath = pkg.dir;
|
|
534
|
+
const prefix = formatTagPrefix(tagPrefix);
|
|
535
|
+
const latestTag = await getLatestTag();
|
|
536
|
+
const nextVersion = await this.calculateVersion({
|
|
537
|
+
latestTag,
|
|
538
|
+
tagPrefix: prefix,
|
|
539
|
+
path: pkgPath,
|
|
540
|
+
name: packageName
|
|
541
|
+
});
|
|
542
|
+
if (!nextVersion) {
|
|
543
|
+
log("info", `No version change needed for ${packageName}`);
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
updatePackageVersion({
|
|
547
|
+
path: pkgPath,
|
|
548
|
+
version: nextVersion,
|
|
549
|
+
name: packageName,
|
|
550
|
+
dryRun: this.config.dryRun
|
|
551
|
+
});
|
|
552
|
+
const nextTag = formatTag(
|
|
553
|
+
{ tagPrefix, name: packageName, synced: false },
|
|
554
|
+
{ tagPrefix: prefix, version: nextVersion }
|
|
555
|
+
);
|
|
556
|
+
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
|
|
557
|
+
await this.createGitCommitAndTag(
|
|
558
|
+
[import_node_path2.default.join(pkgPath, "package.json")],
|
|
559
|
+
nextTag,
|
|
560
|
+
formattedCommitMessage,
|
|
561
|
+
this.config.dryRun
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
async asyncStrategy() {
|
|
565
|
+
const {
|
|
566
|
+
packages: configPackages,
|
|
567
|
+
commitMessage = "chore(release): ${version}",
|
|
568
|
+
skipHooks
|
|
569
|
+
} = this.config;
|
|
570
|
+
let pkgsResult;
|
|
571
|
+
try {
|
|
572
|
+
pkgsResult = (0, import_get_packages.getPackagesSync)((0, import_node_process3.cwd)());
|
|
573
|
+
if (!pkgsResult || !pkgsResult.packages) {
|
|
574
|
+
throw new Error("Failed to get packages information");
|
|
575
|
+
}
|
|
576
|
+
} catch (error) {
|
|
577
|
+
log("error", "Failed to get packages information");
|
|
578
|
+
console.error(error);
|
|
579
|
+
(0, import_node_process3.exit)(1);
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
const pkgsToProcess = await this.processPackages(pkgsResult.packages, configPackages);
|
|
583
|
+
if (pkgsToProcess.length === 0) {
|
|
584
|
+
log("info", "No packages to process");
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
const formattedCommitMessage = commitMessage;
|
|
588
|
+
try {
|
|
589
|
+
await gitProcess({
|
|
590
|
+
files: pkgsToProcess,
|
|
591
|
+
nextTag: "",
|
|
592
|
+
commitMessage: formattedCommitMessage,
|
|
593
|
+
skipHooks,
|
|
594
|
+
dryRun: this.config.dryRun
|
|
595
|
+
});
|
|
596
|
+
if (!this.config.dryRun) {
|
|
597
|
+
log("success", "Created version commit");
|
|
598
|
+
}
|
|
599
|
+
} catch (error) {
|
|
600
|
+
log("error", "Failed to create version commit");
|
|
601
|
+
console.error(error);
|
|
602
|
+
(0, import_node_process3.exit)(1);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
// src/index.ts
|
|
608
|
+
var name = "package-versioner";
|
|
609
|
+
var program = new import_commander.Command();
|
|
610
|
+
program.name("package-versioner").description("Manages package versions using Git context.").version(package_default.version);
|
|
611
|
+
program.option("-t, --target <project>", "specific package to update").option("-b, --bump <version>", "type of version bump to perform", (value) => {
|
|
612
|
+
const validBumps = [
|
|
613
|
+
"patch",
|
|
614
|
+
"minor",
|
|
615
|
+
"major",
|
|
616
|
+
"premajor",
|
|
617
|
+
"preminor",
|
|
618
|
+
"prepatch",
|
|
619
|
+
"prerelease"
|
|
620
|
+
];
|
|
621
|
+
if (!validBumps.includes(value)) {
|
|
622
|
+
log("error", `Invalid bump type '${value}'. Valid options are: ${validBumps.join(", ")}`);
|
|
623
|
+
process.exit(1);
|
|
624
|
+
}
|
|
625
|
+
return value;
|
|
626
|
+
}).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(
|
|
627
|
+
"--skip <packages>",
|
|
628
|
+
"comma-separated list of packages to skip",
|
|
629
|
+
(value) => value.split(",")
|
|
630
|
+
).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");
|
|
631
|
+
program.description("Version packages based on Git context and conventional commits").action(async (options) => {
|
|
632
|
+
const figletText = import_figlet.default.textSync(name);
|
|
633
|
+
const versionText = `v${package_default.version}`;
|
|
634
|
+
process.stdout.write(`${import_chalk2.default.hex("#FF1F57")(figletText)}
|
|
635
|
+
`);
|
|
636
|
+
process.stdout.write(`${import_chalk2.default.hex("#0096FF")(versionText)}
|
|
637
|
+
|
|
638
|
+
`);
|
|
639
|
+
try {
|
|
640
|
+
const configPath = options.config || void 0;
|
|
641
|
+
const config = await loadConfig(configPath);
|
|
642
|
+
if (options.baseBranch)
|
|
643
|
+
config.baseBranch = options.baseBranch;
|
|
644
|
+
if (options.synced !== void 0)
|
|
645
|
+
config.synced = options.synced;
|
|
646
|
+
if (options.skip)
|
|
647
|
+
config.skip = options.skip;
|
|
648
|
+
if (options.prerelease)
|
|
649
|
+
config.prereleaseIdentifier = options.prerelease;
|
|
650
|
+
if (options.skipHooks !== void 0)
|
|
651
|
+
config.skipHooks = options.skipHooks;
|
|
652
|
+
if (options.dryRun !== void 0)
|
|
653
|
+
config.dryRun = options.dryRun;
|
|
654
|
+
const engine = new VersionEngine(config);
|
|
655
|
+
if (config.synced) {
|
|
656
|
+
await engine.syncedStrategy();
|
|
657
|
+
} else if (options.bump && options.target) {
|
|
658
|
+
await engine.singleStrategy();
|
|
659
|
+
} else {
|
|
660
|
+
await engine.asyncStrategy();
|
|
661
|
+
}
|
|
662
|
+
} catch (err) {
|
|
663
|
+
log("error", `${err instanceof Error ? err.message : String(err)}`);
|
|
664
|
+
(0, import_node_process4.exit)(1);
|
|
665
|
+
}
|
|
666
|
+
});
|
|
667
|
+
program.parse();
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|