package-versioner 0.2.0 → 0.3.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 +36 -3
- package/dist/index.cjs +713 -576
- package/dist/index.js +711 -575
- package/docs/CI_CD_INTEGRATION.md +165 -0
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -49,90 +49,136 @@ function loadConfig(configPath) {
|
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
// src/
|
|
53
|
-
var
|
|
52
|
+
// src/core/versionEngine.ts
|
|
53
|
+
var import_node_process5 = require("process");
|
|
54
|
+
var import_get_packages = require("@manypkg/get-packages");
|
|
55
|
+
|
|
56
|
+
// src/errors/gitError.ts
|
|
57
|
+
var GitError = class extends Error {
|
|
58
|
+
constructor(message, code) {
|
|
59
|
+
super(message);
|
|
60
|
+
this.code = code;
|
|
61
|
+
this.name = "GitError";
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
function createGitError(code, details) {
|
|
65
|
+
const messages = {
|
|
66
|
+
["NOT_GIT_REPO" /* NOT_GIT_REPO */]: "Not a git repository",
|
|
67
|
+
["GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */]: "Failed to create new version",
|
|
68
|
+
["NO_FILES" /* NO_FILES */]: "No files specified for commit",
|
|
69
|
+
["NO_COMMIT_MESSAGE" /* NO_COMMIT_MESSAGE */]: "Commit message is required",
|
|
70
|
+
["GIT_ERROR" /* GIT_ERROR */]: "Git operation failed"
|
|
71
|
+
};
|
|
72
|
+
const baseMessage = messages[code];
|
|
73
|
+
const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
|
|
74
|
+
return new GitError(fullMessage, code);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/errors/versionError.ts
|
|
78
|
+
var VersionError = class extends Error {
|
|
79
|
+
constructor(message, code) {
|
|
80
|
+
super(message);
|
|
81
|
+
this.code = code;
|
|
82
|
+
this.name = "VersionError";
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
function createVersionError(code, details) {
|
|
86
|
+
const messages = {
|
|
87
|
+
["CONFIG_REQUIRED" /* CONFIG_REQUIRED */]: "Configuration is required",
|
|
88
|
+
["PACKAGES_NOT_FOUND" /* PACKAGES_NOT_FOUND */]: "Failed to get packages information",
|
|
89
|
+
["WORKSPACE_ERROR" /* WORKSPACE_ERROR */]: "Failed to get workspace packages",
|
|
90
|
+
["INVALID_CONFIG" /* INVALID_CONFIG */]: "Invalid configuration",
|
|
91
|
+
["PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */]: "Package not found",
|
|
92
|
+
["VERSION_CALCULATION_ERROR" /* VERSION_CALCULATION_ERROR */]: "Failed to calculate version"
|
|
93
|
+
};
|
|
94
|
+
const baseMessage = messages[code];
|
|
95
|
+
const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
|
|
96
|
+
return new VersionError(fullMessage, code);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// src/utils/logging.ts
|
|
54
100
|
var import_chalk = __toESM(require("chalk"), 1);
|
|
55
101
|
var import_figlet = __toESM(require("figlet"), 1);
|
|
56
102
|
|
|
57
|
-
//
|
|
58
|
-
var
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
main: "./dist/index.js",
|
|
64
|
-
module: "./dist/index.mjs",
|
|
65
|
-
types: "./dist/index.d.ts",
|
|
66
|
-
author: {
|
|
67
|
-
name: "Sam Maister",
|
|
68
|
-
email: "goosewobbler@protonmail.com"
|
|
69
|
-
},
|
|
70
|
-
repository: {
|
|
71
|
-
type: "git",
|
|
72
|
-
url: "https://github.com/goosewobbler/package-versioner",
|
|
73
|
-
homepage: "https://github.com/goosewobbler/package-versioner"
|
|
74
|
-
},
|
|
75
|
-
keywords: ["version", "semver", "git", "package"],
|
|
76
|
-
license: "MIT",
|
|
77
|
-
files: ["dist/**", "docs/**", "package-versioner.schema.json"],
|
|
78
|
-
bin: {
|
|
79
|
-
"package-versioner": "./dist/index.js"
|
|
80
|
-
},
|
|
81
|
-
scripts: {
|
|
82
|
-
build: "tsup src/index.ts --format esm,cjs --dts",
|
|
83
|
-
dev: "tsup src/index.ts --format esm,cjs --watch --dts",
|
|
84
|
-
clean: "rm -rf node_modules && rm -rf dist",
|
|
85
|
-
test: "vitest run --coverage",
|
|
86
|
-
"test:watch": "vitest --coverage",
|
|
87
|
-
lint: "biome check .",
|
|
88
|
-
"lint:fix": "biome check --apply .",
|
|
89
|
-
format: "biome format --write .",
|
|
90
|
-
"format:check": "biome format .",
|
|
91
|
-
fix: "pnpm run lint:fix && pnpm run format",
|
|
92
|
-
prepare: "husky"
|
|
93
|
-
},
|
|
94
|
-
"lint-staged": {
|
|
95
|
-
"*.{js,ts,jsx,tsx}": ["biome check --apply", "biome format --write"]
|
|
96
|
-
},
|
|
97
|
-
devDependencies: {
|
|
98
|
-
"@biomejs/biome": "^1.9.4",
|
|
99
|
-
"@types/figlet": "^1.5.5",
|
|
100
|
-
"@types/node": "^22.14.0",
|
|
101
|
-
"@types/semver": "^7.3.13",
|
|
102
|
-
"@vitest/coverage-v8": "^3.1.1",
|
|
103
|
-
husky: "^9.1.7",
|
|
104
|
-
"lint-staged": "^15.5.0",
|
|
105
|
-
tsup: "^8.4.0",
|
|
106
|
-
typescript: "^5.8.3",
|
|
107
|
-
vitest: "^3.1.1"
|
|
108
|
-
},
|
|
109
|
-
dependencies: {
|
|
110
|
-
"@manypkg/get-packages": "^2.2.2",
|
|
111
|
-
chalk: "^5.4.1",
|
|
112
|
-
commander: "^13.1.0",
|
|
113
|
-
"conventional-changelog-angular": "^8.0.0",
|
|
114
|
-
"conventional-recommended-bump": "^11.0.0",
|
|
115
|
-
figlet: "^1.8.0",
|
|
116
|
-
"git-semver-tags": "^8.0.0",
|
|
117
|
-
semver: "^7.7.1"
|
|
118
|
-
},
|
|
119
|
-
packageManager: "pnpm@10.8.0+sha512.0e82714d1b5b43c74610193cb20734897c1d00de89d0e18420aebc5977fa13d780a9cb05734624e81ebd81cc876cd464794850641c48b9544326b5622ca29971"
|
|
103
|
+
// src/utils/jsonOutput.ts
|
|
104
|
+
var _jsonOutputMode = false;
|
|
105
|
+
var _jsonData = {
|
|
106
|
+
dryRun: false,
|
|
107
|
+
updates: [],
|
|
108
|
+
tags: []
|
|
120
109
|
};
|
|
110
|
+
function enableJsonOutput(dryRun = false) {
|
|
111
|
+
_jsonOutputMode = true;
|
|
112
|
+
_jsonData.dryRun = dryRun;
|
|
113
|
+
_jsonData.updates = [];
|
|
114
|
+
_jsonData.tags = [];
|
|
115
|
+
_jsonData.commitMessage = void 0;
|
|
116
|
+
}
|
|
117
|
+
function isJsonOutputMode() {
|
|
118
|
+
return _jsonOutputMode;
|
|
119
|
+
}
|
|
120
|
+
function addPackageUpdate(packageName, newVersion, filePath) {
|
|
121
|
+
if (!_jsonOutputMode) return;
|
|
122
|
+
_jsonData.updates.push({
|
|
123
|
+
packageName,
|
|
124
|
+
newVersion,
|
|
125
|
+
filePath
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
function addTag(tag) {
|
|
129
|
+
if (!_jsonOutputMode) return;
|
|
130
|
+
_jsonData.tags.push(tag);
|
|
131
|
+
}
|
|
132
|
+
function setCommitMessage(message) {
|
|
133
|
+
if (!_jsonOutputMode) return;
|
|
134
|
+
_jsonData.commitMessage = message;
|
|
135
|
+
}
|
|
136
|
+
function printJsonOutput() {
|
|
137
|
+
if (_jsonOutputMode) {
|
|
138
|
+
console.log(JSON.stringify(_jsonData, null, 2));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
121
141
|
|
|
122
|
-
// src/utils.ts
|
|
123
|
-
|
|
142
|
+
// src/utils/logging.ts
|
|
143
|
+
function log(message, status = "info") {
|
|
144
|
+
if (isJsonOutputMode() && status !== "error") {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
let chalkFn;
|
|
148
|
+
switch (status) {
|
|
149
|
+
case "success":
|
|
150
|
+
chalkFn = import_chalk.default.green;
|
|
151
|
+
break;
|
|
152
|
+
case "warning":
|
|
153
|
+
chalkFn = import_chalk.default.yellow;
|
|
154
|
+
break;
|
|
155
|
+
case "error":
|
|
156
|
+
chalkFn = import_chalk.default.red;
|
|
157
|
+
break;
|
|
158
|
+
case "debug":
|
|
159
|
+
chalkFn = import_chalk.default.gray;
|
|
160
|
+
break;
|
|
161
|
+
default:
|
|
162
|
+
chalkFn = import_chalk.default.blue;
|
|
163
|
+
}
|
|
164
|
+
console.log(chalkFn(message));
|
|
165
|
+
}
|
|
124
166
|
|
|
125
|
-
// src/
|
|
126
|
-
var
|
|
127
|
-
var
|
|
128
|
-
|
|
167
|
+
// src/core/versionStrategies.ts
|
|
168
|
+
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
169
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
170
|
+
|
|
171
|
+
// src/git/commands.ts
|
|
129
172
|
var import_node_process2 = require("process");
|
|
130
|
-
|
|
173
|
+
|
|
174
|
+
// src/git/commandExecutor.ts
|
|
175
|
+
var import_node_child_process = require("child_process");
|
|
176
|
+
var execAsync = (command, options) => {
|
|
177
|
+
const defaultOptions = { maxBuffer: 1024 * 1024 * 10, ...options };
|
|
131
178
|
return new Promise((resolve, reject) => {
|
|
132
|
-
const options = { maxBuffer: 1024 * 1024 * 10 };
|
|
133
179
|
(0, import_node_child_process.exec)(
|
|
134
180
|
command,
|
|
135
|
-
|
|
181
|
+
defaultOptions,
|
|
136
182
|
(error, stdout, stderr) => {
|
|
137
183
|
if (error) {
|
|
138
184
|
reject(error);
|
|
@@ -144,6 +190,32 @@ var execAsync = (command) => {
|
|
|
144
190
|
});
|
|
145
191
|
};
|
|
146
192
|
var execSync = (command, args) => (0, import_node_child_process.execSync)(command, { maxBuffer: 1024 * 1024 * 10, ...args });
|
|
193
|
+
|
|
194
|
+
// src/git/repository.ts
|
|
195
|
+
var import_node_fs = require("fs");
|
|
196
|
+
var import_node_path = require("path");
|
|
197
|
+
function isGitRepository(directory) {
|
|
198
|
+
const gitDir = (0, import_node_path.join)(directory, ".git");
|
|
199
|
+
if (!(0, import_node_fs.existsSync)(gitDir)) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
const stats = (0, import_node_fs.statSync)(gitDir);
|
|
203
|
+
if (!stats.isDirectory()) {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
execSync("git rev-parse --is-inside-work-tree", { cwd: directory });
|
|
208
|
+
return true;
|
|
209
|
+
} catch (_error) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function getCurrentBranch() {
|
|
214
|
+
const result = execSync("git rev-parse --abbrev-ref HEAD");
|
|
215
|
+
return result.toString().trim();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// src/git/commands.ts
|
|
147
219
|
async function gitAdd(files) {
|
|
148
220
|
const command = `git add ${files.join(" ")}`;
|
|
149
221
|
return execAsync(command);
|
|
@@ -170,36 +242,12 @@ async function createGitTag(options) {
|
|
|
170
242
|
const command = `git tag -a -m "${message}" ${tag} ${args}`;
|
|
171
243
|
return execAsync(command);
|
|
172
244
|
}
|
|
173
|
-
function
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
return Number(amount);
|
|
178
|
-
} catch {
|
|
179
|
-
return 0;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
function isGitRepository(directory) {
|
|
183
|
-
const gitDir = (0, import_node_path.join)(directory, ".git");
|
|
184
|
-
if (!(0, import_node_fs.existsSync)(gitDir)) {
|
|
185
|
-
return false;
|
|
186
|
-
}
|
|
187
|
-
const stats = (0, import_node_fs.statSync)(gitDir);
|
|
188
|
-
if (!stats.isDirectory()) {
|
|
189
|
-
return false;
|
|
190
|
-
}
|
|
191
|
-
try {
|
|
192
|
-
execSync("git rev-parse --is-inside-work-tree", { cwd: directory });
|
|
193
|
-
return true;
|
|
194
|
-
} catch (_error) {
|
|
195
|
-
return false;
|
|
245
|
+
async function gitProcess(options) {
|
|
246
|
+
const { files, nextTag, commitMessage, skipHooks, dryRun } = options;
|
|
247
|
+
if (!isGitRepository((0, import_node_process2.cwd)())) {
|
|
248
|
+
throw createGitError("NOT_GIT_REPO" /* NOT_GIT_REPO */);
|
|
196
249
|
}
|
|
197
|
-
}
|
|
198
|
-
async function gitProcess({ files, nextTag, commitMessage, skipHooks, dryRun }) {
|
|
199
250
|
try {
|
|
200
|
-
if (!isGitRepository((0, import_node_process2.cwd)())) {
|
|
201
|
-
throw new Error("Not a git repository (or any parent up to mount point /)");
|
|
202
|
-
}
|
|
203
251
|
if (!dryRun) {
|
|
204
252
|
await gitAdd(files);
|
|
205
253
|
await gitCommit({
|
|
@@ -214,503 +262,302 @@ async function gitProcess({ files, nextTag, commitMessage, skipHooks, dryRun })
|
|
|
214
262
|
});
|
|
215
263
|
}
|
|
216
264
|
} else {
|
|
217
|
-
log("
|
|
265
|
+
log("[DRY RUN] Would add files:", "info");
|
|
218
266
|
for (const file of files) {
|
|
219
|
-
log(
|
|
267
|
+
log(` - ${file}`, "info");
|
|
220
268
|
}
|
|
221
|
-
log(
|
|
269
|
+
log(`[DRY RUN] Would commit with message: "${commitMessage}"`, "info");
|
|
222
270
|
if (nextTag) {
|
|
223
|
-
log(
|
|
271
|
+
log(`[DRY RUN] Would create tag: ${nextTag}`, "info");
|
|
224
272
|
}
|
|
225
273
|
}
|
|
226
274
|
} catch (err) {
|
|
227
|
-
console.log(err);
|
|
228
275
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
229
|
-
throw
|
|
276
|
+
throw createGitError("GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */, errorMessage);
|
|
230
277
|
}
|
|
231
278
|
}
|
|
232
|
-
async function
|
|
279
|
+
async function createGitCommitAndTag(files, nextTag, commitMessage, skipHooks, dryRun) {
|
|
233
280
|
try {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
281
|
+
if (!files || files.length === 0) {
|
|
282
|
+
throw createGitError("NO_FILES" /* NO_FILES */);
|
|
283
|
+
}
|
|
284
|
+
if (!commitMessage) {
|
|
285
|
+
throw createGitError("NO_COMMIT_MESSAGE" /* NO_COMMIT_MESSAGE */);
|
|
286
|
+
}
|
|
287
|
+
setCommitMessage(commitMessage);
|
|
288
|
+
if (nextTag) {
|
|
289
|
+
addTag(nextTag);
|
|
290
|
+
}
|
|
291
|
+
await gitProcess({
|
|
292
|
+
files,
|
|
293
|
+
nextTag,
|
|
294
|
+
commitMessage,
|
|
295
|
+
skipHooks,
|
|
296
|
+
dryRun
|
|
297
|
+
});
|
|
298
|
+
if (!dryRun) {
|
|
299
|
+
log(`Created tag: ${nextTag}`, "success");
|
|
300
|
+
}
|
|
238
301
|
} catch (error) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
302
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
303
|
+
log(`Failed to create git commit and tag: ${errorMessage}`, "error");
|
|
304
|
+
if (error instanceof Error) {
|
|
305
|
+
console.error(error.stack || error.message);
|
|
306
|
+
} else {
|
|
307
|
+
console.error(error);
|
|
308
|
+
}
|
|
309
|
+
throw new GitError(`Git operation failed: ${errorMessage}`, "GIT_ERROR" /* GIT_ERROR */);
|
|
244
310
|
}
|
|
245
311
|
}
|
|
246
|
-
function getCurrentBranch() {
|
|
247
|
-
const result = execSync("git rev-parse --abbrev-ref HEAD");
|
|
248
|
-
return result.toString().trim();
|
|
249
|
-
}
|
|
250
312
|
|
|
251
|
-
// src/
|
|
252
|
-
|
|
253
|
-
const font = "Standard";
|
|
254
|
-
import_figlet.default.text(package_default.name, { font }, (err, data) => {
|
|
255
|
-
if (err) {
|
|
256
|
-
log("warning", "Could not print figlet banner: Figlet error");
|
|
257
|
-
console.error(err);
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
if (data) {
|
|
261
|
-
const figletText = data;
|
|
262
|
-
const versionText = `v${package_default.version}`;
|
|
263
|
-
process.stdout.write(`${import_chalk.default.hex("#FF1F57")(figletText)}
|
|
264
|
-
`);
|
|
265
|
-
process.stdout.write(`${import_chalk.default.hex("#0096FF")(versionText)}
|
|
313
|
+
// src/git/tagsAndBranches.ts
|
|
314
|
+
var import_git_semver_tags = require("git-semver-tags");
|
|
266
315
|
|
|
267
|
-
|
|
316
|
+
// src/utils/formatting.ts
|
|
317
|
+
function escapeRegExp(string) {
|
|
318
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
319
|
+
}
|
|
320
|
+
function formatTag(version, tagPrefix) {
|
|
321
|
+
if (!tagPrefix) return version;
|
|
322
|
+
return tagPrefix.endsWith("/") ? `${tagPrefix}${version}` : `${tagPrefix}/${version}`;
|
|
323
|
+
}
|
|
324
|
+
function formatTagPrefix(tagPrefix, scope) {
|
|
325
|
+
if (!tagPrefix) return "";
|
|
326
|
+
const prefix = tagPrefix.replace(/\/$/, "");
|
|
327
|
+
if (scope) {
|
|
328
|
+
return `${prefix}/${scope}`;
|
|
329
|
+
}
|
|
330
|
+
return prefix;
|
|
331
|
+
}
|
|
332
|
+
function formatCommitMessage(template, version, scope) {
|
|
333
|
+
return createTemplateString(template, { version, scope });
|
|
334
|
+
}
|
|
335
|
+
function createTemplateString(template, variables) {
|
|
336
|
+
return Object.entries(variables).reduce((result, [key, value]) => {
|
|
337
|
+
if (value === void 0) {
|
|
338
|
+
return result;
|
|
268
339
|
}
|
|
269
|
-
|
|
340
|
+
const regex = new RegExp(`\\$\\{${key}\\}`, "g");
|
|
341
|
+
return result.replace(regex, value);
|
|
342
|
+
}, template);
|
|
270
343
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
344
|
+
|
|
345
|
+
// src/git/tagsAndBranches.ts
|
|
346
|
+
function getCommitsLength(pkgRoot) {
|
|
347
|
+
try {
|
|
348
|
+
const gitCommand = `git rev-list --count HEAD ^$(git describe --tags --abbrev=0) ${pkgRoot}`;
|
|
349
|
+
const amount = execSync(gitCommand).toString().trim();
|
|
350
|
+
return Number(amount);
|
|
351
|
+
} catch (error) {
|
|
352
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
353
|
+
log(`Failed to get number of commits since last tag: ${errorMessage}`, "error");
|
|
354
|
+
return 0;
|
|
355
|
+
}
|
|
280
356
|
}
|
|
281
357
|
async function getLatestTag() {
|
|
282
358
|
try {
|
|
283
359
|
const tags = await (0, import_git_semver_tags.getSemverTags)({});
|
|
284
360
|
return tags[0] || "";
|
|
285
361
|
} catch (error) {
|
|
286
|
-
|
|
287
|
-
|
|
362
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
363
|
+
log(`Failed to get latest tag: ${errorMessage}`, "error");
|
|
288
364
|
if (error instanceof Error && error.message.includes("No names found")) {
|
|
289
|
-
log("
|
|
365
|
+
log("No tags found in the repository.", "info");
|
|
290
366
|
}
|
|
291
367
|
return "";
|
|
292
368
|
}
|
|
293
369
|
}
|
|
294
|
-
function
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
370
|
+
async function lastMergeBranchName(branches, baseBranch) {
|
|
371
|
+
try {
|
|
372
|
+
const escapedBranches = branches.map((branch) => escapeRegExp(branch));
|
|
373
|
+
const branchesRegex = `${escapedBranches.join("/(.*)|")}/(.*)`;
|
|
374
|
+
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`;
|
|
375
|
+
const { stdout } = await execAsync(command);
|
|
376
|
+
return stdout.trim();
|
|
377
|
+
} catch (error) {
|
|
378
|
+
console.error(
|
|
379
|
+
"Error while getting the last branch name:",
|
|
380
|
+
error instanceof Error ? error.message : String(error)
|
|
381
|
+
);
|
|
382
|
+
return null;
|
|
299
383
|
}
|
|
300
|
-
return `${tagPrefix ? tagPrefix : "v"}${version}`;
|
|
301
|
-
}
|
|
302
|
-
function formatTagPrefix(tagPrefix) {
|
|
303
|
-
return tagPrefix ? `${tagPrefix}@` : "";
|
|
304
|
-
}
|
|
305
|
-
function createTemplateString(template, data) {
|
|
306
|
-
return template.replace(/\$\{([^}]+)\}/g, (_, key) => data[key] || "");
|
|
307
|
-
}
|
|
308
|
-
function formatCommitMessage(template, version) {
|
|
309
|
-
return createTemplateString(template, { version });
|
|
310
384
|
}
|
|
311
|
-
|
|
385
|
+
|
|
386
|
+
// src/package/packageManagement.ts
|
|
387
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
388
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
389
|
+
function updatePackageVersion(packagePath, version) {
|
|
312
390
|
try {
|
|
313
|
-
const
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
391
|
+
const packageContent = import_node_fs2.default.readFileSync(packagePath, "utf8");
|
|
392
|
+
const packageJson = JSON.parse(packageContent);
|
|
393
|
+
const packageName = packageJson.name;
|
|
394
|
+
packageJson.version = version;
|
|
395
|
+
import_node_fs2.default.writeFileSync(packagePath, `${JSON.stringify(packageJson, null, 2)}
|
|
318
396
|
`);
|
|
319
|
-
|
|
320
|
-
}
|
|
321
|
-
log("info", `[DRY RUN] Would update ${name} package.json to version ${version}`);
|
|
322
|
-
}
|
|
397
|
+
addPackageUpdate(packageName, version, packagePath);
|
|
398
|
+
log(`Updated package.json at ${packagePath} to version ${version}`, "success");
|
|
323
399
|
} catch (error) {
|
|
324
|
-
log(
|
|
325
|
-
|
|
400
|
+
log(`Failed to update package.json at ${packagePath}`, "error");
|
|
401
|
+
if (error instanceof Error) {
|
|
402
|
+
log(error.message, "error");
|
|
403
|
+
}
|
|
404
|
+
throw error;
|
|
326
405
|
}
|
|
327
406
|
}
|
|
328
407
|
|
|
329
|
-
// src/
|
|
330
|
-
var
|
|
331
|
-
var
|
|
408
|
+
// src/package/packageProcessor.ts
|
|
409
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
410
|
+
var import_node_process4 = require("process");
|
|
411
|
+
|
|
412
|
+
// src/core/versionCalculator.ts
|
|
332
413
|
var import_node_process3 = require("process");
|
|
333
|
-
var import_get_packages = require("@manypkg/get-packages");
|
|
334
414
|
var import_conventional_recommended_bump = require("conventional-recommended-bump");
|
|
335
415
|
var import_semver = __toESM(require("semver"), 1);
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
416
|
+
async function calculateVersion(config, options) {
|
|
417
|
+
const { latestTag, type, path: path4, name, branchPattern, prereleaseIdentifier } = options;
|
|
418
|
+
const originalPrefix = config.tagPrefix || "v";
|
|
419
|
+
const initialVersion = prereleaseIdentifier ? `0.0.1-${prereleaseIdentifier}` : "0.0.1";
|
|
420
|
+
function determineTagSearchPattern(packageName, prefix) {
|
|
421
|
+
if (packageName) {
|
|
422
|
+
return prefix ? `${prefix}${packageName}@` : `${packageName}@`;
|
|
423
|
+
}
|
|
424
|
+
return prefix ? `${prefix}v` : "v";
|
|
340
425
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
const initialVersion = prereleaseIdentifier ? `0.0.1-${prereleaseIdentifier}` : "0.0.1";
|
|
348
|
-
const tagSearchPattern = name ? originalPrefix ? `${originalPrefix}${name}@` : `${name}@` : originalPrefix ? `${originalPrefix}v` : "v";
|
|
349
|
-
let determinedReleaseType = type || null;
|
|
350
|
-
if (determinedReleaseType) {
|
|
351
|
-
if (!latestTag) {
|
|
352
|
-
return initialVersion;
|
|
353
|
-
}
|
|
354
|
-
const currentVersion = import_semver.default.clean(latestTag.replace(tagSearchPattern, "")) || "0.0.0";
|
|
355
|
-
return import_semver.default.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
|
|
426
|
+
const tagSearchPattern = determineTagSearchPattern(name, originalPrefix);
|
|
427
|
+
const escapedTagPattern = escapeRegExp(tagSearchPattern);
|
|
428
|
+
let determinedReleaseType = type || null;
|
|
429
|
+
if (determinedReleaseType) {
|
|
430
|
+
if (!latestTag) {
|
|
431
|
+
return initialVersion;
|
|
356
432
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
if (!latestTag) {
|
|
370
|
-
return initialVersion;
|
|
371
|
-
}
|
|
372
|
-
const currentVersion = import_semver.default.clean(latestTag.replace(tagSearchPattern, "")) || "0.0.0";
|
|
373
|
-
return import_semver.default.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
|
|
433
|
+
const currentVersion = import_semver.default.clean(latestTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
|
|
434
|
+
return import_semver.default.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
|
|
435
|
+
}
|
|
436
|
+
if (config.versionStrategy === "branchPattern" && (branchPattern == null ? void 0 : branchPattern.length)) {
|
|
437
|
+
const currentBranch = await getCurrentBranch();
|
|
438
|
+
const mergeBranch = await lastMergeBranchName(branchPattern, config.baseBranch);
|
|
439
|
+
const branch = mergeBranch || currentBranch;
|
|
440
|
+
for (const pattern of branchPattern) {
|
|
441
|
+
const [match, releaseType] = pattern.split(":");
|
|
442
|
+
if (branch.includes(match) && releaseType) {
|
|
443
|
+
determinedReleaseType = releaseType;
|
|
444
|
+
break;
|
|
374
445
|
}
|
|
375
446
|
}
|
|
376
|
-
|
|
377
|
-
const bumper = new import_conventional_recommended_bump.Bumper();
|
|
378
|
-
bumper.loadPreset(this.config.preset);
|
|
379
|
-
const recommendedBump = await bumper.bump();
|
|
380
|
-
const releaseTypeFromCommits = recommendedBump.releaseType;
|
|
447
|
+
if (determinedReleaseType) {
|
|
381
448
|
if (!latestTag) {
|
|
382
449
|
return initialVersion;
|
|
383
450
|
}
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
if (commitsLength === 0) {
|
|
387
|
-
log(
|
|
388
|
-
"info",
|
|
389
|
-
`No new commits found for ${name || "project"} since ${latestTag}, skipping version bump`
|
|
390
|
-
);
|
|
391
|
-
return "";
|
|
392
|
-
}
|
|
393
|
-
if (!releaseTypeFromCommits) {
|
|
394
|
-
log(
|
|
395
|
-
"info",
|
|
396
|
-
`No relevant commits found for ${name || "project"} since ${latestTag}, skipping version bump`
|
|
397
|
-
);
|
|
398
|
-
return "";
|
|
399
|
-
}
|
|
400
|
-
const currentVersion = import_semver.default.clean(latestTag.replace(tagSearchPattern, "")) || "0.0.0";
|
|
401
|
-
return import_semver.default.inc(currentVersion, releaseTypeFromCommits, prereleaseIdentifier) || "";
|
|
402
|
-
} catch (error) {
|
|
403
|
-
log("error", `Failed to calculate version for ${name || "project"}`);
|
|
404
|
-
console.error(error);
|
|
405
|
-
if (error instanceof Error && error.message.includes("No names found")) {
|
|
406
|
-
log("info", "No tags found, proceeding with initial version calculation (if applicable).");
|
|
407
|
-
return initialVersion;
|
|
408
|
-
}
|
|
409
|
-
return "";
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
/**
|
|
413
|
-
* Process packages based on discovery, skip list, and optional target list.
|
|
414
|
-
* Returns a list of package.json file paths that were updated (or would be in dry run).
|
|
415
|
-
*/
|
|
416
|
-
async processPackages(discoveredPackages = [], targets = []) {
|
|
417
|
-
const { tagPrefix, skip, dryRun } = this.config;
|
|
418
|
-
const files = [];
|
|
419
|
-
const pkgsToConsider = discoveredPackages.filter((pkg) => {
|
|
420
|
-
if (skip == null ? void 0 : skip.includes(pkg.packageJson.name)) {
|
|
421
|
-
log("info", `Skipping package ${pkg.packageJson.name} based on config skip list.`);
|
|
422
|
-
return false;
|
|
423
|
-
}
|
|
424
|
-
if (targets.length > 0) {
|
|
425
|
-
const isTargeted = targets.includes(pkg.packageJson.name);
|
|
426
|
-
if (!isTargeted) {
|
|
427
|
-
}
|
|
428
|
-
return isTargeted;
|
|
429
|
-
}
|
|
430
|
-
return true;
|
|
431
|
-
});
|
|
432
|
-
log("info", `Found ${pkgsToConsider.length} package(s) to process after filtering.`);
|
|
433
|
-
for (const pkg of pkgsToConsider) {
|
|
434
|
-
const name = pkg.packageJson.name;
|
|
435
|
-
const pkgPath = pkg.dir;
|
|
436
|
-
const prefix = formatTagPrefix(tagPrefix);
|
|
437
|
-
const latestTag = await getLatestTag();
|
|
438
|
-
const nextVersion = await this.calculateVersion({
|
|
439
|
-
latestTag,
|
|
440
|
-
tagPrefix: prefix,
|
|
441
|
-
path: pkgPath,
|
|
442
|
-
name,
|
|
443
|
-
branchPattern: this.config.branchPattern,
|
|
444
|
-
baseBranch: this.config.baseBranch,
|
|
445
|
-
prereleaseIdentifier: this.config.prereleaseIdentifier,
|
|
446
|
-
type: this.config.forceType
|
|
447
|
-
});
|
|
448
|
-
if (!nextVersion) {
|
|
449
|
-
continue;
|
|
450
|
-
}
|
|
451
|
-
updatePackageVersion({
|
|
452
|
-
path: pkgPath,
|
|
453
|
-
version: nextVersion,
|
|
454
|
-
name,
|
|
455
|
-
dryRun
|
|
456
|
-
});
|
|
457
|
-
files.push(import_node_path2.default.join(pkgPath, "package.json"));
|
|
458
|
-
}
|
|
459
|
-
return files;
|
|
460
|
-
}
|
|
461
|
-
/**
|
|
462
|
-
* Create git commit and tag
|
|
463
|
-
*/
|
|
464
|
-
async createGitCommitAndTag(files, nextTag, commitMessage, dryRun) {
|
|
465
|
-
try {
|
|
466
|
-
await gitProcess({
|
|
467
|
-
files,
|
|
468
|
-
nextTag,
|
|
469
|
-
commitMessage,
|
|
470
|
-
skipHooks: this.config.skipHooks,
|
|
471
|
-
dryRun
|
|
472
|
-
});
|
|
473
|
-
if (!dryRun) {
|
|
474
|
-
log("success", `Created tag: ${nextTag}`);
|
|
475
|
-
}
|
|
476
|
-
} catch (error) {
|
|
477
|
-
log("error", "Failed to create git commit and tag");
|
|
478
|
-
console.error(error);
|
|
479
|
-
(0, import_node_process3.exit)(1);
|
|
451
|
+
const currentVersion = import_semver.default.clean(latestTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
|
|
452
|
+
return import_semver.default.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
|
|
480
453
|
}
|
|
481
454
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
baseBranch,
|
|
490
|
-
branchPattern,
|
|
491
|
-
commitMessage = "chore(release): v${version}",
|
|
492
|
-
prereleaseIdentifier
|
|
493
|
-
} = this.config;
|
|
494
|
-
const prefix = formatTagPrefix(tagPrefix);
|
|
495
|
-
const latestTag = await getLatestTag();
|
|
496
|
-
const nextVersion = await this.calculateVersion({
|
|
497
|
-
latestTag,
|
|
498
|
-
tagPrefix: prefix,
|
|
499
|
-
branchPattern,
|
|
500
|
-
baseBranch,
|
|
501
|
-
prereleaseIdentifier
|
|
502
|
-
});
|
|
503
|
-
if (!nextVersion) {
|
|
504
|
-
log("info", "No version change needed");
|
|
505
|
-
return;
|
|
455
|
+
try {
|
|
456
|
+
const bumper = new import_conventional_recommended_bump.Bumper();
|
|
457
|
+
bumper.loadPreset(config.preset);
|
|
458
|
+
const recommendedBump = await bumper.bump();
|
|
459
|
+
const releaseTypeFromCommits = recommendedBump.releaseType;
|
|
460
|
+
if (!latestTag) {
|
|
461
|
+
return initialVersion;
|
|
506
462
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
console.error(error);
|
|
516
|
-
(0, import_node_process3.exit)(1);
|
|
517
|
-
return;
|
|
463
|
+
const checkPath = path4 || (0, import_node_process3.cwd)();
|
|
464
|
+
const commitsLength = getCommitsLength(checkPath);
|
|
465
|
+
if (commitsLength === 0) {
|
|
466
|
+
log(
|
|
467
|
+
`No new commits found for ${name || "project"} since ${latestTag}, skipping version bump`,
|
|
468
|
+
"info"
|
|
469
|
+
);
|
|
470
|
+
return "";
|
|
518
471
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
version: nextVersion,
|
|
526
|
-
name: "root",
|
|
527
|
-
dryRun: this.config.dryRun
|
|
528
|
-
});
|
|
529
|
-
files.push(rootPkgPath);
|
|
530
|
-
}
|
|
531
|
-
} catch (_error) {
|
|
532
|
-
log("error", "Failed to update root package.json");
|
|
472
|
+
if (!releaseTypeFromCommits) {
|
|
473
|
+
log(
|
|
474
|
+
`No relevant commits found for ${name || "project"} since ${latestTag}, skipping version bump`,
|
|
475
|
+
"info"
|
|
476
|
+
);
|
|
477
|
+
return "";
|
|
533
478
|
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
dryRun: this.config.dryRun
|
|
543
|
-
});
|
|
544
|
-
files.push(import_node_path2.default.join(pkg.dir, "package.json"));
|
|
479
|
+
const currentVersion = import_semver.default.clean(latestTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
|
|
480
|
+
return import_semver.default.inc(currentVersion, releaseTypeFromCommits, prereleaseIdentifier) || "";
|
|
481
|
+
} catch (error) {
|
|
482
|
+
log(`Failed to calculate version for ${name || "project"}`, "error");
|
|
483
|
+
console.error(error);
|
|
484
|
+
if (error instanceof Error && error.message.includes("No names found")) {
|
|
485
|
+
log("No tags found, proceeding with initial version calculation (if applicable).", "info");
|
|
486
|
+
return initialVersion;
|
|
545
487
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
488
|
+
throw error;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// src/package/packageProcessor.ts
|
|
493
|
+
var PackageProcessor = class {
|
|
494
|
+
skip;
|
|
495
|
+
targets;
|
|
496
|
+
tagPrefix;
|
|
497
|
+
commitMessageTemplate;
|
|
498
|
+
dryRun;
|
|
499
|
+
skipHooks;
|
|
500
|
+
getLatestTag;
|
|
501
|
+
config;
|
|
502
|
+
// Config for version calculation
|
|
503
|
+
fullConfig;
|
|
504
|
+
constructor(options) {
|
|
505
|
+
this.skip = options.skip || [];
|
|
506
|
+
this.targets = options.targets || [];
|
|
507
|
+
this.tagPrefix = options.tagPrefix || "v";
|
|
508
|
+
this.commitMessageTemplate = options.commitMessageTemplate || "";
|
|
509
|
+
this.dryRun = options.dryRun || false;
|
|
510
|
+
this.skipHooks = options.skipHooks || false;
|
|
511
|
+
this.getLatestTag = options.getLatestTag;
|
|
512
|
+
this.config = options.config;
|
|
513
|
+
this.fullConfig = options.fullConfig;
|
|
552
514
|
}
|
|
553
515
|
/**
|
|
554
|
-
*
|
|
516
|
+
* Set package targets to process
|
|
555
517
|
*/
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
packages: configPackages,
|
|
559
|
-
tagPrefix,
|
|
560
|
-
commitMessage = "chore(release): ${version}"
|
|
561
|
-
} = this.config;
|
|
562
|
-
if (configPackages.length !== 1) {
|
|
563
|
-
log("error", "Single mode requires exactly one package name");
|
|
564
|
-
(0, import_node_process3.exit)(1);
|
|
565
|
-
}
|
|
566
|
-
const packageName = configPackages[0];
|
|
567
|
-
let pkgsResult;
|
|
568
|
-
try {
|
|
569
|
-
pkgsResult = (0, import_get_packages.getPackagesSync)((0, import_node_process3.cwd)());
|
|
570
|
-
if (!pkgsResult || !pkgsResult.packages) {
|
|
571
|
-
throw new Error("Failed to get packages information");
|
|
572
|
-
}
|
|
573
|
-
} catch (error) {
|
|
574
|
-
log("error", "Failed to get packages information");
|
|
575
|
-
console.error(error);
|
|
576
|
-
(0, import_node_process3.exit)(1);
|
|
577
|
-
return;
|
|
578
|
-
}
|
|
579
|
-
const pkg = pkgsResult.packages.find((p) => p.packageJson.name === packageName);
|
|
580
|
-
if (!pkg) {
|
|
581
|
-
log("error", `Package ${packageName} not found`);
|
|
582
|
-
(0, import_node_process3.exit)(1);
|
|
583
|
-
}
|
|
584
|
-
const pkgPath = pkg.dir;
|
|
585
|
-
const prefix = formatTagPrefix(tagPrefix);
|
|
586
|
-
const latestTag = await getLatestTag();
|
|
587
|
-
let nextVersion = void 0;
|
|
588
|
-
try {
|
|
589
|
-
nextVersion = await this.calculateVersion({
|
|
590
|
-
latestTag,
|
|
591
|
-
tagPrefix: prefix,
|
|
592
|
-
path: pkgPath,
|
|
593
|
-
name: packageName
|
|
594
|
-
});
|
|
595
|
-
} catch (error) {
|
|
596
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
597
|
-
log("error", `Failed to calculate version for ${packageName}: ${errorMessage}`);
|
|
598
|
-
}
|
|
599
|
-
if (nextVersion === void 0 || nextVersion === "") {
|
|
600
|
-
log("info", `No version change needed for ${packageName}`);
|
|
601
|
-
return;
|
|
602
|
-
}
|
|
603
|
-
updatePackageVersion({
|
|
604
|
-
path: pkgPath,
|
|
605
|
-
version: nextVersion,
|
|
606
|
-
name: packageName,
|
|
607
|
-
dryRun: this.config.dryRun
|
|
608
|
-
});
|
|
609
|
-
const nextTag = formatTag(
|
|
610
|
-
{ tagPrefix, name: packageName, synced: false },
|
|
611
|
-
{ tagPrefix: prefix, version: nextVersion }
|
|
612
|
-
);
|
|
613
|
-
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
|
|
614
|
-
await this.createGitCommitAndTag(
|
|
615
|
-
[import_node_path2.default.join(pkgPath, "package.json")],
|
|
616
|
-
nextTag,
|
|
617
|
-
formattedCommitMessage,
|
|
618
|
-
this.config.dryRun
|
|
619
|
-
);
|
|
518
|
+
setTargets(targets) {
|
|
519
|
+
this.targets = targets;
|
|
620
520
|
}
|
|
621
521
|
/**
|
|
622
|
-
*
|
|
522
|
+
* Process packages based on targeting criteria
|
|
623
523
|
*/
|
|
624
|
-
async
|
|
625
|
-
if (cliTargets.length > 0) {
|
|
626
|
-
await this.asyncTargetedStrategy(cliTargets);
|
|
627
|
-
return;
|
|
628
|
-
}
|
|
629
|
-
const {
|
|
630
|
-
commitMessage = "chore(release): ${version}",
|
|
631
|
-
// Align with test expectations
|
|
632
|
-
skipHooks
|
|
633
|
-
} = this.config;
|
|
634
|
-
let pkgsResult;
|
|
635
|
-
try {
|
|
636
|
-
pkgsResult = (0, import_get_packages.getPackagesSync)((0, import_node_process3.cwd)());
|
|
637
|
-
if (!pkgsResult || !pkgsResult.packages) {
|
|
638
|
-
throw new Error("Failed to get packages information");
|
|
639
|
-
}
|
|
640
|
-
} catch (error) {
|
|
641
|
-
log("error", "Failed to get packages information");
|
|
642
|
-
console.error(error);
|
|
643
|
-
(0, import_node_process3.exit)(1);
|
|
644
|
-
return;
|
|
645
|
-
}
|
|
646
|
-
const pkgsToProcess = await this.processPackages(pkgsResult.packages, cliTargets);
|
|
647
|
-
if (pkgsToProcess.length === 0) {
|
|
648
|
-
log("info", "No packages to process based on changes and targets");
|
|
649
|
-
return;
|
|
650
|
-
}
|
|
651
|
-
const formattedCommitMessage = commitMessage;
|
|
652
|
-
try {
|
|
653
|
-
await gitProcess({
|
|
654
|
-
files: pkgsToProcess,
|
|
655
|
-
nextTag: "",
|
|
656
|
-
// No tag for default async
|
|
657
|
-
commitMessage: formattedCommitMessage,
|
|
658
|
-
skipHooks,
|
|
659
|
-
dryRun: this.config.dryRun
|
|
660
|
-
});
|
|
661
|
-
if (!this.config.dryRun) {
|
|
662
|
-
log("success", `Created version commit for ${pkgsToProcess.length} package(s)`);
|
|
663
|
-
}
|
|
664
|
-
} catch (error) {
|
|
665
|
-
log("error", "Failed to create version commit");
|
|
666
|
-
console.error(error);
|
|
667
|
-
(0, import_node_process3.exit)(1);
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
// --- NEW METHOD for Async + Targeted ---
|
|
671
|
-
async asyncTargetedStrategy(cliTargets) {
|
|
524
|
+
async processPackages(packages) {
|
|
672
525
|
var _a;
|
|
673
|
-
const
|
|
674
|
-
tagPrefix,
|
|
675
|
-
skip,
|
|
676
|
-
dryRun,
|
|
677
|
-
skipHooks,
|
|
678
|
-
commitMessage: commitMessageTemplate
|
|
679
|
-
} = this.config;
|
|
526
|
+
const tags = [];
|
|
680
527
|
const updatedPackagesInfo = [];
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
if (!pkgsResult || !pkgsResult.packages) {
|
|
686
|
-
throw new Error("Failed to get packages information");
|
|
687
|
-
}
|
|
688
|
-
} catch (error) {
|
|
689
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
690
|
-
log("error", `Failed to get packages information: ${errorMessage}`);
|
|
691
|
-
(0, import_node_process3.exit)(1);
|
|
528
|
+
const tagPrefix = this.tagPrefix;
|
|
529
|
+
if (!packages || !Array.isArray(packages)) {
|
|
530
|
+
log("Invalid packages data provided. Expected array of packages.", "error");
|
|
531
|
+
return { updatedPackages: [], tags: [] };
|
|
692
532
|
}
|
|
693
|
-
const pkgsToConsider =
|
|
694
|
-
|
|
695
|
-
|
|
533
|
+
const pkgsToConsider = packages.filter((pkg) => {
|
|
534
|
+
var _a2;
|
|
535
|
+
const pkgName = pkg.packageJson.name;
|
|
536
|
+
if ((_a2 = this.skip) == null ? void 0 : _a2.includes(pkgName)) {
|
|
537
|
+
log(`Skipping package ${pkgName} as it's in the skip list.`, "info");
|
|
696
538
|
return false;
|
|
697
539
|
}
|
|
698
|
-
|
|
540
|
+
if (!this.targets || this.targets.length === 0) {
|
|
541
|
+
return true;
|
|
542
|
+
}
|
|
543
|
+
const isTargeted = this.targets.includes(pkgName);
|
|
699
544
|
if (!isTargeted) {
|
|
545
|
+
log(`Package ${pkgName} not in target list, skipping.`, "info");
|
|
700
546
|
}
|
|
701
547
|
return isTargeted;
|
|
702
548
|
});
|
|
703
|
-
log(
|
|
549
|
+
log(`Found ${pkgsToConsider.length} targeted package(s) to process after filtering.`, "info");
|
|
704
550
|
if (pkgsToConsider.length === 0) {
|
|
705
|
-
log("
|
|
706
|
-
return;
|
|
551
|
+
log("No matching targeted packages found to process.", "info");
|
|
552
|
+
return { updatedPackages: [], tags: [] };
|
|
707
553
|
}
|
|
708
554
|
for (const pkg of pkgsToConsider) {
|
|
709
555
|
const name = pkg.packageJson.name;
|
|
710
556
|
const pkgPath = pkg.dir;
|
|
711
557
|
const prefix = formatTagPrefix(tagPrefix);
|
|
712
|
-
const
|
|
713
|
-
const
|
|
558
|
+
const latestTagResult = await this.getLatestTag();
|
|
559
|
+
const latestTag = latestTagResult || "";
|
|
560
|
+
const nextVersion = await calculateVersion(this.fullConfig, {
|
|
714
561
|
latestTag,
|
|
715
562
|
tagPrefix: prefix,
|
|
716
563
|
path: pkgPath,
|
|
@@ -723,111 +570,401 @@ var VersionEngine = class {
|
|
|
723
570
|
if (!nextVersion) {
|
|
724
571
|
continue;
|
|
725
572
|
}
|
|
726
|
-
updatePackageVersion(
|
|
727
|
-
|
|
728
|
-
version: nextVersion,
|
|
729
|
-
name,
|
|
730
|
-
dryRun
|
|
731
|
-
});
|
|
732
|
-
const packageTag = formatTag(
|
|
733
|
-
{ synced: false, name, tagPrefix },
|
|
734
|
-
{ version: nextVersion, tagPrefix }
|
|
735
|
-
);
|
|
573
|
+
updatePackageVersion(import_node_path3.default.join(pkgPath, "package.json"), nextVersion);
|
|
574
|
+
const packageTag = formatTag(nextVersion, tagPrefix);
|
|
736
575
|
const tagMessage = `chore(release): ${name} ${nextVersion}`;
|
|
737
|
-
|
|
576
|
+
addTag(packageTag);
|
|
577
|
+
tags.push(packageTag);
|
|
578
|
+
if (!this.dryRun) {
|
|
738
579
|
try {
|
|
739
580
|
await createGitTag({ tag: packageTag, message: tagMessage });
|
|
740
|
-
log(
|
|
581
|
+
log(`Created tag: ${packageTag}`, "success");
|
|
741
582
|
} catch (tagError) {
|
|
742
583
|
log(
|
|
743
|
-
|
|
744
|
-
|
|
584
|
+
`Failed to create tag ${packageTag} for ${name}: ${tagError.message}`,
|
|
585
|
+
"error"
|
|
745
586
|
);
|
|
746
|
-
log(
|
|
587
|
+
log(tagError.stack || "No stack trace available", "error");
|
|
747
588
|
}
|
|
748
589
|
} else {
|
|
749
|
-
log(
|
|
590
|
+
log(`[DRY RUN] Would create tag: ${packageTag}`, "info");
|
|
750
591
|
}
|
|
751
592
|
updatedPackagesInfo.push({ name, version: nextVersion, path: pkgPath });
|
|
752
593
|
}
|
|
753
594
|
if (updatedPackagesInfo.length === 0) {
|
|
754
|
-
log("
|
|
755
|
-
return;
|
|
595
|
+
log("No targeted packages required a version update.", "info");
|
|
596
|
+
return { updatedPackages: [], tags };
|
|
756
597
|
}
|
|
757
|
-
const filesToCommit = updatedPackagesInfo.map((info) =>
|
|
598
|
+
const filesToCommit = updatedPackagesInfo.map((info) => import_node_path3.default.join(info.path, "package.json"));
|
|
758
599
|
const packageNames = updatedPackagesInfo.map((p) => p.name).join(", ");
|
|
759
600
|
const representativeVersion = ((_a = updatedPackagesInfo[0]) == null ? void 0 : _a.version) || "multiple";
|
|
760
|
-
let commitMessage = commitMessageTemplate || "chore(release): publish packages";
|
|
601
|
+
let commitMessage = this.commitMessageTemplate || "chore(release): publish packages";
|
|
761
602
|
if (updatedPackagesInfo.length === 1 && commitMessage.includes("${version}")) {
|
|
762
603
|
commitMessage = formatCommitMessage(commitMessage, representativeVersion);
|
|
763
604
|
} else {
|
|
764
605
|
commitMessage = `chore(release): ${packageNames} ${representativeVersion}`;
|
|
765
606
|
}
|
|
766
607
|
commitMessage += " [skip-ci]";
|
|
767
|
-
|
|
608
|
+
setCommitMessage(commitMessage);
|
|
609
|
+
if (!this.dryRun) {
|
|
768
610
|
try {
|
|
769
611
|
await gitAdd(filesToCommit);
|
|
770
|
-
await gitCommit({ message: commitMessage, skipHooks });
|
|
771
|
-
log(
|
|
612
|
+
await gitCommit({ message: commitMessage, skipHooks: this.skipHooks });
|
|
613
|
+
log(`Created commit for targeted release: ${packageNames}`, "success");
|
|
772
614
|
} catch (commitError) {
|
|
773
|
-
log("
|
|
615
|
+
log("Failed to create commit for targeted release.", "error");
|
|
774
616
|
console.error(commitError);
|
|
775
|
-
(0,
|
|
617
|
+
(0, import_node_process4.exit)(1);
|
|
776
618
|
}
|
|
777
619
|
} else {
|
|
778
|
-
log("
|
|
620
|
+
log("[DRY RUN] Would add files:", "info");
|
|
779
621
|
for (const file of filesToCommit) {
|
|
780
|
-
log(
|
|
622
|
+
log(` - ${file}`, "info");
|
|
623
|
+
}
|
|
624
|
+
log(`[DRY RUN] Would commit with message: "${commitMessage}"`, "info");
|
|
625
|
+
}
|
|
626
|
+
return {
|
|
627
|
+
updatedPackages: updatedPackagesInfo,
|
|
628
|
+
commitMessage,
|
|
629
|
+
tags
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
// src/core/versionStrategies.ts
|
|
635
|
+
function shouldProcessPackage(pkg, config, targets = []) {
|
|
636
|
+
var _a;
|
|
637
|
+
const pkgName = pkg.packageJson.name;
|
|
638
|
+
if ((_a = config.skip) == null ? void 0 : _a.includes(pkgName)) {
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
if (!targets || targets.length === 0) {
|
|
642
|
+
return true;
|
|
643
|
+
}
|
|
644
|
+
return targets.includes(pkgName);
|
|
645
|
+
}
|
|
646
|
+
function createSyncedStrategy(config) {
|
|
647
|
+
return async (packages) => {
|
|
648
|
+
try {
|
|
649
|
+
const {
|
|
650
|
+
tagPrefix,
|
|
651
|
+
baseBranch,
|
|
652
|
+
branchPattern,
|
|
653
|
+
commitMessage = "chore(release): v${version}",
|
|
654
|
+
prereleaseIdentifier,
|
|
655
|
+
dryRun,
|
|
656
|
+
skipHooks
|
|
657
|
+
} = config;
|
|
658
|
+
const prefix = formatTagPrefix(tagPrefix || "v");
|
|
659
|
+
const latestTag = await getLatestTag();
|
|
660
|
+
const nextVersion = await calculateVersion(config, {
|
|
661
|
+
latestTag,
|
|
662
|
+
tagPrefix: prefix,
|
|
663
|
+
branchPattern,
|
|
664
|
+
baseBranch,
|
|
665
|
+
prereleaseIdentifier
|
|
666
|
+
});
|
|
667
|
+
if (!nextVersion) {
|
|
668
|
+
log("No version change needed", "info");
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
const files = [];
|
|
672
|
+
const updatedPackages = [];
|
|
673
|
+
try {
|
|
674
|
+
const rootPkgPath = import_node_path4.default.join(packages.root, "package.json");
|
|
675
|
+
if (import_node_fs3.default.existsSync(rootPkgPath)) {
|
|
676
|
+
updatePackageVersion(rootPkgPath, nextVersion);
|
|
677
|
+
files.push(rootPkgPath);
|
|
678
|
+
updatedPackages.push("root");
|
|
679
|
+
}
|
|
680
|
+
} catch (_error) {
|
|
681
|
+
log("Failed to update root package.json", "error");
|
|
682
|
+
}
|
|
683
|
+
for (const pkg of packages.packages) {
|
|
684
|
+
if (!shouldProcessPackage(pkg, config)) {
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
const packageJsonPath = import_node_path4.default.join(pkg.dir, "package.json");
|
|
688
|
+
updatePackageVersion(packageJsonPath, nextVersion);
|
|
689
|
+
files.push(packageJsonPath);
|
|
690
|
+
updatedPackages.push(pkg.packageJson.name);
|
|
691
|
+
}
|
|
692
|
+
if (updatedPackages.length > 0) {
|
|
693
|
+
log(`Updated ${updatedPackages.length} package(s) to version ${nextVersion}`, "success");
|
|
694
|
+
} else {
|
|
695
|
+
log("No packages were updated", "warning");
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
const nextTag = formatTag(nextVersion, tagPrefix || "v");
|
|
699
|
+
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
|
|
700
|
+
await createGitCommitAndTag(files, nextTag, formattedCommitMessage, skipHooks, dryRun);
|
|
701
|
+
} catch (error) {
|
|
702
|
+
if (error instanceof VersionError || error instanceof GitError) {
|
|
703
|
+
log(`Synced Strategy failed: ${error.message} (${error.code || "UNKNOWN"})`, "error");
|
|
704
|
+
} else {
|
|
705
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
706
|
+
log(`Synced Strategy failed: ${errorMessage}`, "error");
|
|
707
|
+
}
|
|
708
|
+
throw error;
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
function createSingleStrategy(config) {
|
|
713
|
+
return async (packages) => {
|
|
714
|
+
try {
|
|
715
|
+
const {
|
|
716
|
+
packages: configPackages,
|
|
717
|
+
tagPrefix,
|
|
718
|
+
commitMessage = "chore(release): ${version}",
|
|
719
|
+
dryRun,
|
|
720
|
+
skipHooks
|
|
721
|
+
} = config;
|
|
722
|
+
if (!configPackages || configPackages.length !== 1) {
|
|
723
|
+
throw createVersionError(
|
|
724
|
+
"INVALID_CONFIG" /* INVALID_CONFIG */,
|
|
725
|
+
"Single mode requires exactly one package name"
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
const packageName = configPackages[0];
|
|
729
|
+
const pkg = packages.packages.find((p) => p.packageJson.name === packageName);
|
|
730
|
+
if (!pkg) {
|
|
731
|
+
throw createVersionError("PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */, packageName);
|
|
732
|
+
}
|
|
733
|
+
const pkgPath = pkg.dir;
|
|
734
|
+
const prefix = formatTagPrefix(tagPrefix || "v");
|
|
735
|
+
const latestTag = await getLatestTag();
|
|
736
|
+
let nextVersion = void 0;
|
|
737
|
+
try {
|
|
738
|
+
nextVersion = await calculateVersion(config, {
|
|
739
|
+
latestTag,
|
|
740
|
+
tagPrefix: prefix,
|
|
741
|
+
path: pkgPath,
|
|
742
|
+
name: packageName
|
|
743
|
+
});
|
|
744
|
+
} catch (error) {
|
|
745
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
746
|
+
throw createVersionError("VERSION_CALCULATION_ERROR" /* VERSION_CALCULATION_ERROR */, errorMessage);
|
|
747
|
+
}
|
|
748
|
+
if (nextVersion === void 0 || nextVersion === "") {
|
|
749
|
+
log(`No version change needed for ${packageName}`, "info");
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
const packageJsonPath = import_node_path4.default.join(pkgPath, "package.json");
|
|
753
|
+
updatePackageVersion(packageJsonPath, nextVersion);
|
|
754
|
+
log(`Updated package ${packageName} to version ${nextVersion}`, "success");
|
|
755
|
+
const nextTag = formatTag(nextVersion, tagPrefix || "v");
|
|
756
|
+
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
|
|
757
|
+
await createGitCommitAndTag(
|
|
758
|
+
[packageJsonPath],
|
|
759
|
+
nextTag,
|
|
760
|
+
formattedCommitMessage,
|
|
761
|
+
skipHooks,
|
|
762
|
+
dryRun
|
|
763
|
+
);
|
|
764
|
+
} catch (error) {
|
|
765
|
+
if (error instanceof VersionError || error instanceof GitError) {
|
|
766
|
+
log(
|
|
767
|
+
`Single Package Strategy failed: ${error.message} (${error.code || "UNKNOWN"})`,
|
|
768
|
+
"error"
|
|
769
|
+
);
|
|
770
|
+
} else {
|
|
771
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
772
|
+
log(`Single Package Strategy failed: ${errorMessage}`, "error");
|
|
773
|
+
}
|
|
774
|
+
throw error;
|
|
775
|
+
}
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
function createAsyncStrategy(config) {
|
|
779
|
+
const dependencies = {
|
|
780
|
+
getLatestTag
|
|
781
|
+
};
|
|
782
|
+
const processorOptions = {
|
|
783
|
+
skip: config.skip || [],
|
|
784
|
+
targets: config.packages || [],
|
|
785
|
+
tagPrefix: config.tagPrefix || "v",
|
|
786
|
+
commitMessageTemplate: config.commitMessage || "",
|
|
787
|
+
dryRun: config.dryRun || false,
|
|
788
|
+
skipHooks: config.skipHooks || false,
|
|
789
|
+
getLatestTag: dependencies.getLatestTag,
|
|
790
|
+
fullConfig: config,
|
|
791
|
+
config: {
|
|
792
|
+
branchPattern: config.branchPattern || [],
|
|
793
|
+
baseBranch: config.baseBranch || "main",
|
|
794
|
+
prereleaseIdentifier: config.prereleaseIdentifier,
|
|
795
|
+
forceType: config.forceType
|
|
796
|
+
}
|
|
797
|
+
};
|
|
798
|
+
const packageProcessor = new PackageProcessor(processorOptions);
|
|
799
|
+
return async (packages, targets = []) => {
|
|
800
|
+
try {
|
|
801
|
+
const targetPackages = targets.length > 0 ? targets : config.packages || [];
|
|
802
|
+
packageProcessor.setTargets(targetPackages);
|
|
803
|
+
if (targetPackages.length > 0) {
|
|
804
|
+
log(`Processing targeted packages: ${targetPackages.join(", ")}`, "info");
|
|
805
|
+
} else {
|
|
806
|
+
log("No targets specified, processing all non-skipped packages", "info");
|
|
807
|
+
}
|
|
808
|
+
const result = await packageProcessor.processPackages(packages.packages);
|
|
809
|
+
if (result.updatedPackages.length === 0) {
|
|
810
|
+
log("No packages required a version update.", "info");
|
|
811
|
+
} else {
|
|
812
|
+
const packageNames = result.updatedPackages.map((p) => p.name).join(", ");
|
|
813
|
+
log(`Updated ${result.updatedPackages.length} package(s): ${packageNames}`, "success");
|
|
814
|
+
if (result.tags.length > 0) {
|
|
815
|
+
log(`Created ${result.tags.length} tag(s): ${result.tags.join(", ")}`, "success");
|
|
816
|
+
}
|
|
817
|
+
if (result.commitMessage) {
|
|
818
|
+
log(`Created commit with message: "${result.commitMessage}"`, "success");
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
} catch (error) {
|
|
822
|
+
if (error instanceof VersionError || error instanceof GitError) {
|
|
823
|
+
log(`Async Strategy failed: ${error.message} (${error.code || "UNKNOWN"})`, "error");
|
|
824
|
+
} else {
|
|
825
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
826
|
+
log(`Async Strategy failed: ${errorMessage}`, "error");
|
|
827
|
+
}
|
|
828
|
+
throw error;
|
|
829
|
+
}
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
function createStrategy(config) {
|
|
833
|
+
var _a;
|
|
834
|
+
if (config.synced) {
|
|
835
|
+
return createSyncedStrategy(config);
|
|
836
|
+
}
|
|
837
|
+
if (((_a = config.packages) == null ? void 0 : _a.length) === 1) {
|
|
838
|
+
return createSingleStrategy(config);
|
|
839
|
+
}
|
|
840
|
+
return createAsyncStrategy(config);
|
|
841
|
+
}
|
|
842
|
+
function createStrategyMap(config) {
|
|
843
|
+
return {
|
|
844
|
+
synced: createSyncedStrategy(config),
|
|
845
|
+
single: createSingleStrategy(config),
|
|
846
|
+
async: createAsyncStrategy(config)
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// src/core/versionEngine.ts
|
|
851
|
+
var VersionEngine = class {
|
|
852
|
+
config;
|
|
853
|
+
jsonMode;
|
|
854
|
+
workspaceCache = null;
|
|
855
|
+
strategies;
|
|
856
|
+
currentStrategy;
|
|
857
|
+
constructor(config, jsonMode = false) {
|
|
858
|
+
if (!config) {
|
|
859
|
+
throw createVersionError("CONFIG_REQUIRED" /* CONFIG_REQUIRED */);
|
|
860
|
+
}
|
|
861
|
+
if (!config.preset) {
|
|
862
|
+
config.preset = "conventional-commits";
|
|
863
|
+
log("No preset specified, using default: conventional-commits", "warning");
|
|
864
|
+
}
|
|
865
|
+
this.config = config;
|
|
866
|
+
this.jsonMode = jsonMode;
|
|
867
|
+
this.strategies = createStrategyMap(config);
|
|
868
|
+
this.currentStrategy = createStrategy(config);
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
* Get workspace packages information - with caching for performance
|
|
872
|
+
*/
|
|
873
|
+
async getWorkspacePackages() {
|
|
874
|
+
try {
|
|
875
|
+
if (this.workspaceCache) {
|
|
876
|
+
return this.workspaceCache;
|
|
877
|
+
}
|
|
878
|
+
const pkgsResult = (0, import_get_packages.getPackagesSync)((0, import_node_process5.cwd)());
|
|
879
|
+
if (!pkgsResult || !pkgsResult.packages) {
|
|
880
|
+
throw createVersionError("PACKAGES_NOT_FOUND" /* PACKAGES_NOT_FOUND */);
|
|
781
881
|
}
|
|
782
|
-
|
|
882
|
+
this.workspaceCache = pkgsResult;
|
|
883
|
+
return pkgsResult;
|
|
884
|
+
} catch (error) {
|
|
885
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
886
|
+
log(`Failed to get packages information: ${errorMessage}`, "error");
|
|
887
|
+
console.error(error);
|
|
888
|
+
throw createVersionError("WORKSPACE_ERROR" /* WORKSPACE_ERROR */, errorMessage);
|
|
783
889
|
}
|
|
784
890
|
}
|
|
891
|
+
/**
|
|
892
|
+
* Run the current strategy
|
|
893
|
+
* @param targets Optional package targets to process (only used by async strategy)
|
|
894
|
+
*/
|
|
895
|
+
async run(targets = []) {
|
|
896
|
+
try {
|
|
897
|
+
const packages = await this.getWorkspacePackages();
|
|
898
|
+
return this.currentStrategy(packages, targets);
|
|
899
|
+
} catch (error) {
|
|
900
|
+
if (error instanceof VersionError || error instanceof GitError) {
|
|
901
|
+
log(`Version engine failed: ${error.message} (${error.code || "UNKNOWN"})`, "error");
|
|
902
|
+
} else {
|
|
903
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
904
|
+
log(`Version engine failed: ${errorMessage}`, "error");
|
|
905
|
+
}
|
|
906
|
+
throw error;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Change the current strategy
|
|
911
|
+
* @param strategyType The strategy type to use: 'synced', 'single', or 'async'
|
|
912
|
+
*/
|
|
913
|
+
setStrategy(strategyType) {
|
|
914
|
+
this.currentStrategy = this.strategies[strategyType];
|
|
915
|
+
}
|
|
785
916
|
};
|
|
786
917
|
|
|
787
918
|
// src/index.ts
|
|
788
919
|
async function run() {
|
|
789
|
-
printFiglet();
|
|
790
920
|
const program = new import_commander.Command();
|
|
791
921
|
program.name("package-versioner").description(
|
|
792
|
-
"
|
|
793
|
-
).version(
|
|
794
|
-
"--
|
|
795
|
-
"
|
|
796
|
-
).option(
|
|
797
|
-
"-t, --target <targets>",
|
|
798
|
-
"Comma-separated list of package names to target (only for async strategy)"
|
|
799
|
-
).parse(process.argv);
|
|
922
|
+
"A lightweight yet powerful CLI tool for automated semantic versioning based on Git history and conventional commits."
|
|
923
|
+
).version(process.env.npm_package_version || "0.0.0").option(
|
|
924
|
+
"-c, --config <path>",
|
|
925
|
+
"Path to config file (defaults to version.config.json in current directory)"
|
|
926
|
+
).option("-d, --dry-run", "Dry run (no changes made)", false).option("-b, --bump <type>", "Force specific bump type (patch|minor|major)").option("-p, --prerelease [identifier]", "Create prerelease version").option("-s, --synced", "Force synchronized versioning across all packages").option("-j, --json", "Output results as JSON", false).option("-t, --target <packages>", "Comma-delimited list of package names to target").parse(process.argv);
|
|
800
927
|
const options = program.opts();
|
|
928
|
+
if (options.json) {
|
|
929
|
+
enableJsonOutput(options.dryRun);
|
|
930
|
+
}
|
|
801
931
|
try {
|
|
802
932
|
const config = await loadConfig(options.config);
|
|
803
|
-
log(
|
|
933
|
+
log(`Loaded configuration from ${options.config || "version.config.json"}`, "info");
|
|
804
934
|
if (options.dryRun) config.dryRun = true;
|
|
805
935
|
if (options.synced) config.synced = true;
|
|
806
936
|
if (options.bump) config.forceType = options.bump;
|
|
807
937
|
if (options.prerelease)
|
|
808
938
|
config.prereleaseIdentifier = options.prerelease === true ? "rc" : options.prerelease;
|
|
809
939
|
const cliTargets = options.target ? options.target.split(",").map((t) => t.trim()) : [];
|
|
810
|
-
const engine = new VersionEngine(config);
|
|
940
|
+
const engine = new VersionEngine(config, !!options.json);
|
|
811
941
|
if (config.synced) {
|
|
812
|
-
log("
|
|
813
|
-
|
|
942
|
+
log("Using synced versioning strategy.", "info");
|
|
943
|
+
engine.setStrategy("synced");
|
|
944
|
+
await engine.run();
|
|
814
945
|
} else if (config.packages && config.packages.length === 1) {
|
|
815
|
-
log("
|
|
946
|
+
log("Using single package versioning strategy.", "info");
|
|
816
947
|
if (cliTargets.length > 0) {
|
|
817
|
-
log("
|
|
948
|
+
log("--target flag is ignored for single package strategy.", "warning");
|
|
818
949
|
}
|
|
819
|
-
|
|
950
|
+
engine.setStrategy("single");
|
|
951
|
+
await engine.run();
|
|
820
952
|
} else {
|
|
821
|
-
log("
|
|
953
|
+
log("Using async versioning strategy.", "info");
|
|
822
954
|
if (cliTargets.length > 0) {
|
|
823
|
-
log(
|
|
955
|
+
log(`Targeting specific packages: ${cliTargets.join(", ")}`, "info");
|
|
824
956
|
}
|
|
825
|
-
|
|
957
|
+
engine.setStrategy("async");
|
|
958
|
+
await engine.run(cliTargets);
|
|
826
959
|
}
|
|
827
|
-
log("
|
|
960
|
+
log("Versioning process completed.", "success");
|
|
961
|
+
printJsonOutput();
|
|
828
962
|
} catch (error) {
|
|
829
|
-
log(
|
|
963
|
+
log(error instanceof Error ? error.message : String(error), "error");
|
|
830
964
|
process.exit(1);
|
|
831
965
|
}
|
|
832
966
|
}
|
|
833
|
-
run()
|
|
967
|
+
run().catch((error) => {
|
|
968
|
+
console.error("Fatal error:", error);
|
|
969
|
+
process.exit(1);
|
|
970
|
+
});
|