package-versioner 0.6.3 → 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 +1072 -174
- package/dist/index.js +1063 -165
- package/docs/changelogs.md +65 -0
- package/docs/{VERSIONING_STRATEGIES.md → versioning.md} +1 -1
- package/package-versioner.schema.json +32 -1
- 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
|
|
|
@@ -326,8 +760,12 @@ function formatVersionPrefix(versionPrefix, scope) {
|
|
|
326
760
|
}
|
|
327
761
|
return cleanPrefix;
|
|
328
762
|
}
|
|
329
|
-
function formatCommitMessage(template, version, scope) {
|
|
330
|
-
return createTemplateString(template, {
|
|
763
|
+
function formatCommitMessage(template, version, packageName, scope) {
|
|
764
|
+
return createTemplateString(template, {
|
|
765
|
+
version,
|
|
766
|
+
scope,
|
|
767
|
+
packageName: packageName || ""
|
|
768
|
+
});
|
|
331
769
|
}
|
|
332
770
|
function createTemplateString(template, variables) {
|
|
333
771
|
return Object.entries(variables).reduce((result, [key, value]) => {
|
|
@@ -343,7 +781,7 @@ function createTemplateString(template, variables) {
|
|
|
343
781
|
function getCommitsLength(pkgRoot) {
|
|
344
782
|
try {
|
|
345
783
|
const gitCommand = `git rev-list --count HEAD ^$(git describe --tags --abbrev=0) ${pkgRoot}`;
|
|
346
|
-
const amount =
|
|
784
|
+
const amount = execSync3(gitCommand).toString().trim();
|
|
347
785
|
return Number(amount);
|
|
348
786
|
} catch (error) {
|
|
349
787
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -440,20 +878,20 @@ async function getLatestTagForPackage(packageName, versionPrefix) {
|
|
|
440
878
|
}
|
|
441
879
|
|
|
442
880
|
// src/package/packageManagement.ts
|
|
443
|
-
import
|
|
881
|
+
import fs4 from "node:fs";
|
|
444
882
|
|
|
445
883
|
// src/cargo/cargoHandler.ts
|
|
446
|
-
import
|
|
447
|
-
import
|
|
884
|
+
import fs3 from "node:fs";
|
|
885
|
+
import path2 from "node:path";
|
|
448
886
|
import * as TOML from "smol-toml";
|
|
449
887
|
function getCargoInfo(cargoPath) {
|
|
450
888
|
var _a;
|
|
451
|
-
if (!
|
|
889
|
+
if (!fs3.existsSync(cargoPath)) {
|
|
452
890
|
log(`Cargo.toml file not found at: ${cargoPath}`, "error");
|
|
453
891
|
throw new Error(`Cargo.toml file not found at: ${cargoPath}`);
|
|
454
892
|
}
|
|
455
893
|
try {
|
|
456
|
-
const fileContent =
|
|
894
|
+
const fileContent = fs3.readFileSync(cargoPath, "utf8");
|
|
457
895
|
const cargo = TOML.parse(fileContent);
|
|
458
896
|
if (!((_a = cargo.package) == null ? void 0 : _a.name)) {
|
|
459
897
|
log(`Package name not found in: ${cargoPath}`, "error");
|
|
@@ -463,7 +901,7 @@ function getCargoInfo(cargoPath) {
|
|
|
463
901
|
name: cargo.package.name,
|
|
464
902
|
version: cargo.package.version || "0.0.0",
|
|
465
903
|
path: cargoPath,
|
|
466
|
-
dir:
|
|
904
|
+
dir: path2.dirname(cargoPath),
|
|
467
905
|
content: cargo
|
|
468
906
|
};
|
|
469
907
|
} catch (error) {
|
|
@@ -476,12 +914,12 @@ function getCargoInfo(cargoPath) {
|
|
|
476
914
|
}
|
|
477
915
|
}
|
|
478
916
|
function isCargoToml(filePath) {
|
|
479
|
-
return
|
|
917
|
+
return path2.basename(filePath) === "Cargo.toml";
|
|
480
918
|
}
|
|
481
919
|
function updateCargoVersion(cargoPath, version) {
|
|
482
920
|
var _a;
|
|
483
921
|
try {
|
|
484
|
-
const originalContent =
|
|
922
|
+
const originalContent = fs3.readFileSync(cargoPath, "utf8");
|
|
485
923
|
const cargo = TOML.parse(originalContent);
|
|
486
924
|
const packageName = (_a = cargo.package) == null ? void 0 : _a.name;
|
|
487
925
|
if (!packageName) {
|
|
@@ -493,7 +931,7 @@ function updateCargoVersion(cargoPath, version) {
|
|
|
493
931
|
cargo.package.version = version;
|
|
494
932
|
}
|
|
495
933
|
const updatedContent = TOML.stringify(cargo);
|
|
496
|
-
|
|
934
|
+
fs3.writeFileSync(cargoPath, updatedContent);
|
|
497
935
|
addPackageUpdate(packageName, version, cargoPath);
|
|
498
936
|
log(`Updated Cargo.toml at ${cargoPath} to version ${version}`, "success");
|
|
499
937
|
} catch (error) {
|
|
@@ -512,11 +950,11 @@ function updatePackageVersion(packagePath, version) {
|
|
|
512
950
|
return;
|
|
513
951
|
}
|
|
514
952
|
try {
|
|
515
|
-
const packageContent =
|
|
953
|
+
const packageContent = fs4.readFileSync(packagePath, "utf8");
|
|
516
954
|
const packageJson = JSON.parse(packageContent);
|
|
517
955
|
const packageName = packageJson.name;
|
|
518
956
|
packageJson.version = version;
|
|
519
|
-
|
|
957
|
+
fs4.writeFileSync(packagePath, `${JSON.stringify(packageJson, null, 2)}
|
|
520
958
|
`);
|
|
521
959
|
addPackageUpdate(packageName, version, packagePath);
|
|
522
960
|
log(`Updated package.json at ${packagePath} to version ${version}`, "success");
|
|
@@ -530,24 +968,349 @@ function updatePackageVersion(packagePath, version) {
|
|
|
530
968
|
}
|
|
531
969
|
|
|
532
970
|
// src/package/packageProcessor.ts
|
|
533
|
-
import * as
|
|
534
|
-
import
|
|
971
|
+
import * as fs7 from "node:fs";
|
|
972
|
+
import path5 from "node:path";
|
|
535
973
|
import { exit } from "node:process";
|
|
536
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
|
+
|
|
537
1300
|
// src/core/versionCalculator.ts
|
|
538
1301
|
import { cwd as cwd3 } from "node:process";
|
|
539
1302
|
import { Bumper } from "conventional-recommended-bump";
|
|
540
1303
|
import semver2 from "semver";
|
|
541
1304
|
|
|
542
1305
|
// src/utils/manifestHelpers.ts
|
|
543
|
-
import
|
|
544
|
-
import
|
|
1306
|
+
import fs6 from "node:fs";
|
|
1307
|
+
import path4 from "node:path";
|
|
545
1308
|
function getVersionFromManifests(packageDir) {
|
|
546
|
-
const packageJsonPath =
|
|
547
|
-
const cargoTomlPath =
|
|
548
|
-
if (
|
|
1309
|
+
const packageJsonPath = path4.join(packageDir, "package.json");
|
|
1310
|
+
const cargoTomlPath = path4.join(packageDir, "Cargo.toml");
|
|
1311
|
+
if (fs6.existsSync(packageJsonPath)) {
|
|
549
1312
|
try {
|
|
550
|
-
const packageJson = JSON.parse(
|
|
1313
|
+
const packageJson = JSON.parse(fs6.readFileSync(packageJsonPath, "utf-8"));
|
|
551
1314
|
if (packageJson.version) {
|
|
552
1315
|
log(`Found version ${packageJson.version} in package.json`, "debug");
|
|
553
1316
|
return {
|
|
@@ -563,7 +1326,7 @@ function getVersionFromManifests(packageDir) {
|
|
|
563
1326
|
log(`Error reading package.json: ${errMsg}`, "warning");
|
|
564
1327
|
}
|
|
565
1328
|
}
|
|
566
|
-
if (
|
|
1329
|
+
if (fs6.existsSync(cargoTomlPath)) {
|
|
567
1330
|
try {
|
|
568
1331
|
const cargoInfo = getCargoInfo(cargoTomlPath);
|
|
569
1332
|
if (cargoInfo.version) {
|
|
@@ -589,8 +1352,8 @@ function getVersionFromManifests(packageDir) {
|
|
|
589
1352
|
};
|
|
590
1353
|
}
|
|
591
1354
|
function throwIfNoManifestsFound(packageDir) {
|
|
592
|
-
const packageJsonPath =
|
|
593
|
-
const cargoTomlPath =
|
|
1355
|
+
const packageJsonPath = path4.join(packageDir, "package.json");
|
|
1356
|
+
const cargoTomlPath = path4.join(packageDir, "Cargo.toml");
|
|
594
1357
|
throw new Error(
|
|
595
1358
|
`Neither package.json nor Cargo.toml found at ${packageDir}. Checked paths: ${packageJsonPath}, ${cargoTomlPath}. Cannot determine version.`
|
|
596
1359
|
);
|
|
@@ -845,7 +1608,7 @@ var PackageProcessor = class {
|
|
|
845
1608
|
* Process packages based on targeting criteria
|
|
846
1609
|
*/
|
|
847
1610
|
async processPackages(packages) {
|
|
848
|
-
var _a;
|
|
1611
|
+
var _a, _b, _c, _d, _e;
|
|
849
1612
|
const tags = [];
|
|
850
1613
|
const updatedPackagesInfo = [];
|
|
851
1614
|
if (!packages || !Array.isArray(packages)) {
|
|
@@ -930,13 +1693,81 @@ var PackageProcessor = class {
|
|
|
930
1693
|
if (!nextVersion) {
|
|
931
1694
|
continue;
|
|
932
1695
|
}
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
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)) {
|
|
936
1753
|
updatePackageVersion(packageJsonPath, nextVersion);
|
|
937
1754
|
}
|
|
938
|
-
|
|
939
|
-
|
|
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
|
+
}
|
|
940
1771
|
}
|
|
941
1772
|
const packageTag = formatTag(
|
|
942
1773
|
nextVersion,
|
|
@@ -968,12 +1799,37 @@ var PackageProcessor = class {
|
|
|
968
1799
|
log("No targeted packages required a version update.", "info");
|
|
969
1800
|
return { updatedPackages: [], tags };
|
|
970
1801
|
}
|
|
971
|
-
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
|
+
}
|
|
972
1826
|
const packageNames = updatedPackagesInfo.map((p) => p.name).join(", ");
|
|
973
|
-
const representativeVersion = ((
|
|
1827
|
+
const representativeVersion = ((_e = updatedPackagesInfo[0]) == null ? void 0 : _e.version) || "multiple";
|
|
974
1828
|
let commitMessage = this.commitMessageTemplate || "chore(release): publish packages";
|
|
975
|
-
|
|
976
|
-
|
|
1829
|
+
const placeholderRegex = /\$\{[^}]+\}/;
|
|
1830
|
+
if (updatedPackagesInfo.length === 1 && placeholderRegex.test(commitMessage)) {
|
|
1831
|
+
const packageName = updatedPackagesInfo[0].name;
|
|
1832
|
+
commitMessage = formatCommitMessage(commitMessage, representativeVersion, packageName);
|
|
977
1833
|
} else {
|
|
978
1834
|
commitMessage = `chore(release): ${packageNames} ${representativeVersion}`;
|
|
979
1835
|
}
|
|
@@ -1045,20 +1901,21 @@ function createSyncedStrategy(config) {
|
|
|
1045
1901
|
const files = [];
|
|
1046
1902
|
const updatedPackages = [];
|
|
1047
1903
|
try {
|
|
1048
|
-
const rootPkgPath =
|
|
1049
|
-
if (
|
|
1904
|
+
const rootPkgPath = path6.join(packages.root, "package.json");
|
|
1905
|
+
if (fs8.existsSync(rootPkgPath)) {
|
|
1050
1906
|
updatePackageVersion(rootPkgPath, nextVersion);
|
|
1051
1907
|
files.push(rootPkgPath);
|
|
1052
1908
|
updatedPackages.push("root");
|
|
1053
1909
|
}
|
|
1054
|
-
} catch (
|
|
1055
|
-
|
|
1910
|
+
} catch (error) {
|
|
1911
|
+
const errMessage = error instanceof Error ? error.message : String(error);
|
|
1912
|
+
log(`Failed to update root package.json: ${errMessage}`, "error");
|
|
1056
1913
|
}
|
|
1057
1914
|
for (const pkg of packages.packages) {
|
|
1058
1915
|
if (!shouldProcessPackage(pkg, config)) {
|
|
1059
1916
|
continue;
|
|
1060
1917
|
}
|
|
1061
|
-
const packageJsonPath =
|
|
1918
|
+
const packageJsonPath = path6.join(pkg.dir, "package.json");
|
|
1062
1919
|
updatePackageVersion(packageJsonPath, nextVersion);
|
|
1063
1920
|
files.push(packageJsonPath);
|
|
1064
1921
|
updatedPackages.push(pkg.packageJson.name);
|
|
@@ -1131,7 +1988,7 @@ function createSingleStrategy(config) {
|
|
|
1131
1988
|
log(`No version change needed for ${packageName}`, "info");
|
|
1132
1989
|
return;
|
|
1133
1990
|
}
|
|
1134
|
-
const packageJsonPath =
|
|
1991
|
+
const packageJsonPath = path6.join(pkgPath, "package.json");
|
|
1135
1992
|
updatePackageVersion(packageJsonPath, nextVersion);
|
|
1136
1993
|
log(`Updated package ${packageName} to version ${nextVersion}`, "success");
|
|
1137
1994
|
const nextTag = formatTag(
|
|
@@ -1141,7 +1998,7 @@ function createSingleStrategy(config) {
|
|
|
1141
1998
|
tagTemplate,
|
|
1142
1999
|
packageTagTemplate
|
|
1143
2000
|
);
|
|
1144
|
-
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
|
|
2001
|
+
const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion, packageName);
|
|
1145
2002
|
await createGitCommitAndTag(
|
|
1146
2003
|
[packageJsonPath],
|
|
1147
2004
|
nextTag,
|
|
@@ -1309,11 +2166,11 @@ var VersionEngine = class {
|
|
|
1309
2166
|
// src/index.ts
|
|
1310
2167
|
function getPackageVersion() {
|
|
1311
2168
|
try {
|
|
1312
|
-
const packageJsonPath =
|
|
1313
|
-
|
|
2169
|
+
const packageJsonPath = path7.resolve(
|
|
2170
|
+
path7.dirname(import.meta.url.replace("file:", "")),
|
|
1314
2171
|
"../package.json"
|
|
1315
2172
|
);
|
|
1316
|
-
const packageJsonContent =
|
|
2173
|
+
const packageJsonContent = fs9.readFileSync(packageJsonPath, "utf-8");
|
|
1317
2174
|
const packageJson = JSON.parse(packageJsonContent);
|
|
1318
2175
|
return packageJson.version || "0.0.0";
|
|
1319
2176
|
} catch (error) {
|
|
@@ -1322,53 +2179,94 @@ function getPackageVersion() {
|
|
|
1322
2179
|
}
|
|
1323
2180
|
}
|
|
1324
2181
|
async function run() {
|
|
1325
|
-
const buildTimestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
1326
|
-
const packageVersion = getPackageVersion();
|
|
1327
|
-
log(`package-versioner v${packageVersion} (Build: ${buildTimestamp})`, "debug");
|
|
1328
|
-
const program = new Command();
|
|
1329
|
-
program.name("package-versioner").description(
|
|
1330
|
-
"A lightweight yet powerful CLI tool for automated semantic versioning based on Git history and conventional commits."
|
|
1331
|
-
).version(packageVersion).option(
|
|
1332
|
-
"-c, --config <path>",
|
|
1333
|
-
"Path to config file (defaults to version.config.json in current directory)"
|
|
1334
|
-
).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);
|
|
1335
|
-
const options = program.opts();
|
|
1336
|
-
if (options.json) {
|
|
1337
|
-
enableJsonOutput(options.dryRun);
|
|
1338
|
-
}
|
|
1339
2182
|
try {
|
|
1340
|
-
const
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
} else if (config.packages && config.packages.length === 1) {
|
|
1354
|
-
log("Using single package versioning strategy.", "info");
|
|
1355
|
-
if (cliTargets.length > 0) {
|
|
1356
|
-
log("--target flag is ignored for single package strategy.", "warning");
|
|
1357
|
-
}
|
|
1358
|
-
engine.setStrategy("single");
|
|
1359
|
-
await engine.run();
|
|
1360
|
-
} else {
|
|
1361
|
-
log("Using async versioning strategy.", "info");
|
|
1362
|
-
if (cliTargets.length > 0) {
|
|
1363
|
-
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);
|
|
1364
2196
|
}
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
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);
|
|
1370
2268
|
} catch (error) {
|
|
1371
|
-
|
|
2269
|
+
console.error("Fatal error:", error);
|
|
1372
2270
|
process.exit(1);
|
|
1373
2271
|
}
|
|
1374
2272
|
}
|