package-versioner 0.6.4 → 0.7.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 +13 -6
- package/dist/index.cjs +1061 -169
- package/dist/index.js +1052 -160
- package/docs/changelogs.md +65 -0
- package/docs/{VERSIONING_STRATEGIES.md → versioning.md} +1 -1
- package/package-versioner.schema.json +31 -0
- package/package.json +11 -7
package/dist/index.js
CHANGED
|
@@ -1,79 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import * as
|
|
5
|
-
import
|
|
4
|
+
import * as fs9 from "node:fs";
|
|
5
|
+
import path7 from "node:path";
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
|
|
8
|
-
// src/
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
const localProcess = cwd();
|
|
13
|
-
const filePath = configPath || `${localProcess}/version.config.json`;
|
|
14
|
-
return new Promise((resolve, reject) => {
|
|
15
|
-
fs.readFile(filePath, "utf-8", (err, data) => {
|
|
16
|
-
if (err) {
|
|
17
|
-
reject(new Error(`Could not locate the config file at ${filePath}: ${err.message}`));
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
try {
|
|
21
|
-
const config = JSON.parse(data);
|
|
22
|
-
resolve(config);
|
|
23
|
-
} catch (err2) {
|
|
24
|
-
const errorMessage = err2 instanceof Error ? err2.message : String(err2);
|
|
25
|
-
reject(new Error(`Failed to parse config file ${filePath}: ${errorMessage}`));
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// src/core/versionEngine.ts
|
|
32
|
-
import { cwd as cwd4 } from "node:process";
|
|
33
|
-
import { getPackagesSync } from "@manypkg/get-packages";
|
|
34
|
-
|
|
35
|
-
// src/errors/gitError.ts
|
|
36
|
-
var GitError = class extends Error {
|
|
37
|
-
constructor(message, code) {
|
|
38
|
-
super(message);
|
|
39
|
-
this.code = code;
|
|
40
|
-
this.name = "GitError";
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
function createGitError(code, details) {
|
|
44
|
-
const messages = {
|
|
45
|
-
["NOT_GIT_REPO" /* NOT_GIT_REPO */]: "Not a git repository",
|
|
46
|
-
["GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */]: "Failed to create new version",
|
|
47
|
-
["NO_FILES" /* NO_FILES */]: "No files specified for commit",
|
|
48
|
-
["NO_COMMIT_MESSAGE" /* NO_COMMIT_MESSAGE */]: "Commit message is required",
|
|
49
|
-
["GIT_ERROR" /* GIT_ERROR */]: "Git operation failed"
|
|
50
|
-
};
|
|
51
|
-
const baseMessage = messages[code];
|
|
52
|
-
const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
|
|
53
|
-
return new GitError(fullMessage, code);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// src/errors/versionError.ts
|
|
57
|
-
var VersionError = class extends Error {
|
|
58
|
-
constructor(message, code) {
|
|
59
|
-
super(message);
|
|
60
|
-
this.code = code;
|
|
61
|
-
this.name = "VersionError";
|
|
62
|
-
}
|
|
63
|
-
};
|
|
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 baseMessage = messages[code];
|
|
74
|
-
const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
|
|
75
|
-
return new VersionError(fullMessage, code);
|
|
76
|
-
}
|
|
8
|
+
// src/changelog/changelogRegenerator.ts
|
|
9
|
+
import { execSync as execSync2 } from "node:child_process";
|
|
10
|
+
import fs from "node:fs";
|
|
11
|
+
import path from "node:path";
|
|
77
12
|
|
|
78
13
|
// src/utils/logging.ts
|
|
79
14
|
import chalk from "chalk";
|
|
@@ -156,9 +91,508 @@ function log(message, level = "info") {
|
|
|
156
91
|
}
|
|
157
92
|
}
|
|
158
93
|
|
|
94
|
+
// src/changelog/commitParser.ts
|
|
95
|
+
import { execSync } from "node:child_process";
|
|
96
|
+
var CONVENTIONAL_COMMIT_REGEX = /^(\w+)(?:\(([^)]+)\))?(!)?: (.+)(?:\n\n([\s\S]*))?/;
|
|
97
|
+
var BREAKING_CHANGE_REGEX = /BREAKING CHANGE: ([\s\S]+?)(?:\n\n|$)/;
|
|
98
|
+
function extractChangelogEntriesFromCommits(projectDir, revisionRange) {
|
|
99
|
+
try {
|
|
100
|
+
const command = `git log ${revisionRange} --pretty=format:"%B---COMMIT_DELIMITER---" --no-merges`;
|
|
101
|
+
const output = execSync(command, {
|
|
102
|
+
cwd: projectDir,
|
|
103
|
+
encoding: "utf8"
|
|
104
|
+
});
|
|
105
|
+
const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
|
|
106
|
+
return commits.map((commit) => parseCommitMessage(commit)).filter((entry) => entry !== null);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
log(`Error extracting commits: ${error}`, "error");
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function parseCommitMessage(message) {
|
|
113
|
+
const match = message.match(CONVENTIONAL_COMMIT_REGEX);
|
|
114
|
+
if (match) {
|
|
115
|
+
const [, type, scope, breakingMark, subject, body = ""] = match;
|
|
116
|
+
const breakingFromMark = breakingMark === "!";
|
|
117
|
+
const breakingChangeMatch = body.match(BREAKING_CHANGE_REGEX);
|
|
118
|
+
const hasBreakingChange = breakingFromMark || breakingChangeMatch !== null;
|
|
119
|
+
const changelogType = mapCommitTypeToChangelogType(type);
|
|
120
|
+
if (!changelogType) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const issueIds = extractIssueIds(body);
|
|
124
|
+
let description = subject;
|
|
125
|
+
if (hasBreakingChange) {
|
|
126
|
+
description = `**BREAKING** ${description}`;
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
type: changelogType,
|
|
130
|
+
description,
|
|
131
|
+
scope: scope || void 0,
|
|
132
|
+
issueIds: issueIds.length > 0 ? issueIds : void 0,
|
|
133
|
+
originalType: type
|
|
134
|
+
// Store original type for custom formatting
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
if (!message.startsWith("Merge") && !message.match(/^v?\d+\.\d+\.\d+/)) {
|
|
138
|
+
const firstLine = message.split("\n")[0].trim();
|
|
139
|
+
return {
|
|
140
|
+
type: "changed",
|
|
141
|
+
description: firstLine
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
function mapCommitTypeToChangelogType(type) {
|
|
147
|
+
switch (type) {
|
|
148
|
+
case "feat":
|
|
149
|
+
return "added";
|
|
150
|
+
case "fix":
|
|
151
|
+
return "fixed";
|
|
152
|
+
case "docs":
|
|
153
|
+
case "style":
|
|
154
|
+
case "refactor":
|
|
155
|
+
case "perf":
|
|
156
|
+
case "build":
|
|
157
|
+
case "ci":
|
|
158
|
+
return "changed";
|
|
159
|
+
case "revert":
|
|
160
|
+
return "removed";
|
|
161
|
+
case "chore":
|
|
162
|
+
return "changed";
|
|
163
|
+
case "test":
|
|
164
|
+
return null;
|
|
165
|
+
default:
|
|
166
|
+
return "changed";
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function extractIssueIds(body) {
|
|
170
|
+
const issueRegex = /(?:fix|fixes|close|closes|resolve|resolves)\s+#(\d+)/gi;
|
|
171
|
+
const issueIds = [];
|
|
172
|
+
let match = issueRegex.exec(body);
|
|
173
|
+
while (match !== null) {
|
|
174
|
+
issueIds.push(`#${match[1]}`);
|
|
175
|
+
match = issueRegex.exec(body);
|
|
176
|
+
}
|
|
177
|
+
return issueIds;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// src/changelog/formatters.ts
|
|
181
|
+
function formatChangelogEntries(format, version, date, entries, packageName, repoUrl) {
|
|
182
|
+
const formattingEntries = entries.map((entry) => {
|
|
183
|
+
const hasBreaking = entry.description.includes("**BREAKING**");
|
|
184
|
+
return {
|
|
185
|
+
...entry,
|
|
186
|
+
breaking: hasBreaking
|
|
187
|
+
};
|
|
188
|
+
});
|
|
189
|
+
return format === "keep-a-changelog" ? formatKeepAChangelogEntries(version, date, formattingEntries, repoUrl) : formatAngularEntries(version, date, formattingEntries, packageName);
|
|
190
|
+
}
|
|
191
|
+
function formatKeepAChangelogEntries(version, date, entries, repoUrl) {
|
|
192
|
+
const added = [];
|
|
193
|
+
const changed = [];
|
|
194
|
+
const deprecated = [];
|
|
195
|
+
const removed = [];
|
|
196
|
+
const fixed = [];
|
|
197
|
+
const security = [];
|
|
198
|
+
for (const entry of entries) {
|
|
199
|
+
const entryText = entry.scope ? `- **${entry.scope}**: ${entry.description}` : `- ${entry.description}`;
|
|
200
|
+
const formattedEntry = entry.breaking ? entryText.replace(/^- /, "- **BREAKING** ") : entryText;
|
|
201
|
+
const entryType = entry.originalType || entry.type;
|
|
202
|
+
switch (entryType) {
|
|
203
|
+
case "feat":
|
|
204
|
+
added.push(formattedEntry);
|
|
205
|
+
break;
|
|
206
|
+
case "fix":
|
|
207
|
+
fixed.push(formattedEntry);
|
|
208
|
+
break;
|
|
209
|
+
case "docs":
|
|
210
|
+
case "style":
|
|
211
|
+
case "refactor":
|
|
212
|
+
case "perf":
|
|
213
|
+
case "build":
|
|
214
|
+
case "ci":
|
|
215
|
+
changed.push(formattedEntry);
|
|
216
|
+
break;
|
|
217
|
+
case "test":
|
|
218
|
+
break;
|
|
219
|
+
case "chore":
|
|
220
|
+
if (entry.description.toLowerCase().includes("deprecat")) {
|
|
221
|
+
deprecated.push(formattedEntry);
|
|
222
|
+
} else {
|
|
223
|
+
changed.push(formattedEntry);
|
|
224
|
+
}
|
|
225
|
+
break;
|
|
226
|
+
// Keep-a-changelog standard types
|
|
227
|
+
case "added":
|
|
228
|
+
added.push(formattedEntry);
|
|
229
|
+
break;
|
|
230
|
+
case "changed":
|
|
231
|
+
changed.push(formattedEntry);
|
|
232
|
+
break;
|
|
233
|
+
case "deprecated":
|
|
234
|
+
deprecated.push(formattedEntry);
|
|
235
|
+
break;
|
|
236
|
+
case "removed":
|
|
237
|
+
removed.push(formattedEntry);
|
|
238
|
+
break;
|
|
239
|
+
case "fixed":
|
|
240
|
+
fixed.push(formattedEntry);
|
|
241
|
+
break;
|
|
242
|
+
case "security":
|
|
243
|
+
security.push(formattedEntry);
|
|
244
|
+
break;
|
|
245
|
+
default:
|
|
246
|
+
changed.push(formattedEntry);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
let content = `## [${version}] - ${date}
|
|
250
|
+
|
|
251
|
+
`;
|
|
252
|
+
if (added.length > 0) {
|
|
253
|
+
content += `### Added
|
|
254
|
+
|
|
255
|
+
${added.join("\n")}
|
|
256
|
+
|
|
257
|
+
`;
|
|
258
|
+
}
|
|
259
|
+
if (changed.length > 0) {
|
|
260
|
+
content += `### Changed
|
|
261
|
+
|
|
262
|
+
${changed.join("\n")}
|
|
263
|
+
|
|
264
|
+
`;
|
|
265
|
+
}
|
|
266
|
+
if (deprecated.length > 0) {
|
|
267
|
+
content += `### Deprecated
|
|
268
|
+
|
|
269
|
+
${deprecated.join("\n")}
|
|
270
|
+
|
|
271
|
+
`;
|
|
272
|
+
}
|
|
273
|
+
if (removed.length > 0) {
|
|
274
|
+
content += `### Removed
|
|
275
|
+
|
|
276
|
+
${removed.join("\n")}
|
|
277
|
+
|
|
278
|
+
`;
|
|
279
|
+
}
|
|
280
|
+
if (fixed.length > 0) {
|
|
281
|
+
content += `### Fixed
|
|
282
|
+
|
|
283
|
+
${fixed.join("\n")}
|
|
284
|
+
|
|
285
|
+
`;
|
|
286
|
+
}
|
|
287
|
+
if (security.length > 0) {
|
|
288
|
+
content += `### Security
|
|
289
|
+
|
|
290
|
+
${security.join("\n")}
|
|
291
|
+
|
|
292
|
+
`;
|
|
293
|
+
}
|
|
294
|
+
if (repoUrl) {
|
|
295
|
+
content += `[${version}]: ${repoUrl}/compare/v${version}...HEAD
|
|
296
|
+
`;
|
|
297
|
+
}
|
|
298
|
+
return content.trim();
|
|
299
|
+
}
|
|
300
|
+
function formatAngularEntries(version, date, entries, packageName) {
|
|
301
|
+
const features = [];
|
|
302
|
+
const bugfixes = [];
|
|
303
|
+
const performance = [];
|
|
304
|
+
const breaking = [];
|
|
305
|
+
for (const entry of entries) {
|
|
306
|
+
if (entry.breaking) {
|
|
307
|
+
breaking.push(entry);
|
|
308
|
+
}
|
|
309
|
+
const entryType = entry.originalType || entry.type;
|
|
310
|
+
switch (entryType) {
|
|
311
|
+
case "feat":
|
|
312
|
+
case "added":
|
|
313
|
+
features.push(entry);
|
|
314
|
+
break;
|
|
315
|
+
case "fix":
|
|
316
|
+
case "fixed":
|
|
317
|
+
bugfixes.push(entry);
|
|
318
|
+
break;
|
|
319
|
+
case "perf":
|
|
320
|
+
performance.push(entry);
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
let content = `## [${version}]${packageName ? ` (${packageName})` : ""} (${date})
|
|
325
|
+
|
|
326
|
+
`;
|
|
327
|
+
if (features.length > 0) {
|
|
328
|
+
content += "### Features\n\n";
|
|
329
|
+
content += formatAngularTypeEntries(features);
|
|
330
|
+
content += "\n";
|
|
331
|
+
}
|
|
332
|
+
if (bugfixes.length > 0) {
|
|
333
|
+
content += "### Bug Fixes\n\n";
|
|
334
|
+
content += formatAngularTypeEntries(bugfixes);
|
|
335
|
+
content += "\n";
|
|
336
|
+
}
|
|
337
|
+
if (performance.length > 0) {
|
|
338
|
+
content += "### Performance Improvements\n\n";
|
|
339
|
+
content += formatAngularTypeEntries(performance);
|
|
340
|
+
content += "\n";
|
|
341
|
+
}
|
|
342
|
+
if (breaking.length > 0) {
|
|
343
|
+
content += "### BREAKING CHANGES\n\n";
|
|
344
|
+
content += formatAngularTypeEntries(breaking);
|
|
345
|
+
content += "\n";
|
|
346
|
+
}
|
|
347
|
+
return content.trim();
|
|
348
|
+
}
|
|
349
|
+
function formatAngularTypeEntries(entries) {
|
|
350
|
+
var _a;
|
|
351
|
+
const entriesByScope = /* @__PURE__ */ new Map();
|
|
352
|
+
for (const entry of entries) {
|
|
353
|
+
const scope = entry.scope || "";
|
|
354
|
+
if (!entriesByScope.has(scope)) {
|
|
355
|
+
entriesByScope.set(scope, []);
|
|
356
|
+
}
|
|
357
|
+
(_a = entriesByScope.get(scope)) == null ? void 0 : _a.push(entry);
|
|
358
|
+
}
|
|
359
|
+
const result = [];
|
|
360
|
+
for (const [scope, scopeEntries] of Object.entries(groupEntriesByScope(entries))) {
|
|
361
|
+
if (scope !== "undefined" && scope !== "") {
|
|
362
|
+
result.push(`* **${scope}:**`);
|
|
363
|
+
for (const entry of scopeEntries) {
|
|
364
|
+
const description = entry.description.replace("**BREAKING** ", "");
|
|
365
|
+
result.push(` * ${description}`);
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
for (const entry of scopeEntries) {
|
|
369
|
+
const description = entry.description.replace("**BREAKING** ", "");
|
|
370
|
+
result.push(`* ${description}`);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return result.join("\n");
|
|
375
|
+
}
|
|
376
|
+
function groupEntriesByScope(entries) {
|
|
377
|
+
const result = {};
|
|
378
|
+
for (const entry of entries) {
|
|
379
|
+
const scope = entry.scope || "";
|
|
380
|
+
if (!result[scope]) {
|
|
381
|
+
result[scope] = [];
|
|
382
|
+
}
|
|
383
|
+
result[scope].push(entry);
|
|
384
|
+
}
|
|
385
|
+
return result;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// src/changelog/templates.ts
|
|
389
|
+
function getDefaultTemplate(format) {
|
|
390
|
+
return format === "keep-a-changelog" ? getKeepAChangelogTemplate() : getAngularTemplate();
|
|
391
|
+
}
|
|
392
|
+
function getKeepAChangelogTemplate() {
|
|
393
|
+
return `# Changelog
|
|
394
|
+
|
|
395
|
+
All notable changes to this project will be documented in this file.
|
|
396
|
+
|
|
397
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
398
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
399
|
+
|
|
400
|
+
`;
|
|
401
|
+
}
|
|
402
|
+
function getAngularTemplate() {
|
|
403
|
+
return `# Changelog
|
|
404
|
+
|
|
405
|
+
`;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// src/changelog/changelogRegenerator.ts
|
|
409
|
+
function getAllVersionTags(since, versionPrefix = "v") {
|
|
410
|
+
try {
|
|
411
|
+
const command = since ? `git tag --list "${versionPrefix}*" --sort=creatordate --contains ${since}` : `git tag --list "${versionPrefix}*" --sort=creatordate`;
|
|
412
|
+
const tagOutput = execSync2(command, { encoding: "utf8" }).trim();
|
|
413
|
+
if (!tagOutput) {
|
|
414
|
+
return [];
|
|
415
|
+
}
|
|
416
|
+
const tags = tagOutput.split("\n").filter((tag) => !!tag);
|
|
417
|
+
return tags.map((tag) => {
|
|
418
|
+
try {
|
|
419
|
+
const date = execSync2(`git log -1 --format=%ad --date=short ${tag}`, {
|
|
420
|
+
encoding: "utf8"
|
|
421
|
+
}).trim();
|
|
422
|
+
const version = tag.replace(new RegExp(`^${versionPrefix}`), "");
|
|
423
|
+
return { tag, version, date };
|
|
424
|
+
} catch (error) {
|
|
425
|
+
log(`Failed to get date for tag ${tag}: ${error}`, "warning");
|
|
426
|
+
return { tag, version: tag.replace(new RegExp(`^${versionPrefix}`), ""), date: "Unknown" };
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
} catch (error) {
|
|
430
|
+
log(`Failed to get version tags: ${error}`, "error");
|
|
431
|
+
return [];
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
async function regenerateChangelog(options) {
|
|
435
|
+
const { format, since, projectDir } = options;
|
|
436
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
437
|
+
let packageName = "";
|
|
438
|
+
let repoUrl = options.repoUrl;
|
|
439
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
440
|
+
try {
|
|
441
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
442
|
+
packageName = packageJson.name || "";
|
|
443
|
+
if (!repoUrl && packageJson.repository) {
|
|
444
|
+
if (typeof packageJson.repository === "string") {
|
|
445
|
+
repoUrl = packageJson.repository;
|
|
446
|
+
} else if (packageJson.repository.url) {
|
|
447
|
+
repoUrl = packageJson.repository.url;
|
|
448
|
+
}
|
|
449
|
+
if ((repoUrl == null ? void 0 : repoUrl.startsWith("git+")) && (repoUrl == null ? void 0 : repoUrl.endsWith(".git"))) {
|
|
450
|
+
repoUrl = repoUrl.substring(4, repoUrl.length - 4);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
} catch (error) {
|
|
454
|
+
log(`Failed to read package.json: ${error}`, "warning");
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
let versionPrefix = "v";
|
|
458
|
+
try {
|
|
459
|
+
const allTags = execSync2("git tag --list", { encoding: "utf8" }).trim().split("\n");
|
|
460
|
+
const versionTag = allTags.find((tag) => /^[vV][0-9]/.test(tag));
|
|
461
|
+
if (versionTag) {
|
|
462
|
+
versionPrefix = versionTag.charAt(0);
|
|
463
|
+
}
|
|
464
|
+
} catch {
|
|
465
|
+
}
|
|
466
|
+
const tags = getAllVersionTags(since, versionPrefix);
|
|
467
|
+
if (!tags.length) {
|
|
468
|
+
throw new Error(
|
|
469
|
+
'No version tags found in git history. Make sure you have tags that start with the version prefix (usually "v").'
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
let changelogContent = getDefaultTemplate(format);
|
|
473
|
+
log(`Found ${tags.length} version tags, generating changelog...`, "info");
|
|
474
|
+
const versions = [];
|
|
475
|
+
for (let i = tags.length - 1; i >= 0; i--) {
|
|
476
|
+
const currentTag = tags[i];
|
|
477
|
+
const previousTag = i > 0 ? tags[i - 1].tag : null;
|
|
478
|
+
log(`Processing changes for ${currentTag.tag}...`, "info");
|
|
479
|
+
try {
|
|
480
|
+
const tagRange = previousTag ? `${previousTag}..${currentTag.tag}` : currentTag.tag;
|
|
481
|
+
const entries = extractChangelogEntriesFromCommits(projectDir, tagRange);
|
|
482
|
+
if (!entries.length) {
|
|
483
|
+
log(`No changelog entries found for ${currentTag.tag}, adding placeholder entry`, "info");
|
|
484
|
+
entries.push({
|
|
485
|
+
type: "changed",
|
|
486
|
+
description: `Release version ${currentTag.version}`
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
versions.unshift(
|
|
490
|
+
formatChangelogEntries(
|
|
491
|
+
format,
|
|
492
|
+
currentTag.version,
|
|
493
|
+
currentTag.date,
|
|
494
|
+
entries,
|
|
495
|
+
packageName,
|
|
496
|
+
repoUrl
|
|
497
|
+
)
|
|
498
|
+
);
|
|
499
|
+
} catch (error) {
|
|
500
|
+
log(`Failed to process version ${currentTag.tag}: ${error}`, "error");
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
changelogContent += versions.join("\n\n");
|
|
504
|
+
return changelogContent;
|
|
505
|
+
}
|
|
506
|
+
async function writeChangelog(content, outputPath, dryRun) {
|
|
507
|
+
if (dryRun) {
|
|
508
|
+
log("--- Changelog Preview ---", "info");
|
|
509
|
+
console.log(content);
|
|
510
|
+
log("--- End Preview ---", "info");
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
try {
|
|
514
|
+
fs.writeFileSync(outputPath, content, "utf8");
|
|
515
|
+
log(`Changelog successfully written to ${outputPath}`, "success");
|
|
516
|
+
} catch (error) {
|
|
517
|
+
throw new Error(
|
|
518
|
+
`Failed to write changelog: ${error instanceof Error ? error.message : String(error)}`
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// src/config.ts
|
|
524
|
+
import * as fs2 from "node:fs";
|
|
525
|
+
import { cwd } from "node:process";
|
|
526
|
+
function loadConfig(configPath) {
|
|
527
|
+
const localProcess = cwd();
|
|
528
|
+
const filePath = configPath || `${localProcess}/version.config.json`;
|
|
529
|
+
return new Promise((resolve, reject) => {
|
|
530
|
+
fs2.readFile(filePath, "utf-8", (err, data) => {
|
|
531
|
+
if (err) {
|
|
532
|
+
reject(new Error(`Could not locate the config file at ${filePath}: ${err.message}`));
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
try {
|
|
536
|
+
const config = JSON.parse(data);
|
|
537
|
+
resolve(config);
|
|
538
|
+
} catch (err2) {
|
|
539
|
+
const errorMessage = err2 instanceof Error ? err2.message : String(err2);
|
|
540
|
+
reject(new Error(`Failed to parse config file ${filePath}: ${errorMessage}`));
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// src/core/versionEngine.ts
|
|
547
|
+
import { cwd as cwd4 } from "node:process";
|
|
548
|
+
import { getPackagesSync } from "@manypkg/get-packages";
|
|
549
|
+
|
|
550
|
+
// src/errors/gitError.ts
|
|
551
|
+
var GitError = class extends Error {
|
|
552
|
+
constructor(message, code) {
|
|
553
|
+
super(message);
|
|
554
|
+
this.code = code;
|
|
555
|
+
this.name = "GitError";
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
function createGitError(code, details) {
|
|
559
|
+
const messages = {
|
|
560
|
+
["NOT_GIT_REPO" /* NOT_GIT_REPO */]: "Not a git repository",
|
|
561
|
+
["GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */]: "Failed to create new version",
|
|
562
|
+
["NO_FILES" /* NO_FILES */]: "No files specified for commit",
|
|
563
|
+
["NO_COMMIT_MESSAGE" /* NO_COMMIT_MESSAGE */]: "Commit message is required",
|
|
564
|
+
["GIT_ERROR" /* GIT_ERROR */]: "Git operation failed"
|
|
565
|
+
};
|
|
566
|
+
const baseMessage = messages[code];
|
|
567
|
+
const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
|
|
568
|
+
return new GitError(fullMessage, code);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// src/errors/versionError.ts
|
|
572
|
+
var VersionError = class extends Error {
|
|
573
|
+
constructor(message, code) {
|
|
574
|
+
super(message);
|
|
575
|
+
this.code = code;
|
|
576
|
+
this.name = "VersionError";
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
function createVersionError(code, details) {
|
|
580
|
+
const messages = {
|
|
581
|
+
["CONFIG_REQUIRED" /* CONFIG_REQUIRED */]: "Configuration is required",
|
|
582
|
+
["PACKAGES_NOT_FOUND" /* PACKAGES_NOT_FOUND */]: "Failed to get packages information",
|
|
583
|
+
["WORKSPACE_ERROR" /* WORKSPACE_ERROR */]: "Failed to get workspace packages",
|
|
584
|
+
["INVALID_CONFIG" /* INVALID_CONFIG */]: "Invalid configuration",
|
|
585
|
+
["PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */]: "Package not found",
|
|
586
|
+
["VERSION_CALCULATION_ERROR" /* VERSION_CALCULATION_ERROR */]: "Failed to calculate version"
|
|
587
|
+
};
|
|
588
|
+
const baseMessage = messages[code];
|
|
589
|
+
const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
|
|
590
|
+
return new VersionError(fullMessage, code);
|
|
591
|
+
}
|
|
592
|
+
|
|
159
593
|
// src/core/versionStrategies.ts
|
|
160
|
-
import
|
|
161
|
-
import * as
|
|
594
|
+
import fs8 from "node:fs";
|
|
595
|
+
import * as path6 from "node:path";
|
|
162
596
|
|
|
163
597
|
// src/git/commands.ts
|
|
164
598
|
import { cwd as cwd2 } from "node:process";
|
|
@@ -181,7 +615,7 @@ var execAsync = (command, options) => {
|
|
|
181
615
|
);
|
|
182
616
|
});
|
|
183
617
|
};
|
|
184
|
-
var
|
|
618
|
+
var execSync3 = (command, args) => nativeExecSync(command, { maxBuffer: 1024 * 1024 * 10, ...args });
|
|
185
619
|
|
|
186
620
|
// src/git/repository.ts
|
|
187
621
|
import { existsSync, statSync } from "node:fs";
|
|
@@ -196,14 +630,14 @@ function isGitRepository(directory) {
|
|
|
196
630
|
return false;
|
|
197
631
|
}
|
|
198
632
|
try {
|
|
199
|
-
|
|
633
|
+
execSync3("git rev-parse --is-inside-work-tree", { cwd: directory });
|
|
200
634
|
return true;
|
|
201
635
|
} catch (_error) {
|
|
202
636
|
return false;
|
|
203
637
|
}
|
|
204
638
|
}
|
|
205
639
|
function getCurrentBranch() {
|
|
206
|
-
const result =
|
|
640
|
+
const result = execSync3("git rev-parse --abbrev-ref HEAD");
|
|
207
641
|
return result.toString().trim();
|
|
208
642
|
}
|
|
209
643
|
|
|
@@ -347,7 +781,7 @@ function createTemplateString(template, variables) {
|
|
|
347
781
|
function getCommitsLength(pkgRoot) {
|
|
348
782
|
try {
|
|
349
783
|
const gitCommand = `git rev-list --count HEAD ^$(git describe --tags --abbrev=0) ${pkgRoot}`;
|
|
350
|
-
const amount =
|
|
784
|
+
const amount = execSync3(gitCommand).toString().trim();
|
|
351
785
|
return Number(amount);
|
|
352
786
|
} catch (error) {
|
|
353
787
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -444,20 +878,20 @@ async function getLatestTagForPackage(packageName, versionPrefix) {
|
|
|
444
878
|
}
|
|
445
879
|
|
|
446
880
|
// src/package/packageManagement.ts
|
|
447
|
-
import
|
|
881
|
+
import fs4 from "node:fs";
|
|
448
882
|
|
|
449
883
|
// src/cargo/cargoHandler.ts
|
|
450
|
-
import
|
|
451
|
-
import
|
|
884
|
+
import fs3 from "node:fs";
|
|
885
|
+
import path2 from "node:path";
|
|
452
886
|
import * as TOML from "smol-toml";
|
|
453
887
|
function getCargoInfo(cargoPath) {
|
|
454
888
|
var _a;
|
|
455
|
-
if (!
|
|
889
|
+
if (!fs3.existsSync(cargoPath)) {
|
|
456
890
|
log(`Cargo.toml file not found at: ${cargoPath}`, "error");
|
|
457
891
|
throw new Error(`Cargo.toml file not found at: ${cargoPath}`);
|
|
458
892
|
}
|
|
459
893
|
try {
|
|
460
|
-
const fileContent =
|
|
894
|
+
const fileContent = fs3.readFileSync(cargoPath, "utf8");
|
|
461
895
|
const cargo = TOML.parse(fileContent);
|
|
462
896
|
if (!((_a = cargo.package) == null ? void 0 : _a.name)) {
|
|
463
897
|
log(`Package name not found in: ${cargoPath}`, "error");
|
|
@@ -467,7 +901,7 @@ function getCargoInfo(cargoPath) {
|
|
|
467
901
|
name: cargo.package.name,
|
|
468
902
|
version: cargo.package.version || "0.0.0",
|
|
469
903
|
path: cargoPath,
|
|
470
|
-
dir:
|
|
904
|
+
dir: path2.dirname(cargoPath),
|
|
471
905
|
content: cargo
|
|
472
906
|
};
|
|
473
907
|
} catch (error) {
|
|
@@ -480,12 +914,12 @@ function getCargoInfo(cargoPath) {
|
|
|
480
914
|
}
|
|
481
915
|
}
|
|
482
916
|
function isCargoToml(filePath) {
|
|
483
|
-
return
|
|
917
|
+
return path2.basename(filePath) === "Cargo.toml";
|
|
484
918
|
}
|
|
485
919
|
function updateCargoVersion(cargoPath, version) {
|
|
486
920
|
var _a;
|
|
487
921
|
try {
|
|
488
|
-
const originalContent =
|
|
922
|
+
const originalContent = fs3.readFileSync(cargoPath, "utf8");
|
|
489
923
|
const cargo = TOML.parse(originalContent);
|
|
490
924
|
const packageName = (_a = cargo.package) == null ? void 0 : _a.name;
|
|
491
925
|
if (!packageName) {
|
|
@@ -497,7 +931,7 @@ function updateCargoVersion(cargoPath, version) {
|
|
|
497
931
|
cargo.package.version = version;
|
|
498
932
|
}
|
|
499
933
|
const updatedContent = TOML.stringify(cargo);
|
|
500
|
-
|
|
934
|
+
fs3.writeFileSync(cargoPath, updatedContent);
|
|
501
935
|
addPackageUpdate(packageName, version, cargoPath);
|
|
502
936
|
log(`Updated Cargo.toml at ${cargoPath} to version ${version}`, "success");
|
|
503
937
|
} catch (error) {
|
|
@@ -516,11 +950,11 @@ function updatePackageVersion(packagePath, version) {
|
|
|
516
950
|
return;
|
|
517
951
|
}
|
|
518
952
|
try {
|
|
519
|
-
const packageContent =
|
|
953
|
+
const packageContent = fs4.readFileSync(packagePath, "utf8");
|
|
520
954
|
const packageJson = JSON.parse(packageContent);
|
|
521
955
|
const packageName = packageJson.name;
|
|
522
956
|
packageJson.version = version;
|
|
523
|
-
|
|
957
|
+
fs4.writeFileSync(packagePath, `${JSON.stringify(packageJson, null, 2)}
|
|
524
958
|
`);
|
|
525
959
|
addPackageUpdate(packageName, version, packagePath);
|
|
526
960
|
log(`Updated package.json at ${packagePath} to version ${version}`, "success");
|
|
@@ -534,24 +968,349 @@ function updatePackageVersion(packagePath, version) {
|
|
|
534
968
|
}
|
|
535
969
|
|
|
536
970
|
// src/package/packageProcessor.ts
|
|
537
|
-
import * as
|
|
538
|
-
import
|
|
971
|
+
import * as fs7 from "node:fs";
|
|
972
|
+
import path5 from "node:path";
|
|
539
973
|
import { exit } from "node:process";
|
|
540
974
|
|
|
975
|
+
// src/changelog/changelogManager.ts
|
|
976
|
+
import * as fs5 from "node:fs";
|
|
977
|
+
import * as path3 from "node:path";
|
|
978
|
+
function createChangelog(_packagePath, packageName) {
|
|
979
|
+
return {
|
|
980
|
+
projectName: packageName,
|
|
981
|
+
unreleased: [],
|
|
982
|
+
versions: []
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
function parseChangelog(filePath) {
|
|
986
|
+
try {
|
|
987
|
+
if (!fs5.existsSync(filePath)) {
|
|
988
|
+
return null;
|
|
989
|
+
}
|
|
990
|
+
fs5.readFileSync(filePath, "utf8");
|
|
991
|
+
log(`Parsed changelog at ${filePath}`, "info");
|
|
992
|
+
return {
|
|
993
|
+
projectName: path3.basename(path3.dirname(filePath)),
|
|
994
|
+
unreleased: [],
|
|
995
|
+
versions: []
|
|
996
|
+
};
|
|
997
|
+
} catch (error) {
|
|
998
|
+
log(
|
|
999
|
+
`Error parsing changelog: ${error instanceof Error ? error.message : String(error)}`,
|
|
1000
|
+
"error"
|
|
1001
|
+
);
|
|
1002
|
+
return null;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
function generateLinks(changelog, repoUrl) {
|
|
1006
|
+
var _a, _b;
|
|
1007
|
+
if (!repoUrl || changelog.versions.length === 0) {
|
|
1008
|
+
return "";
|
|
1009
|
+
}
|
|
1010
|
+
let links = "\n";
|
|
1011
|
+
if (changelog.unreleased.length > 0) {
|
|
1012
|
+
const latestVersion = ((_a = changelog.versions[0]) == null ? void 0 : _a.version) || "";
|
|
1013
|
+
links += `[unreleased]: ${repoUrl}/compare/v${latestVersion}...HEAD
|
|
1014
|
+
`;
|
|
1015
|
+
}
|
|
1016
|
+
for (let i = 0; i < changelog.versions.length; i++) {
|
|
1017
|
+
const currentVersion = changelog.versions[i].version;
|
|
1018
|
+
const previousVersion = (_b = changelog.versions[i + 1]) == null ? void 0 : _b.version;
|
|
1019
|
+
if (previousVersion) {
|
|
1020
|
+
links += `[${currentVersion}]: ${repoUrl}/compare/v${previousVersion}...v${currentVersion}
|
|
1021
|
+
`;
|
|
1022
|
+
} else if (i === changelog.versions.length - 1) {
|
|
1023
|
+
links += `[${currentVersion}]: ${repoUrl}/releases/tag/v${currentVersion}
|
|
1024
|
+
`;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
return links;
|
|
1028
|
+
}
|
|
1029
|
+
function generateAngularChangelogContent(changelog, repoUrl) {
|
|
1030
|
+
let content = "# Changelog\n\n";
|
|
1031
|
+
if (changelog.unreleased.length > 0) {
|
|
1032
|
+
content += "## [Unreleased]\n\n";
|
|
1033
|
+
const groupedByType = groupEntriesByAngularType(changelog.unreleased);
|
|
1034
|
+
for (const [type, entries] of Object.entries(groupedByType)) {
|
|
1035
|
+
content += `### ${formatAngularType(type)}
|
|
1036
|
+
|
|
1037
|
+
`;
|
|
1038
|
+
const groupedByScope = groupEntriesByScope2(entries);
|
|
1039
|
+
for (const [scope, scopeEntries] of Object.entries(groupedByScope)) {
|
|
1040
|
+
if (scope !== "undefined" && scope !== "") {
|
|
1041
|
+
content += `* **${scope}:**
|
|
1042
|
+
`;
|
|
1043
|
+
for (const entry of scopeEntries) {
|
|
1044
|
+
content += formatAngularEntry(entry, false);
|
|
1045
|
+
}
|
|
1046
|
+
content += "\n";
|
|
1047
|
+
} else {
|
|
1048
|
+
for (const entry of scopeEntries) {
|
|
1049
|
+
content += formatAngularEntry(entry, true);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
content += "\n";
|
|
1054
|
+
}
|
|
1055
|
+
const breakingChanges = changelog.unreleased.filter(
|
|
1056
|
+
(entry) => entry.description.includes("**BREAKING**")
|
|
1057
|
+
);
|
|
1058
|
+
if (breakingChanges.length > 0) {
|
|
1059
|
+
content += "### BREAKING CHANGES\n\n";
|
|
1060
|
+
for (const entry of breakingChanges) {
|
|
1061
|
+
const description = entry.description.replace("**BREAKING** ", "");
|
|
1062
|
+
content += `* ${entry.scope ? `**${entry.scope}:** ` : ""}${description}`;
|
|
1063
|
+
if (entry.issueIds && entry.issueIds.length > 0) {
|
|
1064
|
+
content += ` (${entry.issueIds.join(", ")})`;
|
|
1065
|
+
}
|
|
1066
|
+
content += "\n";
|
|
1067
|
+
}
|
|
1068
|
+
content += "\n";
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
for (const version of changelog.versions) {
|
|
1072
|
+
content += `## [${version.version}] - ${version.date}
|
|
1073
|
+
|
|
1074
|
+
`;
|
|
1075
|
+
const groupedByType = groupEntriesByAngularType(version.entries);
|
|
1076
|
+
for (const [type, entries] of Object.entries(groupedByType)) {
|
|
1077
|
+
content += `### ${formatAngularType(type)}
|
|
1078
|
+
|
|
1079
|
+
`;
|
|
1080
|
+
const groupedByScope = groupEntriesByScope2(entries);
|
|
1081
|
+
for (const [scope, scopeEntries] of Object.entries(groupedByScope)) {
|
|
1082
|
+
if (scope !== "undefined" && scope !== "") {
|
|
1083
|
+
content += `* **${scope}:**
|
|
1084
|
+
`;
|
|
1085
|
+
for (const entry of scopeEntries) {
|
|
1086
|
+
content += formatAngularEntry(entry, false);
|
|
1087
|
+
}
|
|
1088
|
+
content += "\n";
|
|
1089
|
+
} else {
|
|
1090
|
+
for (const entry of scopeEntries) {
|
|
1091
|
+
content += formatAngularEntry(entry, true);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
content += "\n";
|
|
1096
|
+
}
|
|
1097
|
+
const breakingChanges = version.entries.filter(
|
|
1098
|
+
(entry) => entry.description.includes("**BREAKING**")
|
|
1099
|
+
);
|
|
1100
|
+
if (breakingChanges.length > 0) {
|
|
1101
|
+
content += "### BREAKING CHANGES\n\n";
|
|
1102
|
+
for (const entry of breakingChanges) {
|
|
1103
|
+
const description = entry.description.replace("**BREAKING** ", "");
|
|
1104
|
+
content += `* ${entry.scope ? `**${entry.scope}:** ` : ""}${description}`;
|
|
1105
|
+
if (entry.issueIds && entry.issueIds.length > 0) {
|
|
1106
|
+
content += ` (${entry.issueIds.join(", ")})`;
|
|
1107
|
+
}
|
|
1108
|
+
content += "\n";
|
|
1109
|
+
}
|
|
1110
|
+
content += "\n";
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
content += generateLinks(changelog, repoUrl);
|
|
1114
|
+
return content;
|
|
1115
|
+
}
|
|
1116
|
+
function groupEntriesByAngularType(entries) {
|
|
1117
|
+
const result = {};
|
|
1118
|
+
for (const entry of entries) {
|
|
1119
|
+
const type = entry.originalType || mapToAngularType(entry.type);
|
|
1120
|
+
if (!result[type]) {
|
|
1121
|
+
result[type] = [];
|
|
1122
|
+
}
|
|
1123
|
+
result[type].push(entry);
|
|
1124
|
+
}
|
|
1125
|
+
return result;
|
|
1126
|
+
}
|
|
1127
|
+
function mapToAngularType(type) {
|
|
1128
|
+
switch (type) {
|
|
1129
|
+
case "added":
|
|
1130
|
+
return "feat";
|
|
1131
|
+
case "fixed":
|
|
1132
|
+
return "fix";
|
|
1133
|
+
case "changed":
|
|
1134
|
+
return "perf";
|
|
1135
|
+
case "deprecated":
|
|
1136
|
+
case "removed":
|
|
1137
|
+
case "security":
|
|
1138
|
+
return type;
|
|
1139
|
+
default:
|
|
1140
|
+
return type;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
function formatAngularType(type) {
|
|
1144
|
+
switch (type) {
|
|
1145
|
+
case "feat":
|
|
1146
|
+
return "Features";
|
|
1147
|
+
case "fix":
|
|
1148
|
+
return "Bug Fixes";
|
|
1149
|
+
case "perf":
|
|
1150
|
+
return "Performance Improvements";
|
|
1151
|
+
case "security":
|
|
1152
|
+
return "Security";
|
|
1153
|
+
case "deprecated":
|
|
1154
|
+
return "Deprecated";
|
|
1155
|
+
case "removed":
|
|
1156
|
+
return "Removed";
|
|
1157
|
+
default:
|
|
1158
|
+
return capitalizeFirstLetter(type);
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
function groupEntriesByScope2(entries) {
|
|
1162
|
+
const result = {};
|
|
1163
|
+
for (const entry of entries) {
|
|
1164
|
+
const scope = entry.scope || "";
|
|
1165
|
+
if (!result[scope]) {
|
|
1166
|
+
result[scope] = [];
|
|
1167
|
+
}
|
|
1168
|
+
result[scope].push(entry);
|
|
1169
|
+
}
|
|
1170
|
+
return result;
|
|
1171
|
+
}
|
|
1172
|
+
function formatAngularEntry(entry, includeScope) {
|
|
1173
|
+
let result = " * ";
|
|
1174
|
+
if (includeScope && entry.scope) {
|
|
1175
|
+
result += `**${entry.scope}:** `;
|
|
1176
|
+
}
|
|
1177
|
+
let description = entry.description;
|
|
1178
|
+
if (!includeScope && entry.scope && description.startsWith(`**${entry.scope}**: `)) {
|
|
1179
|
+
description = description.substring(`**${entry.scope}**: `.length);
|
|
1180
|
+
}
|
|
1181
|
+
if (description.startsWith("**BREAKING** ")) {
|
|
1182
|
+
description = description.substring("**BREAKING** ".length);
|
|
1183
|
+
}
|
|
1184
|
+
result += description;
|
|
1185
|
+
if (entry.issueIds && entry.issueIds.length > 0) {
|
|
1186
|
+
result += ` (${entry.issueIds.join(", ")})`;
|
|
1187
|
+
}
|
|
1188
|
+
result += "\n";
|
|
1189
|
+
return result;
|
|
1190
|
+
}
|
|
1191
|
+
function generateChangelogContent(changelog, repoUrl, format = "keep-a-changelog") {
|
|
1192
|
+
if (format === "angular") {
|
|
1193
|
+
return generateAngularChangelogContent(changelog, repoUrl);
|
|
1194
|
+
}
|
|
1195
|
+
let content = "# Changelog\n\n";
|
|
1196
|
+
content += `All notable changes to ${changelog.projectName} will be documented in this file.
|
|
1197
|
+
|
|
1198
|
+
`;
|
|
1199
|
+
content += "The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\n";
|
|
1200
|
+
content += "and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n";
|
|
1201
|
+
if (changelog.unreleased.length > 0) {
|
|
1202
|
+
content += "## [Unreleased]\n\n";
|
|
1203
|
+
const grouped = changelog.unreleased.reduce(
|
|
1204
|
+
(acc, entry) => {
|
|
1205
|
+
if (!acc[entry.type]) {
|
|
1206
|
+
acc[entry.type] = [];
|
|
1207
|
+
}
|
|
1208
|
+
acc[entry.type].push(entry);
|
|
1209
|
+
return acc;
|
|
1210
|
+
},
|
|
1211
|
+
{}
|
|
1212
|
+
);
|
|
1213
|
+
for (const [type, entries] of Object.entries(grouped)) {
|
|
1214
|
+
content += `### ${capitalizeFirstLetter(type)}
|
|
1215
|
+
|
|
1216
|
+
`;
|
|
1217
|
+
for (const entry of entries) {
|
|
1218
|
+
let entryText = `- ${entry.description}`;
|
|
1219
|
+
if (entry.issueIds && entry.issueIds.length > 0) {
|
|
1220
|
+
entryText += ` (${entry.issueIds.join(", ")})`;
|
|
1221
|
+
}
|
|
1222
|
+
content += `${entryText}.
|
|
1223
|
+
`;
|
|
1224
|
+
}
|
|
1225
|
+
content += "\n";
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
for (const version of changelog.versions) {
|
|
1229
|
+
content += `## [${version.version}] - ${version.date}
|
|
1230
|
+
|
|
1231
|
+
`;
|
|
1232
|
+
const grouped = version.entries.reduce(
|
|
1233
|
+
(acc, entry) => {
|
|
1234
|
+
if (!acc[entry.type]) {
|
|
1235
|
+
acc[entry.type] = [];
|
|
1236
|
+
}
|
|
1237
|
+
acc[entry.type].push(entry);
|
|
1238
|
+
return acc;
|
|
1239
|
+
},
|
|
1240
|
+
{}
|
|
1241
|
+
);
|
|
1242
|
+
for (const [type, entries] of Object.entries(grouped)) {
|
|
1243
|
+
content += `### ${capitalizeFirstLetter(type)}
|
|
1244
|
+
|
|
1245
|
+
`;
|
|
1246
|
+
for (const entry of entries) {
|
|
1247
|
+
let entryText = `- ${entry.description}`;
|
|
1248
|
+
if (entry.issueIds && entry.issueIds.length > 0) {
|
|
1249
|
+
entryText += ` (${entry.issueIds.join(", ")})`;
|
|
1250
|
+
}
|
|
1251
|
+
content += `${entryText}.
|
|
1252
|
+
`;
|
|
1253
|
+
}
|
|
1254
|
+
content += "\n";
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
content += generateLinks(changelog, repoUrl);
|
|
1258
|
+
return content;
|
|
1259
|
+
}
|
|
1260
|
+
function updateChangelog(packagePath, packageName, version, entries, repoUrl, format = "keep-a-changelog") {
|
|
1261
|
+
try {
|
|
1262
|
+
const changelogPath = path3.join(packagePath, "CHANGELOG.md");
|
|
1263
|
+
let changelog;
|
|
1264
|
+
if (fs5.existsSync(changelogPath)) {
|
|
1265
|
+
const existingChangelog = parseChangelog(changelogPath);
|
|
1266
|
+
if (existingChangelog) {
|
|
1267
|
+
changelog = existingChangelog;
|
|
1268
|
+
} else {
|
|
1269
|
+
changelog = createChangelog(packagePath, packageName);
|
|
1270
|
+
}
|
|
1271
|
+
} else {
|
|
1272
|
+
changelog = createChangelog(packagePath, packageName);
|
|
1273
|
+
}
|
|
1274
|
+
if (version) {
|
|
1275
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1276
|
+
const newVersion = {
|
|
1277
|
+
version,
|
|
1278
|
+
date: today,
|
|
1279
|
+
entries: [...changelog.unreleased, ...entries]
|
|
1280
|
+
};
|
|
1281
|
+
changelog.unreleased = [];
|
|
1282
|
+
changelog.versions.unshift(newVersion);
|
|
1283
|
+
} else {
|
|
1284
|
+
changelog.unreleased = [...changelog.unreleased, ...entries];
|
|
1285
|
+
}
|
|
1286
|
+
const content = generateChangelogContent(changelog, repoUrl, format);
|
|
1287
|
+
fs5.writeFileSync(changelogPath, content);
|
|
1288
|
+
log(`Updated changelog at ${changelogPath}`, "success");
|
|
1289
|
+
} catch (error) {
|
|
1290
|
+
log(
|
|
1291
|
+
`Error updating changelog: ${error instanceof Error ? error.message : String(error)}`,
|
|
1292
|
+
"error"
|
|
1293
|
+
);
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
function capitalizeFirstLetter(input) {
|
|
1297
|
+
return input.charAt(0).toUpperCase() + input.slice(1);
|
|
1298
|
+
}
|
|
1299
|
+
|
|
541
1300
|
// src/core/versionCalculator.ts
|
|
542
1301
|
import { cwd as cwd3 } from "node:process";
|
|
543
1302
|
import { Bumper } from "conventional-recommended-bump";
|
|
544
1303
|
import semver2 from "semver";
|
|
545
1304
|
|
|
546
1305
|
// src/utils/manifestHelpers.ts
|
|
547
|
-
import
|
|
548
|
-
import
|
|
1306
|
+
import fs6 from "node:fs";
|
|
1307
|
+
import path4 from "node:path";
|
|
549
1308
|
function getVersionFromManifests(packageDir) {
|
|
550
|
-
const packageJsonPath =
|
|
551
|
-
const cargoTomlPath =
|
|
552
|
-
if (
|
|
1309
|
+
const packageJsonPath = path4.join(packageDir, "package.json");
|
|
1310
|
+
const cargoTomlPath = path4.join(packageDir, "Cargo.toml");
|
|
1311
|
+
if (fs6.existsSync(packageJsonPath)) {
|
|
553
1312
|
try {
|
|
554
|
-
const packageJson = JSON.parse(
|
|
1313
|
+
const packageJson = JSON.parse(fs6.readFileSync(packageJsonPath, "utf-8"));
|
|
555
1314
|
if (packageJson.version) {
|
|
556
1315
|
log(`Found version ${packageJson.version} in package.json`, "debug");
|
|
557
1316
|
return {
|
|
@@ -567,7 +1326,7 @@ function getVersionFromManifests(packageDir) {
|
|
|
567
1326
|
log(`Error reading package.json: ${errMsg}`, "warning");
|
|
568
1327
|
}
|
|
569
1328
|
}
|
|
570
|
-
if (
|
|
1329
|
+
if (fs6.existsSync(cargoTomlPath)) {
|
|
571
1330
|
try {
|
|
572
1331
|
const cargoInfo = getCargoInfo(cargoTomlPath);
|
|
573
1332
|
if (cargoInfo.version) {
|
|
@@ -593,8 +1352,8 @@ function getVersionFromManifests(packageDir) {
|
|
|
593
1352
|
};
|
|
594
1353
|
}
|
|
595
1354
|
function throwIfNoManifestsFound(packageDir) {
|
|
596
|
-
const packageJsonPath =
|
|
597
|
-
const cargoTomlPath =
|
|
1355
|
+
const packageJsonPath = path4.join(packageDir, "package.json");
|
|
1356
|
+
const cargoTomlPath = path4.join(packageDir, "Cargo.toml");
|
|
598
1357
|
throw new Error(
|
|
599
1358
|
`Neither package.json nor Cargo.toml found at ${packageDir}. Checked paths: ${packageJsonPath}, ${cargoTomlPath}. Cannot determine version.`
|
|
600
1359
|
);
|
|
@@ -849,7 +1608,7 @@ var PackageProcessor = class {
|
|
|
849
1608
|
* Process packages based on targeting criteria
|
|
850
1609
|
*/
|
|
851
1610
|
async processPackages(packages) {
|
|
852
|
-
var _a;
|
|
1611
|
+
var _a, _b, _c, _d, _e;
|
|
853
1612
|
const tags = [];
|
|
854
1613
|
const updatedPackagesInfo = [];
|
|
855
1614
|
if (!packages || !Array.isArray(packages)) {
|
|
@@ -934,13 +1693,81 @@ var PackageProcessor = class {
|
|
|
934
1693
|
if (!nextVersion) {
|
|
935
1694
|
continue;
|
|
936
1695
|
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1696
|
+
if (this.fullConfig.updateChangelog !== false) {
|
|
1697
|
+
let changelogEntries = [];
|
|
1698
|
+
try {
|
|
1699
|
+
changelogEntries = extractChangelogEntriesFromCommits(pkgPath, latestTag);
|
|
1700
|
+
if (changelogEntries.length === 0) {
|
|
1701
|
+
changelogEntries = [
|
|
1702
|
+
{
|
|
1703
|
+
type: "changed",
|
|
1704
|
+
description: `Update version to ${nextVersion}`
|
|
1705
|
+
}
|
|
1706
|
+
];
|
|
1707
|
+
}
|
|
1708
|
+
} catch (error) {
|
|
1709
|
+
log(
|
|
1710
|
+
`Error extracting changelog entries: ${error instanceof Error ? error.message : String(error)}`,
|
|
1711
|
+
"warning"
|
|
1712
|
+
);
|
|
1713
|
+
changelogEntries = [
|
|
1714
|
+
{
|
|
1715
|
+
type: "changed",
|
|
1716
|
+
description: `Update version to ${nextVersion}`
|
|
1717
|
+
}
|
|
1718
|
+
];
|
|
1719
|
+
}
|
|
1720
|
+
let repoUrl;
|
|
1721
|
+
try {
|
|
1722
|
+
const packageJsonPath2 = path5.join(pkgPath, "package.json");
|
|
1723
|
+
if (fs7.existsSync(packageJsonPath2)) {
|
|
1724
|
+
const packageJson = JSON.parse(fs7.readFileSync(packageJsonPath2, "utf8"));
|
|
1725
|
+
if (packageJson.repository) {
|
|
1726
|
+
if (typeof packageJson.repository === "string") {
|
|
1727
|
+
repoUrl = packageJson.repository;
|
|
1728
|
+
} else if (packageJson.repository.url) {
|
|
1729
|
+
repoUrl = packageJson.repository.url;
|
|
1730
|
+
}
|
|
1731
|
+
if ((repoUrl == null ? void 0 : repoUrl.startsWith("git+")) && (repoUrl == null ? void 0 : repoUrl.endsWith(".git"))) {
|
|
1732
|
+
repoUrl = repoUrl.substring(4, repoUrl.length - 4);
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
} catch (error) {
|
|
1737
|
+
log(
|
|
1738
|
+
`Could not determine repository URL for changelog links: ${error instanceof Error ? error.message : String(error)}`,
|
|
1739
|
+
"warning"
|
|
1740
|
+
);
|
|
1741
|
+
}
|
|
1742
|
+
updateChangelog(
|
|
1743
|
+
pkgPath,
|
|
1744
|
+
name,
|
|
1745
|
+
nextVersion,
|
|
1746
|
+
changelogEntries,
|
|
1747
|
+
repoUrl,
|
|
1748
|
+
this.fullConfig.changelogFormat
|
|
1749
|
+
);
|
|
1750
|
+
}
|
|
1751
|
+
const packageJsonPath = path5.join(pkgPath, "package.json");
|
|
1752
|
+
if (fs7.existsSync(packageJsonPath)) {
|
|
940
1753
|
updatePackageVersion(packageJsonPath, nextVersion);
|
|
941
1754
|
}
|
|
942
|
-
|
|
943
|
-
|
|
1755
|
+
const cargoEnabled = ((_a = this.fullConfig.cargo) == null ? void 0 : _a.enabled) !== false;
|
|
1756
|
+
if (cargoEnabled) {
|
|
1757
|
+
const cargoPaths = (_b = this.fullConfig.cargo) == null ? void 0 : _b.paths;
|
|
1758
|
+
if (cargoPaths && cargoPaths.length > 0) {
|
|
1759
|
+
for (const cargoPath of cargoPaths) {
|
|
1760
|
+
const resolvedCargoPath = path5.resolve(pkgPath, cargoPath, "Cargo.toml");
|
|
1761
|
+
if (fs7.existsSync(resolvedCargoPath)) {
|
|
1762
|
+
updatePackageVersion(resolvedCargoPath, nextVersion);
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
} else {
|
|
1766
|
+
const cargoTomlPath = path5.join(pkgPath, "Cargo.toml");
|
|
1767
|
+
if (fs7.existsSync(cargoTomlPath)) {
|
|
1768
|
+
updatePackageVersion(cargoTomlPath, nextVersion);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
944
1771
|
}
|
|
945
1772
|
const packageTag = formatTag(
|
|
946
1773
|
nextVersion,
|
|
@@ -972,9 +1799,32 @@ var PackageProcessor = class {
|
|
|
972
1799
|
log("No targeted packages required a version update.", "info");
|
|
973
1800
|
return { updatedPackages: [], tags };
|
|
974
1801
|
}
|
|
975
|
-
const filesToCommit =
|
|
1802
|
+
const filesToCommit = [];
|
|
1803
|
+
for (const info of updatedPackagesInfo) {
|
|
1804
|
+
const packageJsonPath = path5.join(info.path, "package.json");
|
|
1805
|
+
if (fs7.existsSync(packageJsonPath)) {
|
|
1806
|
+
filesToCommit.push(packageJsonPath);
|
|
1807
|
+
}
|
|
1808
|
+
const cargoEnabled = ((_c = this.fullConfig.cargo) == null ? void 0 : _c.enabled) !== false;
|
|
1809
|
+
if (cargoEnabled) {
|
|
1810
|
+
const cargoPaths = (_d = this.fullConfig.cargo) == null ? void 0 : _d.paths;
|
|
1811
|
+
if (cargoPaths && cargoPaths.length > 0) {
|
|
1812
|
+
for (const cargoPath of cargoPaths) {
|
|
1813
|
+
const resolvedCargoPath = path5.resolve(info.path, cargoPath, "Cargo.toml");
|
|
1814
|
+
if (fs7.existsSync(resolvedCargoPath)) {
|
|
1815
|
+
filesToCommit.push(resolvedCargoPath);
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
} else {
|
|
1819
|
+
const cargoTomlPath = path5.join(info.path, "Cargo.toml");
|
|
1820
|
+
if (fs7.existsSync(cargoTomlPath)) {
|
|
1821
|
+
filesToCommit.push(cargoTomlPath);
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
976
1826
|
const packageNames = updatedPackagesInfo.map((p) => p.name).join(", ");
|
|
977
|
-
const representativeVersion = ((
|
|
1827
|
+
const representativeVersion = ((_e = updatedPackagesInfo[0]) == null ? void 0 : _e.version) || "multiple";
|
|
978
1828
|
let commitMessage = this.commitMessageTemplate || "chore(release): publish packages";
|
|
979
1829
|
const placeholderRegex = /\$\{[^}]+\}/;
|
|
980
1830
|
if (updatedPackagesInfo.length === 1 && placeholderRegex.test(commitMessage)) {
|
|
@@ -1051,20 +1901,21 @@ function createSyncedStrategy(config) {
|
|
|
1051
1901
|
const files = [];
|
|
1052
1902
|
const updatedPackages = [];
|
|
1053
1903
|
try {
|
|
1054
|
-
const rootPkgPath =
|
|
1055
|
-
if (
|
|
1904
|
+
const rootPkgPath = path6.join(packages.root, "package.json");
|
|
1905
|
+
if (fs8.existsSync(rootPkgPath)) {
|
|
1056
1906
|
updatePackageVersion(rootPkgPath, nextVersion);
|
|
1057
1907
|
files.push(rootPkgPath);
|
|
1058
1908
|
updatedPackages.push("root");
|
|
1059
1909
|
}
|
|
1060
|
-
} catch (
|
|
1061
|
-
|
|
1910
|
+
} catch (error) {
|
|
1911
|
+
const errMessage = error instanceof Error ? error.message : String(error);
|
|
1912
|
+
log(`Failed to update root package.json: ${errMessage}`, "error");
|
|
1062
1913
|
}
|
|
1063
1914
|
for (const pkg of packages.packages) {
|
|
1064
1915
|
if (!shouldProcessPackage(pkg, config)) {
|
|
1065
1916
|
continue;
|
|
1066
1917
|
}
|
|
1067
|
-
const packageJsonPath =
|
|
1918
|
+
const packageJsonPath = path6.join(pkg.dir, "package.json");
|
|
1068
1919
|
updatePackageVersion(packageJsonPath, nextVersion);
|
|
1069
1920
|
files.push(packageJsonPath);
|
|
1070
1921
|
updatedPackages.push(pkg.packageJson.name);
|
|
@@ -1137,7 +1988,7 @@ function createSingleStrategy(config) {
|
|
|
1137
1988
|
log(`No version change needed for ${packageName}`, "info");
|
|
1138
1989
|
return;
|
|
1139
1990
|
}
|
|
1140
|
-
const packageJsonPath =
|
|
1991
|
+
const packageJsonPath = path6.join(pkgPath, "package.json");
|
|
1141
1992
|
updatePackageVersion(packageJsonPath, nextVersion);
|
|
1142
1993
|
log(`Updated package ${packageName} to version ${nextVersion}`, "success");
|
|
1143
1994
|
const nextTag = formatTag(
|
|
@@ -1315,11 +2166,11 @@ var VersionEngine = class {
|
|
|
1315
2166
|
// src/index.ts
|
|
1316
2167
|
function getPackageVersion() {
|
|
1317
2168
|
try {
|
|
1318
|
-
const packageJsonPath =
|
|
1319
|
-
|
|
2169
|
+
const packageJsonPath = path7.resolve(
|
|
2170
|
+
path7.dirname(import.meta.url.replace("file:", "")),
|
|
1320
2171
|
"../package.json"
|
|
1321
2172
|
);
|
|
1322
|
-
const packageJsonContent =
|
|
2173
|
+
const packageJsonContent = fs9.readFileSync(packageJsonPath, "utf-8");
|
|
1323
2174
|
const packageJson = JSON.parse(packageJsonContent);
|
|
1324
2175
|
return packageJson.version || "0.0.0";
|
|
1325
2176
|
} catch (error) {
|
|
@@ -1328,53 +2179,94 @@ function getPackageVersion() {
|
|
|
1328
2179
|
}
|
|
1329
2180
|
}
|
|
1330
2181
|
async function run() {
|
|
1331
|
-
const buildTimestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
1332
|
-
const packageVersion = getPackageVersion();
|
|
1333
|
-
log(`package-versioner v${packageVersion} (Build: ${buildTimestamp})`, "debug");
|
|
1334
|
-
const program = new Command();
|
|
1335
|
-
program.name("package-versioner").description(
|
|
1336
|
-
"A lightweight yet powerful CLI tool for automated semantic versioning based on Git history and conventional commits."
|
|
1337
|
-
).version(packageVersion).option(
|
|
1338
|
-
"-c, --config <path>",
|
|
1339
|
-
"Path to config file (defaults to version.config.json in current directory)"
|
|
1340
|
-
).option("-d, --dry-run", "Dry run (no changes made)", false).option("-b, --bump <type>", "Specify bump type (patch|minor|major)").option("-p, --prerelease [identifier]", "Create prerelease version").option("-s, --synced", "Use synchronized versioning across all packages").option("-j, --json", "Output results as JSON", false).option("-t, --target <packages>", "Comma-delimited list of package names to target").parse(process.argv);
|
|
1341
|
-
const options = program.opts();
|
|
1342
|
-
if (options.json) {
|
|
1343
|
-
enableJsonOutput(options.dryRun);
|
|
1344
|
-
}
|
|
1345
2182
|
try {
|
|
1346
|
-
const
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
} else if (config.packages && config.packages.length === 1) {
|
|
1360
|
-
log("Using single package versioning strategy.", "info");
|
|
1361
|
-
if (cliTargets.length > 0) {
|
|
1362
|
-
log("--target flag is ignored for single package strategy.", "warning");
|
|
1363
|
-
}
|
|
1364
|
-
engine.setStrategy("single");
|
|
1365
|
-
await engine.run();
|
|
1366
|
-
} else {
|
|
1367
|
-
log("Using async versioning strategy.", "info");
|
|
1368
|
-
if (cliTargets.length > 0) {
|
|
1369
|
-
log(`Targeting specific packages: ${cliTargets.join(", ")}`, "info");
|
|
2183
|
+
const buildTimestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
2184
|
+
const packageVersion = getPackageVersion();
|
|
2185
|
+
log(`package-versioner v${packageVersion} (Build: ${buildTimestamp})`, "debug");
|
|
2186
|
+
const program = new Command();
|
|
2187
|
+
program.name("package-versioner").description(
|
|
2188
|
+
"A lightweight yet powerful CLI tool for automated semantic versioning based on Git history and conventional commits."
|
|
2189
|
+
).version(packageVersion);
|
|
2190
|
+
program.command("version", { isDefault: true }).description("Version a package or packages based on configuration").option(
|
|
2191
|
+
"-c, --config <path>",
|
|
2192
|
+
"Path to config file (defaults to version.config.json in current directory)"
|
|
2193
|
+
).option("-d, --dry-run", "Dry run (no changes made)", false).option("-b, --bump <type>", "Specify bump type (patch|minor|major)").option("-p, --prerelease [identifier]", "Create prerelease version").option("-s, --synced", "Use synchronized versioning across all packages").option("-j, --json", "Output results as JSON", false).option("-t, --target <packages>", "Comma-delimited list of package names to target").action(async (options) => {
|
|
2194
|
+
if (options.json) {
|
|
2195
|
+
enableJsonOutput(options.dryRun);
|
|
1370
2196
|
}
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
2197
|
+
try {
|
|
2198
|
+
const config = await loadConfig(options.config);
|
|
2199
|
+
log(`Loaded configuration from ${options.config || "version.config.json"}`, "info");
|
|
2200
|
+
if (options.dryRun) config.dryRun = true;
|
|
2201
|
+
if (options.synced) config.synced = true;
|
|
2202
|
+
if (options.bump) config.type = options.bump;
|
|
2203
|
+
if (options.prerelease)
|
|
2204
|
+
config.prereleaseIdentifier = options.prerelease === true ? "next" : options.prerelease;
|
|
2205
|
+
const cliTargets = options.target ? options.target.split(",").map((t) => t.trim()) : [];
|
|
2206
|
+
const engine = new VersionEngine(config, !!options.json);
|
|
2207
|
+
if (config.synced) {
|
|
2208
|
+
log("Using synced versioning strategy.", "info");
|
|
2209
|
+
engine.setStrategy("synced");
|
|
2210
|
+
await engine.run();
|
|
2211
|
+
} else if (config.packages && config.packages.length === 1) {
|
|
2212
|
+
log("Using single package versioning strategy.", "info");
|
|
2213
|
+
if (cliTargets.length > 0) {
|
|
2214
|
+
log("--target flag is ignored for single package strategy.", "warning");
|
|
2215
|
+
}
|
|
2216
|
+
engine.setStrategy("single");
|
|
2217
|
+
await engine.run();
|
|
2218
|
+
} else {
|
|
2219
|
+
log("Using async versioning strategy.", "info");
|
|
2220
|
+
if (cliTargets.length > 0) {
|
|
2221
|
+
log(`Targeting specific packages: ${cliTargets.join(", ")}`, "info");
|
|
2222
|
+
}
|
|
2223
|
+
engine.setStrategy("async");
|
|
2224
|
+
await engine.run(cliTargets);
|
|
2225
|
+
}
|
|
2226
|
+
log("Versioning process completed.", "success");
|
|
2227
|
+
printJsonOutput();
|
|
2228
|
+
} catch (error) {
|
|
2229
|
+
log(error instanceof Error ? error.message : String(error), "error");
|
|
2230
|
+
process.exit(1);
|
|
2231
|
+
}
|
|
2232
|
+
});
|
|
2233
|
+
program.command("regenerate-changelog").description("Regenerate a complete changelog from git history").option("-o, --output <path>", "Output path for changelog file", "CHANGELOG.md").option(
|
|
2234
|
+
"-f, --format <format>",
|
|
2235
|
+
"Changelog format (keep-a-changelog|angular)",
|
|
2236
|
+
"keep-a-changelog"
|
|
2237
|
+
).option("-s, --since <tag>", "Start changelog from specific tag").option("-u, --repo-url <url>", "Repository URL for changelog links").option("-d, --dry-run", "Preview changelog without writing to file", false).option("-p, --project-dir <path>", "Project directory", process.cwd()).action(async (options) => {
|
|
2238
|
+
try {
|
|
2239
|
+
log("Regenerating changelog from git history...", "info");
|
|
2240
|
+
if (options.format !== "keep-a-changelog" && options.format !== "angular") {
|
|
2241
|
+
throw new Error(
|
|
2242
|
+
'Invalid format specified. Must be either "keep-a-changelog" or "angular"'
|
|
2243
|
+
);
|
|
2244
|
+
}
|
|
2245
|
+
const regenerateOptions = {
|
|
2246
|
+
format: options.format,
|
|
2247
|
+
since: options.since,
|
|
2248
|
+
output: options.output,
|
|
2249
|
+
dryRun: options.dryRun,
|
|
2250
|
+
projectDir: options.projectDir,
|
|
2251
|
+
repoUrl: options.repoUrl
|
|
2252
|
+
};
|
|
2253
|
+
const content = await regenerateChangelog(regenerateOptions);
|
|
2254
|
+
await writeChangelog(
|
|
2255
|
+
content,
|
|
2256
|
+
path7.resolve(options.projectDir, options.output),
|
|
2257
|
+
options.dryRun
|
|
2258
|
+
);
|
|
2259
|
+
if (!options.dryRun) {
|
|
2260
|
+
log(`Changelog successfully regenerated at ${options.output}`, "success");
|
|
2261
|
+
}
|
|
2262
|
+
} catch (error) {
|
|
2263
|
+
log(error instanceof Error ? error.message : String(error), "error");
|
|
2264
|
+
process.exit(1);
|
|
2265
|
+
}
|
|
2266
|
+
});
|
|
2267
|
+
program.parse(process.argv);
|
|
1376
2268
|
} catch (error) {
|
|
1377
|
-
|
|
2269
|
+
console.error("Fatal error:", error);
|
|
1378
2270
|
process.exit(1);
|
|
1379
2271
|
}
|
|
1380
2272
|
}
|