@releasekit/version 0.1.0 → 0.1.1-next.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 +81 -243
- package/dist/{chunk-GLFC564Q.js → chunk-3JG7UWIT.js} +4 -1
- package/dist/cli.cjs +4 -1
- package/dist/cli.js +1 -1
- package/dist/index.cjs +4 -1
- package/dist/index.js +1 -1
- package/package.json +5 -5
- package/dist/baseError-IKMJCSYK.js +0 -6
- package/dist/chunk-6CLV2DJG.js +0 -2166
- package/dist/chunk-7GDPUNML.js +0 -128
- package/dist/chunk-KZDV4EBO.js +0 -2170
- package/dist/chunk-WEP3ACTS.js +0 -2125
package/dist/chunk-KZDV4EBO.js
DELETED
|
@@ -1,2170 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BaseVersionError
|
|
3
|
-
} from "./chunk-GQLJ7JQY.js";
|
|
4
|
-
|
|
5
|
-
// src/config.ts
|
|
6
|
-
import { loadVersionConfig } from "@releasekit/config";
|
|
7
|
-
|
|
8
|
-
// src/types.ts
|
|
9
|
-
function toVersionConfig(config) {
|
|
10
|
-
if (!config) {
|
|
11
|
-
return {
|
|
12
|
-
tagTemplate: "v{version}",
|
|
13
|
-
packageSpecificTags: false,
|
|
14
|
-
preset: "conventional",
|
|
15
|
-
sync: true,
|
|
16
|
-
packages: [],
|
|
17
|
-
updateInternalDependencies: "minor",
|
|
18
|
-
versionPrefix: ""
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
return {
|
|
22
|
-
tagTemplate: config.tagTemplate ?? "v{version}",
|
|
23
|
-
packageSpecificTags: config.packageSpecificTags,
|
|
24
|
-
preset: config.preset ?? "conventional",
|
|
25
|
-
sync: config.sync ?? true,
|
|
26
|
-
packages: config.packages ?? [],
|
|
27
|
-
mainPackage: config.mainPackage,
|
|
28
|
-
updateInternalDependencies: config.updateInternalDependencies ?? "minor",
|
|
29
|
-
skip: config.skip,
|
|
30
|
-
commitMessage: config.commitMessage,
|
|
31
|
-
versionStrategy: config.versionStrategy,
|
|
32
|
-
branchPatterns: config.branchPatterns?.map((bp) => ({
|
|
33
|
-
pattern: bp.pattern,
|
|
34
|
-
releaseType: bp.releaseType
|
|
35
|
-
})),
|
|
36
|
-
defaultReleaseType: config.defaultReleaseType,
|
|
37
|
-
skipHooks: config.skipHooks,
|
|
38
|
-
mismatchStrategy: config.mismatchStrategy,
|
|
39
|
-
versionPrefix: config.versionPrefix ?? "",
|
|
40
|
-
prereleaseIdentifier: config.prereleaseIdentifier,
|
|
41
|
-
baseBranch: config.baseBranch,
|
|
42
|
-
cargo: config.cargo
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// src/config.ts
|
|
47
|
-
function loadConfig(options) {
|
|
48
|
-
const versionConfig = loadVersionConfig(options);
|
|
49
|
-
return toVersionConfig(versionConfig);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// src/errors/versionError.ts
|
|
53
|
-
var VersionError = class extends BaseVersionError {
|
|
54
|
-
};
|
|
55
|
-
var VersionErrorCode = /* @__PURE__ */ ((VersionErrorCode2) => {
|
|
56
|
-
VersionErrorCode2["CONFIG_REQUIRED"] = "CONFIG_REQUIRED";
|
|
57
|
-
VersionErrorCode2["PACKAGES_NOT_FOUND"] = "PACKAGES_NOT_FOUND";
|
|
58
|
-
VersionErrorCode2["WORKSPACE_ERROR"] = "WORKSPACE_ERROR";
|
|
59
|
-
VersionErrorCode2["INVALID_CONFIG"] = "INVALID_CONFIG";
|
|
60
|
-
VersionErrorCode2["PACKAGE_NOT_FOUND"] = "PACKAGE_NOT_FOUND";
|
|
61
|
-
VersionErrorCode2["VERSION_CALCULATION_ERROR"] = "VERSION_CALCULATION_ERROR";
|
|
62
|
-
return VersionErrorCode2;
|
|
63
|
-
})(VersionErrorCode || {});
|
|
64
|
-
function createVersionError(code, details) {
|
|
65
|
-
const messages = {
|
|
66
|
-
["CONFIG_REQUIRED" /* CONFIG_REQUIRED */]: "Configuration is required",
|
|
67
|
-
["PACKAGES_NOT_FOUND" /* PACKAGES_NOT_FOUND */]: "Failed to get packages information",
|
|
68
|
-
["WORKSPACE_ERROR" /* WORKSPACE_ERROR */]: "Failed to get workspace packages",
|
|
69
|
-
["INVALID_CONFIG" /* INVALID_CONFIG */]: "Invalid configuration",
|
|
70
|
-
["PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */]: "Package not found",
|
|
71
|
-
["VERSION_CALCULATION_ERROR" /* VERSION_CALCULATION_ERROR */]: "Failed to calculate version"
|
|
72
|
-
};
|
|
73
|
-
const suggestions = {
|
|
74
|
-
["CONFIG_REQUIRED" /* CONFIG_REQUIRED */]: [
|
|
75
|
-
"Create a version.config.json file in your project root",
|
|
76
|
-
"Check the documentation for configuration examples"
|
|
77
|
-
],
|
|
78
|
-
["PACKAGES_NOT_FOUND" /* PACKAGES_NOT_FOUND */]: [
|
|
79
|
-
"Ensure package.json or Cargo.toml files exist in your project",
|
|
80
|
-
"Check workspace configuration (pnpm-workspace.yaml, etc.)",
|
|
81
|
-
"Verify file permissions and paths"
|
|
82
|
-
],
|
|
83
|
-
["WORKSPACE_ERROR" /* WORKSPACE_ERROR */]: [
|
|
84
|
-
"Verify workspace configuration files are valid",
|
|
85
|
-
"Check that workspace packages are accessible",
|
|
86
|
-
"Ensure proper monorepo structure"
|
|
87
|
-
],
|
|
88
|
-
["INVALID_CONFIG" /* INVALID_CONFIG */]: [
|
|
89
|
-
"Validate version.config.json syntax",
|
|
90
|
-
"Check configuration against schema",
|
|
91
|
-
"Review documentation for valid configuration options"
|
|
92
|
-
],
|
|
93
|
-
["PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */]: [
|
|
94
|
-
"Verify package name spelling and case",
|
|
95
|
-
"Check if package exists in workspace",
|
|
96
|
-
"Review packages configuration in version.config.json"
|
|
97
|
-
],
|
|
98
|
-
["VERSION_CALCULATION_ERROR" /* VERSION_CALCULATION_ERROR */]: [
|
|
99
|
-
"Ensure git repository has commits",
|
|
100
|
-
"Check conventional commit message format",
|
|
101
|
-
"Verify git tags are properly formatted"
|
|
102
|
-
]
|
|
103
|
-
};
|
|
104
|
-
const baseMessage = messages[code];
|
|
105
|
-
const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
|
|
106
|
-
return new VersionError(fullMessage, code, suggestions[code]);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// src/utils/jsonOutput.ts
|
|
110
|
-
var _jsonOutputMode = false;
|
|
111
|
-
var _jsonData = {
|
|
112
|
-
dryRun: false,
|
|
113
|
-
updates: [],
|
|
114
|
-
changelogs: [],
|
|
115
|
-
tags: []
|
|
116
|
-
};
|
|
117
|
-
function enableJsonOutput(dryRun = false) {
|
|
118
|
-
_jsonOutputMode = true;
|
|
119
|
-
_jsonData.dryRun = dryRun;
|
|
120
|
-
_jsonData.updates = [];
|
|
121
|
-
_jsonData.changelogs = [];
|
|
122
|
-
_jsonData.tags = [];
|
|
123
|
-
_jsonData.commitMessage = void 0;
|
|
124
|
-
}
|
|
125
|
-
function isJsonOutputMode() {
|
|
126
|
-
return _jsonOutputMode;
|
|
127
|
-
}
|
|
128
|
-
function addPackageUpdate(packageName, newVersion, filePath) {
|
|
129
|
-
if (!_jsonOutputMode) return;
|
|
130
|
-
_jsonData.updates.push({
|
|
131
|
-
packageName,
|
|
132
|
-
newVersion,
|
|
133
|
-
filePath
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
function addChangelogData(data) {
|
|
137
|
-
if (!_jsonOutputMode) return;
|
|
138
|
-
_jsonData.changelogs.push(data);
|
|
139
|
-
}
|
|
140
|
-
function addTag(tag) {
|
|
141
|
-
if (!_jsonOutputMode) return;
|
|
142
|
-
_jsonData.tags.push(tag);
|
|
143
|
-
}
|
|
144
|
-
function setCommitMessage(message) {
|
|
145
|
-
if (!_jsonOutputMode) return;
|
|
146
|
-
_jsonData.commitMessage = message;
|
|
147
|
-
}
|
|
148
|
-
function getJsonData() {
|
|
149
|
-
return { ..._jsonData };
|
|
150
|
-
}
|
|
151
|
-
function printJsonOutput() {
|
|
152
|
-
if (_jsonOutputMode) {
|
|
153
|
-
console.log(JSON.stringify(_jsonData, null, 2));
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// src/utils/logging.ts
|
|
158
|
-
import chalk from "chalk";
|
|
159
|
-
import figlet from "figlet";
|
|
160
|
-
function log(message, level = "info") {
|
|
161
|
-
const showDebug = process.env.DEBUG === "true" || process.env.DEBUG === "1";
|
|
162
|
-
if (level === "debug" && !showDebug) {
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
let chalkFn;
|
|
166
|
-
switch (level) {
|
|
167
|
-
case "success":
|
|
168
|
-
chalkFn = chalk.green;
|
|
169
|
-
break;
|
|
170
|
-
case "warning":
|
|
171
|
-
chalkFn = chalk.yellow;
|
|
172
|
-
break;
|
|
173
|
-
case "error":
|
|
174
|
-
chalkFn = chalk.red;
|
|
175
|
-
break;
|
|
176
|
-
case "debug":
|
|
177
|
-
chalkFn = chalk.gray;
|
|
178
|
-
break;
|
|
179
|
-
default:
|
|
180
|
-
chalkFn = chalk.blue;
|
|
181
|
-
}
|
|
182
|
-
if (isJsonOutputMode()) {
|
|
183
|
-
if (level === "error") {
|
|
184
|
-
chalkFn(message);
|
|
185
|
-
console.error(message);
|
|
186
|
-
}
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
const formattedMessage = level === "debug" ? `[DEBUG] ${message}` : message;
|
|
190
|
-
if (level === "error") {
|
|
191
|
-
console.error(chalkFn(formattedMessage));
|
|
192
|
-
} else {
|
|
193
|
-
console.log(chalkFn(formattedMessage));
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// src/core/versionCalculator.ts
|
|
198
|
-
import { cwd } from "process";
|
|
199
|
-
import { Bumper } from "conventional-recommended-bump";
|
|
200
|
-
import semver3 from "semver";
|
|
201
|
-
|
|
202
|
-
// src/git/repository.ts
|
|
203
|
-
import { existsSync, statSync } from "fs";
|
|
204
|
-
import { join } from "path";
|
|
205
|
-
|
|
206
|
-
// src/git/commandExecutor.ts
|
|
207
|
-
import { execFile, execFileSync } from "child_process";
|
|
208
|
-
var execAsync = (file, args, options) => {
|
|
209
|
-
const defaultOptions = { maxBuffer: 1024 * 1024 * 10, ...options };
|
|
210
|
-
return new Promise((resolve2, reject) => {
|
|
211
|
-
execFile(file, args, defaultOptions, (error, stdout, stderr) => {
|
|
212
|
-
if (error) {
|
|
213
|
-
reject(error);
|
|
214
|
-
} else {
|
|
215
|
-
resolve2({ stdout: stdout.toString(), stderr: stderr.toString() });
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
});
|
|
219
|
-
};
|
|
220
|
-
var execSync = (file, args, options) => execFileSync(file, args, { maxBuffer: 1024 * 1024 * 10, ...options });
|
|
221
|
-
|
|
222
|
-
// src/git/repository.ts
|
|
223
|
-
function isGitRepository(directory) {
|
|
224
|
-
const gitDir = join(directory, ".git");
|
|
225
|
-
if (!existsSync(gitDir)) {
|
|
226
|
-
return false;
|
|
227
|
-
}
|
|
228
|
-
const stats = statSync(gitDir);
|
|
229
|
-
if (!stats.isDirectory()) {
|
|
230
|
-
return false;
|
|
231
|
-
}
|
|
232
|
-
try {
|
|
233
|
-
execSync("git", ["rev-parse", "--is-inside-work-tree"], { cwd: directory });
|
|
234
|
-
return true;
|
|
235
|
-
} catch (_error) {
|
|
236
|
-
return false;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
function getCurrentBranch() {
|
|
240
|
-
const result = execSync("git", ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
241
|
-
return result.toString().trim();
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// src/git/tagsAndBranches.ts
|
|
245
|
-
import { getSemverTags } from "git-semver-tags";
|
|
246
|
-
import semver from "semver";
|
|
247
|
-
|
|
248
|
-
// src/utils/formatting.ts
|
|
249
|
-
function escapeRegExp(string) {
|
|
250
|
-
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
251
|
-
}
|
|
252
|
-
function formatVersionPrefix(prefix) {
|
|
253
|
-
return prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
|
|
254
|
-
}
|
|
255
|
-
function formatTag(version, prefix, packageName, template, packageSpecificTags) {
|
|
256
|
-
if (template?.includes("${packageName}") && !packageName) {
|
|
257
|
-
log(
|
|
258
|
-
`Warning: Your tagTemplate contains \${packageName} but no package name is available.
|
|
259
|
-
This will result in an empty package name in the tag (e.g., "@v1.0.0" instead of "my-package@v1.0.0").
|
|
260
|
-
|
|
261
|
-
To fix this:
|
|
262
|
-
\u2022 If using sync mode: Set "packageSpecificTags": true in your config to enable package names in tags
|
|
263
|
-
\u2022 If you want global tags: Remove \${packageName} from your tagTemplate (e.g., use "\${prefix}\${version}")
|
|
264
|
-
\u2022 If using single/async mode: Ensure your package.json has a valid "name" field`,
|
|
265
|
-
"warning"
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
if (template) {
|
|
269
|
-
return template.replace(/\$\{version\}/g, version).replace(/\$\{prefix\}/g, prefix).replace(/\$\{packageName\}/g, packageName || "");
|
|
270
|
-
}
|
|
271
|
-
if (packageSpecificTags && packageName) {
|
|
272
|
-
return `${packageName}@${prefix}${version}`;
|
|
273
|
-
}
|
|
274
|
-
return `${prefix}${version}`;
|
|
275
|
-
}
|
|
276
|
-
function formatCommitMessage(template, version, packageName, additionalContext) {
|
|
277
|
-
if (template.includes("${packageName}") && !packageName) {
|
|
278
|
-
log(
|
|
279
|
-
`Warning: Your commitMessage template contains \${packageName} but no package name is available.
|
|
280
|
-
This will result in an empty package name in the commit message (e.g., "Release @v1.0.0").
|
|
281
|
-
|
|
282
|
-
To fix this:
|
|
283
|
-
\u2022 If using sync mode: Set "packageSpecificTags": true to enable package names in commits
|
|
284
|
-
\u2022 If you want generic commit messages: Remove \${packageName} from your commitMessage template
|
|
285
|
-
\u2022 If using single/async mode: Ensure your package.json has a valid "name" field`,
|
|
286
|
-
"warning"
|
|
287
|
-
);
|
|
288
|
-
}
|
|
289
|
-
let result = template.replace(/\$\{version\}/g, version).replace(/\$\{packageName\}/g, packageName || "");
|
|
290
|
-
if (additionalContext) {
|
|
291
|
-
for (const [key, value] of Object.entries(additionalContext)) {
|
|
292
|
-
const placeholder = `\${${key}}`;
|
|
293
|
-
result = result.replace(new RegExp(placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), value);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
return result;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// src/git/tagsAndBranches.ts
|
|
300
|
-
function getCommitsLength(pkgRoot, sinceTag) {
|
|
301
|
-
try {
|
|
302
|
-
let amount;
|
|
303
|
-
if (sinceTag && sinceTag.trim() !== "") {
|
|
304
|
-
amount = execSync("git", ["rev-list", "--count", `${sinceTag}..HEAD`, pkgRoot]).toString().trim();
|
|
305
|
-
} else {
|
|
306
|
-
const latestTag = execSync("git", ["describe", "--tags", "--abbrev=0"]).toString().trim();
|
|
307
|
-
amount = execSync("git", ["rev-list", "--count", "HEAD", `^${latestTag}`, pkgRoot]).toString().trim();
|
|
308
|
-
}
|
|
309
|
-
return Number(amount);
|
|
310
|
-
} catch (error) {
|
|
311
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
312
|
-
log(`Failed to get number of commits since last tag: ${errorMessage}`, "error");
|
|
313
|
-
return 0;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
async function getLatestTag(versionPrefix) {
|
|
317
|
-
try {
|
|
318
|
-
const tags = await getSemverTags({
|
|
319
|
-
tagPrefix: versionPrefix
|
|
320
|
-
});
|
|
321
|
-
if (tags.length === 0) {
|
|
322
|
-
return "";
|
|
323
|
-
}
|
|
324
|
-
const chronologicalLatest = tags[0];
|
|
325
|
-
const sortedTags = [...tags].sort((a, b) => {
|
|
326
|
-
const versionA = semver.clean(a) || "0.0.0";
|
|
327
|
-
const versionB = semver.clean(b) || "0.0.0";
|
|
328
|
-
return semver.rcompare(versionA, versionB);
|
|
329
|
-
});
|
|
330
|
-
const semanticLatest = sortedTags[0];
|
|
331
|
-
if (semanticLatest !== chronologicalLatest) {
|
|
332
|
-
log(
|
|
333
|
-
`Tag ordering differs: chronological latest is ${chronologicalLatest}, semantic latest is ${semanticLatest}`,
|
|
334
|
-
"debug"
|
|
335
|
-
);
|
|
336
|
-
log(`Using semantic latest (${semanticLatest}) to handle out-of-order tag creation`, "info");
|
|
337
|
-
}
|
|
338
|
-
return semanticLatest;
|
|
339
|
-
} catch (error) {
|
|
340
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
341
|
-
log(`Failed to get latest tag: ${errorMessage}`, "error");
|
|
342
|
-
if (error instanceof Error && error.message.includes("No names found")) {
|
|
343
|
-
log("No tags found in the repository.", "info");
|
|
344
|
-
}
|
|
345
|
-
return "";
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
async function lastMergeBranchName(branches, baseBranch) {
|
|
349
|
-
try {
|
|
350
|
-
const escapedBranches = branches.map((branch) => escapeRegExp(branch));
|
|
351
|
-
const branchesRegex = `${escapedBranches.join("/(.*)|")}/(.*)`;
|
|
352
|
-
const { stdout } = await execAsync("git", [
|
|
353
|
-
"for-each-ref",
|
|
354
|
-
"--sort=-committerdate",
|
|
355
|
-
"--format=%(refname:short)",
|
|
356
|
-
"refs/heads",
|
|
357
|
-
`--merged=${baseBranch}`
|
|
358
|
-
]);
|
|
359
|
-
const regex = new RegExp(branchesRegex, "i");
|
|
360
|
-
const matched = stdout.split("\n").map((l) => l.trim()).filter(Boolean).find((b) => regex.test(b));
|
|
361
|
-
return matched ?? null;
|
|
362
|
-
} catch (error) {
|
|
363
|
-
console.error("Error while getting the last branch name:", error instanceof Error ? error.message : String(error));
|
|
364
|
-
return null;
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
async function getLatestTagForPackage(packageName, versionPrefix, options) {
|
|
368
|
-
try {
|
|
369
|
-
const tagTemplate = options?.tagTemplate || `\${prefix}\${version}`;
|
|
370
|
-
const packageSpecificTags = options?.packageSpecificTags ?? false;
|
|
371
|
-
const escapedPackageName = escapeRegExp(packageName);
|
|
372
|
-
const escapedPrefix = versionPrefix ? escapeRegExp(versionPrefix) : "";
|
|
373
|
-
log(
|
|
374
|
-
`Looking for tags for package ${packageName} with prefix ${versionPrefix || "none"}, packageSpecificTags: ${packageSpecificTags}`,
|
|
375
|
-
"debug"
|
|
376
|
-
);
|
|
377
|
-
const allTags = await getSemverTags({
|
|
378
|
-
tagPrefix: versionPrefix
|
|
379
|
-
});
|
|
380
|
-
log(`Retrieved ${allTags.length} tags: ${allTags.join(", ")}`, "debug");
|
|
381
|
-
if (packageSpecificTags) {
|
|
382
|
-
const packageTagPattern = escapeRegExp(tagTemplate).replace(/\\\$\\\{packageName\\\}/g, `(?:${escapedPackageName})`).replace(/\\\$\\\{prefix\\\}/g, `(?:${escapedPrefix})`).replace(/\\\$\\\{version\\\}/g, "(?:[0-9]+\\.[0-9]+\\.[0-9]+(?:-[a-zA-Z0-9.-]+)?)");
|
|
383
|
-
log(`Using package tag pattern: ${packageTagPattern}`, "debug");
|
|
384
|
-
const packageTagRegex = new RegExp(`^${packageTagPattern}$`);
|
|
385
|
-
let packageTags = allTags.filter((tag) => packageTagRegex.test(tag));
|
|
386
|
-
if (packageTags.length > 0) {
|
|
387
|
-
const chronologicalFirst = packageTags[0];
|
|
388
|
-
const sortedPackageTags2 = [...packageTags].sort((a, b) => {
|
|
389
|
-
let versionA = "";
|
|
390
|
-
let versionB = "";
|
|
391
|
-
if (a.includes("@")) {
|
|
392
|
-
const afterAt = a.split("@")[1] || "";
|
|
393
|
-
versionA = afterAt.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
394
|
-
} else {
|
|
395
|
-
versionA = a.replace(new RegExp(`^${escapeRegExp(packageName)}`), "").replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
396
|
-
}
|
|
397
|
-
if (b.includes("@")) {
|
|
398
|
-
const afterAtB = b.split("@")[1] || "";
|
|
399
|
-
versionB = afterAtB.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
400
|
-
} else {
|
|
401
|
-
versionB = b.replace(new RegExp(`^${escapeRegExp(packageName)}`), "").replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
402
|
-
}
|
|
403
|
-
const cleanVersionA = semver.clean(versionA) || "0.0.0";
|
|
404
|
-
const cleanVersionB = semver.clean(versionB) || "0.0.0";
|
|
405
|
-
return semver.rcompare(cleanVersionA, cleanVersionB);
|
|
406
|
-
});
|
|
407
|
-
log(`Found ${packageTags.length} package tags using configured pattern`, "debug");
|
|
408
|
-
log(`Using semantically latest tag: ${sortedPackageTags2[0]}`, "debug");
|
|
409
|
-
if (sortedPackageTags2[0] !== chronologicalFirst) {
|
|
410
|
-
log(
|
|
411
|
-
`Package tag ordering differs: chronological first is ${chronologicalFirst}, semantic latest is ${sortedPackageTags2[0]}`,
|
|
412
|
-
"debug"
|
|
413
|
-
);
|
|
414
|
-
}
|
|
415
|
-
return sortedPackageTags2[0];
|
|
416
|
-
}
|
|
417
|
-
if (versionPrefix) {
|
|
418
|
-
const pattern1 = new RegExp(`^${escapedPackageName}@${escapeRegExp(versionPrefix)}`);
|
|
419
|
-
packageTags = allTags.filter((tag) => pattern1.test(tag));
|
|
420
|
-
if (packageTags.length > 0) {
|
|
421
|
-
const sortedPackageTags2 = [...packageTags].sort((a, b) => {
|
|
422
|
-
const afterAt = a.split("@")[1] || "";
|
|
423
|
-
const versionA = afterAt.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
424
|
-
const afterAtB = b.split("@")[1] || "";
|
|
425
|
-
const versionB = afterAtB.replace(new RegExp(`^${escapeRegExp(versionPrefix || "")}`), "");
|
|
426
|
-
const cleanVersionA = semver.clean(versionA) || "0.0.0";
|
|
427
|
-
const cleanVersionB = semver.clean(versionB) || "0.0.0";
|
|
428
|
-
return semver.rcompare(cleanVersionA, cleanVersionB);
|
|
429
|
-
});
|
|
430
|
-
log(`Found ${packageTags.length} package tags using pattern: packageName@${versionPrefix}...`, "debug");
|
|
431
|
-
log(`Using semantically latest tag: ${sortedPackageTags2[0]}`, "debug");
|
|
432
|
-
return sortedPackageTags2[0];
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
if (versionPrefix) {
|
|
436
|
-
const pattern2 = new RegExp(`^${escapeRegExp(versionPrefix)}${escapedPackageName}@`);
|
|
437
|
-
packageTags = allTags.filter((tag) => pattern2.test(tag));
|
|
438
|
-
if (packageTags.length > 0) {
|
|
439
|
-
const sortedPackageTags2 = [...packageTags].sort((a, b) => {
|
|
440
|
-
const versionA = semver.clean(a.split("@")[1] || "") || "0.0.0";
|
|
441
|
-
const versionB = semver.clean(b.split("@")[1] || "") || "0.0.0";
|
|
442
|
-
return semver.rcompare(versionA, versionB);
|
|
443
|
-
});
|
|
444
|
-
log(`Found ${packageTags.length} package tags using pattern: ${versionPrefix}packageName@...`, "debug");
|
|
445
|
-
log(`Using semantically latest tag: ${sortedPackageTags2[0]}`, "debug");
|
|
446
|
-
return sortedPackageTags2[0];
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
const pattern3 = new RegExp(`^${escapedPackageName}@`);
|
|
450
|
-
packageTags = allTags.filter((tag) => pattern3.test(tag));
|
|
451
|
-
if (packageTags.length === 0) {
|
|
452
|
-
log("No matching tags found for pattern: packageName@version", "debug");
|
|
453
|
-
if (allTags.length > 0) {
|
|
454
|
-
log(`Available tags: ${allTags.join(", ")}`, "debug");
|
|
455
|
-
} else {
|
|
456
|
-
log("No tags available in the repository", "debug");
|
|
457
|
-
}
|
|
458
|
-
return "";
|
|
459
|
-
}
|
|
460
|
-
const sortedPackageTags = [...packageTags].sort((a, b) => {
|
|
461
|
-
const versionA = semver.clean(a.split("@")[1] || "") || "0.0.0";
|
|
462
|
-
const versionB = semver.clean(b.split("@")[1] || "") || "0.0.0";
|
|
463
|
-
return semver.rcompare(versionA, versionB);
|
|
464
|
-
});
|
|
465
|
-
log(`Found ${packageTags.length} package tags for ${packageName}`, "debug");
|
|
466
|
-
log(`Using semantically latest tag: ${sortedPackageTags[0]}`, "debug");
|
|
467
|
-
return sortedPackageTags[0];
|
|
468
|
-
}
|
|
469
|
-
log(`Package-specific tags disabled for ${packageName}, falling back to global tags`, "debug");
|
|
470
|
-
return "";
|
|
471
|
-
} catch (error) {
|
|
472
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
473
|
-
log(`Failed to get latest tag for package ${packageName}: ${errorMessage}`, "error");
|
|
474
|
-
if (error instanceof Error && error.message.includes("No names found")) {
|
|
475
|
-
log(`No tags found for package ${packageName}.`, "info");
|
|
476
|
-
}
|
|
477
|
-
return "";
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
// src/utils/manifestHelpers.ts
|
|
482
|
-
import fs2 from "fs";
|
|
483
|
-
import path2 from "path";
|
|
484
|
-
|
|
485
|
-
// src/cargo/cargoHandler.ts
|
|
486
|
-
import fs from "fs";
|
|
487
|
-
import path from "path";
|
|
488
|
-
import { isCargoToml, parseCargoToml } from "@releasekit/config";
|
|
489
|
-
import * as TOML from "smol-toml";
|
|
490
|
-
function getCargoInfo(cargoPath) {
|
|
491
|
-
if (!fs.existsSync(cargoPath)) {
|
|
492
|
-
log(`Cargo.toml file not found at: ${cargoPath}`, "error");
|
|
493
|
-
throw new Error(`Cargo.toml file not found at: ${cargoPath}`);
|
|
494
|
-
}
|
|
495
|
-
try {
|
|
496
|
-
const cargo = parseCargoToml(cargoPath);
|
|
497
|
-
if (!cargo.package?.name) {
|
|
498
|
-
log(`Package name not found in: ${cargoPath}`, "error");
|
|
499
|
-
throw new Error(`Package name not found in: ${cargoPath}`);
|
|
500
|
-
}
|
|
501
|
-
return {
|
|
502
|
-
name: cargo.package.name,
|
|
503
|
-
version: cargo.package.version || "0.0.0",
|
|
504
|
-
path: cargoPath,
|
|
505
|
-
dir: path.dirname(cargoPath),
|
|
506
|
-
content: cargo
|
|
507
|
-
};
|
|
508
|
-
} catch (error) {
|
|
509
|
-
log(`Error reading Cargo.toml: ${cargoPath}`, "error");
|
|
510
|
-
if (error instanceof Error) {
|
|
511
|
-
log(error.message, "error");
|
|
512
|
-
throw error;
|
|
513
|
-
}
|
|
514
|
-
throw new Error(`Failed to process Cargo.toml at ${cargoPath}`);
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
function updateCargoVersion(cargoPath, version) {
|
|
518
|
-
try {
|
|
519
|
-
const cargo = parseCargoToml(cargoPath);
|
|
520
|
-
const packageName = cargo.package?.name;
|
|
521
|
-
if (!packageName) {
|
|
522
|
-
throw new Error(`No package name found in ${cargoPath}`);
|
|
523
|
-
}
|
|
524
|
-
if (!cargo.package) {
|
|
525
|
-
cargo.package = { name: packageName, version };
|
|
526
|
-
} else {
|
|
527
|
-
cargo.package.version = version;
|
|
528
|
-
}
|
|
529
|
-
const updatedContent = TOML.stringify(cargo);
|
|
530
|
-
fs.writeFileSync(cargoPath, updatedContent);
|
|
531
|
-
addPackageUpdate(packageName, version, cargoPath);
|
|
532
|
-
log(`Updated Cargo.toml at ${cargoPath} to version ${version}`, "success");
|
|
533
|
-
} catch (error) {
|
|
534
|
-
log(`Failed to update Cargo.toml at ${cargoPath}`, "error");
|
|
535
|
-
if (error instanceof Error) {
|
|
536
|
-
log(error.message, "error");
|
|
537
|
-
}
|
|
538
|
-
throw error;
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
// src/utils/manifestHelpers.ts
|
|
543
|
-
function getVersionFromManifests(packageDir) {
|
|
544
|
-
const packageJsonPath = path2.join(packageDir, "package.json");
|
|
545
|
-
const cargoTomlPath = path2.join(packageDir, "Cargo.toml");
|
|
546
|
-
if (fs2.existsSync(packageJsonPath)) {
|
|
547
|
-
try {
|
|
548
|
-
const packageJson = JSON.parse(fs2.readFileSync(packageJsonPath, "utf-8"));
|
|
549
|
-
if (packageJson.version) {
|
|
550
|
-
log(`Found version ${packageJson.version} in package.json`, "debug");
|
|
551
|
-
return {
|
|
552
|
-
version: packageJson.version,
|
|
553
|
-
manifestFound: true,
|
|
554
|
-
manifestPath: packageJsonPath,
|
|
555
|
-
manifestType: "package.json"
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
log("No version field found in package.json", "debug");
|
|
559
|
-
} catch (packageJsonError) {
|
|
560
|
-
const errMsg = packageJsonError instanceof Error ? packageJsonError.message : String(packageJsonError);
|
|
561
|
-
log(`Error reading package.json: ${errMsg}`, "warning");
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
if (fs2.existsSync(cargoTomlPath)) {
|
|
565
|
-
try {
|
|
566
|
-
const cargoInfo = getCargoInfo(cargoTomlPath);
|
|
567
|
-
if (cargoInfo.version) {
|
|
568
|
-
log(`Found version ${cargoInfo.version} in Cargo.toml`, "debug");
|
|
569
|
-
return {
|
|
570
|
-
version: cargoInfo.version,
|
|
571
|
-
manifestFound: true,
|
|
572
|
-
manifestPath: cargoTomlPath,
|
|
573
|
-
manifestType: "Cargo.toml"
|
|
574
|
-
};
|
|
575
|
-
}
|
|
576
|
-
log("No version field found in Cargo.toml", "debug");
|
|
577
|
-
} catch (cargoTomlError) {
|
|
578
|
-
const errMsg = cargoTomlError instanceof Error ? cargoTomlError.message : String(cargoTomlError);
|
|
579
|
-
log(`Error reading Cargo.toml: ${errMsg}`, "warning");
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
return {
|
|
583
|
-
version: null,
|
|
584
|
-
manifestFound: false,
|
|
585
|
-
manifestPath: "",
|
|
586
|
-
manifestType: null
|
|
587
|
-
};
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
// src/utils/versionUtils.ts
|
|
591
|
-
import fs3 from "fs";
|
|
592
|
-
import { parseCargoToml as parseCargoToml2 } from "@releasekit/config";
|
|
593
|
-
import semver2 from "semver";
|
|
594
|
-
|
|
595
|
-
// src/git/tagVerification.ts
|
|
596
|
-
function verifyTag(tagName, cwd4) {
|
|
597
|
-
if (!tagName || tagName.trim() === "") {
|
|
598
|
-
return { exists: false, reachable: false, error: "Empty tag name" };
|
|
599
|
-
}
|
|
600
|
-
try {
|
|
601
|
-
execSync("git", ["rev-parse", "--verify", tagName], {
|
|
602
|
-
cwd: cwd4,
|
|
603
|
-
stdio: "ignore"
|
|
604
|
-
});
|
|
605
|
-
return { exists: true, reachable: true };
|
|
606
|
-
} catch (error) {
|
|
607
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
608
|
-
if (errorMessage.includes("unknown revision") || errorMessage.includes("bad revision") || errorMessage.includes("No such ref")) {
|
|
609
|
-
return {
|
|
610
|
-
exists: false,
|
|
611
|
-
reachable: false,
|
|
612
|
-
error: `Tag '${tagName}' not found in repository`
|
|
613
|
-
};
|
|
614
|
-
}
|
|
615
|
-
return {
|
|
616
|
-
exists: false,
|
|
617
|
-
reachable: false,
|
|
618
|
-
error: `Git error: ${errorMessage}`
|
|
619
|
-
};
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
// src/utils/versionUtils.ts
|
|
624
|
-
var STANDARD_BUMP_TYPES = ["major", "minor", "patch"];
|
|
625
|
-
function normalizePrereleaseIdentifier(prereleaseIdentifier, config) {
|
|
626
|
-
if (prereleaseIdentifier === true) {
|
|
627
|
-
return config?.prereleaseIdentifier || "next";
|
|
628
|
-
}
|
|
629
|
-
if (typeof prereleaseIdentifier === "string") {
|
|
630
|
-
return prereleaseIdentifier;
|
|
631
|
-
}
|
|
632
|
-
return void 0;
|
|
633
|
-
}
|
|
634
|
-
function bumpVersion(currentVersion, bumpType, prereleaseIdentifier) {
|
|
635
|
-
if (prereleaseIdentifier && STANDARD_BUMP_TYPES.includes(bumpType) && !semver2.prerelease(currentVersion)) {
|
|
636
|
-
const preBumpType = `pre${bumpType}`;
|
|
637
|
-
log(`Creating prerelease version with identifier '${prereleaseIdentifier}' using ${preBumpType}`, "debug");
|
|
638
|
-
return semver2.inc(currentVersion, preBumpType, prereleaseIdentifier) || "";
|
|
639
|
-
}
|
|
640
|
-
if (semver2.prerelease(currentVersion) && STANDARD_BUMP_TYPES.includes(bumpType)) {
|
|
641
|
-
const parsed = semver2.parse(currentVersion);
|
|
642
|
-
if (!parsed) {
|
|
643
|
-
return semver2.inc(currentVersion, bumpType) || "";
|
|
644
|
-
}
|
|
645
|
-
if (bumpType === "major" && parsed.minor === 0 && parsed.patch === 0 || bumpType === "minor" && parsed.patch === 0 || bumpType === "patch") {
|
|
646
|
-
log(`Cleaning prerelease identifier from ${currentVersion} for ${bumpType} bump`, "debug");
|
|
647
|
-
return `${parsed.major}.${parsed.minor}.${parsed.patch}`;
|
|
648
|
-
}
|
|
649
|
-
log(`Standard increment for ${currentVersion} with ${bumpType} bump`, "debug");
|
|
650
|
-
return semver2.inc(currentVersion, bumpType) || "";
|
|
651
|
-
}
|
|
652
|
-
if (prereleaseIdentifier) {
|
|
653
|
-
return semver2.inc(currentVersion, bumpType, prereleaseIdentifier) || "";
|
|
654
|
-
}
|
|
655
|
-
return semver2.inc(currentVersion, bumpType) || "";
|
|
656
|
-
}
|
|
657
|
-
function detectVersionMismatch(tagVersion, packageVersion) {
|
|
658
|
-
const tagIsPrerelease = semver2.prerelease(tagVersion) !== null;
|
|
659
|
-
const packageIsPrerelease = semver2.prerelease(packageVersion) !== null;
|
|
660
|
-
const tagParsed = semver2.parse(tagVersion);
|
|
661
|
-
const packageParsed = semver2.parse(packageVersion);
|
|
662
|
-
if (!tagParsed || !packageParsed) {
|
|
663
|
-
return { isMismatch: false, severity: "minor", message: "" };
|
|
664
|
-
}
|
|
665
|
-
if (!tagIsPrerelease && packageIsPrerelease && tagParsed.major === packageParsed.major) {
|
|
666
|
-
return {
|
|
667
|
-
isMismatch: true,
|
|
668
|
-
severity: "major",
|
|
669
|
-
message: `Git tag ${tagVersion} (stable) is ahead of package ${packageVersion} (prerelease). This may indicate a reverted release. Consider deleting tag ${tagVersion} or updating package.json.`
|
|
670
|
-
};
|
|
671
|
-
}
|
|
672
|
-
const tagHigher = semver2.gt(tagVersion, packageVersion);
|
|
673
|
-
if (tagHigher) {
|
|
674
|
-
const diff = semver2.diff(packageVersion, tagVersion);
|
|
675
|
-
if (diff === "major" || diff === "minor") {
|
|
676
|
-
return {
|
|
677
|
-
isMismatch: true,
|
|
678
|
-
severity: "major",
|
|
679
|
-
message: `Git tag ${tagVersion} is significantly ahead (${diff}) of package ${packageVersion}. This may cause unexpected version bumps.`
|
|
680
|
-
};
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
if (tagIsPrerelease && !packageIsPrerelease) {
|
|
684
|
-
return {
|
|
685
|
-
isMismatch: true,
|
|
686
|
-
severity: "minor",
|
|
687
|
-
message: `Git tag ${tagVersion} is a prerelease but package ${packageVersion} is stable. Consider aligning your versioning.`
|
|
688
|
-
};
|
|
689
|
-
}
|
|
690
|
-
return { isMismatch: false, severity: "minor", message: "" };
|
|
691
|
-
}
|
|
692
|
-
var VersionMismatchError = class extends Error {
|
|
693
|
-
constructor(message, severity) {
|
|
694
|
-
super(message);
|
|
695
|
-
this.severity = severity;
|
|
696
|
-
this.name = "VersionMismatchError";
|
|
697
|
-
}
|
|
698
|
-
};
|
|
699
|
-
async function getBestVersionSource(tagName, packageVersion, cwd4, mismatchStrategy = "error") {
|
|
700
|
-
if (!tagName?.trim()) {
|
|
701
|
-
return packageVersion ? { source: "package", version: packageVersion, reason: "No git tag provided" } : { source: "initial", version: "0.1.0", reason: "No git tag or package version available" };
|
|
702
|
-
}
|
|
703
|
-
const verification = verifyTag(tagName, cwd4);
|
|
704
|
-
if (!verification.exists || !verification.reachable) {
|
|
705
|
-
if (packageVersion) {
|
|
706
|
-
log(
|
|
707
|
-
`Git tag '${tagName}' unreachable (${verification.error}), using package version: ${packageVersion}`,
|
|
708
|
-
"warning"
|
|
709
|
-
);
|
|
710
|
-
return { source: "package", version: packageVersion, reason: "Git tag unreachable" };
|
|
711
|
-
}
|
|
712
|
-
log(`Git tag '${tagName}' unreachable and no package version available, using initial version`, "warning");
|
|
713
|
-
return {
|
|
714
|
-
source: "initial",
|
|
715
|
-
version: "0.1.0",
|
|
716
|
-
reason: "Git tag unreachable, no package version"
|
|
717
|
-
};
|
|
718
|
-
}
|
|
719
|
-
if (!packageVersion) {
|
|
720
|
-
return {
|
|
721
|
-
source: "git",
|
|
722
|
-
version: tagName,
|
|
723
|
-
reason: "Git tag exists, no package version to compare"
|
|
724
|
-
};
|
|
725
|
-
}
|
|
726
|
-
try {
|
|
727
|
-
const cleanTagVersion = tagName.replace(/^.*?([0-9])/, "$1");
|
|
728
|
-
const cleanPackageVersion = packageVersion;
|
|
729
|
-
const mismatch = detectVersionMismatch(cleanTagVersion, cleanPackageVersion);
|
|
730
|
-
const mismatchInfo = mismatch.isMismatch ? { detected: true, severity: mismatch.severity, message: mismatch.message } : void 0;
|
|
731
|
-
if (mismatch.isMismatch) {
|
|
732
|
-
switch (mismatchStrategy) {
|
|
733
|
-
case "error":
|
|
734
|
-
throw new VersionMismatchError(
|
|
735
|
-
`Version mismatch detected: ${mismatch.message}
|
|
736
|
-
To resolve: delete the conflicting tag, update package.json, or change mismatchStrategy to 'warn' or 'ignore'`,
|
|
737
|
-
mismatch.severity
|
|
738
|
-
);
|
|
739
|
-
case "warn":
|
|
740
|
-
log(mismatch.message, "warning");
|
|
741
|
-
log(
|
|
742
|
-
`Continuing with git tag ${tagName}. To use package version instead, set mismatchStrategy to 'prefer-package'`,
|
|
743
|
-
"warning"
|
|
744
|
-
);
|
|
745
|
-
break;
|
|
746
|
-
case "ignore":
|
|
747
|
-
break;
|
|
748
|
-
case "prefer-package":
|
|
749
|
-
log(mismatch.message, "warning");
|
|
750
|
-
log(`Using package version ${packageVersion} due to mismatchStrategy='prefer-package'`, "info");
|
|
751
|
-
return {
|
|
752
|
-
source: "package",
|
|
753
|
-
version: packageVersion,
|
|
754
|
-
reason: "Mismatch detected, using package version per strategy",
|
|
755
|
-
mismatch: mismatchInfo
|
|
756
|
-
};
|
|
757
|
-
case "prefer-git":
|
|
758
|
-
log(mismatch.message, "warning");
|
|
759
|
-
log(`Using git tag ${tagName} due to mismatchStrategy='prefer-git'`, "info");
|
|
760
|
-
return {
|
|
761
|
-
source: "git",
|
|
762
|
-
version: tagName,
|
|
763
|
-
reason: "Mismatch detected, using git tag per strategy",
|
|
764
|
-
mismatch: mismatchInfo
|
|
765
|
-
};
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
if (semver2.gt(cleanPackageVersion, cleanTagVersion)) {
|
|
769
|
-
log(`Package version ${packageVersion} is newer than git tag ${tagName}, using package version`, "info");
|
|
770
|
-
return {
|
|
771
|
-
source: "package",
|
|
772
|
-
version: packageVersion,
|
|
773
|
-
reason: "Package version is newer",
|
|
774
|
-
mismatch: mismatchInfo
|
|
775
|
-
};
|
|
776
|
-
}
|
|
777
|
-
if (semver2.gt(cleanTagVersion, cleanPackageVersion)) {
|
|
778
|
-
log(`Git tag ${tagName} is newer than package version ${packageVersion}, using git tag`, "info");
|
|
779
|
-
return {
|
|
780
|
-
source: "git",
|
|
781
|
-
version: tagName,
|
|
782
|
-
reason: "Git tag is newer",
|
|
783
|
-
mismatch: mismatchInfo
|
|
784
|
-
};
|
|
785
|
-
}
|
|
786
|
-
return {
|
|
787
|
-
source: "git",
|
|
788
|
-
version: tagName,
|
|
789
|
-
reason: "Versions equal, using git tag",
|
|
790
|
-
mismatch: mismatchInfo
|
|
791
|
-
};
|
|
792
|
-
} catch (error) {
|
|
793
|
-
if (error instanceof VersionMismatchError) {
|
|
794
|
-
throw error;
|
|
795
|
-
}
|
|
796
|
-
log(`Failed to compare versions, defaulting to git tag: ${error}`, "warning");
|
|
797
|
-
return { source: "git", version: tagName, reason: "Version comparison failed" };
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
// src/core/versionCalculator.ts
|
|
802
|
-
async function calculateVersion(config, options) {
|
|
803
|
-
const {
|
|
804
|
-
type: configType,
|
|
805
|
-
preset = "angular",
|
|
806
|
-
versionPrefix,
|
|
807
|
-
prereleaseIdentifier: configPrereleaseIdentifier,
|
|
808
|
-
branchPattern,
|
|
809
|
-
baseBranch,
|
|
810
|
-
mismatchStrategy
|
|
811
|
-
} = config;
|
|
812
|
-
const {
|
|
813
|
-
latestTag,
|
|
814
|
-
name,
|
|
815
|
-
path: pkgPath,
|
|
816
|
-
type: optionsType,
|
|
817
|
-
prereleaseIdentifier: optionsPrereleaseIdentifier
|
|
818
|
-
} = options;
|
|
819
|
-
const type = optionsType || configType;
|
|
820
|
-
const prereleaseIdentifier = optionsPrereleaseIdentifier || configPrereleaseIdentifier;
|
|
821
|
-
const initialVersion = "0.1.0";
|
|
822
|
-
const hasNoTags = !latestTag || latestTag.trim() === "";
|
|
823
|
-
const normalizedPrereleaseId = normalizePrereleaseIdentifier(prereleaseIdentifier, config);
|
|
824
|
-
try {
|
|
825
|
-
let determineTagSearchPattern2 = function(packageName, prefix) {
|
|
826
|
-
if (!packageName) {
|
|
827
|
-
return prefix;
|
|
828
|
-
}
|
|
829
|
-
return `${packageName}@${prefix}`;
|
|
830
|
-
}, escapeRegExp3 = function(string) {
|
|
831
|
-
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
832
|
-
}, getCurrentVersionFromSource2 = function() {
|
|
833
|
-
if (!versionSource) {
|
|
834
|
-
if (hasNoTags) {
|
|
835
|
-
return initialVersion;
|
|
836
|
-
}
|
|
837
|
-
const cleanedTag = semver3.clean(latestTag) || latestTag;
|
|
838
|
-
return semver3.clean(cleanedTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
|
|
839
|
-
}
|
|
840
|
-
if (versionSource.source === "git") {
|
|
841
|
-
const cleanedTag = semver3.clean(versionSource.version) || versionSource.version;
|
|
842
|
-
return semver3.clean(cleanedTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
|
|
843
|
-
}
|
|
844
|
-
return versionSource.version;
|
|
845
|
-
};
|
|
846
|
-
var determineTagSearchPattern = determineTagSearchPattern2, escapeRegExp2 = escapeRegExp3, getCurrentVersionFromSource = getCurrentVersionFromSource2;
|
|
847
|
-
const originalPrefix = versionPrefix || "";
|
|
848
|
-
const tagSearchPattern = determineTagSearchPattern2(name, originalPrefix);
|
|
849
|
-
const escapedTagPattern = escapeRegExp3(tagSearchPattern);
|
|
850
|
-
let versionSource;
|
|
851
|
-
if (pkgPath) {
|
|
852
|
-
const packageDir = pkgPath || cwd();
|
|
853
|
-
const manifestResult = getVersionFromManifests(packageDir);
|
|
854
|
-
const packageVersion = manifestResult.manifestFound && manifestResult.version ? manifestResult.version : void 0;
|
|
855
|
-
versionSource = await getBestVersionSource(latestTag, packageVersion, packageDir, mismatchStrategy);
|
|
856
|
-
log(`Using version source: ${versionSource.source} (${versionSource.reason})`, "info");
|
|
857
|
-
}
|
|
858
|
-
const specifiedType = type;
|
|
859
|
-
if (specifiedType) {
|
|
860
|
-
const currentVersion = getCurrentVersionFromSource2();
|
|
861
|
-
const isCurrentPrerelease = semver3.prerelease(currentVersion);
|
|
862
|
-
const explicitlyRequestedPrerelease = config.isPrerelease;
|
|
863
|
-
if (STANDARD_BUMP_TYPES.includes(specifiedType) && (isCurrentPrerelease || explicitlyRequestedPrerelease)) {
|
|
864
|
-
const prereleaseId2 = explicitlyRequestedPrerelease || isCurrentPrerelease ? normalizedPrereleaseId : void 0;
|
|
865
|
-
log(
|
|
866
|
-
explicitlyRequestedPrerelease ? `Creating prerelease version with identifier '${prereleaseId2}' using ${specifiedType}` : `Cleaning prerelease identifier from ${currentVersion} for ${specifiedType} bump`,
|
|
867
|
-
"debug"
|
|
868
|
-
);
|
|
869
|
-
return bumpVersion(currentVersion, specifiedType, prereleaseId2);
|
|
870
|
-
}
|
|
871
|
-
const isPrereleaseBumpType = ["prerelease", "premajor", "preminor", "prepatch"].includes(specifiedType);
|
|
872
|
-
const prereleaseId = config.isPrerelease || isPrereleaseBumpType ? normalizedPrereleaseId : void 0;
|
|
873
|
-
return bumpVersion(currentVersion, specifiedType, prereleaseId);
|
|
874
|
-
}
|
|
875
|
-
if (branchPattern && branchPattern.length > 0) {
|
|
876
|
-
const currentBranch = getCurrentBranch();
|
|
877
|
-
if (baseBranch) {
|
|
878
|
-
lastMergeBranchName(branchPattern, baseBranch);
|
|
879
|
-
}
|
|
880
|
-
const branchToCheck = currentBranch;
|
|
881
|
-
let branchVersionType;
|
|
882
|
-
for (const pattern of branchPattern) {
|
|
883
|
-
if (!pattern.includes(":")) {
|
|
884
|
-
log(`Invalid branch pattern "${pattern}" - missing colon. Skipping.`, "warning");
|
|
885
|
-
continue;
|
|
886
|
-
}
|
|
887
|
-
const [patternRegex, releaseType] = pattern.split(":");
|
|
888
|
-
if (new RegExp(patternRegex).test(branchToCheck)) {
|
|
889
|
-
branchVersionType = releaseType;
|
|
890
|
-
log(`Using branch pattern ${patternRegex} for version type ${releaseType}`, "debug");
|
|
891
|
-
break;
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
if (branchVersionType) {
|
|
895
|
-
const currentVersion = getCurrentVersionFromSource2();
|
|
896
|
-
log(`Applying ${branchVersionType} bump based on branch pattern`, "debug");
|
|
897
|
-
const isPrereleaseBumpType = ["prerelease", "premajor", "preminor", "prepatch"].includes(branchVersionType);
|
|
898
|
-
const prereleaseId = config.isPrerelease || isPrereleaseBumpType ? normalizedPrereleaseId : void 0;
|
|
899
|
-
return bumpVersion(currentVersion, branchVersionType, prereleaseId);
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
try {
|
|
903
|
-
const bumper = new Bumper();
|
|
904
|
-
bumper.loadPreset(preset);
|
|
905
|
-
const recommendedBump = await bumper.bump();
|
|
906
|
-
const releaseTypeFromCommits = recommendedBump && "releaseType" in recommendedBump ? recommendedBump.releaseType : void 0;
|
|
907
|
-
const currentVersion = getCurrentVersionFromSource2();
|
|
908
|
-
if (versionSource && versionSource.source === "git") {
|
|
909
|
-
const checkPath = pkgPath || cwd();
|
|
910
|
-
const commitsLength = getCommitsLength(checkPath, versionSource.version);
|
|
911
|
-
if (commitsLength === 0) {
|
|
912
|
-
log(
|
|
913
|
-
`No new commits found for ${name || "project"} since ${versionSource.version}, skipping version bump`,
|
|
914
|
-
"info"
|
|
915
|
-
);
|
|
916
|
-
return "";
|
|
917
|
-
}
|
|
918
|
-
} else if (versionSource && versionSource.source === "package") {
|
|
919
|
-
log(
|
|
920
|
-
`Using package version ${versionSource.version} as base, letting conventional commits determine bump necessity`,
|
|
921
|
-
"debug"
|
|
922
|
-
);
|
|
923
|
-
}
|
|
924
|
-
if (!releaseTypeFromCommits) {
|
|
925
|
-
if (latestTag && latestTag.trim() !== "") {
|
|
926
|
-
log(`No relevant commits found for ${name || "project"} since ${latestTag}, skipping version bump`, "info");
|
|
927
|
-
} else {
|
|
928
|
-
log(`No relevant commits found for ${name || "project"}, skipping version bump`, "info");
|
|
929
|
-
}
|
|
930
|
-
return "";
|
|
931
|
-
}
|
|
932
|
-
const isPrereleaseBumpType = ["prerelease", "premajor", "preminor", "prepatch"].includes(releaseTypeFromCommits);
|
|
933
|
-
const prereleaseId = config.isPrerelease || isPrereleaseBumpType ? normalizedPrereleaseId : void 0;
|
|
934
|
-
return bumpVersion(currentVersion, releaseTypeFromCommits, prereleaseId);
|
|
935
|
-
} catch (error) {
|
|
936
|
-
log(`Failed to calculate version for ${name || "project"}`, "error");
|
|
937
|
-
console.error(error);
|
|
938
|
-
if (error instanceof Error && error.message.includes("No names found")) {
|
|
939
|
-
log("No tags found, proceeding with initial version calculation (if applicable).", "info");
|
|
940
|
-
return initialVersion;
|
|
941
|
-
}
|
|
942
|
-
throw error;
|
|
943
|
-
}
|
|
944
|
-
} catch (error) {
|
|
945
|
-
log(`Failed to calculate version for ${name || "project"}`, "error");
|
|
946
|
-
console.error(error);
|
|
947
|
-
if (error instanceof Error && error.message.includes("No names found")) {
|
|
948
|
-
log("No tags found, proceeding with initial version calculation (if applicable).", "info");
|
|
949
|
-
return initialVersion;
|
|
950
|
-
}
|
|
951
|
-
throw error;
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
|
|
955
|
-
// src/package/packageProcessor.ts
|
|
956
|
-
import * as fs5 from "fs";
|
|
957
|
-
import path4 from "path";
|
|
958
|
-
import { exit } from "process";
|
|
959
|
-
|
|
960
|
-
// src/changelog/commitParser.ts
|
|
961
|
-
var CONVENTIONAL_COMMIT_REGEX = /^(\w+)(?:\(([^)]+)\))?(!)?: (.+)(?:\n\n([\s\S]*))?/;
|
|
962
|
-
var BREAKING_CHANGE_REGEX = /BREAKING CHANGE: ([\s\S]+?)(?:\n\n|$)/;
|
|
963
|
-
function extractChangelogEntriesFromCommits(projectDir, revisionRange) {
|
|
964
|
-
try {
|
|
965
|
-
const output = execSync("git", ["log", revisionRange, "--pretty=format:%B---COMMIT_DELIMITER---", "--no-merges"], {
|
|
966
|
-
cwd: projectDir,
|
|
967
|
-
encoding: "utf8"
|
|
968
|
-
}).toString();
|
|
969
|
-
const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
|
|
970
|
-
return commits.map((commit) => parseCommitMessage(commit)).filter((entry) => entry !== null);
|
|
971
|
-
} catch (error) {
|
|
972
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
973
|
-
if (errorMessage.includes("ambiguous argument") && errorMessage.includes("unknown revision")) {
|
|
974
|
-
const tagName = revisionRange.split("..")[0] || revisionRange;
|
|
975
|
-
if (tagName.startsWith("v") && !tagName.includes("@")) {
|
|
976
|
-
log(
|
|
977
|
-
`Error: Tag "${tagName}" not found. If you're using package-specific tags (like "package-name@v1.0.0"), you may need to configure "tagTemplate" in your version.config.json to use: \${packageName}@\${prefix}\${version}`,
|
|
978
|
-
"error"
|
|
979
|
-
);
|
|
980
|
-
} else {
|
|
981
|
-
log(
|
|
982
|
-
`Error: Tag or revision "${tagName}" not found in the repository. Please check if this tag exists or if you need to fetch it from the remote.`,
|
|
983
|
-
"error"
|
|
984
|
-
);
|
|
985
|
-
}
|
|
986
|
-
} else {
|
|
987
|
-
log(`Error extracting commits: ${errorMessage}`, "error");
|
|
988
|
-
}
|
|
989
|
-
return [];
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
function parseCommitMessage(message) {
|
|
993
|
-
const trimmedMessage = message.trim();
|
|
994
|
-
const match = trimmedMessage.match(CONVENTIONAL_COMMIT_REGEX);
|
|
995
|
-
if (match) {
|
|
996
|
-
const [, type, scope, breakingMark, subject, body = ""] = match;
|
|
997
|
-
const breakingFromMark = breakingMark === "!";
|
|
998
|
-
const breakingChangeMatch = body.match(BREAKING_CHANGE_REGEX);
|
|
999
|
-
const hasBreakingChange = breakingFromMark || breakingChangeMatch !== null;
|
|
1000
|
-
const changelogType = mapCommitTypeToChangelogType(type);
|
|
1001
|
-
if (!changelogType) {
|
|
1002
|
-
return null;
|
|
1003
|
-
}
|
|
1004
|
-
const issueIds = extractIssueIds(body);
|
|
1005
|
-
let description = subject;
|
|
1006
|
-
if (hasBreakingChange) {
|
|
1007
|
-
description = `**BREAKING** ${description}`;
|
|
1008
|
-
}
|
|
1009
|
-
return {
|
|
1010
|
-
type: changelogType,
|
|
1011
|
-
description,
|
|
1012
|
-
scope: scope || void 0,
|
|
1013
|
-
issueIds: issueIds.length > 0 ? issueIds : void 0,
|
|
1014
|
-
originalType: type
|
|
1015
|
-
// Store original type for custom formatting
|
|
1016
|
-
};
|
|
1017
|
-
}
|
|
1018
|
-
if (!trimmedMessage.startsWith("Merge") && !trimmedMessage.match(/^v?\d+\.\d+\.\d+/)) {
|
|
1019
|
-
const firstLine = trimmedMessage.split("\n")[0].trim();
|
|
1020
|
-
return {
|
|
1021
|
-
type: "changed",
|
|
1022
|
-
description: firstLine
|
|
1023
|
-
};
|
|
1024
|
-
}
|
|
1025
|
-
return null;
|
|
1026
|
-
}
|
|
1027
|
-
function mapCommitTypeToChangelogType(type) {
|
|
1028
|
-
switch (type) {
|
|
1029
|
-
case "feat":
|
|
1030
|
-
return "added";
|
|
1031
|
-
case "fix":
|
|
1032
|
-
return "fixed";
|
|
1033
|
-
case "docs":
|
|
1034
|
-
case "style":
|
|
1035
|
-
case "refactor":
|
|
1036
|
-
case "perf":
|
|
1037
|
-
case "build":
|
|
1038
|
-
case "ci":
|
|
1039
|
-
return "changed";
|
|
1040
|
-
case "revert":
|
|
1041
|
-
return "removed";
|
|
1042
|
-
case "chore":
|
|
1043
|
-
return "changed";
|
|
1044
|
-
case "test":
|
|
1045
|
-
return null;
|
|
1046
|
-
default:
|
|
1047
|
-
return "changed";
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
function extractIssueIds(body) {
|
|
1051
|
-
const issueRegex = /(?:fix|fixes|close|closes|resolve|resolves)\s+#(\d+)/gi;
|
|
1052
|
-
const issueIds = [];
|
|
1053
|
-
let match = issueRegex.exec(body);
|
|
1054
|
-
while (match !== null) {
|
|
1055
|
-
issueIds.push(`#${match[1]}`);
|
|
1056
|
-
match = issueRegex.exec(body);
|
|
1057
|
-
}
|
|
1058
|
-
return issueIds;
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
// src/git/commands.ts
|
|
1062
|
-
import { cwd as cwd2 } from "process";
|
|
1063
|
-
|
|
1064
|
-
// src/errors/gitError.ts
|
|
1065
|
-
var GitError = class extends BaseVersionError {
|
|
1066
|
-
};
|
|
1067
|
-
function createGitError(code, details) {
|
|
1068
|
-
const messages = {
|
|
1069
|
-
["NOT_GIT_REPO" /* NOT_GIT_REPO */]: "Not a git repository",
|
|
1070
|
-
["GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */]: "Failed to create new version",
|
|
1071
|
-
["NO_FILES" /* NO_FILES */]: "No files specified for commit",
|
|
1072
|
-
["NO_COMMIT_MESSAGE" /* NO_COMMIT_MESSAGE */]: "Commit message is required",
|
|
1073
|
-
["GIT_ERROR" /* GIT_ERROR */]: "Git operation failed",
|
|
1074
|
-
["TAG_ALREADY_EXISTS" /* TAG_ALREADY_EXISTS */]: "Git tag already exists"
|
|
1075
|
-
};
|
|
1076
|
-
const suggestions = {
|
|
1077
|
-
["NOT_GIT_REPO" /* NOT_GIT_REPO */]: [
|
|
1078
|
-
"Initialize git repository with: git init",
|
|
1079
|
-
"Ensure you are in the correct directory"
|
|
1080
|
-
],
|
|
1081
|
-
["TAG_ALREADY_EXISTS" /* TAG_ALREADY_EXISTS */]: [
|
|
1082
|
-
"Delete the existing tag: git tag -d <tag-name>",
|
|
1083
|
-
"Use a different version by incrementing manually",
|
|
1084
|
-
"Check if this version was already released"
|
|
1085
|
-
],
|
|
1086
|
-
["GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */]: void 0,
|
|
1087
|
-
["NO_FILES" /* NO_FILES */]: void 0,
|
|
1088
|
-
["NO_COMMIT_MESSAGE" /* NO_COMMIT_MESSAGE */]: void 0,
|
|
1089
|
-
["GIT_ERROR" /* GIT_ERROR */]: void 0
|
|
1090
|
-
};
|
|
1091
|
-
const baseMessage = messages[code];
|
|
1092
|
-
const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
|
|
1093
|
-
return new GitError(fullMessage, code, suggestions[code]);
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
// src/git/commands.ts
|
|
1097
|
-
async function gitAdd(files) {
|
|
1098
|
-
return execAsync("git", ["add", ...files]);
|
|
1099
|
-
}
|
|
1100
|
-
async function gitCommit(options) {
|
|
1101
|
-
const args = ["commit"];
|
|
1102
|
-
if (options.amend) {
|
|
1103
|
-
args.push("--amend");
|
|
1104
|
-
}
|
|
1105
|
-
if (options.author) {
|
|
1106
|
-
args.push("--author", options.author);
|
|
1107
|
-
}
|
|
1108
|
-
if (options.date) {
|
|
1109
|
-
args.push("--date", options.date);
|
|
1110
|
-
}
|
|
1111
|
-
if (options.skipHooks) {
|
|
1112
|
-
args.push("--no-verify");
|
|
1113
|
-
}
|
|
1114
|
-
args.push("-m", options.message);
|
|
1115
|
-
return execAsync("git", args);
|
|
1116
|
-
}
|
|
1117
|
-
async function createGitTag(options) {
|
|
1118
|
-
const { tag, message = "" } = options;
|
|
1119
|
-
const args = ["tag", "-a", "-m", message, tag];
|
|
1120
|
-
try {
|
|
1121
|
-
return await execAsync("git", args);
|
|
1122
|
-
} catch (error) {
|
|
1123
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1124
|
-
if (errorMessage.includes("already exists")) {
|
|
1125
|
-
throw createGitError(
|
|
1126
|
-
"TAG_ALREADY_EXISTS" /* TAG_ALREADY_EXISTS */,
|
|
1127
|
-
`Tag '${tag}' already exists in the repository. Please use a different version or delete the existing tag first.`
|
|
1128
|
-
);
|
|
1129
|
-
}
|
|
1130
|
-
throw createGitError("GIT_ERROR" /* GIT_ERROR */, errorMessage);
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
async function gitProcess(options) {
|
|
1134
|
-
const { files, nextTag, commitMessage, skipHooks, dryRun } = options;
|
|
1135
|
-
if (!isGitRepository(cwd2())) {
|
|
1136
|
-
throw createGitError("NOT_GIT_REPO" /* NOT_GIT_REPO */);
|
|
1137
|
-
}
|
|
1138
|
-
try {
|
|
1139
|
-
if (!dryRun) {
|
|
1140
|
-
await gitAdd(files);
|
|
1141
|
-
await gitCommit({
|
|
1142
|
-
message: commitMessage,
|
|
1143
|
-
skipHooks
|
|
1144
|
-
});
|
|
1145
|
-
if (nextTag) {
|
|
1146
|
-
const tagMessage = `New Version ${nextTag} generated at ${(/* @__PURE__ */ new Date()).toISOString()}`;
|
|
1147
|
-
await createGitTag({
|
|
1148
|
-
tag: nextTag,
|
|
1149
|
-
message: tagMessage
|
|
1150
|
-
});
|
|
1151
|
-
}
|
|
1152
|
-
} else {
|
|
1153
|
-
log("[DRY RUN] Would add files:", "info");
|
|
1154
|
-
for (const file of files) {
|
|
1155
|
-
log(` - ${file}`, "info");
|
|
1156
|
-
}
|
|
1157
|
-
log(`[DRY RUN] Would commit with message: "${commitMessage}"`, "info");
|
|
1158
|
-
if (nextTag) {
|
|
1159
|
-
log(`[DRY RUN] Would create tag: ${nextTag}`, "info");
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1162
|
-
} catch (err) {
|
|
1163
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
1164
|
-
if (errorMessage.includes("already exists") && nextTag) {
|
|
1165
|
-
log(`Tag '${nextTag}' already exists in the repository.`, "error");
|
|
1166
|
-
throw createGitError(
|
|
1167
|
-
"TAG_ALREADY_EXISTS" /* TAG_ALREADY_EXISTS */,
|
|
1168
|
-
`Tag '${nextTag}' already exists in the repository. Please use a different version or delete the existing tag first.`
|
|
1169
|
-
);
|
|
1170
|
-
}
|
|
1171
|
-
log(`Git process error: ${errorMessage}`, "error");
|
|
1172
|
-
if (err instanceof Error && err.stack) {
|
|
1173
|
-
console.error("Git process stack trace:");
|
|
1174
|
-
console.error(err.stack);
|
|
1175
|
-
}
|
|
1176
|
-
throw createGitError("GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */, errorMessage);
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
async function createGitCommitAndTag(files, nextTag, commitMessage, skipHooks, dryRun) {
|
|
1180
|
-
try {
|
|
1181
|
-
if (!files || files.length === 0) {
|
|
1182
|
-
throw createGitError("NO_FILES" /* NO_FILES */);
|
|
1183
|
-
}
|
|
1184
|
-
if (!commitMessage) {
|
|
1185
|
-
throw createGitError("NO_COMMIT_MESSAGE" /* NO_COMMIT_MESSAGE */);
|
|
1186
|
-
}
|
|
1187
|
-
setCommitMessage(commitMessage);
|
|
1188
|
-
if (nextTag) {
|
|
1189
|
-
addTag(nextTag);
|
|
1190
|
-
}
|
|
1191
|
-
await gitProcess({
|
|
1192
|
-
files,
|
|
1193
|
-
nextTag,
|
|
1194
|
-
commitMessage,
|
|
1195
|
-
skipHooks,
|
|
1196
|
-
dryRun
|
|
1197
|
-
});
|
|
1198
|
-
if (!dryRun) {
|
|
1199
|
-
log(`Created tag: ${nextTag}`, "success");
|
|
1200
|
-
}
|
|
1201
|
-
} catch (error) {
|
|
1202
|
-
if (error instanceof GitError) {
|
|
1203
|
-
throw error;
|
|
1204
|
-
}
|
|
1205
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1206
|
-
log(`Failed to create git commit and tag: ${errorMessage}`, "error");
|
|
1207
|
-
if (error instanceof Error) {
|
|
1208
|
-
console.error("Git operation error details:");
|
|
1209
|
-
console.error(error.stack || error.message);
|
|
1210
|
-
if (errorMessage.includes("Command failed:")) {
|
|
1211
|
-
const cmdOutput = errorMessage.split("Command failed:")[1];
|
|
1212
|
-
if (cmdOutput) {
|
|
1213
|
-
console.error("Git command output:", cmdOutput.trim());
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
} else {
|
|
1217
|
-
console.error("Unknown git error:", error);
|
|
1218
|
-
}
|
|
1219
|
-
throw new GitError(`Git operation failed: ${errorMessage}`, "GIT_ERROR" /* GIT_ERROR */);
|
|
1220
|
-
}
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
// src/utils/packageMatching.ts
|
|
1224
|
-
import micromatch from "micromatch";
|
|
1225
|
-
function matchesPackageTarget(packageName, target) {
|
|
1226
|
-
if (packageName === target) {
|
|
1227
|
-
return true;
|
|
1228
|
-
}
|
|
1229
|
-
if (target.startsWith("@") && target.endsWith("/*") && !target.includes("**")) {
|
|
1230
|
-
const scope = target.slice(0, -2);
|
|
1231
|
-
return packageName.startsWith(`${scope}/`);
|
|
1232
|
-
}
|
|
1233
|
-
try {
|
|
1234
|
-
return micromatch.isMatch(packageName, target, {
|
|
1235
|
-
dot: true,
|
|
1236
|
-
contains: false,
|
|
1237
|
-
// Changed to false to ensure full pattern matching
|
|
1238
|
-
noglobstar: false,
|
|
1239
|
-
bash: true
|
|
1240
|
-
});
|
|
1241
|
-
} catch (error) {
|
|
1242
|
-
log(`Invalid pattern "${target}": ${error instanceof Error ? error.message : String(error)}`, "warning");
|
|
1243
|
-
return false;
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
function shouldMatchPackageTargets(packageName, targets) {
|
|
1247
|
-
return targets.some((target) => matchesPackageTarget(packageName, target));
|
|
1248
|
-
}
|
|
1249
|
-
function shouldProcessPackage(packageName, skip = []) {
|
|
1250
|
-
if (skip.length === 0) {
|
|
1251
|
-
return true;
|
|
1252
|
-
}
|
|
1253
|
-
return !shouldMatchPackageTargets(packageName, skip);
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
|
-
// src/package/packageManagement.ts
|
|
1257
|
-
import fs4 from "fs";
|
|
1258
|
-
import path3 from "path";
|
|
1259
|
-
function updatePackageVersion(packagePath, version) {
|
|
1260
|
-
if (isCargoToml(packagePath)) {
|
|
1261
|
-
updateCargoVersion(packagePath, version);
|
|
1262
|
-
return;
|
|
1263
|
-
}
|
|
1264
|
-
try {
|
|
1265
|
-
const packageContent = fs4.readFileSync(packagePath, "utf8");
|
|
1266
|
-
const packageJson = JSON.parse(packageContent);
|
|
1267
|
-
const packageName = packageJson.name;
|
|
1268
|
-
packageJson.version = version;
|
|
1269
|
-
fs4.writeFileSync(packagePath, `${JSON.stringify(packageJson, null, 2)}
|
|
1270
|
-
`);
|
|
1271
|
-
addPackageUpdate(packageName, version, packagePath);
|
|
1272
|
-
log(`Updated package.json at ${packagePath} to version ${version}`, "success");
|
|
1273
|
-
} catch (error) {
|
|
1274
|
-
log(`Failed to update package.json at ${packagePath}`, "error");
|
|
1275
|
-
if (error instanceof Error) {
|
|
1276
|
-
log(error.message, "error");
|
|
1277
|
-
}
|
|
1278
|
-
throw error;
|
|
1279
|
-
}
|
|
1280
|
-
}
|
|
1281
|
-
|
|
1282
|
-
// src/package/packageProcessor.ts
|
|
1283
|
-
var PackageProcessor = class {
|
|
1284
|
-
skip;
|
|
1285
|
-
versionPrefix;
|
|
1286
|
-
tagTemplate;
|
|
1287
|
-
commitMessageTemplate;
|
|
1288
|
-
dryRun;
|
|
1289
|
-
skipHooks;
|
|
1290
|
-
getLatestTag;
|
|
1291
|
-
config;
|
|
1292
|
-
// Config for version calculation
|
|
1293
|
-
fullConfig;
|
|
1294
|
-
constructor(options) {
|
|
1295
|
-
this.skip = options.skip || [];
|
|
1296
|
-
this.versionPrefix = options.versionPrefix || "v";
|
|
1297
|
-
this.tagTemplate = options.tagTemplate;
|
|
1298
|
-
this.commitMessageTemplate = options.commitMessageTemplate || "";
|
|
1299
|
-
this.dryRun = options.dryRun || false;
|
|
1300
|
-
this.skipHooks = options.skipHooks || false;
|
|
1301
|
-
this.getLatestTag = options.getLatestTag;
|
|
1302
|
-
this.config = options.config;
|
|
1303
|
-
this.fullConfig = options.fullConfig;
|
|
1304
|
-
}
|
|
1305
|
-
/**
|
|
1306
|
-
* Process packages based on skip list only (targeting handled at discovery time)
|
|
1307
|
-
*/
|
|
1308
|
-
async processPackages(packages) {
|
|
1309
|
-
const tags = [];
|
|
1310
|
-
const updatedPackagesInfo = [];
|
|
1311
|
-
if (!packages || !Array.isArray(packages)) {
|
|
1312
|
-
log("Invalid packages data provided. Expected array of packages.", "error");
|
|
1313
|
-
return { updatedPackages: [], tags: [] };
|
|
1314
|
-
}
|
|
1315
|
-
const pkgsToConsider = packages.filter((pkg) => {
|
|
1316
|
-
const pkgName = pkg.packageJson.name;
|
|
1317
|
-
const shouldProcess = shouldProcessPackage(pkgName, this.skip);
|
|
1318
|
-
if (!shouldProcess) {
|
|
1319
|
-
log(`Skipping package ${pkgName} as it's in the skip list.`, "info");
|
|
1320
|
-
}
|
|
1321
|
-
return shouldProcess;
|
|
1322
|
-
});
|
|
1323
|
-
log(`Found ${pkgsToConsider.length} package(s) to process after filtering.`, "info");
|
|
1324
|
-
if (pkgsToConsider.length === 0) {
|
|
1325
|
-
log("No packages found to process.", "info");
|
|
1326
|
-
return { updatedPackages: [], tags: [] };
|
|
1327
|
-
}
|
|
1328
|
-
for (const pkg of pkgsToConsider) {
|
|
1329
|
-
const name = pkg.packageJson.name;
|
|
1330
|
-
const pkgPath = pkg.dir;
|
|
1331
|
-
log(`Processing package ${name} at path: ${pkgPath}`, "info");
|
|
1332
|
-
const formattedPrefix = formatVersionPrefix(this.versionPrefix);
|
|
1333
|
-
let latestTagResult = "";
|
|
1334
|
-
try {
|
|
1335
|
-
latestTagResult = await getLatestTagForPackage(name, this.versionPrefix, {
|
|
1336
|
-
tagTemplate: this.tagTemplate,
|
|
1337
|
-
packageSpecificTags: this.fullConfig.packageSpecificTags
|
|
1338
|
-
});
|
|
1339
|
-
} catch (error) {
|
|
1340
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1341
|
-
log(`Error getting package-specific tag for ${name}, falling back to global tag: ${errorMessage}`, "warning");
|
|
1342
|
-
}
|
|
1343
|
-
if (!latestTagResult) {
|
|
1344
|
-
try {
|
|
1345
|
-
const packageDir = pkgPath;
|
|
1346
|
-
let manifestFallbackUsed = false;
|
|
1347
|
-
const manifestResult = getVersionFromManifests(packageDir);
|
|
1348
|
-
if (manifestResult.manifestFound && manifestResult.version) {
|
|
1349
|
-
log(
|
|
1350
|
-
`Using ${manifestResult.manifestType} version ${manifestResult.version} for ${name} as no package-specific tags found`,
|
|
1351
|
-
"info"
|
|
1352
|
-
);
|
|
1353
|
-
log(`FALLBACK: Using package version from ${manifestResult.manifestType} instead of global tag`, "debug");
|
|
1354
|
-
latestTagResult = `${this.versionPrefix || ""}${manifestResult.version}`;
|
|
1355
|
-
manifestFallbackUsed = true;
|
|
1356
|
-
}
|
|
1357
|
-
if (!manifestFallbackUsed) {
|
|
1358
|
-
const globalTagResult = await this.getLatestTag();
|
|
1359
|
-
if (globalTagResult) {
|
|
1360
|
-
latestTagResult = globalTagResult;
|
|
1361
|
-
log(`Using global tag ${globalTagResult} as fallback for package ${name}`, "info");
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
} catch (error) {
|
|
1365
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1366
|
-
log(`Error getting fallback version, using empty tag value: ${errorMessage}`, "warning");
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
const latestTag = latestTagResult;
|
|
1370
|
-
const nextVersion = await calculateVersion(this.fullConfig, {
|
|
1371
|
-
latestTag,
|
|
1372
|
-
versionPrefix: formattedPrefix,
|
|
1373
|
-
path: pkgPath,
|
|
1374
|
-
name,
|
|
1375
|
-
branchPattern: this.config.branchPattern,
|
|
1376
|
-
baseBranch: this.config.baseBranch,
|
|
1377
|
-
prereleaseIdentifier: this.config.prereleaseIdentifier,
|
|
1378
|
-
type: this.config.type
|
|
1379
|
-
});
|
|
1380
|
-
if (!nextVersion) {
|
|
1381
|
-
continue;
|
|
1382
|
-
}
|
|
1383
|
-
let changelogEntries = [];
|
|
1384
|
-
let revisionRange = "HEAD";
|
|
1385
|
-
try {
|
|
1386
|
-
if (latestTag) {
|
|
1387
|
-
const verification = verifyTag(latestTag, pkgPath);
|
|
1388
|
-
if (verification.exists && verification.reachable) {
|
|
1389
|
-
revisionRange = `${latestTag}..HEAD`;
|
|
1390
|
-
} else {
|
|
1391
|
-
log(`Tag ${latestTag} is unreachable (${verification.error}), using all commits for changelog`, "debug");
|
|
1392
|
-
revisionRange = "HEAD";
|
|
1393
|
-
}
|
|
1394
|
-
} else {
|
|
1395
|
-
revisionRange = "HEAD";
|
|
1396
|
-
}
|
|
1397
|
-
changelogEntries = extractChangelogEntriesFromCommits(pkgPath, revisionRange);
|
|
1398
|
-
if (changelogEntries.length === 0) {
|
|
1399
|
-
changelogEntries = [
|
|
1400
|
-
{
|
|
1401
|
-
type: "changed",
|
|
1402
|
-
description: `Update version to ${nextVersion}`
|
|
1403
|
-
}
|
|
1404
|
-
];
|
|
1405
|
-
}
|
|
1406
|
-
} catch (error) {
|
|
1407
|
-
log(`Error extracting changelog entries: ${error instanceof Error ? error.message : String(error)}`, "warning");
|
|
1408
|
-
changelogEntries = [
|
|
1409
|
-
{
|
|
1410
|
-
type: "changed",
|
|
1411
|
-
description: `Update version to ${nextVersion}`
|
|
1412
|
-
}
|
|
1413
|
-
];
|
|
1414
|
-
}
|
|
1415
|
-
let repoUrl;
|
|
1416
|
-
try {
|
|
1417
|
-
const packageJsonPath2 = path4.join(pkgPath, "package.json");
|
|
1418
|
-
if (fs5.existsSync(packageJsonPath2)) {
|
|
1419
|
-
const packageJson = JSON.parse(fs5.readFileSync(packageJsonPath2, "utf8"));
|
|
1420
|
-
if (packageJson.repository) {
|
|
1421
|
-
if (typeof packageJson.repository === "string") {
|
|
1422
|
-
repoUrl = packageJson.repository;
|
|
1423
|
-
} else if (packageJson.repository.url) {
|
|
1424
|
-
repoUrl = packageJson.repository.url;
|
|
1425
|
-
}
|
|
1426
|
-
if (repoUrl?.startsWith("git+") && repoUrl?.endsWith(".git")) {
|
|
1427
|
-
repoUrl = repoUrl.substring(4, repoUrl.length - 4);
|
|
1428
|
-
}
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
} catch (error) {
|
|
1432
|
-
log(
|
|
1433
|
-
`Could not determine repository URL for changelog links: ${error instanceof Error ? error.message : String(error)}`,
|
|
1434
|
-
"warning"
|
|
1435
|
-
);
|
|
1436
|
-
}
|
|
1437
|
-
addChangelogData({
|
|
1438
|
-
packageName: name,
|
|
1439
|
-
version: nextVersion,
|
|
1440
|
-
previousVersion: latestTag || null,
|
|
1441
|
-
revisionRange,
|
|
1442
|
-
repoUrl: repoUrl || null,
|
|
1443
|
-
entries: changelogEntries
|
|
1444
|
-
});
|
|
1445
|
-
const packageJsonPath = path4.join(pkgPath, "package.json");
|
|
1446
|
-
if (fs5.existsSync(packageJsonPath)) {
|
|
1447
|
-
updatePackageVersion(packageJsonPath, nextVersion);
|
|
1448
|
-
}
|
|
1449
|
-
const cargoEnabled = this.fullConfig.cargo?.enabled !== false;
|
|
1450
|
-
log(`Cargo enabled for ${name}: ${cargoEnabled}, config: ${JSON.stringify(this.fullConfig.cargo)}`, "debug");
|
|
1451
|
-
if (cargoEnabled) {
|
|
1452
|
-
const cargoPaths = this.fullConfig.cargo?.paths;
|
|
1453
|
-
log(`Cargo paths config for ${name}: ${JSON.stringify(cargoPaths)}`, "debug");
|
|
1454
|
-
if (cargoPaths && cargoPaths.length > 0) {
|
|
1455
|
-
for (const cargoPath of cargoPaths) {
|
|
1456
|
-
const resolvedCargoPath = path4.resolve(pkgPath, cargoPath, "Cargo.toml");
|
|
1457
|
-
log(`Checking cargo path for ${name}: ${resolvedCargoPath}`, "debug");
|
|
1458
|
-
if (fs5.existsSync(resolvedCargoPath)) {
|
|
1459
|
-
log(`Found Cargo.toml for ${name} at ${resolvedCargoPath}, updating...`, "debug");
|
|
1460
|
-
updatePackageVersion(resolvedCargoPath, nextVersion);
|
|
1461
|
-
} else {
|
|
1462
|
-
log(`Cargo.toml not found at ${resolvedCargoPath}`, "debug");
|
|
1463
|
-
}
|
|
1464
|
-
}
|
|
1465
|
-
} else {
|
|
1466
|
-
const cargoTomlPath = path4.join(pkgPath, "Cargo.toml");
|
|
1467
|
-
log(`Checking default cargo path for ${name}: ${cargoTomlPath}`, "debug");
|
|
1468
|
-
if (fs5.existsSync(cargoTomlPath)) {
|
|
1469
|
-
log(`Found Cargo.toml for ${name} at ${cargoTomlPath}, updating...`, "debug");
|
|
1470
|
-
updatePackageVersion(cargoTomlPath, nextVersion);
|
|
1471
|
-
} else {
|
|
1472
|
-
log(`Cargo.toml not found for ${name} at ${cargoTomlPath}`, "debug");
|
|
1473
|
-
}
|
|
1474
|
-
}
|
|
1475
|
-
} else {
|
|
1476
|
-
log(`Cargo disabled for ${name}`, "debug");
|
|
1477
|
-
}
|
|
1478
|
-
const packageTag = formatTag(
|
|
1479
|
-
nextVersion,
|
|
1480
|
-
this.versionPrefix,
|
|
1481
|
-
name,
|
|
1482
|
-
this.tagTemplate,
|
|
1483
|
-
this.fullConfig.packageSpecificTags
|
|
1484
|
-
);
|
|
1485
|
-
const tagMessage = `chore(release): ${name} ${nextVersion}`;
|
|
1486
|
-
addTag(packageTag);
|
|
1487
|
-
tags.push(packageTag);
|
|
1488
|
-
if (!this.dryRun) {
|
|
1489
|
-
try {
|
|
1490
|
-
await createGitTag({ tag: packageTag, message: tagMessage });
|
|
1491
|
-
log(`Created tag: ${packageTag}`, "success");
|
|
1492
|
-
} catch (tagError) {
|
|
1493
|
-
log(`Failed to create tag ${packageTag} for ${name}: ${tagError.message}`, "error");
|
|
1494
|
-
log(tagError.stack || "No stack trace available", "error");
|
|
1495
|
-
}
|
|
1496
|
-
} else {
|
|
1497
|
-
log(`[DRY RUN] Would create tag: ${packageTag}`, "info");
|
|
1498
|
-
}
|
|
1499
|
-
updatedPackagesInfo.push({ name, version: nextVersion, path: pkgPath });
|
|
1500
|
-
}
|
|
1501
|
-
if (updatedPackagesInfo.length === 0) {
|
|
1502
|
-
log("No packages required a version update.", "info");
|
|
1503
|
-
return { updatedPackages: [], tags };
|
|
1504
|
-
}
|
|
1505
|
-
const filesToCommit = [];
|
|
1506
|
-
for (const info of updatedPackagesInfo) {
|
|
1507
|
-
const packageJsonPath = path4.join(info.path, "package.json");
|
|
1508
|
-
if (fs5.existsSync(packageJsonPath)) {
|
|
1509
|
-
filesToCommit.push(packageJsonPath);
|
|
1510
|
-
}
|
|
1511
|
-
const cargoEnabled = this.fullConfig.cargo?.enabled !== false;
|
|
1512
|
-
if (cargoEnabled) {
|
|
1513
|
-
const cargoPaths = this.fullConfig.cargo?.paths;
|
|
1514
|
-
if (cargoPaths && cargoPaths.length > 0) {
|
|
1515
|
-
for (const cargoPath of cargoPaths) {
|
|
1516
|
-
const resolvedCargoPath = path4.resolve(info.path, cargoPath, "Cargo.toml");
|
|
1517
|
-
if (fs5.existsSync(resolvedCargoPath)) {
|
|
1518
|
-
filesToCommit.push(resolvedCargoPath);
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
|
-
} else {
|
|
1522
|
-
const cargoTomlPath = path4.join(info.path, "Cargo.toml");
|
|
1523
|
-
if (fs5.existsSync(cargoTomlPath)) {
|
|
1524
|
-
filesToCommit.push(cargoTomlPath);
|
|
1525
|
-
}
|
|
1526
|
-
}
|
|
1527
|
-
}
|
|
1528
|
-
}
|
|
1529
|
-
const packageNames = updatedPackagesInfo.map((p) => p.name).join(", ");
|
|
1530
|
-
const representativeVersion = updatedPackagesInfo[0]?.version || "multiple";
|
|
1531
|
-
let commitMessage = this.commitMessageTemplate || "chore(release): publish packages";
|
|
1532
|
-
const placeholderRegex = /\$\{[^}]+\}/;
|
|
1533
|
-
if (updatedPackagesInfo.length === 1 && placeholderRegex.test(commitMessage)) {
|
|
1534
|
-
const packageName = updatedPackagesInfo[0].name;
|
|
1535
|
-
commitMessage = formatCommitMessage(commitMessage, representativeVersion, packageName);
|
|
1536
|
-
} else {
|
|
1537
|
-
commitMessage = `chore(release): ${packageNames} ${representativeVersion}`;
|
|
1538
|
-
}
|
|
1539
|
-
setCommitMessage(commitMessage);
|
|
1540
|
-
if (!this.dryRun) {
|
|
1541
|
-
try {
|
|
1542
|
-
await gitAdd(filesToCommit);
|
|
1543
|
-
await gitCommit({ message: commitMessage, skipHooks: this.skipHooks });
|
|
1544
|
-
log(`Created commit for targeted release: ${packageNames}`, "success");
|
|
1545
|
-
} catch (commitError) {
|
|
1546
|
-
log("Failed to create commit for targeted release.", "error");
|
|
1547
|
-
console.error(commitError);
|
|
1548
|
-
exit(1);
|
|
1549
|
-
}
|
|
1550
|
-
} else {
|
|
1551
|
-
log("[DRY RUN] Would add files:", "info");
|
|
1552
|
-
for (const file of filesToCommit) {
|
|
1553
|
-
log(` - ${file}`, "info");
|
|
1554
|
-
}
|
|
1555
|
-
log(`[DRY RUN] Would commit with message: "${commitMessage}"`, "info");
|
|
1556
|
-
}
|
|
1557
|
-
return {
|
|
1558
|
-
updatedPackages: updatedPackagesInfo,
|
|
1559
|
-
commitMessage,
|
|
1560
|
-
tags
|
|
1561
|
-
};
|
|
1562
|
-
}
|
|
1563
|
-
};
|
|
1564
|
-
|
|
1565
|
-
// src/core/versionStrategies.ts
|
|
1566
|
-
import fs6 from "fs";
|
|
1567
|
-
import * as path5 from "path";
|
|
1568
|
-
function shouldProcessPackage2(pkg, config) {
|
|
1569
|
-
const pkgName = pkg.packageJson.name;
|
|
1570
|
-
return shouldProcessPackage(pkgName, config.skip);
|
|
1571
|
-
}
|
|
1572
|
-
function updateCargoFiles(packageDir, version, cargoConfig) {
|
|
1573
|
-
const updatedFiles = [];
|
|
1574
|
-
const cargoEnabled = cargoConfig?.enabled !== false;
|
|
1575
|
-
if (!cargoEnabled) {
|
|
1576
|
-
return updatedFiles;
|
|
1577
|
-
}
|
|
1578
|
-
const cargoPaths = cargoConfig?.paths;
|
|
1579
|
-
if (cargoPaths && cargoPaths.length > 0) {
|
|
1580
|
-
for (const cargoPath of cargoPaths) {
|
|
1581
|
-
const resolvedCargoPath = path5.resolve(packageDir, cargoPath, "Cargo.toml");
|
|
1582
|
-
if (fs6.existsSync(resolvedCargoPath)) {
|
|
1583
|
-
updatePackageVersion(resolvedCargoPath, version);
|
|
1584
|
-
updatedFiles.push(resolvedCargoPath);
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1587
|
-
} else {
|
|
1588
|
-
const cargoTomlPath = path5.join(packageDir, "Cargo.toml");
|
|
1589
|
-
if (fs6.existsSync(cargoTomlPath)) {
|
|
1590
|
-
updatePackageVersion(cargoTomlPath, version);
|
|
1591
|
-
updatedFiles.push(cargoTomlPath);
|
|
1592
|
-
}
|
|
1593
|
-
}
|
|
1594
|
-
return updatedFiles;
|
|
1595
|
-
}
|
|
1596
|
-
function createSyncStrategy(config) {
|
|
1597
|
-
return async (packages) => {
|
|
1598
|
-
try {
|
|
1599
|
-
const {
|
|
1600
|
-
versionPrefix,
|
|
1601
|
-
tagTemplate,
|
|
1602
|
-
baseBranch,
|
|
1603
|
-
branchPattern,
|
|
1604
|
-
commitMessage = `chore(release): v\${version}`,
|
|
1605
|
-
prereleaseIdentifier,
|
|
1606
|
-
dryRun,
|
|
1607
|
-
skipHooks,
|
|
1608
|
-
mainPackage
|
|
1609
|
-
} = config;
|
|
1610
|
-
const formattedPrefix = formatVersionPrefix(versionPrefix || "v");
|
|
1611
|
-
let latestTag = await getLatestTag();
|
|
1612
|
-
let mainPkgPath = packages.root;
|
|
1613
|
-
let mainPkgName;
|
|
1614
|
-
if (mainPackage) {
|
|
1615
|
-
const mainPkg = packages.packages.find((p) => p.packageJson.name === mainPackage);
|
|
1616
|
-
if (mainPkg) {
|
|
1617
|
-
mainPkgPath = mainPkg.dir;
|
|
1618
|
-
mainPkgName = mainPkg.packageJson.name;
|
|
1619
|
-
log(`Using ${mainPkgName} as primary package for version determination`, "info");
|
|
1620
|
-
} else {
|
|
1621
|
-
log(`Main package '${mainPackage}' not found. Using root package for version determination.`, "warning");
|
|
1622
|
-
}
|
|
1623
|
-
}
|
|
1624
|
-
if (!mainPkgPath) {
|
|
1625
|
-
mainPkgPath = process.cwd();
|
|
1626
|
-
log(`No valid package path found, using current working directory: ${mainPkgPath}`, "warning");
|
|
1627
|
-
}
|
|
1628
|
-
if (mainPkgName) {
|
|
1629
|
-
const packageSpecificTag = await getLatestTagForPackage(mainPkgName, formattedPrefix, {
|
|
1630
|
-
tagTemplate,
|
|
1631
|
-
packageSpecificTags: config.packageSpecificTags
|
|
1632
|
-
});
|
|
1633
|
-
if (packageSpecificTag) {
|
|
1634
|
-
latestTag = packageSpecificTag;
|
|
1635
|
-
log(`Using package-specific tag for ${mainPkgName}: ${latestTag}`, "debug");
|
|
1636
|
-
} else {
|
|
1637
|
-
log(`No package-specific tag found for ${mainPkgName}, using global tag: ${latestTag}`, "debug");
|
|
1638
|
-
}
|
|
1639
|
-
}
|
|
1640
|
-
const nextVersion = await calculateVersion(config, {
|
|
1641
|
-
latestTag,
|
|
1642
|
-
versionPrefix: formattedPrefix,
|
|
1643
|
-
branchPattern,
|
|
1644
|
-
baseBranch,
|
|
1645
|
-
prereleaseIdentifier,
|
|
1646
|
-
path: mainPkgPath,
|
|
1647
|
-
name: mainPkgName,
|
|
1648
|
-
type: config.type
|
|
1649
|
-
});
|
|
1650
|
-
if (!nextVersion) {
|
|
1651
|
-
const msg = mainPkgName ? `No version change needed for ${mainPkgName}` : "No version change needed";
|
|
1652
|
-
log(msg, "info");
|
|
1653
|
-
return;
|
|
1654
|
-
}
|
|
1655
|
-
const files = [];
|
|
1656
|
-
const updatedPackages = [];
|
|
1657
|
-
const processedPaths = /* @__PURE__ */ new Set();
|
|
1658
|
-
try {
|
|
1659
|
-
if (packages.root) {
|
|
1660
|
-
const rootPkgPath = path5.join(packages.root, "package.json");
|
|
1661
|
-
if (fs6.existsSync(rootPkgPath)) {
|
|
1662
|
-
updatePackageVersion(rootPkgPath, nextVersion);
|
|
1663
|
-
files.push(rootPkgPath);
|
|
1664
|
-
updatedPackages.push("root");
|
|
1665
|
-
processedPaths.add(rootPkgPath);
|
|
1666
|
-
const rootCargoFiles = updateCargoFiles(packages.root, nextVersion, config.cargo);
|
|
1667
|
-
files.push(...rootCargoFiles);
|
|
1668
|
-
}
|
|
1669
|
-
} else {
|
|
1670
|
-
log("Root package path is undefined, skipping root package.json update", "warning");
|
|
1671
|
-
}
|
|
1672
|
-
} catch (error) {
|
|
1673
|
-
const errMessage = error instanceof Error ? error.message : String(error);
|
|
1674
|
-
log(`Failed to update root package.json: ${errMessage}`, "error");
|
|
1675
|
-
}
|
|
1676
|
-
for (const pkg of packages.packages) {
|
|
1677
|
-
if (!shouldProcessPackage2(pkg, config)) {
|
|
1678
|
-
continue;
|
|
1679
|
-
}
|
|
1680
|
-
const packageJsonPath = path5.join(pkg.dir, "package.json");
|
|
1681
|
-
if (processedPaths.has(packageJsonPath)) {
|
|
1682
|
-
continue;
|
|
1683
|
-
}
|
|
1684
|
-
updatePackageVersion(packageJsonPath, nextVersion);
|
|
1685
|
-
files.push(packageJsonPath);
|
|
1686
|
-
updatedPackages.push(pkg.packageJson.name);
|
|
1687
|
-
processedPaths.add(packageJsonPath);
|
|
1688
|
-
const pkgCargoFiles = updateCargoFiles(pkg.dir, nextVersion, config.cargo);
|
|
1689
|
-
files.push(...pkgCargoFiles);
|
|
1690
|
-
}
|
|
1691
|
-
if (updatedPackages.length > 0) {
|
|
1692
|
-
log(`Updated ${updatedPackages.length} package(s) to version ${nextVersion}`, "success");
|
|
1693
|
-
} else {
|
|
1694
|
-
log("No packages were updated", "warning");
|
|
1695
|
-
return;
|
|
1696
|
-
}
|
|
1697
|
-
let changelogEntries = [];
|
|
1698
|
-
let revisionRange = "HEAD";
|
|
1699
|
-
try {
|
|
1700
|
-
if (latestTag) {
|
|
1701
|
-
try {
|
|
1702
|
-
execSync("git", ["rev-parse", "--verify", latestTag], {
|
|
1703
|
-
cwd: mainPkgPath,
|
|
1704
|
-
stdio: "ignore"
|
|
1705
|
-
});
|
|
1706
|
-
revisionRange = `${latestTag}..HEAD`;
|
|
1707
|
-
} catch {
|
|
1708
|
-
log(`Tag ${latestTag} doesn't exist, using all commits for changelog`, "debug");
|
|
1709
|
-
revisionRange = "HEAD";
|
|
1710
|
-
}
|
|
1711
|
-
}
|
|
1712
|
-
changelogEntries = extractChangelogEntriesFromCommits(mainPkgPath, revisionRange);
|
|
1713
|
-
if (changelogEntries.length === 0) {
|
|
1714
|
-
changelogEntries = [
|
|
1715
|
-
{
|
|
1716
|
-
type: "changed",
|
|
1717
|
-
description: `Update version to ${nextVersion}`
|
|
1718
|
-
}
|
|
1719
|
-
];
|
|
1720
|
-
}
|
|
1721
|
-
} catch (error) {
|
|
1722
|
-
log(`Error extracting changelog entries: ${error instanceof Error ? error.message : String(error)}`, "warning");
|
|
1723
|
-
changelogEntries = [
|
|
1724
|
-
{
|
|
1725
|
-
type: "changed",
|
|
1726
|
-
description: `Update version to ${nextVersion}`
|
|
1727
|
-
}
|
|
1728
|
-
];
|
|
1729
|
-
}
|
|
1730
|
-
addChangelogData({
|
|
1731
|
-
packageName: mainPkgName || "monorepo",
|
|
1732
|
-
version: nextVersion,
|
|
1733
|
-
previousVersion: latestTag || null,
|
|
1734
|
-
revisionRange,
|
|
1735
|
-
repoUrl: null,
|
|
1736
|
-
entries: changelogEntries
|
|
1737
|
-
});
|
|
1738
|
-
let tagPackageName = null;
|
|
1739
|
-
let commitPackageName;
|
|
1740
|
-
if (config.packageSpecificTags && packages.packages.length === 1) {
|
|
1741
|
-
tagPackageName = packages.packages[0].packageJson.name;
|
|
1742
|
-
commitPackageName = packages.packages[0].packageJson.name;
|
|
1743
|
-
}
|
|
1744
|
-
const nextTag = formatTag(
|
|
1745
|
-
nextVersion,
|
|
1746
|
-
formattedPrefix,
|
|
1747
|
-
tagPackageName,
|
|
1748
|
-
tagTemplate,
|
|
1749
|
-
config.packageSpecificTags || false
|
|
1750
|
-
);
|
|
1751
|
-
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion, commitPackageName, void 0);
|
|
1752
|
-
await createGitCommitAndTag(files, nextTag, formattedCommitMessage, skipHooks, dryRun);
|
|
1753
|
-
} catch (error) {
|
|
1754
|
-
if (BaseVersionError.isVersionError(error)) {
|
|
1755
|
-
log(`Synced Strategy failed: ${error.message} (${error.code})`, "error");
|
|
1756
|
-
} else {
|
|
1757
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1758
|
-
log(`Synced Strategy failed: ${errorMessage}`, "error");
|
|
1759
|
-
}
|
|
1760
|
-
throw error;
|
|
1761
|
-
}
|
|
1762
|
-
};
|
|
1763
|
-
}
|
|
1764
|
-
function createSingleStrategy(config) {
|
|
1765
|
-
return async (packages) => {
|
|
1766
|
-
try {
|
|
1767
|
-
const {
|
|
1768
|
-
mainPackage,
|
|
1769
|
-
versionPrefix,
|
|
1770
|
-
tagTemplate,
|
|
1771
|
-
commitMessage = `chore(release): \${version}`,
|
|
1772
|
-
dryRun,
|
|
1773
|
-
skipHooks
|
|
1774
|
-
} = config;
|
|
1775
|
-
let packageName;
|
|
1776
|
-
if (mainPackage) {
|
|
1777
|
-
packageName = mainPackage;
|
|
1778
|
-
} else if (packages.packages.length === 1) {
|
|
1779
|
-
packageName = packages.packages[0].packageJson.name;
|
|
1780
|
-
} else {
|
|
1781
|
-
throw createVersionError(
|
|
1782
|
-
"INVALID_CONFIG" /* INVALID_CONFIG */,
|
|
1783
|
-
"Single mode requires either mainPackage or exactly one resolved package"
|
|
1784
|
-
);
|
|
1785
|
-
}
|
|
1786
|
-
const pkg = packages.packages.find((p) => p.packageJson.name === packageName);
|
|
1787
|
-
if (!pkg) {
|
|
1788
|
-
throw createVersionError("PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */, packageName);
|
|
1789
|
-
}
|
|
1790
|
-
const pkgPath = pkg.dir;
|
|
1791
|
-
const formattedPrefix = formatVersionPrefix(versionPrefix || "v");
|
|
1792
|
-
let latestTagResult = await getLatestTagForPackage(packageName, formattedPrefix, {
|
|
1793
|
-
tagTemplate,
|
|
1794
|
-
packageSpecificTags: config.packageSpecificTags
|
|
1795
|
-
});
|
|
1796
|
-
if (!latestTagResult) {
|
|
1797
|
-
const globalTagResult = await getLatestTag();
|
|
1798
|
-
latestTagResult = globalTagResult || "";
|
|
1799
|
-
}
|
|
1800
|
-
const latestTag = latestTagResult;
|
|
1801
|
-
let nextVersion;
|
|
1802
|
-
nextVersion = await calculateVersion(config, {
|
|
1803
|
-
latestTag,
|
|
1804
|
-
versionPrefix: formattedPrefix,
|
|
1805
|
-
branchPattern: config.branchPattern,
|
|
1806
|
-
baseBranch: config.baseBranch,
|
|
1807
|
-
prereleaseIdentifier: config.prereleaseIdentifier,
|
|
1808
|
-
path: pkgPath,
|
|
1809
|
-
name: packageName,
|
|
1810
|
-
type: config.type
|
|
1811
|
-
});
|
|
1812
|
-
if (!nextVersion) {
|
|
1813
|
-
log(`No version change needed for ${packageName}`, "info");
|
|
1814
|
-
return;
|
|
1815
|
-
}
|
|
1816
|
-
let changelogEntries = [];
|
|
1817
|
-
let revisionRange = "HEAD";
|
|
1818
|
-
try {
|
|
1819
|
-
if (latestTag) {
|
|
1820
|
-
try {
|
|
1821
|
-
execSync("git", ["rev-parse", "--verify", latestTag], {
|
|
1822
|
-
cwd: pkgPath,
|
|
1823
|
-
stdio: "ignore"
|
|
1824
|
-
});
|
|
1825
|
-
revisionRange = `${latestTag}..HEAD`;
|
|
1826
|
-
} catch {
|
|
1827
|
-
log(`Tag ${latestTag} doesn't exist, using all commits for changelog`, "debug");
|
|
1828
|
-
revisionRange = "HEAD";
|
|
1829
|
-
}
|
|
1830
|
-
} else {
|
|
1831
|
-
revisionRange = "HEAD";
|
|
1832
|
-
}
|
|
1833
|
-
changelogEntries = extractChangelogEntriesFromCommits(pkgPath, revisionRange);
|
|
1834
|
-
if (changelogEntries.length === 0) {
|
|
1835
|
-
changelogEntries = [
|
|
1836
|
-
{
|
|
1837
|
-
type: "changed",
|
|
1838
|
-
description: `Update version to ${nextVersion}`
|
|
1839
|
-
}
|
|
1840
|
-
];
|
|
1841
|
-
}
|
|
1842
|
-
} catch (error) {
|
|
1843
|
-
log(`Error extracting changelog entries: ${error instanceof Error ? error.message : String(error)}`, "warning");
|
|
1844
|
-
changelogEntries = [
|
|
1845
|
-
{
|
|
1846
|
-
type: "changed",
|
|
1847
|
-
description: `Update version to ${nextVersion}`
|
|
1848
|
-
}
|
|
1849
|
-
];
|
|
1850
|
-
}
|
|
1851
|
-
let repoUrl;
|
|
1852
|
-
try {
|
|
1853
|
-
const packageJsonPath2 = path5.join(pkgPath, "package.json");
|
|
1854
|
-
if (fs6.existsSync(packageJsonPath2)) {
|
|
1855
|
-
const packageJson = JSON.parse(fs6.readFileSync(packageJsonPath2, "utf8"));
|
|
1856
|
-
if (packageJson.repository) {
|
|
1857
|
-
if (typeof packageJson.repository === "string") {
|
|
1858
|
-
repoUrl = packageJson.repository;
|
|
1859
|
-
} else if (packageJson.repository.url) {
|
|
1860
|
-
repoUrl = packageJson.repository.url;
|
|
1861
|
-
}
|
|
1862
|
-
if (repoUrl?.startsWith("git+") && repoUrl?.endsWith(".git")) {
|
|
1863
|
-
repoUrl = repoUrl.substring(4, repoUrl.length - 4);
|
|
1864
|
-
}
|
|
1865
|
-
}
|
|
1866
|
-
}
|
|
1867
|
-
} catch (error) {
|
|
1868
|
-
log(
|
|
1869
|
-
`Could not determine repository URL for changelog links: ${error instanceof Error ? error.message : String(error)}`,
|
|
1870
|
-
"warning"
|
|
1871
|
-
);
|
|
1872
|
-
}
|
|
1873
|
-
addChangelogData({
|
|
1874
|
-
packageName,
|
|
1875
|
-
version: nextVersion,
|
|
1876
|
-
previousVersion: latestTag || null,
|
|
1877
|
-
revisionRange,
|
|
1878
|
-
repoUrl: repoUrl || null,
|
|
1879
|
-
entries: changelogEntries
|
|
1880
|
-
});
|
|
1881
|
-
const packageJsonPath = path5.join(pkgPath, "package.json");
|
|
1882
|
-
updatePackageVersion(packageJsonPath, nextVersion);
|
|
1883
|
-
const filesToCommit = [packageJsonPath];
|
|
1884
|
-
const cargoFiles = updateCargoFiles(pkgPath, nextVersion, config.cargo);
|
|
1885
|
-
filesToCommit.push(...cargoFiles);
|
|
1886
|
-
log(`Updated package ${packageName} to version ${nextVersion}`, "success");
|
|
1887
|
-
const tagName = formatTag(nextVersion, formattedPrefix, packageName, tagTemplate, config.packageSpecificTags);
|
|
1888
|
-
const commitMsg = formatCommitMessage(commitMessage, nextVersion, packageName);
|
|
1889
|
-
if (!dryRun) {
|
|
1890
|
-
await createGitCommitAndTag(filesToCommit, tagName, commitMsg, skipHooks, dryRun);
|
|
1891
|
-
log(`Created tag: ${tagName}`, "success");
|
|
1892
|
-
} else {
|
|
1893
|
-
log(`Would create tag: ${tagName}`, "info");
|
|
1894
|
-
}
|
|
1895
|
-
} catch (error) {
|
|
1896
|
-
if (BaseVersionError.isVersionError(error)) {
|
|
1897
|
-
log(`Single Strategy failed: ${error.message} (${error.code})`, "error");
|
|
1898
|
-
} else {
|
|
1899
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1900
|
-
log(`Single Strategy failed: ${errorMessage}`, "error");
|
|
1901
|
-
}
|
|
1902
|
-
throw error;
|
|
1903
|
-
}
|
|
1904
|
-
};
|
|
1905
|
-
}
|
|
1906
|
-
function createAsyncStrategy(config) {
|
|
1907
|
-
const dependencies = {
|
|
1908
|
-
getLatestTag
|
|
1909
|
-
};
|
|
1910
|
-
const processorOptions = {
|
|
1911
|
-
skip: config.skip || [],
|
|
1912
|
-
versionPrefix: config.versionPrefix || "v",
|
|
1913
|
-
tagTemplate: config.tagTemplate,
|
|
1914
|
-
commitMessageTemplate: config.commitMessage || "",
|
|
1915
|
-
dryRun: config.dryRun || false,
|
|
1916
|
-
skipHooks: config.skipHooks || false,
|
|
1917
|
-
getLatestTag: dependencies.getLatestTag,
|
|
1918
|
-
fullConfig: config,
|
|
1919
|
-
// Extract common version configuration properties
|
|
1920
|
-
config: {
|
|
1921
|
-
branchPattern: config.branchPattern || [],
|
|
1922
|
-
baseBranch: config.baseBranch || "main",
|
|
1923
|
-
prereleaseIdentifier: config.prereleaseIdentifier,
|
|
1924
|
-
type: config.type
|
|
1925
|
-
}
|
|
1926
|
-
};
|
|
1927
|
-
const packageProcessor = new PackageProcessor(processorOptions);
|
|
1928
|
-
return async (packages, targets = []) => {
|
|
1929
|
-
try {
|
|
1930
|
-
let packagesToProcess = packages.packages;
|
|
1931
|
-
if (targets.length > 0) {
|
|
1932
|
-
const beforeCount = packagesToProcess.length;
|
|
1933
|
-
packagesToProcess = packagesToProcess.filter((pkg) => targets.includes(pkg.packageJson.name));
|
|
1934
|
-
log(
|
|
1935
|
-
`Runtime targets filter: ${beforeCount} \u2192 ${packagesToProcess.length} packages (${targets.join(", ")})`,
|
|
1936
|
-
"info"
|
|
1937
|
-
);
|
|
1938
|
-
}
|
|
1939
|
-
log(`Processing ${packagesToProcess.length} packages`, "info");
|
|
1940
|
-
const result = await packageProcessor.processPackages(packagesToProcess);
|
|
1941
|
-
if (result.updatedPackages.length === 0) {
|
|
1942
|
-
log("No packages required a version update.", "info");
|
|
1943
|
-
} else {
|
|
1944
|
-
const packageNames = result.updatedPackages.map((p) => p.name).join(", ");
|
|
1945
|
-
log(`Updated ${result.updatedPackages.length} package(s): ${packageNames}`, "success");
|
|
1946
|
-
if (result.tags.length > 0) {
|
|
1947
|
-
log(`Created ${result.tags.length} tag(s): ${result.tags.join(", ")}`, "success");
|
|
1948
|
-
}
|
|
1949
|
-
if (result.commitMessage) {
|
|
1950
|
-
log(`Created commit with message: "${result.commitMessage}"`, "success");
|
|
1951
|
-
}
|
|
1952
|
-
}
|
|
1953
|
-
} catch (error) {
|
|
1954
|
-
if (BaseVersionError.isVersionError(error)) {
|
|
1955
|
-
log(`Async Strategy failed: ${error.message} (${error.code})`, "error");
|
|
1956
|
-
} else {
|
|
1957
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1958
|
-
log(`Async Strategy failed: ${errorMessage}`, "error");
|
|
1959
|
-
}
|
|
1960
|
-
throw error;
|
|
1961
|
-
}
|
|
1962
|
-
};
|
|
1963
|
-
}
|
|
1964
|
-
function createStrategy(config) {
|
|
1965
|
-
if (config.sync) {
|
|
1966
|
-
return createSyncStrategy(config);
|
|
1967
|
-
}
|
|
1968
|
-
return createAsyncStrategy(config);
|
|
1969
|
-
}
|
|
1970
|
-
function createStrategyMap(config) {
|
|
1971
|
-
return {
|
|
1972
|
-
sync: createSyncStrategy(config),
|
|
1973
|
-
single: createSingleStrategy(config),
|
|
1974
|
-
async: createAsyncStrategy(config)
|
|
1975
|
-
};
|
|
1976
|
-
}
|
|
1977
|
-
|
|
1978
|
-
// src/core/versionEngine.ts
|
|
1979
|
-
import { cwd as cwd3 } from "process";
|
|
1980
|
-
import { getPackagesSync } from "@manypkg/get-packages";
|
|
1981
|
-
|
|
1982
|
-
// src/utils/packageFiltering.ts
|
|
1983
|
-
import path6 from "path";
|
|
1984
|
-
import micromatch2 from "micromatch";
|
|
1985
|
-
function filterPackagesByConfig(packages, configTargets, workspaceRoot) {
|
|
1986
|
-
if (configTargets.length === 0) {
|
|
1987
|
-
log("No config targets specified, returning all packages", "debug");
|
|
1988
|
-
return packages;
|
|
1989
|
-
}
|
|
1990
|
-
const matchedPackages = /* @__PURE__ */ new Set();
|
|
1991
|
-
for (const target of configTargets) {
|
|
1992
|
-
const dirMatches = filterByDirectoryPattern(packages, target, workspaceRoot);
|
|
1993
|
-
const nameMatches = filterByPackageNamePattern(packages, target);
|
|
1994
|
-
for (const pkg of dirMatches) {
|
|
1995
|
-
matchedPackages.add(pkg);
|
|
1996
|
-
}
|
|
1997
|
-
for (const pkg of nameMatches) {
|
|
1998
|
-
matchedPackages.add(pkg);
|
|
1999
|
-
}
|
|
2000
|
-
}
|
|
2001
|
-
return Array.from(matchedPackages);
|
|
2002
|
-
}
|
|
2003
|
-
function filterByDirectoryPattern(packages, pattern, workspaceRoot) {
|
|
2004
|
-
if (pattern === "./" || pattern === ".") {
|
|
2005
|
-
return packages.filter((pkg) => pkg.dir === workspaceRoot);
|
|
2006
|
-
}
|
|
2007
|
-
const normalizedPattern = pattern.replace(/\\/g, "/");
|
|
2008
|
-
return packages.filter((pkg) => {
|
|
2009
|
-
const relativePath = path6.relative(workspaceRoot, pkg.dir);
|
|
2010
|
-
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
2011
|
-
if (normalizedPattern === normalizedRelativePath) {
|
|
2012
|
-
return true;
|
|
2013
|
-
}
|
|
2014
|
-
try {
|
|
2015
|
-
return micromatch2.isMatch(normalizedRelativePath, normalizedPattern, {
|
|
2016
|
-
dot: true,
|
|
2017
|
-
noglobstar: false,
|
|
2018
|
-
bash: true
|
|
2019
|
-
});
|
|
2020
|
-
} catch (error) {
|
|
2021
|
-
log(
|
|
2022
|
-
`Invalid directory pattern "${pattern}": ${error instanceof Error ? error.message : String(error)}`,
|
|
2023
|
-
"warning"
|
|
2024
|
-
);
|
|
2025
|
-
return false;
|
|
2026
|
-
}
|
|
2027
|
-
});
|
|
2028
|
-
}
|
|
2029
|
-
function filterByPackageNamePattern(packages, pattern) {
|
|
2030
|
-
return packages.filter((pkg) => {
|
|
2031
|
-
if (!pkg.packageJson?.name || typeof pkg.packageJson.name !== "string") {
|
|
2032
|
-
return false;
|
|
2033
|
-
}
|
|
2034
|
-
return matchesPackageNamePattern(pkg.packageJson.name, pattern);
|
|
2035
|
-
});
|
|
2036
|
-
}
|
|
2037
|
-
function matchesPackageNamePattern(packageName, pattern) {
|
|
2038
|
-
if (packageName === pattern) {
|
|
2039
|
-
return true;
|
|
2040
|
-
}
|
|
2041
|
-
if (pattern.startsWith("@") && pattern.endsWith("/*") && !pattern.includes("**")) {
|
|
2042
|
-
const scope = pattern.slice(0, -2);
|
|
2043
|
-
return packageName.startsWith(`${scope}/`);
|
|
2044
|
-
}
|
|
2045
|
-
try {
|
|
2046
|
-
return micromatch2.isMatch(packageName, pattern, {
|
|
2047
|
-
dot: true,
|
|
2048
|
-
contains: false,
|
|
2049
|
-
noglobstar: false,
|
|
2050
|
-
bash: true
|
|
2051
|
-
});
|
|
2052
|
-
} catch (error) {
|
|
2053
|
-
log(
|
|
2054
|
-
`Invalid package name pattern "${pattern}": ${error instanceof Error ? error.message : String(error)}`,
|
|
2055
|
-
"warning"
|
|
2056
|
-
);
|
|
2057
|
-
return false;
|
|
2058
|
-
}
|
|
2059
|
-
}
|
|
2060
|
-
|
|
2061
|
-
// src/core/versionEngine.ts
|
|
2062
|
-
var VersionEngine = class {
|
|
2063
|
-
config;
|
|
2064
|
-
workspaceCache = null;
|
|
2065
|
-
strategies;
|
|
2066
|
-
currentStrategy;
|
|
2067
|
-
constructor(config, _jsonMode = false) {
|
|
2068
|
-
if (!config) {
|
|
2069
|
-
throw createVersionError("CONFIG_REQUIRED" /* CONFIG_REQUIRED */);
|
|
2070
|
-
}
|
|
2071
|
-
if (!config.preset) {
|
|
2072
|
-
config.preset = "conventional-commits";
|
|
2073
|
-
log("No preset specified, using default: conventional-commits", "warning");
|
|
2074
|
-
}
|
|
2075
|
-
this.config = config;
|
|
2076
|
-
this.strategies = createStrategyMap(config);
|
|
2077
|
-
this.currentStrategy = createStrategy(config);
|
|
2078
|
-
}
|
|
2079
|
-
/**
|
|
2080
|
-
* Get workspace packages information - with caching for performance
|
|
2081
|
-
*/
|
|
2082
|
-
async getWorkspacePackages() {
|
|
2083
|
-
try {
|
|
2084
|
-
if (this.workspaceCache) {
|
|
2085
|
-
return this.workspaceCache;
|
|
2086
|
-
}
|
|
2087
|
-
const pkgsResult = getPackagesSync(cwd3());
|
|
2088
|
-
if (!pkgsResult || !pkgsResult.packages) {
|
|
2089
|
-
throw createVersionError("PACKAGES_NOT_FOUND" /* PACKAGES_NOT_FOUND */);
|
|
2090
|
-
}
|
|
2091
|
-
if (!pkgsResult.root) {
|
|
2092
|
-
log("Root path is undefined in packages result, setting to current working directory", "warning");
|
|
2093
|
-
pkgsResult.root = cwd3();
|
|
2094
|
-
}
|
|
2095
|
-
if (this.config.packages && this.config.packages.length > 0) {
|
|
2096
|
-
const originalCount = pkgsResult.packages.length;
|
|
2097
|
-
const filteredPackages = filterPackagesByConfig(pkgsResult.packages, this.config.packages, pkgsResult.root);
|
|
2098
|
-
pkgsResult.packages = filteredPackages;
|
|
2099
|
-
log(
|
|
2100
|
-
`Filtered ${originalCount} workspace packages to ${filteredPackages.length} based on packages config`,
|
|
2101
|
-
"info"
|
|
2102
|
-
);
|
|
2103
|
-
if (filteredPackages.length === 0) {
|
|
2104
|
-
log("Warning: No packages matched the specified patterns in config.packages", "warning");
|
|
2105
|
-
}
|
|
2106
|
-
}
|
|
2107
|
-
this.workspaceCache = pkgsResult;
|
|
2108
|
-
return pkgsResult;
|
|
2109
|
-
} catch (error) {
|
|
2110
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2111
|
-
log(`Failed to get packages information: ${errorMessage}`, "error");
|
|
2112
|
-
console.error(error);
|
|
2113
|
-
throw createVersionError("WORKSPACE_ERROR" /* WORKSPACE_ERROR */, errorMessage);
|
|
2114
|
-
}
|
|
2115
|
-
}
|
|
2116
|
-
/**
|
|
2117
|
-
* Run the current strategy
|
|
2118
|
-
* @param packages Workspace packages to process
|
|
2119
|
-
* @param targets Optional package targets to process (only used by async strategy)
|
|
2120
|
-
*/
|
|
2121
|
-
async run(packages, targets = []) {
|
|
2122
|
-
try {
|
|
2123
|
-
return this.currentStrategy(packages, targets);
|
|
2124
|
-
} catch (error) {
|
|
2125
|
-
if (error instanceof VersionError || error instanceof GitError) {
|
|
2126
|
-
log(`Version engine failed: ${error.message} (${error.code || "UNKNOWN"})`, "error");
|
|
2127
|
-
if (error instanceof GitError) {
|
|
2128
|
-
console.error("Git error details:");
|
|
2129
|
-
if (error.message.includes("Command failed:")) {
|
|
2130
|
-
const cmdOutput = error.message.split("Command failed:")[1];
|
|
2131
|
-
if (cmdOutput) {
|
|
2132
|
-
console.error("Command output:", cmdOutput.trim());
|
|
2133
|
-
}
|
|
2134
|
-
}
|
|
2135
|
-
}
|
|
2136
|
-
} else {
|
|
2137
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2138
|
-
log(`Version engine failed: ${errorMessage}`, "error");
|
|
2139
|
-
if (error instanceof Error && error.stack) {
|
|
2140
|
-
console.error("Error stack trace:");
|
|
2141
|
-
console.error(error.stack);
|
|
2142
|
-
}
|
|
2143
|
-
}
|
|
2144
|
-
throw error;
|
|
2145
|
-
}
|
|
2146
|
-
}
|
|
2147
|
-
/**
|
|
2148
|
-
* Change the current strategy
|
|
2149
|
-
* @param strategyType The strategy type to use: 'sync', 'single', or 'async'
|
|
2150
|
-
*/
|
|
2151
|
-
setStrategy(strategyType) {
|
|
2152
|
-
this.currentStrategy = this.strategies[strategyType];
|
|
2153
|
-
}
|
|
2154
|
-
};
|
|
2155
|
-
|
|
2156
|
-
export {
|
|
2157
|
-
loadConfig,
|
|
2158
|
-
VersionErrorCode,
|
|
2159
|
-
createVersionError,
|
|
2160
|
-
enableJsonOutput,
|
|
2161
|
-
getJsonData,
|
|
2162
|
-
printJsonOutput,
|
|
2163
|
-
log,
|
|
2164
|
-
calculateVersion,
|
|
2165
|
-
PackageProcessor,
|
|
2166
|
-
createSyncStrategy,
|
|
2167
|
-
createSingleStrategy,
|
|
2168
|
-
createAsyncStrategy,
|
|
2169
|
-
VersionEngine
|
|
2170
|
-
};
|