githublogen 0.2.0 → 0.2.2
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 +2 -0
- package/dist/cli.cjs +3 -44
- package/dist/cli.mjs +4 -45
- package/dist/index.cjs +87 -208
- package/dist/index.d.ts +1 -3
- package/dist/index.mjs +88 -208
- package/package.json +10 -17
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Generate changelog for GitHub releases from [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/), powered by [changelogithub](https://github.com/antfu/changelogithub).
|
|
4
4
|
|
|
5
|
+
Auto Generate CHANGELOG.md from [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/), powered by [changelogen](https://github.com/unjs/changelogen).
|
|
6
|
+
|
|
5
7
|
## Usage
|
|
6
8
|
|
|
7
9
|
In GitHub Actions:
|
package/dist/cli.cjs
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
const fs = require('node:fs');
|
|
5
4
|
const kolorist = require('kolorist');
|
|
6
|
-
const execa = require('execa');
|
|
7
5
|
const cac = require('cac');
|
|
8
6
|
const index = require('./index.cjs');
|
|
9
7
|
require('ohmyfetch');
|
|
10
8
|
require('convert-gitmoji');
|
|
9
|
+
require('node:fs');
|
|
11
10
|
require('node:module');
|
|
12
11
|
require('node:url');
|
|
13
12
|
require('node:assert');
|
|
@@ -20,7 +19,7 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
|
|
|
20
19
|
|
|
21
20
|
const cac__default = /*#__PURE__*/_interopDefaultCompat(cac);
|
|
22
21
|
|
|
23
|
-
const version = "0.2.
|
|
22
|
+
const version = "0.2.2";
|
|
24
23
|
|
|
25
24
|
const cli = cac__default("githublogen");
|
|
26
25
|
cli.version(version).option("-t, --token <path>", "GitHub Token").option("--from <ref>", "From tag").option("--to <ref>", "To tag").option("--github <path>", "GitHub Repository, e.g. soybeanjs/githublogen").option("--name <name>", "Name of the release").option("--contributors", "Show contributors section").option("--prerelease", "Mark release as prerelease").option("-d, --draft", "Mark release as draft").option("--output <path>", "Output to file instead of sending to GitHub").option("--capitalize", "Should capitalize for each comment message").option("--emoji", "Use emojis in section titles", { default: true }).option("--group", "Nest commit messages under their scopes").option("--dry", "Dry run").help();
|
|
@@ -29,7 +28,7 @@ cli.command("").action(async (args) => {
|
|
|
29
28
|
console.log();
|
|
30
29
|
console.log(kolorist.dim(`${kolorist.bold("github")}logen `) + kolorist.dim(`v${version}`));
|
|
31
30
|
const cwd = process.cwd();
|
|
32
|
-
const { config, md,
|
|
31
|
+
const { config, md, commits } = await index.generate(cwd, args);
|
|
33
32
|
const markdown = md.replace(/ /g, "");
|
|
34
33
|
console.log(kolorist.cyan(config.from) + kolorist.dim(" -> ") + kolorist.blue(config.to) + kolorist.dim(` (${commits.length} commits)`));
|
|
35
34
|
console.log(kolorist.dim("--------------"));
|
|
@@ -41,46 +40,6 @@ cli.command("").action(async (args) => {
|
|
|
41
40
|
console.log(kolorist.yellow("Dry run. Release skipped."));
|
|
42
41
|
return;
|
|
43
42
|
}
|
|
44
|
-
if (typeof config.output === "string") {
|
|
45
|
-
const pushUrl = index.getGitPushUrl(config.repo, config.tokens.github);
|
|
46
|
-
if (!pushUrl) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
let changelogMD;
|
|
50
|
-
const changelogPrefix = "# Changelog";
|
|
51
|
-
if (fs.existsSync(config.output)) {
|
|
52
|
-
console.info(`Updating ${config.output}`);
|
|
53
|
-
changelogMD = await fs.promises.readFile(config.output, "utf8");
|
|
54
|
-
if (!changelogMD.startsWith(changelogPrefix)) {
|
|
55
|
-
changelogMD = `${changelogPrefix}
|
|
56
|
-
|
|
57
|
-
${changelogMD}`;
|
|
58
|
-
}
|
|
59
|
-
} else {
|
|
60
|
-
console.info(`Creating ${config.output}`);
|
|
61
|
-
changelogMD = `${changelogPrefix}
|
|
62
|
-
|
|
63
|
-
`;
|
|
64
|
-
}
|
|
65
|
-
const lastEntry = changelogMD.match(/^###?\s+.*$/m);
|
|
66
|
-
if (lastEntry) {
|
|
67
|
-
changelogMD = `${changelogMD.slice(0, lastEntry.index) + changelog}
|
|
68
|
-
|
|
69
|
-
${changelogMD.slice(lastEntry.index)}`;
|
|
70
|
-
} else {
|
|
71
|
-
changelogMD += `
|
|
72
|
-
${changelog}
|
|
73
|
-
|
|
74
|
-
`;
|
|
75
|
-
}
|
|
76
|
-
await fs.promises.writeFile(config.output, changelogMD);
|
|
77
|
-
const { email = "unknow@unknow.com", name = "unknow" } = commits[0]?.author || {};
|
|
78
|
-
await execa.execa("git", ["config", "--global", "user.email", `"${email}"`]);
|
|
79
|
-
await execa.execa("git", ["config", "--global", "user.name", `"${name}"`]);
|
|
80
|
-
await execa.execa("git", ["add", "."]);
|
|
81
|
-
await execa.execa("git", ["commit", "-m docs(projects): CHANGELOG.md"], { cwd });
|
|
82
|
-
await execa.execa("git", ["push", pushUrl, `HEAD:${config.gitMainBranch}`], { cwd });
|
|
83
|
-
}
|
|
84
43
|
if (!await index.hasTagOnGitHub(config.to, config)) {
|
|
85
44
|
console.error(kolorist.yellow(`Current ref "${kolorist.bold(config.to)}" is not available as tags on GitHub. Release skipped.`));
|
|
86
45
|
process.exitCode = 1;
|
package/dist/cli.mjs
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { existsSync, promises } from 'node:fs';
|
|
3
2
|
import { dim, bold, cyan, blue, yellow, red } from 'kolorist';
|
|
4
|
-
import { execa } from 'execa';
|
|
5
3
|
import cac from 'cac';
|
|
6
|
-
import { generate,
|
|
4
|
+
import { generate, hasTagOnGitHub, isRepoShallow, sendRelease } from './index.mjs';
|
|
7
5
|
import 'ohmyfetch';
|
|
8
6
|
import 'convert-gitmoji';
|
|
7
|
+
import 'node:fs';
|
|
9
8
|
import 'node:module';
|
|
10
9
|
import 'node:url';
|
|
11
10
|
import 'node:assert';
|
|
@@ -14,7 +13,7 @@ import 'node:path';
|
|
|
14
13
|
import 'node:v8';
|
|
15
14
|
import 'node:util';
|
|
16
15
|
|
|
17
|
-
const version = "0.2.
|
|
16
|
+
const version = "0.2.2";
|
|
18
17
|
|
|
19
18
|
const cli = cac("githublogen");
|
|
20
19
|
cli.version(version).option("-t, --token <path>", "GitHub Token").option("--from <ref>", "From tag").option("--to <ref>", "To tag").option("--github <path>", "GitHub Repository, e.g. soybeanjs/githublogen").option("--name <name>", "Name of the release").option("--contributors", "Show contributors section").option("--prerelease", "Mark release as prerelease").option("-d, --draft", "Mark release as draft").option("--output <path>", "Output to file instead of sending to GitHub").option("--capitalize", "Should capitalize for each comment message").option("--emoji", "Use emojis in section titles", { default: true }).option("--group", "Nest commit messages under their scopes").option("--dry", "Dry run").help();
|
|
@@ -23,7 +22,7 @@ cli.command("").action(async (args) => {
|
|
|
23
22
|
console.log();
|
|
24
23
|
console.log(dim(`${bold("github")}logen `) + dim(`v${version}`));
|
|
25
24
|
const cwd = process.cwd();
|
|
26
|
-
const { config, md,
|
|
25
|
+
const { config, md, commits } = await generate(cwd, args);
|
|
27
26
|
const markdown = md.replace(/ /g, "");
|
|
28
27
|
console.log(cyan(config.from) + dim(" -> ") + blue(config.to) + dim(` (${commits.length} commits)`));
|
|
29
28
|
console.log(dim("--------------"));
|
|
@@ -35,46 +34,6 @@ cli.command("").action(async (args) => {
|
|
|
35
34
|
console.log(yellow("Dry run. Release skipped."));
|
|
36
35
|
return;
|
|
37
36
|
}
|
|
38
|
-
if (typeof config.output === "string") {
|
|
39
|
-
const pushUrl = getGitPushUrl(config.repo, config.tokens.github);
|
|
40
|
-
if (!pushUrl) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
let changelogMD;
|
|
44
|
-
const changelogPrefix = "# Changelog";
|
|
45
|
-
if (existsSync(config.output)) {
|
|
46
|
-
console.info(`Updating ${config.output}`);
|
|
47
|
-
changelogMD = await promises.readFile(config.output, "utf8");
|
|
48
|
-
if (!changelogMD.startsWith(changelogPrefix)) {
|
|
49
|
-
changelogMD = `${changelogPrefix}
|
|
50
|
-
|
|
51
|
-
${changelogMD}`;
|
|
52
|
-
}
|
|
53
|
-
} else {
|
|
54
|
-
console.info(`Creating ${config.output}`);
|
|
55
|
-
changelogMD = `${changelogPrefix}
|
|
56
|
-
|
|
57
|
-
`;
|
|
58
|
-
}
|
|
59
|
-
const lastEntry = changelogMD.match(/^###?\s+.*$/m);
|
|
60
|
-
if (lastEntry) {
|
|
61
|
-
changelogMD = `${changelogMD.slice(0, lastEntry.index) + changelog}
|
|
62
|
-
|
|
63
|
-
${changelogMD.slice(lastEntry.index)}`;
|
|
64
|
-
} else {
|
|
65
|
-
changelogMD += `
|
|
66
|
-
${changelog}
|
|
67
|
-
|
|
68
|
-
`;
|
|
69
|
-
}
|
|
70
|
-
await promises.writeFile(config.output, changelogMD);
|
|
71
|
-
const { email = "unknow@unknow.com", name = "unknow" } = commits[0]?.author || {};
|
|
72
|
-
await execa("git", ["config", "--global", "user.email", `"${email}"`]);
|
|
73
|
-
await execa("git", ["config", "--global", "user.name", `"${name}"`]);
|
|
74
|
-
await execa("git", ["add", "."]);
|
|
75
|
-
await execa("git", ["commit", "-m docs(projects): CHANGELOG.md"], { cwd });
|
|
76
|
-
await execa("git", ["push", pushUrl, `HEAD:${config.gitMainBranch}`], { cwd });
|
|
77
|
-
}
|
|
78
37
|
if (!await hasTagOnGitHub(config.to, config)) {
|
|
79
38
|
console.error(yellow(`Current ref "${bold(config.to)}" is not available as tags on GitHub. Release skipped.`));
|
|
80
39
|
process.exitCode = 1;
|
package/dist/index.cjs
CHANGED
|
@@ -58,9 +58,6 @@ function join$1(array, glue = ", ", finalGlue = " and ") {
|
|
|
58
58
|
return array.join(finalGlue);
|
|
59
59
|
return `${array.slice(0, -1).join(glue)}${finalGlue}${array.slice(-1)}`;
|
|
60
60
|
}
|
|
61
|
-
function upperFirst(string) {
|
|
62
|
-
return !string ? "" : string[0].toUpperCase() + string.slice(1);
|
|
63
|
-
}
|
|
64
61
|
|
|
65
62
|
async function sendRelease(options, content) {
|
|
66
63
|
const headers = getHeaders(options);
|
|
@@ -258,6 +255,92 @@ function getGitPushUrl(config, token) {
|
|
|
258
255
|
return `https://${token}@${config.domain}/${config.repo}`;
|
|
259
256
|
}
|
|
260
257
|
|
|
258
|
+
const emojisRE = /([\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF])/g;
|
|
259
|
+
function formatReferences(references, github, type) {
|
|
260
|
+
const refs = references.filter((i) => {
|
|
261
|
+
if (type === "issues") {
|
|
262
|
+
return i.type === "issue" || i.type === "pull-request";
|
|
263
|
+
}
|
|
264
|
+
return i.type === "hash";
|
|
265
|
+
}).map((ref) => {
|
|
266
|
+
if (!github) {
|
|
267
|
+
return ref.value;
|
|
268
|
+
}
|
|
269
|
+
if (ref.type === "pull-request" || ref.type === "issue") {
|
|
270
|
+
return `https://github.com/${github}/issues/${ref.value.slice(1)}`;
|
|
271
|
+
}
|
|
272
|
+
return `[<samp>(${ref.value.slice(0, 5)})</samp>](https://github.com/${github}/commit/${ref.value})`;
|
|
273
|
+
});
|
|
274
|
+
const referencesString = join$1(refs).trim();
|
|
275
|
+
if (type === "issues") {
|
|
276
|
+
return referencesString && `in ${referencesString}`;
|
|
277
|
+
}
|
|
278
|
+
return referencesString;
|
|
279
|
+
}
|
|
280
|
+
function formatLine(commit, options) {
|
|
281
|
+
const prRefs = formatReferences(commit.references, options.repo.repo || "", "issues");
|
|
282
|
+
const hashRefs = formatReferences(commit.references, options.repo.repo || "", "hash");
|
|
283
|
+
let authors = join$1([
|
|
284
|
+
...new Set(commit.resolvedAuthors?.map((i) => i.login ? `@${i.login}` : `**${i.name}**`))
|
|
285
|
+
])?.trim();
|
|
286
|
+
if (authors) {
|
|
287
|
+
authors = `by ${authors}`;
|
|
288
|
+
}
|
|
289
|
+
let refs = [authors, prRefs, hashRefs].filter((i) => i?.trim()).join(" ");
|
|
290
|
+
if (refs) {
|
|
291
|
+
refs = ` - ${refs}`;
|
|
292
|
+
}
|
|
293
|
+
const description = options.capitalize ? capitalize(commit.description) : commit.description;
|
|
294
|
+
return [description, refs].filter((i) => i?.trim()).join(" ");
|
|
295
|
+
}
|
|
296
|
+
function formatTitle(name, options) {
|
|
297
|
+
let $name = name.trim();
|
|
298
|
+
if (!options.emoji) {
|
|
299
|
+
$name = name.replace(emojisRE, "").trim();
|
|
300
|
+
}
|
|
301
|
+
return `### ${$name}`;
|
|
302
|
+
}
|
|
303
|
+
function formatSection(commits, sectionName, options) {
|
|
304
|
+
if (!commits.length) {
|
|
305
|
+
return [];
|
|
306
|
+
}
|
|
307
|
+
const lines = ["", formatTitle(sectionName, options), ""];
|
|
308
|
+
const scopes = groupBy(commits, "scope");
|
|
309
|
+
let useScopeGroup = options.group;
|
|
310
|
+
if (!Object.entries(scopes).some(([k, v]) => k && v.length > 1)) {
|
|
311
|
+
useScopeGroup = false;
|
|
312
|
+
}
|
|
313
|
+
Object.keys(scopes).sort().forEach((scope) => {
|
|
314
|
+
let padding = "";
|
|
315
|
+
let prefix = "";
|
|
316
|
+
const scopeText = `**${options.scopeMap[scope] || scope}**`;
|
|
317
|
+
if (scope && (useScopeGroup === true || useScopeGroup === "multiple" && scopes[scope].length > 1)) {
|
|
318
|
+
lines.push(`- ${scopeText}:`);
|
|
319
|
+
padding = " ";
|
|
320
|
+
} else if (scope) {
|
|
321
|
+
prefix = `${scopeText}: `;
|
|
322
|
+
}
|
|
323
|
+
lines.push(...scopes[scope].reverse().map((commit) => `${padding}- ${prefix}${formatLine(commit, options)}`));
|
|
324
|
+
});
|
|
325
|
+
return lines;
|
|
326
|
+
}
|
|
327
|
+
function generateMarkdown(commits, options) {
|
|
328
|
+
const lines = [];
|
|
329
|
+
const [breaking, changes] = partition(commits, (c) => c.isBreaking);
|
|
330
|
+
const group = groupBy(changes, "type");
|
|
331
|
+
lines.push(...formatSection(breaking, options.titles.breakingChanges, options));
|
|
332
|
+
for (const type of Object.keys(options.types)) {
|
|
333
|
+
const items = group[type] || [];
|
|
334
|
+
lines.push(...formatSection(items, options.types[type].title, options));
|
|
335
|
+
}
|
|
336
|
+
if (!lines.length) {
|
|
337
|
+
lines.push("*No significant changes*");
|
|
338
|
+
}
|
|
339
|
+
const url = `https://github.com/${options.repo.repo}/compare/${options.from}...${options.to}`;
|
|
340
|
+
lines.push("", `##### [View changes on GitHub](${url})`);
|
|
341
|
+
return convertGitmoji.convert(lines.join("\n").trim(), true);
|
|
342
|
+
}
|
|
343
|
+
|
|
261
344
|
function normalizeWindowsPath(input = "") {
|
|
262
345
|
if (!input || !input.includes("\\")) {
|
|
263
346
|
return input;
|
|
@@ -8064,15 +8147,6 @@ async function resolvePackageJSON(id = process.cwd(), options = {}) {
|
|
|
8064
8147
|
});
|
|
8065
8148
|
}
|
|
8066
8149
|
|
|
8067
|
-
const providerToRefSpec = {
|
|
8068
|
-
github: { "pull-request": "pull", hash: "commit", issue: "issues" },
|
|
8069
|
-
gitlab: { "pull-request": "merge_requests", hash: "commit", issue: "issues" },
|
|
8070
|
-
bitbucket: {
|
|
8071
|
-
"pull-request": "pull-requests",
|
|
8072
|
-
hash: "commit",
|
|
8073
|
-
issue: "issues"
|
|
8074
|
-
}
|
|
8075
|
-
};
|
|
8076
8150
|
const providerToDomain = {
|
|
8077
8151
|
github: "github.com",
|
|
8078
8152
|
gitlab: "gitlab.com",
|
|
@@ -8084,16 +8158,6 @@ const domainToProvider = {
|
|
|
8084
8158
|
"bitbucket.org": "bitbucket"
|
|
8085
8159
|
};
|
|
8086
8160
|
const providerURLRegex = /^(?:(?<user>\w+)@)?(?:(?<provider>[^/:]+):)?(?<repo>\w+\/\w+)(?:\.git)?$/;
|
|
8087
|
-
function baseUrl$1(config) {
|
|
8088
|
-
return `https://${config.domain}/${config.repo}`;
|
|
8089
|
-
}
|
|
8090
|
-
function formatReference(ref, repo) {
|
|
8091
|
-
if (!repo?.provider || !(repo.provider in providerToRefSpec)) {
|
|
8092
|
-
return ref.value;
|
|
8093
|
-
}
|
|
8094
|
-
const refSpec = providerToRefSpec[repo.provider];
|
|
8095
|
-
return `[${ref.value}](${baseUrl$1(repo)}/${refSpec[ref.type]}/${ref.value.replace(/^#/, "")})`;
|
|
8096
|
-
}
|
|
8097
8161
|
async function resolveRepoConfig(cwd) {
|
|
8098
8162
|
const pkg = await readPackageJSON(cwd).catch(() => {
|
|
8099
8163
|
});
|
|
@@ -8138,189 +8202,6 @@ function getRepoConfig(repoUrl = "") {
|
|
|
8138
8202
|
};
|
|
8139
8203
|
}
|
|
8140
8204
|
|
|
8141
|
-
const emojisRE = /([\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF])/g;
|
|
8142
|
-
function formatReferences(references, github, type) {
|
|
8143
|
-
const refs = references.filter((i) => {
|
|
8144
|
-
if (type === "issues") {
|
|
8145
|
-
return i.type === "issue" || i.type === "pull-request";
|
|
8146
|
-
}
|
|
8147
|
-
return i.type === "hash";
|
|
8148
|
-
}).map((ref) => {
|
|
8149
|
-
if (!github) {
|
|
8150
|
-
return ref.value;
|
|
8151
|
-
}
|
|
8152
|
-
if (ref.type === "pull-request" || ref.type === "issue") {
|
|
8153
|
-
return `https://github.com/${github}/issues/${ref.value.slice(1)}`;
|
|
8154
|
-
}
|
|
8155
|
-
return `[<samp>(${ref.value.slice(0, 5)})</samp>](https://github.com/${github}/commit/${ref.value})`;
|
|
8156
|
-
});
|
|
8157
|
-
const referencesString = join$1(refs).trim();
|
|
8158
|
-
if (type === "issues") {
|
|
8159
|
-
return referencesString && `in ${referencesString}`;
|
|
8160
|
-
}
|
|
8161
|
-
return referencesString;
|
|
8162
|
-
}
|
|
8163
|
-
function formatLine(commit, options) {
|
|
8164
|
-
const prRefs = formatReferences(commit.references, options.repo.repo || "", "issues");
|
|
8165
|
-
const hashRefs = formatReferences(commit.references, options.repo.repo || "", "hash");
|
|
8166
|
-
let authors = join$1([
|
|
8167
|
-
...new Set(commit.resolvedAuthors?.map((i) => i.login ? `@${i.login}` : `**${i.name}**`))
|
|
8168
|
-
])?.trim();
|
|
8169
|
-
if (authors) {
|
|
8170
|
-
authors = `by ${authors}`;
|
|
8171
|
-
}
|
|
8172
|
-
let refs = [authors, prRefs, hashRefs].filter((i) => i?.trim()).join(" ");
|
|
8173
|
-
if (refs) {
|
|
8174
|
-
refs = ` - ${refs}`;
|
|
8175
|
-
}
|
|
8176
|
-
const description = options.capitalize ? capitalize(commit.description) : commit.description;
|
|
8177
|
-
return [description, refs].filter((i) => i?.trim()).join(" ");
|
|
8178
|
-
}
|
|
8179
|
-
function formatTitle(name, options) {
|
|
8180
|
-
let $name = name.trim();
|
|
8181
|
-
if (!options.emoji) {
|
|
8182
|
-
$name = name.replace(emojisRE, "").trim();
|
|
8183
|
-
}
|
|
8184
|
-
return `### ${$name}`;
|
|
8185
|
-
}
|
|
8186
|
-
function formatSection(commits, sectionName, options) {
|
|
8187
|
-
if (!commits.length) {
|
|
8188
|
-
return [];
|
|
8189
|
-
}
|
|
8190
|
-
const lines = ["", formatTitle(sectionName, options), ""];
|
|
8191
|
-
const scopes = groupBy(commits, "scope");
|
|
8192
|
-
let useScopeGroup = options.group;
|
|
8193
|
-
if (!Object.entries(scopes).some(([k, v]) => k && v.length > 1)) {
|
|
8194
|
-
useScopeGroup = false;
|
|
8195
|
-
}
|
|
8196
|
-
Object.keys(scopes).sort().forEach((scope) => {
|
|
8197
|
-
let padding = "";
|
|
8198
|
-
let prefix = "";
|
|
8199
|
-
const scopeText = `**${options.scopeMap[scope] || scope}**`;
|
|
8200
|
-
if (scope && (useScopeGroup === true || useScopeGroup === "multiple" && scopes[scope].length > 1)) {
|
|
8201
|
-
lines.push(`- ${scopeText}:`);
|
|
8202
|
-
padding = " ";
|
|
8203
|
-
} else if (scope) {
|
|
8204
|
-
prefix = `${scopeText}: `;
|
|
8205
|
-
}
|
|
8206
|
-
lines.push(...scopes[scope].reverse().map((commit) => `${padding}- ${prefix}${formatLine(commit, options)}`));
|
|
8207
|
-
});
|
|
8208
|
-
return lines;
|
|
8209
|
-
}
|
|
8210
|
-
function generateMarkdown(commits, options) {
|
|
8211
|
-
const lines = [];
|
|
8212
|
-
const [breaking, changes] = partition(commits, (c) => c.isBreaking);
|
|
8213
|
-
const group = groupBy(changes, "type");
|
|
8214
|
-
lines.push(...formatSection(breaking, options.titles.breakingChanges, options));
|
|
8215
|
-
for (const type of Object.keys(options.types)) {
|
|
8216
|
-
const items = group[type] || [];
|
|
8217
|
-
lines.push(...formatSection(items, options.types[type].title, options));
|
|
8218
|
-
}
|
|
8219
|
-
if (!lines.length) {
|
|
8220
|
-
lines.push("*No significant changes*");
|
|
8221
|
-
}
|
|
8222
|
-
const url = `https://github.com/${options.repo.repo}/compare/${options.from}...${options.to}`;
|
|
8223
|
-
lines.push("", `##### [View changes on GitHub](${url})`);
|
|
8224
|
-
return convertGitmoji.convert(lines.join("\n").trim(), true);
|
|
8225
|
-
}
|
|
8226
|
-
async function generateChangelog(commits, config) {
|
|
8227
|
-
const typeGroups = groupBy(commits, "type");
|
|
8228
|
-
const markdown = [];
|
|
8229
|
-
const breakingChanges = [];
|
|
8230
|
-
const v = config.newVersion && `v${config.newVersion}`;
|
|
8231
|
-
markdown.push("", `## ${v || `${config.from || ""}...${config.to}`}`, "");
|
|
8232
|
-
if (config.repo && config.from) {
|
|
8233
|
-
markdown.push(formatCompareChanges(v, config));
|
|
8234
|
-
}
|
|
8235
|
-
const typeKeys = Object.keys(config.types);
|
|
8236
|
-
typeKeys.forEach((typeKey) => {
|
|
8237
|
-
const group = typeGroups[typeKey];
|
|
8238
|
-
if (group?.length) {
|
|
8239
|
-
markdown.push("", `### ${config.types[typeKey].title}`, "");
|
|
8240
|
-
for (const commit of group.reverse()) {
|
|
8241
|
-
const line = formatCommit(commit, config);
|
|
8242
|
-
markdown.push(line);
|
|
8243
|
-
if (commit.isBreaking) {
|
|
8244
|
-
breakingChanges.push(line);
|
|
8245
|
-
}
|
|
8246
|
-
}
|
|
8247
|
-
}
|
|
8248
|
-
});
|
|
8249
|
-
if (breakingChanges.length > 0) {
|
|
8250
|
-
markdown.push("", "#### \u26A0\uFE0F Breaking Changes", "", ...breakingChanges);
|
|
8251
|
-
}
|
|
8252
|
-
const authorMap = /* @__PURE__ */ new Map();
|
|
8253
|
-
commits.forEach((commit) => {
|
|
8254
|
-
const name = formatName(commit.author?.name || "");
|
|
8255
|
-
if (name && !name.includes("[bot]")) {
|
|
8256
|
-
if (!authorMap.has(name)) {
|
|
8257
|
-
authorMap.set(name, { email: /* @__PURE__ */ new Set([commit.author.email]) });
|
|
8258
|
-
} else {
|
|
8259
|
-
const entry = authorMap.get(name);
|
|
8260
|
-
entry?.email?.add(commit.author.email);
|
|
8261
|
-
}
|
|
8262
|
-
}
|
|
8263
|
-
});
|
|
8264
|
-
await Promise.all(
|
|
8265
|
-
[...authorMap.keys()].map(async (authorName) => {
|
|
8266
|
-
const meta = authorMap.get(authorName);
|
|
8267
|
-
if (meta) {
|
|
8268
|
-
for (const email of meta.email) {
|
|
8269
|
-
try {
|
|
8270
|
-
const { user } = await ohmyfetch.$fetch(`https://ungh.cc/users/find/${email}`);
|
|
8271
|
-
if (user) {
|
|
8272
|
-
meta.github = user.username;
|
|
8273
|
-
break;
|
|
8274
|
-
}
|
|
8275
|
-
} catch {
|
|
8276
|
-
}
|
|
8277
|
-
}
|
|
8278
|
-
}
|
|
8279
|
-
})
|
|
8280
|
-
);
|
|
8281
|
-
const authors = [...authorMap.entries()].map((e) => ({ name: e[0], ...e[1] }));
|
|
8282
|
-
if (authors.length > 0) {
|
|
8283
|
-
markdown.push(
|
|
8284
|
-
"",
|
|
8285
|
-
"### \u2764\uFE0F Contributors",
|
|
8286
|
-
"",
|
|
8287
|
-
...authors.map((i) => {
|
|
8288
|
-
const $email = [...i.email].find((e) => !e.includes("noreply.github.com"));
|
|
8289
|
-
const email = $email ? `<${$email}>` : "";
|
|
8290
|
-
const github = i.github ? `([@${i.github}](http://github.com/${i.github}))` : "";
|
|
8291
|
-
return `- ${i.name} ${github || email}`;
|
|
8292
|
-
})
|
|
8293
|
-
);
|
|
8294
|
-
}
|
|
8295
|
-
return convertGitmoji.convert(markdown.join("\n").trim(), true);
|
|
8296
|
-
}
|
|
8297
|
-
function baseUrl(config) {
|
|
8298
|
-
return `https://${config.domain}/${config.repo}`;
|
|
8299
|
-
}
|
|
8300
|
-
function formatCompareChanges(v, config) {
|
|
8301
|
-
const part = config.repo.provider === "bitbucket" ? "branches/compare" : "compare";
|
|
8302
|
-
return `[compare changes](${baseUrl(config.repo)}/${part}/${config.from}...${v || config.to})`;
|
|
8303
|
-
}
|
|
8304
|
-
function formatCommit(commit, config) {
|
|
8305
|
-
return `- ${commit.scope ? `**${commit.scope.trim()}:** ` : ""}${commit.isBreaking ? "\u26A0\uFE0F " : ""}${upperFirst(
|
|
8306
|
-
commit.description
|
|
8307
|
-
)}${formatMultiReference(commit.references, config)}`;
|
|
8308
|
-
}
|
|
8309
|
-
function formatName(name = "") {
|
|
8310
|
-
return name.split(" ").map((p) => upperFirst(p.trim())).join(" ");
|
|
8311
|
-
}
|
|
8312
|
-
function formatMultiReference(references, config) {
|
|
8313
|
-
const pr = references.filter((ref) => ref.type === "pull-request");
|
|
8314
|
-
const issue = references.filter((ref) => ref.type === "issue");
|
|
8315
|
-
if (pr.length > 0 || issue.length > 0) {
|
|
8316
|
-
return ` (${[...pr, ...issue].map((ref) => formatReference(ref, config.repo)).join(", ")})`;
|
|
8317
|
-
}
|
|
8318
|
-
if (references.length > 0) {
|
|
8319
|
-
return ` (${formatReference(references[0], config.repo)})`;
|
|
8320
|
-
}
|
|
8321
|
-
return "";
|
|
8322
|
-
}
|
|
8323
|
-
|
|
8324
8205
|
const defaultConfig = {
|
|
8325
8206
|
cwd: process.cwd(),
|
|
8326
8207
|
from: "",
|
|
@@ -8427,12 +8308,10 @@ async function generate(cwd, options) {
|
|
|
8427
8308
|
await resolveAuthors(commits, resolved);
|
|
8428
8309
|
}
|
|
8429
8310
|
const md = generateMarkdown(commits, resolved);
|
|
8430
|
-
|
|
8431
|
-
return { config: resolved, md, commits, changelog };
|
|
8311
|
+
return { config: resolved, md, commits };
|
|
8432
8312
|
}
|
|
8433
8313
|
|
|
8434
8314
|
exports.generate = generate;
|
|
8435
|
-
exports.generateChangelog = generateChangelog;
|
|
8436
8315
|
exports.generateMarkdown = generateMarkdown;
|
|
8437
8316
|
exports.getCurrentGitBranch = getCurrentGitBranch;
|
|
8438
8317
|
exports.getFirstGitCommit = getFirstGitCommit;
|
package/dist/index.d.ts
CHANGED
|
@@ -129,13 +129,11 @@ declare function getGitRemoteURL(cwd: string, remote?: string): Promise<string>;
|
|
|
129
129
|
declare function getGitPushUrl(config: RepoConfig, token?: string): string | null;
|
|
130
130
|
|
|
131
131
|
declare function generateMarkdown(commits: Commit[], options: ResolvedChangelogOptions): string;
|
|
132
|
-
declare function generateChangelog(commits: Commit[], config: ResolvedChangelogOptions): Promise<string>;
|
|
133
132
|
|
|
134
133
|
declare function generate(cwd: string, options: ChangelogOptions): Promise<{
|
|
135
134
|
config: Required<ChangelogOptions>;
|
|
136
135
|
md: string;
|
|
137
136
|
commits: GitCommit[];
|
|
138
|
-
changelog: string;
|
|
139
137
|
}>;
|
|
140
138
|
|
|
141
139
|
declare function resolveConfig(cwd: string, options: ChangelogOptions): Promise<Required<ChangelogOptions>>;
|
|
@@ -143,4 +141,4 @@ declare function resolveConfig(cwd: string, options: ChangelogOptions): Promise<
|
|
|
143
141
|
declare function parseGitCommit(commit: RawGitCommit, config: ChangelogConfig): GitCommit | null;
|
|
144
142
|
declare function parseCommits(commits: RawGitCommit[], config: ChangelogConfig): GitCommit[];
|
|
145
143
|
|
|
146
|
-
export { AuthorInfo, ChangelogConfig, ChangelogOptions, Commit, GitCommit, GitCommitAuthor, GithubOptions, GithubRelease, RawGitCommit, Reference, RepoConfig, RepoProvider, ResolvedChangelogOptions, SemverBumpType, generate,
|
|
144
|
+
export { AuthorInfo, ChangelogConfig, ChangelogOptions, Commit, GitCommit, GitCommitAuthor, GithubOptions, GithubRelease, RawGitCommit, Reference, RepoConfig, RepoProvider, ResolvedChangelogOptions, SemverBumpType, generate, generateMarkdown, getCurrentGitBranch, getFirstGitCommit, getGitDiff, getGitHubRepo, getGitMainBranchName, getGitPushUrl, getGitRemoteURL, getLastGitTag, hasTagOnGitHub, isPrerelease, isRefGitTag, isRepoShallow, parseCommits, parseGitCommit, resolveAuthorInfo, resolveAuthors, resolveConfig, sendRelease };
|
package/dist/index.mjs
CHANGED
|
@@ -48,9 +48,6 @@ function join$1(array, glue = ", ", finalGlue = " and ") {
|
|
|
48
48
|
return array.join(finalGlue);
|
|
49
49
|
return `${array.slice(0, -1).join(glue)}${finalGlue}${array.slice(-1)}`;
|
|
50
50
|
}
|
|
51
|
-
function upperFirst(string) {
|
|
52
|
-
return !string ? "" : string[0].toUpperCase() + string.slice(1);
|
|
53
|
-
}
|
|
54
51
|
|
|
55
52
|
async function sendRelease(options, content) {
|
|
56
53
|
const headers = getHeaders(options);
|
|
@@ -248,6 +245,92 @@ function getGitPushUrl(config, token) {
|
|
|
248
245
|
return `https://${token}@${config.domain}/${config.repo}`;
|
|
249
246
|
}
|
|
250
247
|
|
|
248
|
+
const emojisRE = /([\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF])/g;
|
|
249
|
+
function formatReferences(references, github, type) {
|
|
250
|
+
const refs = references.filter((i) => {
|
|
251
|
+
if (type === "issues") {
|
|
252
|
+
return i.type === "issue" || i.type === "pull-request";
|
|
253
|
+
}
|
|
254
|
+
return i.type === "hash";
|
|
255
|
+
}).map((ref) => {
|
|
256
|
+
if (!github) {
|
|
257
|
+
return ref.value;
|
|
258
|
+
}
|
|
259
|
+
if (ref.type === "pull-request" || ref.type === "issue") {
|
|
260
|
+
return `https://github.com/${github}/issues/${ref.value.slice(1)}`;
|
|
261
|
+
}
|
|
262
|
+
return `[<samp>(${ref.value.slice(0, 5)})</samp>](https://github.com/${github}/commit/${ref.value})`;
|
|
263
|
+
});
|
|
264
|
+
const referencesString = join$1(refs).trim();
|
|
265
|
+
if (type === "issues") {
|
|
266
|
+
return referencesString && `in ${referencesString}`;
|
|
267
|
+
}
|
|
268
|
+
return referencesString;
|
|
269
|
+
}
|
|
270
|
+
function formatLine(commit, options) {
|
|
271
|
+
const prRefs = formatReferences(commit.references, options.repo.repo || "", "issues");
|
|
272
|
+
const hashRefs = formatReferences(commit.references, options.repo.repo || "", "hash");
|
|
273
|
+
let authors = join$1([
|
|
274
|
+
...new Set(commit.resolvedAuthors?.map((i) => i.login ? `@${i.login}` : `**${i.name}**`))
|
|
275
|
+
])?.trim();
|
|
276
|
+
if (authors) {
|
|
277
|
+
authors = `by ${authors}`;
|
|
278
|
+
}
|
|
279
|
+
let refs = [authors, prRefs, hashRefs].filter((i) => i?.trim()).join(" ");
|
|
280
|
+
if (refs) {
|
|
281
|
+
refs = ` - ${refs}`;
|
|
282
|
+
}
|
|
283
|
+
const description = options.capitalize ? capitalize(commit.description) : commit.description;
|
|
284
|
+
return [description, refs].filter((i) => i?.trim()).join(" ");
|
|
285
|
+
}
|
|
286
|
+
function formatTitle(name, options) {
|
|
287
|
+
let $name = name.trim();
|
|
288
|
+
if (!options.emoji) {
|
|
289
|
+
$name = name.replace(emojisRE, "").trim();
|
|
290
|
+
}
|
|
291
|
+
return `### ${$name}`;
|
|
292
|
+
}
|
|
293
|
+
function formatSection(commits, sectionName, options) {
|
|
294
|
+
if (!commits.length) {
|
|
295
|
+
return [];
|
|
296
|
+
}
|
|
297
|
+
const lines = ["", formatTitle(sectionName, options), ""];
|
|
298
|
+
const scopes = groupBy(commits, "scope");
|
|
299
|
+
let useScopeGroup = options.group;
|
|
300
|
+
if (!Object.entries(scopes).some(([k, v]) => k && v.length > 1)) {
|
|
301
|
+
useScopeGroup = false;
|
|
302
|
+
}
|
|
303
|
+
Object.keys(scopes).sort().forEach((scope) => {
|
|
304
|
+
let padding = "";
|
|
305
|
+
let prefix = "";
|
|
306
|
+
const scopeText = `**${options.scopeMap[scope] || scope}**`;
|
|
307
|
+
if (scope && (useScopeGroup === true || useScopeGroup === "multiple" && scopes[scope].length > 1)) {
|
|
308
|
+
lines.push(`- ${scopeText}:`);
|
|
309
|
+
padding = " ";
|
|
310
|
+
} else if (scope) {
|
|
311
|
+
prefix = `${scopeText}: `;
|
|
312
|
+
}
|
|
313
|
+
lines.push(...scopes[scope].reverse().map((commit) => `${padding}- ${prefix}${formatLine(commit, options)}`));
|
|
314
|
+
});
|
|
315
|
+
return lines;
|
|
316
|
+
}
|
|
317
|
+
function generateMarkdown(commits, options) {
|
|
318
|
+
const lines = [];
|
|
319
|
+
const [breaking, changes] = partition(commits, (c) => c.isBreaking);
|
|
320
|
+
const group = groupBy(changes, "type");
|
|
321
|
+
lines.push(...formatSection(breaking, options.titles.breakingChanges, options));
|
|
322
|
+
for (const type of Object.keys(options.types)) {
|
|
323
|
+
const items = group[type] || [];
|
|
324
|
+
lines.push(...formatSection(items, options.types[type].title, options));
|
|
325
|
+
}
|
|
326
|
+
if (!lines.length) {
|
|
327
|
+
lines.push("*No significant changes*");
|
|
328
|
+
}
|
|
329
|
+
const url = `https://github.com/${options.repo.repo}/compare/${options.from}...${options.to}`;
|
|
330
|
+
lines.push("", `##### [View changes on GitHub](${url})`);
|
|
331
|
+
return convert(lines.join("\n").trim(), true);
|
|
332
|
+
}
|
|
333
|
+
|
|
251
334
|
function normalizeWindowsPath(input = "") {
|
|
252
335
|
if (!input || !input.includes("\\")) {
|
|
253
336
|
return input;
|
|
@@ -8054,15 +8137,6 @@ async function resolvePackageJSON(id = process.cwd(), options = {}) {
|
|
|
8054
8137
|
});
|
|
8055
8138
|
}
|
|
8056
8139
|
|
|
8057
|
-
const providerToRefSpec = {
|
|
8058
|
-
github: { "pull-request": "pull", hash: "commit", issue: "issues" },
|
|
8059
|
-
gitlab: { "pull-request": "merge_requests", hash: "commit", issue: "issues" },
|
|
8060
|
-
bitbucket: {
|
|
8061
|
-
"pull-request": "pull-requests",
|
|
8062
|
-
hash: "commit",
|
|
8063
|
-
issue: "issues"
|
|
8064
|
-
}
|
|
8065
|
-
};
|
|
8066
8140
|
const providerToDomain = {
|
|
8067
8141
|
github: "github.com",
|
|
8068
8142
|
gitlab: "gitlab.com",
|
|
@@ -8074,16 +8148,6 @@ const domainToProvider = {
|
|
|
8074
8148
|
"bitbucket.org": "bitbucket"
|
|
8075
8149
|
};
|
|
8076
8150
|
const providerURLRegex = /^(?:(?<user>\w+)@)?(?:(?<provider>[^/:]+):)?(?<repo>\w+\/\w+)(?:\.git)?$/;
|
|
8077
|
-
function baseUrl$1(config) {
|
|
8078
|
-
return `https://${config.domain}/${config.repo}`;
|
|
8079
|
-
}
|
|
8080
|
-
function formatReference(ref, repo) {
|
|
8081
|
-
if (!repo?.provider || !(repo.provider in providerToRefSpec)) {
|
|
8082
|
-
return ref.value;
|
|
8083
|
-
}
|
|
8084
|
-
const refSpec = providerToRefSpec[repo.provider];
|
|
8085
|
-
return `[${ref.value}](${baseUrl$1(repo)}/${refSpec[ref.type]}/${ref.value.replace(/^#/, "")})`;
|
|
8086
|
-
}
|
|
8087
8151
|
async function resolveRepoConfig(cwd) {
|
|
8088
8152
|
const pkg = await readPackageJSON(cwd).catch(() => {
|
|
8089
8153
|
});
|
|
@@ -8128,189 +8192,6 @@ function getRepoConfig(repoUrl = "") {
|
|
|
8128
8192
|
};
|
|
8129
8193
|
}
|
|
8130
8194
|
|
|
8131
|
-
const emojisRE = /([\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF])/g;
|
|
8132
|
-
function formatReferences(references, github, type) {
|
|
8133
|
-
const refs = references.filter((i) => {
|
|
8134
|
-
if (type === "issues") {
|
|
8135
|
-
return i.type === "issue" || i.type === "pull-request";
|
|
8136
|
-
}
|
|
8137
|
-
return i.type === "hash";
|
|
8138
|
-
}).map((ref) => {
|
|
8139
|
-
if (!github) {
|
|
8140
|
-
return ref.value;
|
|
8141
|
-
}
|
|
8142
|
-
if (ref.type === "pull-request" || ref.type === "issue") {
|
|
8143
|
-
return `https://github.com/${github}/issues/${ref.value.slice(1)}`;
|
|
8144
|
-
}
|
|
8145
|
-
return `[<samp>(${ref.value.slice(0, 5)})</samp>](https://github.com/${github}/commit/${ref.value})`;
|
|
8146
|
-
});
|
|
8147
|
-
const referencesString = join$1(refs).trim();
|
|
8148
|
-
if (type === "issues") {
|
|
8149
|
-
return referencesString && `in ${referencesString}`;
|
|
8150
|
-
}
|
|
8151
|
-
return referencesString;
|
|
8152
|
-
}
|
|
8153
|
-
function formatLine(commit, options) {
|
|
8154
|
-
const prRefs = formatReferences(commit.references, options.repo.repo || "", "issues");
|
|
8155
|
-
const hashRefs = formatReferences(commit.references, options.repo.repo || "", "hash");
|
|
8156
|
-
let authors = join$1([
|
|
8157
|
-
...new Set(commit.resolvedAuthors?.map((i) => i.login ? `@${i.login}` : `**${i.name}**`))
|
|
8158
|
-
])?.trim();
|
|
8159
|
-
if (authors) {
|
|
8160
|
-
authors = `by ${authors}`;
|
|
8161
|
-
}
|
|
8162
|
-
let refs = [authors, prRefs, hashRefs].filter((i) => i?.trim()).join(" ");
|
|
8163
|
-
if (refs) {
|
|
8164
|
-
refs = ` - ${refs}`;
|
|
8165
|
-
}
|
|
8166
|
-
const description = options.capitalize ? capitalize(commit.description) : commit.description;
|
|
8167
|
-
return [description, refs].filter((i) => i?.trim()).join(" ");
|
|
8168
|
-
}
|
|
8169
|
-
function formatTitle(name, options) {
|
|
8170
|
-
let $name = name.trim();
|
|
8171
|
-
if (!options.emoji) {
|
|
8172
|
-
$name = name.replace(emojisRE, "").trim();
|
|
8173
|
-
}
|
|
8174
|
-
return `### ${$name}`;
|
|
8175
|
-
}
|
|
8176
|
-
function formatSection(commits, sectionName, options) {
|
|
8177
|
-
if (!commits.length) {
|
|
8178
|
-
return [];
|
|
8179
|
-
}
|
|
8180
|
-
const lines = ["", formatTitle(sectionName, options), ""];
|
|
8181
|
-
const scopes = groupBy(commits, "scope");
|
|
8182
|
-
let useScopeGroup = options.group;
|
|
8183
|
-
if (!Object.entries(scopes).some(([k, v]) => k && v.length > 1)) {
|
|
8184
|
-
useScopeGroup = false;
|
|
8185
|
-
}
|
|
8186
|
-
Object.keys(scopes).sort().forEach((scope) => {
|
|
8187
|
-
let padding = "";
|
|
8188
|
-
let prefix = "";
|
|
8189
|
-
const scopeText = `**${options.scopeMap[scope] || scope}**`;
|
|
8190
|
-
if (scope && (useScopeGroup === true || useScopeGroup === "multiple" && scopes[scope].length > 1)) {
|
|
8191
|
-
lines.push(`- ${scopeText}:`);
|
|
8192
|
-
padding = " ";
|
|
8193
|
-
} else if (scope) {
|
|
8194
|
-
prefix = `${scopeText}: `;
|
|
8195
|
-
}
|
|
8196
|
-
lines.push(...scopes[scope].reverse().map((commit) => `${padding}- ${prefix}${formatLine(commit, options)}`));
|
|
8197
|
-
});
|
|
8198
|
-
return lines;
|
|
8199
|
-
}
|
|
8200
|
-
function generateMarkdown(commits, options) {
|
|
8201
|
-
const lines = [];
|
|
8202
|
-
const [breaking, changes] = partition(commits, (c) => c.isBreaking);
|
|
8203
|
-
const group = groupBy(changes, "type");
|
|
8204
|
-
lines.push(...formatSection(breaking, options.titles.breakingChanges, options));
|
|
8205
|
-
for (const type of Object.keys(options.types)) {
|
|
8206
|
-
const items = group[type] || [];
|
|
8207
|
-
lines.push(...formatSection(items, options.types[type].title, options));
|
|
8208
|
-
}
|
|
8209
|
-
if (!lines.length) {
|
|
8210
|
-
lines.push("*No significant changes*");
|
|
8211
|
-
}
|
|
8212
|
-
const url = `https://github.com/${options.repo.repo}/compare/${options.from}...${options.to}`;
|
|
8213
|
-
lines.push("", `##### [View changes on GitHub](${url})`);
|
|
8214
|
-
return convert(lines.join("\n").trim(), true);
|
|
8215
|
-
}
|
|
8216
|
-
async function generateChangelog(commits, config) {
|
|
8217
|
-
const typeGroups = groupBy(commits, "type");
|
|
8218
|
-
const markdown = [];
|
|
8219
|
-
const breakingChanges = [];
|
|
8220
|
-
const v = config.newVersion && `v${config.newVersion}`;
|
|
8221
|
-
markdown.push("", `## ${v || `${config.from || ""}...${config.to}`}`, "");
|
|
8222
|
-
if (config.repo && config.from) {
|
|
8223
|
-
markdown.push(formatCompareChanges(v, config));
|
|
8224
|
-
}
|
|
8225
|
-
const typeKeys = Object.keys(config.types);
|
|
8226
|
-
typeKeys.forEach((typeKey) => {
|
|
8227
|
-
const group = typeGroups[typeKey];
|
|
8228
|
-
if (group?.length) {
|
|
8229
|
-
markdown.push("", `### ${config.types[typeKey].title}`, "");
|
|
8230
|
-
for (const commit of group.reverse()) {
|
|
8231
|
-
const line = formatCommit(commit, config);
|
|
8232
|
-
markdown.push(line);
|
|
8233
|
-
if (commit.isBreaking) {
|
|
8234
|
-
breakingChanges.push(line);
|
|
8235
|
-
}
|
|
8236
|
-
}
|
|
8237
|
-
}
|
|
8238
|
-
});
|
|
8239
|
-
if (breakingChanges.length > 0) {
|
|
8240
|
-
markdown.push("", "#### \u26A0\uFE0F Breaking Changes", "", ...breakingChanges);
|
|
8241
|
-
}
|
|
8242
|
-
const authorMap = /* @__PURE__ */ new Map();
|
|
8243
|
-
commits.forEach((commit) => {
|
|
8244
|
-
const name = formatName(commit.author?.name || "");
|
|
8245
|
-
if (name && !name.includes("[bot]")) {
|
|
8246
|
-
if (!authorMap.has(name)) {
|
|
8247
|
-
authorMap.set(name, { email: /* @__PURE__ */ new Set([commit.author.email]) });
|
|
8248
|
-
} else {
|
|
8249
|
-
const entry = authorMap.get(name);
|
|
8250
|
-
entry?.email?.add(commit.author.email);
|
|
8251
|
-
}
|
|
8252
|
-
}
|
|
8253
|
-
});
|
|
8254
|
-
await Promise.all(
|
|
8255
|
-
[...authorMap.keys()].map(async (authorName) => {
|
|
8256
|
-
const meta = authorMap.get(authorName);
|
|
8257
|
-
if (meta) {
|
|
8258
|
-
for (const email of meta.email) {
|
|
8259
|
-
try {
|
|
8260
|
-
const { user } = await $fetch(`https://ungh.cc/users/find/${email}`);
|
|
8261
|
-
if (user) {
|
|
8262
|
-
meta.github = user.username;
|
|
8263
|
-
break;
|
|
8264
|
-
}
|
|
8265
|
-
} catch {
|
|
8266
|
-
}
|
|
8267
|
-
}
|
|
8268
|
-
}
|
|
8269
|
-
})
|
|
8270
|
-
);
|
|
8271
|
-
const authors = [...authorMap.entries()].map((e) => ({ name: e[0], ...e[1] }));
|
|
8272
|
-
if (authors.length > 0) {
|
|
8273
|
-
markdown.push(
|
|
8274
|
-
"",
|
|
8275
|
-
"### \u2764\uFE0F Contributors",
|
|
8276
|
-
"",
|
|
8277
|
-
...authors.map((i) => {
|
|
8278
|
-
const $email = [...i.email].find((e) => !e.includes("noreply.github.com"));
|
|
8279
|
-
const email = $email ? `<${$email}>` : "";
|
|
8280
|
-
const github = i.github ? `([@${i.github}](http://github.com/${i.github}))` : "";
|
|
8281
|
-
return `- ${i.name} ${github || email}`;
|
|
8282
|
-
})
|
|
8283
|
-
);
|
|
8284
|
-
}
|
|
8285
|
-
return convert(markdown.join("\n").trim(), true);
|
|
8286
|
-
}
|
|
8287
|
-
function baseUrl(config) {
|
|
8288
|
-
return `https://${config.domain}/${config.repo}`;
|
|
8289
|
-
}
|
|
8290
|
-
function formatCompareChanges(v, config) {
|
|
8291
|
-
const part = config.repo.provider === "bitbucket" ? "branches/compare" : "compare";
|
|
8292
|
-
return `[compare changes](${baseUrl(config.repo)}/${part}/${config.from}...${v || config.to})`;
|
|
8293
|
-
}
|
|
8294
|
-
function formatCommit(commit, config) {
|
|
8295
|
-
return `- ${commit.scope ? `**${commit.scope.trim()}:** ` : ""}${commit.isBreaking ? "\u26A0\uFE0F " : ""}${upperFirst(
|
|
8296
|
-
commit.description
|
|
8297
|
-
)}${formatMultiReference(commit.references, config)}`;
|
|
8298
|
-
}
|
|
8299
|
-
function formatName(name = "") {
|
|
8300
|
-
return name.split(" ").map((p) => upperFirst(p.trim())).join(" ");
|
|
8301
|
-
}
|
|
8302
|
-
function formatMultiReference(references, config) {
|
|
8303
|
-
const pr = references.filter((ref) => ref.type === "pull-request");
|
|
8304
|
-
const issue = references.filter((ref) => ref.type === "issue");
|
|
8305
|
-
if (pr.length > 0 || issue.length > 0) {
|
|
8306
|
-
return ` (${[...pr, ...issue].map((ref) => formatReference(ref, config.repo)).join(", ")})`;
|
|
8307
|
-
}
|
|
8308
|
-
if (references.length > 0) {
|
|
8309
|
-
return ` (${formatReference(references[0], config.repo)})`;
|
|
8310
|
-
}
|
|
8311
|
-
return "";
|
|
8312
|
-
}
|
|
8313
|
-
|
|
8314
8195
|
const defaultConfig = {
|
|
8315
8196
|
cwd: process.cwd(),
|
|
8316
8197
|
from: "",
|
|
@@ -8417,8 +8298,7 @@ async function generate(cwd, options) {
|
|
|
8417
8298
|
await resolveAuthors(commits, resolved);
|
|
8418
8299
|
}
|
|
8419
8300
|
const md = generateMarkdown(commits, resolved);
|
|
8420
|
-
|
|
8421
|
-
return { config: resolved, md, commits, changelog };
|
|
8301
|
+
return { config: resolved, md, commits };
|
|
8422
8302
|
}
|
|
8423
8303
|
|
|
8424
|
-
export { generate,
|
|
8304
|
+
export { generate, generateMarkdown, getCurrentGitBranch, getFirstGitCommit, getGitDiff, getGitHubRepo, getGitMainBranchName, getGitPushUrl, getGitRemoteURL, getLastGitTag, hasTagOnGitHub, isPrerelease, isRefGitTag, isRepoShallow, parseCommits, parseGitCommit, resolveAuthorInfo, resolveAuthors, resolveConfig, sendRelease };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "githublogen",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.2",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "SoybeanJS",
|
|
@@ -54,36 +54,29 @@
|
|
|
54
54
|
"ohmyfetch": "0.4.21"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@soybeanjs/cli": "0.
|
|
57
|
+
"@soybeanjs/cli": "0.5.0",
|
|
58
58
|
"@types/node": "20.2.5",
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"eslint": "8.41.0",
|
|
62
|
-
"eslint-config-soybeanjs": "0.4.6",
|
|
63
|
-
"lint-staged": "13.2.2",
|
|
59
|
+
"eslint": "8.42.0",
|
|
60
|
+
"eslint-config-soybeanjs": "0.4.8",
|
|
64
61
|
"simple-git-hooks": "2.8.1",
|
|
65
|
-
"tsx": "
|
|
66
|
-
"typescript": "5.
|
|
62
|
+
"tsx": "3.12.7",
|
|
63
|
+
"typescript": "5.1.3",
|
|
67
64
|
"unbuild": "1.2.1"
|
|
68
65
|
},
|
|
69
66
|
"simple-git-hooks": {
|
|
70
67
|
"commit-msg": "pnpm soy git-commit-verify",
|
|
71
|
-
"pre-commit": "pnpm lint-staged"
|
|
72
|
-
},
|
|
73
|
-
"lint-staged": {
|
|
74
|
-
"*.{js,mjs,jsx,ts,mts,tsx,json,vue,svelte}": "eslint . --fix",
|
|
75
|
-
"*.!{js,mjs,jsx,ts,mts,tsx,json,vue,svelte}": "format"
|
|
68
|
+
"pre-commit": "pnpm soy lint-staged"
|
|
76
69
|
},
|
|
70
|
+
"github-token": "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",
|
|
77
71
|
"scripts": {
|
|
78
|
-
"build": "unbuild",
|
|
72
|
+
"build": "pnpm typecheck && unbuild",
|
|
79
73
|
"lint": "eslint . --fix",
|
|
80
74
|
"format": "soy prettier-format",
|
|
81
75
|
"commit": "soy git-commit",
|
|
82
76
|
"cleanup": "soy cleanup",
|
|
83
77
|
"update-pkg": "soy update-pkg",
|
|
84
|
-
"update-version": "bumpp --commit --push --tag",
|
|
85
78
|
"publish-pkg": "pnpm -r publish --access public",
|
|
86
|
-
"release": "pnpm
|
|
79
|
+
"release": "pnpm soy release && pnpm build && pnpm publish-pkg",
|
|
87
80
|
"typecheck": "tsc --noEmit"
|
|
88
81
|
}
|
|
89
82
|
}
|