@soybeanjs/changelog 0.4.0-beta.1 → 0.4.3
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/dist/index.d.ts +1 -1
- package/dist/index.js +42 -73
- package/package.json +14 -14
package/dist/index.d.ts
CHANGED
|
@@ -121,7 +121,7 @@ declare function getChangelogMarkdown(options?: Partial<ChangelogOption>, showTi
|
|
|
121
121
|
* Get the changelog markdown by the total git tags
|
|
122
122
|
*
|
|
123
123
|
* @param options The changelog options
|
|
124
|
-
* @param showProgress
|
|
124
|
+
* @param showProgress Whether show the progress bar
|
|
125
125
|
*/
|
|
126
126
|
declare function getTotalChangelogMarkdown(options?: Partial<ChangelogOption>, showProgress?: boolean): Promise<string>;
|
|
127
127
|
/**
|
package/dist/index.js
CHANGED
|
@@ -11,8 +11,7 @@ import { convert } from "convert-gitmoji";
|
|
|
11
11
|
//#region src/shared.ts
|
|
12
12
|
async function execCommand(cmd, args, options) {
|
|
13
13
|
const { execa } = await import("execa");
|
|
14
|
-
|
|
15
|
-
return (res?.stdout)?.trim() || "";
|
|
14
|
+
return ((await execa(cmd, args, options))?.stdout)?.trim() || "";
|
|
16
15
|
}
|
|
17
16
|
function notNullish(v) {
|
|
18
17
|
return v !== null && v !== void 0;
|
|
@@ -60,14 +59,12 @@ const VERSION_WITH_RELEASE = /release\sv\d+\.\d+\.\d+(-(beta|alpha)\.\d+)?/;
|
|
|
60
59
|
//#region src/git.ts
|
|
61
60
|
/** Get the total git tags */
|
|
62
61
|
async function getTotalGitTags() {
|
|
63
|
-
const
|
|
62
|
+
const filtered = (await execCommand("git", [
|
|
64
63
|
"--no-pager",
|
|
65
64
|
"tag",
|
|
66
65
|
"-l",
|
|
67
66
|
"--sort=v:refname"
|
|
68
|
-
]);
|
|
69
|
-
const tags = tagStr.split("\n");
|
|
70
|
-
const filtered = tags.filter((tag) => VERSION_REG.test(tag));
|
|
67
|
+
])).split("\n").filter((tag) => VERSION_REG.test(tag));
|
|
71
68
|
return semver.sort(filtered);
|
|
72
69
|
}
|
|
73
70
|
/** Get map of the git tag and date */
|
|
@@ -81,8 +78,7 @@ async function getTagDateMap() {
|
|
|
81
78
|
]);
|
|
82
79
|
const TAG_MARK = "tag: ";
|
|
83
80
|
const map = /* @__PURE__ */ new Map();
|
|
84
|
-
|
|
85
|
-
dates.forEach((item) => {
|
|
81
|
+
tagDateStr.split("\n").filter((item) => item.includes(TAG_MARK)).forEach((item) => {
|
|
86
82
|
const [dateStr, tagStr] = item.split(TAG_MARK);
|
|
87
83
|
const date = dayjs(dateStr).format("YYYY-MM-DD");
|
|
88
84
|
const tag = tagStr.match(VERSION_REG)?.[0];
|
|
@@ -104,10 +100,7 @@ function getFromToTags(tags) {
|
|
|
104
100
|
if (index < reversedTags.length - 1) {
|
|
105
101
|
const to = tag;
|
|
106
102
|
let from = reversedTags[index + 1];
|
|
107
|
-
if (!isPrerelease(to))
|
|
108
|
-
const toIndex = releaseTags.indexOf(to);
|
|
109
|
-
from = releaseTags[toIndex - 1];
|
|
110
|
-
}
|
|
103
|
+
if (!isPrerelease(to)) from = releaseTags[releaseTags.indexOf(to) - 1];
|
|
111
104
|
result.push({
|
|
112
105
|
from,
|
|
113
106
|
to
|
|
@@ -117,12 +110,11 @@ function getFromToTags(tags) {
|
|
|
117
110
|
return result.reverse();
|
|
118
111
|
}
|
|
119
112
|
async function getGitMainBranchName() {
|
|
120
|
-
|
|
113
|
+
return await execCommand("git", [
|
|
121
114
|
"rev-parse",
|
|
122
115
|
"--abbrev-ref",
|
|
123
116
|
"HEAD"
|
|
124
117
|
]);
|
|
125
|
-
return main;
|
|
126
118
|
}
|
|
127
119
|
async function getCurrentGitBranch() {
|
|
128
120
|
const tag = await execCommand("git", [
|
|
@@ -144,8 +136,7 @@ async function getGitHubRepo() {
|
|
|
144
136
|
return `${match[1]}/${match[2]}`;
|
|
145
137
|
}
|
|
146
138
|
function isPrerelease(version) {
|
|
147
|
-
|
|
148
|
-
return !REG.test(version);
|
|
139
|
+
return !/^[^.]*[\d.]+$/.test(version);
|
|
149
140
|
}
|
|
150
141
|
function getFirstGitCommit() {
|
|
151
142
|
return execCommand("git", [
|
|
@@ -155,18 +146,16 @@ function getFirstGitCommit() {
|
|
|
155
146
|
]);
|
|
156
147
|
}
|
|
157
148
|
async function getGitDiff(from, to = "HEAD") {
|
|
158
|
-
|
|
149
|
+
return (await execCommand("git", [
|
|
159
150
|
"--no-pager",
|
|
160
151
|
"log",
|
|
161
152
|
`${from ? `${from}...` : ""}${to}`,
|
|
162
153
|
"--pretty=\"----%n%s|%h|%an|%ae%n%b\"",
|
|
163
154
|
"--name-status"
|
|
164
|
-
])
|
|
165
|
-
const rwaGitLines = rawGit.split("----\n").splice(1);
|
|
166
|
-
const gitCommits = rwaGitLines.map((line) => {
|
|
155
|
+
])).split("----\n").splice(1).map((line) => {
|
|
167
156
|
const [firstLine, ...body] = line.split("\n");
|
|
168
157
|
const [message, shortHash, authorName, authorEmail] = firstLine.split("|");
|
|
169
|
-
|
|
158
|
+
return {
|
|
170
159
|
message,
|
|
171
160
|
shortHash,
|
|
172
161
|
author: {
|
|
@@ -175,9 +164,7 @@ async function getGitDiff(from, to = "HEAD") {
|
|
|
175
164
|
},
|
|
176
165
|
body: body.join("\n")
|
|
177
166
|
};
|
|
178
|
-
return gitCommit;
|
|
179
167
|
});
|
|
180
|
-
return gitCommits;
|
|
181
168
|
}
|
|
182
169
|
function parseGitCommit(commit) {
|
|
183
170
|
const ConventionalCommitRegex = /(?<type>[a-z]+)(\((?<scope>.+)\))?(?<breaking>!)?: (?<description>.+)/i;
|
|
@@ -226,9 +213,7 @@ function parseGitCommit(commit) {
|
|
|
226
213
|
};
|
|
227
214
|
}
|
|
228
215
|
async function getGitCommits(from, to = "HEAD") {
|
|
229
|
-
|
|
230
|
-
const commits = rwaGitCommits.map((commit) => parseGitCommit(commit)).filter(notNullish);
|
|
231
|
-
return commits;
|
|
216
|
+
return (await getGitDiff(from, to)).map((commit) => parseGitCommit(commit)).filter(notNullish);
|
|
232
217
|
}
|
|
233
218
|
function getHeaders(githubToken) {
|
|
234
219
|
return {
|
|
@@ -239,8 +224,7 @@ function getHeaders(githubToken) {
|
|
|
239
224
|
async function getResolvedAuthorLogin(github, commitHashes, email) {
|
|
240
225
|
let login = "";
|
|
241
226
|
try {
|
|
242
|
-
|
|
243
|
-
login = data?.user?.username || "";
|
|
227
|
+
login = (await ofetch(`https://ungh.cc/users/find/${email}`))?.user?.username || "";
|
|
244
228
|
} catch (e) {
|
|
245
229
|
consola.log("e: ", e);
|
|
246
230
|
}
|
|
@@ -248,15 +232,13 @@ async function getResolvedAuthorLogin(github, commitHashes, email) {
|
|
|
248
232
|
const { repo, token } = github;
|
|
249
233
|
if (!token) return login;
|
|
250
234
|
if (commitHashes.length) try {
|
|
251
|
-
|
|
252
|
-
login = data?.author?.login || "";
|
|
235
|
+
login = (await ofetch(`https://api.github.com/repos/${repo}/commits/${commitHashes[0]}`, { headers: getHeaders(token) }))?.author?.login || "";
|
|
253
236
|
} catch (e) {
|
|
254
237
|
consola.log("e: ", e);
|
|
255
238
|
}
|
|
256
239
|
if (login) return login;
|
|
257
240
|
try {
|
|
258
|
-
|
|
259
|
-
login = data.items[0].login;
|
|
241
|
+
login = (await ofetch(`https://api.github.com/search/users?q=${encodeURIComponent(email)}`, { headers: getHeaders(token) })).items[0].login;
|
|
260
242
|
} catch (e) {
|
|
261
243
|
consola.log("e: ", e);
|
|
262
244
|
}
|
|
@@ -282,10 +264,7 @@ async function getGitCommitsAndResolvedAuthors(commits, github, resolvedLogins)
|
|
|
282
264
|
const login = await getResolvedAuthorLogin(github, commitHashes, email);
|
|
283
265
|
resolvedAuthor.login = login;
|
|
284
266
|
resolvedLogins?.set(email, login);
|
|
285
|
-
} else
|
|
286
|
-
const login = resolvedLogins?.get(email) || "";
|
|
287
|
-
resolvedAuthor.login = login;
|
|
288
|
-
}
|
|
267
|
+
} else resolvedAuthor.login = resolvedLogins?.get(email) || "";
|
|
289
268
|
resolvedAuthors.push(resolvedAuthor);
|
|
290
269
|
if (!map.has(email)) map.set(email, resolvedAuthor);
|
|
291
270
|
}
|
|
@@ -305,9 +284,8 @@ async function getGitCommitsAndResolvedAuthors(commits, github, resolvedLogins)
|
|
|
305
284
|
//#endregion
|
|
306
285
|
//#region src/options.ts
|
|
307
286
|
function createDefaultOptions() {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
cwd,
|
|
287
|
+
return {
|
|
288
|
+
cwd: process.cwd(),
|
|
311
289
|
types: {
|
|
312
290
|
feat: "🚀 Features",
|
|
313
291
|
fix: "🐞 Bug Fixes",
|
|
@@ -337,14 +315,12 @@ function createDefaultOptions() {
|
|
|
337
315
|
output: "CHANGELOG.md",
|
|
338
316
|
regenerate: false
|
|
339
317
|
};
|
|
340
|
-
return options;
|
|
341
318
|
}
|
|
342
319
|
async function getVersionFromPkgJson(cwd) {
|
|
343
320
|
let newVersion = "";
|
|
344
321
|
try {
|
|
345
322
|
const pkgJson = await readFile(`${cwd}/package.json`, "utf-8");
|
|
346
|
-
|
|
347
|
-
newVersion = pkg?.version || "";
|
|
323
|
+
newVersion = JSON.parse(pkgJson)?.version || "";
|
|
348
324
|
} catch {}
|
|
349
325
|
return { newVersion };
|
|
350
326
|
}
|
|
@@ -375,15 +351,14 @@ async function createOptions(options) {
|
|
|
375
351
|
//#endregion
|
|
376
352
|
//#region src/markdown.ts
|
|
377
353
|
function formatReferences(references, githubRepo, type) {
|
|
378
|
-
const
|
|
354
|
+
const referencesString = join(references.filter((i) => {
|
|
379
355
|
if (type === "issues") return i.type === "issue" || i.type === "pull-request";
|
|
380
356
|
return i.type === "hash";
|
|
381
357
|
}).map((ref) => {
|
|
382
358
|
if (!githubRepo) return ref.value;
|
|
383
359
|
if (ref.type === "pull-request" || ref.type === "issue") return `https://github.com/${githubRepo}/issues/${ref.value.slice(1)}`;
|
|
384
360
|
return `[<samp>(${ref.value.slice(0, 5)})</samp>](https://github.com/${githubRepo}/commit/${ref.value})`;
|
|
385
|
-
});
|
|
386
|
-
const referencesString = join(refs).trim();
|
|
361
|
+
})).trim();
|
|
387
362
|
if (type === "issues") return referencesString && `in ${referencesString}`;
|
|
388
363
|
return referencesString;
|
|
389
364
|
}
|
|
@@ -398,8 +373,7 @@ function formatLine(commit, options) {
|
|
|
398
373
|
hashRefs
|
|
399
374
|
].filter((i) => i?.trim()).join(" ");
|
|
400
375
|
if (refs) refs = ` - ${refs}`;
|
|
401
|
-
|
|
402
|
-
return [description, refs].filter((i) => i?.trim()).join(" ");
|
|
376
|
+
return [options.capitalize ? capitalize(commit.description) : commit.description, refs].filter((i) => i?.trim()).join(" ");
|
|
403
377
|
}
|
|
404
378
|
function formatTitle(name, options) {
|
|
405
379
|
const emojisRE = /([\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF])/g;
|
|
@@ -430,13 +404,10 @@ function formatSection(commits, sectionName, options) {
|
|
|
430
404
|
return lines;
|
|
431
405
|
}
|
|
432
406
|
function getUserGithub(userName) {
|
|
433
|
-
|
|
434
|
-
return githubUrl;
|
|
407
|
+
return `https://github.com/${userName}`;
|
|
435
408
|
}
|
|
436
409
|
function getGitUserAvatar(userName) {
|
|
437
|
-
|
|
438
|
-
const avatarUrl = `${githubUrl}.png?size=48`;
|
|
439
|
-
return avatarUrl;
|
|
410
|
+
return `${getUserGithub(userName)}.png?size=48`;
|
|
440
411
|
}
|
|
441
412
|
function createContributorLine(contributors) {
|
|
442
413
|
let loginLine = "";
|
|
@@ -445,8 +416,7 @@ function createContributorLine(contributors) {
|
|
|
445
416
|
contributors.forEach((contributor) => {
|
|
446
417
|
contributorMap.set(contributor.email, contributor);
|
|
447
418
|
});
|
|
448
|
-
|
|
449
|
-
filteredContributors.forEach((contributor, index) => {
|
|
419
|
+
Array.from(contributorMap.values()).forEach((contributor, index) => {
|
|
450
420
|
const { name, email, login } = contributor;
|
|
451
421
|
if (!login) {
|
|
452
422
|
let line = `[${name}](mailto:${email})`;
|
|
@@ -460,11 +430,15 @@ function createContributorLine(contributors) {
|
|
|
460
430
|
});
|
|
461
431
|
return `${loginLine}\n${unLoginLine}`;
|
|
462
432
|
}
|
|
463
|
-
function generateMarkdown(params) {
|
|
433
|
+
async function generateMarkdown(params) {
|
|
464
434
|
const { options, showTitle, contributors } = params;
|
|
465
435
|
const commits = params.commits.filter((commit) => commit.description.match(VERSION_WITH_RELEASE) === null);
|
|
466
436
|
const lines = [];
|
|
467
|
-
|
|
437
|
+
let url = `https://github.com/${options.github.repo}/compare/${options.from}...${options.to}`;
|
|
438
|
+
if (!options.from) {
|
|
439
|
+
const mainBranch = await getGitMainBranchName();
|
|
440
|
+
url = `https://github.com/${options.github.repo}/compare/${options.to}...${mainBranch || "HEAD"}`;
|
|
441
|
+
}
|
|
468
442
|
if (showTitle) {
|
|
469
443
|
const date = options.tagDateMap.get(options.to) || dayjs().format("YYYY-MM-DD");
|
|
470
444
|
let title = `## [${options.to}](${url})`;
|
|
@@ -485,8 +459,7 @@ function generateMarkdown(params) {
|
|
|
485
459
|
const contributorLine = createContributorLine(contributors);
|
|
486
460
|
lines.push(contributorLine);
|
|
487
461
|
}
|
|
488
|
-
|
|
489
|
-
return md;
|
|
462
|
+
return convert(lines.join("\n").trim(), true);
|
|
490
463
|
}
|
|
491
464
|
async function isVersionInMarkdown(newVersion, mdPath) {
|
|
492
465
|
let isIn = false;
|
|
@@ -530,14 +503,13 @@ async function getChangelogMarkdown(options, showTitle = true) {
|
|
|
530
503
|
const gitCommits = await getGitCommits(opts.from, to);
|
|
531
504
|
const resolvedLogins = /* @__PURE__ */ new Map();
|
|
532
505
|
const { commits, contributors } = await getGitCommitsAndResolvedAuthors(gitCommits, opts.github, resolvedLogins);
|
|
533
|
-
const markdown = generateMarkdown({
|
|
534
|
-
commits,
|
|
535
|
-
options: opts,
|
|
536
|
-
showTitle,
|
|
537
|
-
contributors
|
|
538
|
-
});
|
|
539
506
|
return {
|
|
540
|
-
markdown
|
|
507
|
+
markdown: await generateMarkdown({
|
|
508
|
+
commits,
|
|
509
|
+
options: opts,
|
|
510
|
+
showTitle,
|
|
511
|
+
contributors
|
|
512
|
+
}),
|
|
541
513
|
commits,
|
|
542
514
|
options: opts
|
|
543
515
|
};
|
|
@@ -546,7 +518,7 @@ async function getChangelogMarkdown(options, showTitle = true) {
|
|
|
546
518
|
* Get the changelog markdown by the total git tags
|
|
547
519
|
*
|
|
548
520
|
* @param options The changelog options
|
|
549
|
-
* @param showProgress
|
|
521
|
+
* @param showProgress Whether show the progress bar
|
|
550
522
|
*/
|
|
551
523
|
async function getTotalChangelogMarkdown(options, showProgress = true) {
|
|
552
524
|
const opts = await createOptions(options);
|
|
@@ -562,9 +534,8 @@ async function getTotalChangelogMarkdown(options, showProgress = true) {
|
|
|
562
534
|
const resolvedLogins = /* @__PURE__ */ new Map();
|
|
563
535
|
for await (const [index, tag] of tags.entries()) {
|
|
564
536
|
const { from, to } = tag;
|
|
565
|
-
const
|
|
566
|
-
|
|
567
|
-
const nextMd = generateMarkdown({
|
|
537
|
+
const { commits, contributors } = await getGitCommitsAndResolvedAuthors(await getGitCommits(from, to), opts.github, resolvedLogins);
|
|
538
|
+
markdown = `${await generateMarkdown({
|
|
568
539
|
commits,
|
|
569
540
|
options: {
|
|
570
541
|
...opts,
|
|
@@ -573,8 +544,7 @@ async function getTotalChangelogMarkdown(options, showProgress = true) {
|
|
|
573
544
|
},
|
|
574
545
|
showTitle: true,
|
|
575
546
|
contributors
|
|
576
|
-
})
|
|
577
|
-
markdown = `${nextMd}\n\n${markdown}`;
|
|
547
|
+
})}\n\n${markdown}`;
|
|
578
548
|
bar?.update(index + 1);
|
|
579
549
|
}
|
|
580
550
|
bar?.stop();
|
|
@@ -600,8 +570,7 @@ async function generateChangelog(options) {
|
|
|
600
570
|
*/
|
|
601
571
|
async function generateTotalChangelog(options, showProgress = true) {
|
|
602
572
|
const opts = await createOptions(options);
|
|
603
|
-
|
|
604
|
-
await writeMarkdown(markdown, opts.output, true);
|
|
573
|
+
await writeMarkdown(await getTotalChangelogMarkdown(opts, showProgress), opts.output, true);
|
|
605
574
|
}
|
|
606
575
|
|
|
607
576
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soybeanjs/changelog",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.3",
|
|
5
5
|
"description": "generate changelog form git tags and commits for github",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Soybean",
|
|
@@ -38,25 +38,25 @@
|
|
|
38
38
|
"pnpm": ">=9"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@soybeanjs/eslint-config": "1.7.
|
|
41
|
+
"@soybeanjs/eslint-config": "1.7.5",
|
|
42
42
|
"cli-progress": "3.12.0",
|
|
43
43
|
"convert-gitmoji": "0.1.5",
|
|
44
|
-
"dayjs": "1.11.
|
|
45
|
-
"execa": "9.6.
|
|
46
|
-
"ofetch": "1.
|
|
47
|
-
"semver": "7.7.
|
|
44
|
+
"dayjs": "1.11.19",
|
|
45
|
+
"execa": "9.6.1",
|
|
46
|
+
"ofetch": "1.5.1",
|
|
47
|
+
"semver": "7.7.3"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@soybeanjs/cli": "1.4.
|
|
50
|
+
"@soybeanjs/cli": "1.4.1",
|
|
51
51
|
"@types/cli-progress": "3.11.6",
|
|
52
|
-
"@types/node": "
|
|
53
|
-
"@types/semver": "7.7.
|
|
54
|
-
"eslint": "9.
|
|
55
|
-
"lint-staged": "16.
|
|
52
|
+
"@types/node": "25.0.3",
|
|
53
|
+
"@types/semver": "7.7.1",
|
|
54
|
+
"eslint": "9.39.2",
|
|
55
|
+
"lint-staged": "16.2.7",
|
|
56
56
|
"simple-git-hooks": "2.13.1",
|
|
57
|
-
"tsdown": "0.
|
|
58
|
-
"tsx": "4.
|
|
59
|
-
"typescript": "5.9.
|
|
57
|
+
"tsdown": "0.18.2",
|
|
58
|
+
"tsx": "4.21.0",
|
|
59
|
+
"typescript": "5.9.3"
|
|
60
60
|
},
|
|
61
61
|
"simple-git-hooks": {
|
|
62
62
|
"commit-msg": "pnpm soy git-commit-verify",
|