genereleaselog 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ScaffoldCore
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # genereleaselog
2
+
3
+ 🎨 Generate the Release log in accordance with the
4
+ GitHub [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
5
+
6
+ ## Quick Start
7
+
8
+ Generate a release changelog:
9
+
10
+ ```sh
11
+ npx genereleaselog --token=GITHUB_TOKEN
12
+ ```
13
+
14
+ **Arguments:**
15
+
16
+ - `--from`: Start commit reference. When not provided, **latest git tag** will be used as default.
17
+ - `--to`: End commit reference. When not provided, **latest commit in HEAD** will be used as default.
18
+
19
+ ### Example Workflow: `.github/workflows/release.yml`
20
+
21
+ ```yml
22
+ name: Release
23
+
24
+ permissions:
25
+ contents: write
26
+
27
+ on:
28
+ push:
29
+ tags:
30
+ - 'v*'
31
+
32
+ jobs:
33
+ release:
34
+ runs-on: ubuntu-latest
35
+ steps:
36
+ - uses: actions/checkout@v4
37
+ with:
38
+ fetch-depth: 0
39
+
40
+ - uses: actions/setup-node@v4
41
+ with:
42
+ node-version: lts/*
43
+
44
+ - run: npx genereleaselog
45
+ env:
46
+ GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
47
+ ```
48
+
49
+ # 🤝 How to Contribute
50
+
51
+ We welcome contributions of all kinds! Whether it's fixing a typo in the documentation, improving the code, or
52
+ suggesting new features.
53
+
54
+ ## Contribution Process
55
+
56
+ * Fork this repository
57
+ * Create a new branch (git checkout -b feature/your-feature)
58
+ * Commit your changes (git commit -m 'feat: add some feature')
59
+ * Push to the branch (git push origin feature/your-feature)
60
+ * Open a Pull Request
61
+
62
+ ## License
63
+
64
+ Made with 💛
65
+
66
+ Published under [MIT License](./LICENSE).
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,124 @@
1
+ import { getCommitLogs, resolveConfig } from "./config-BY56Nhu0.js";
2
+ import { blue, cyan, dim, green, red, yellow } from "ansis";
3
+ import cac from "cac";
4
+ import { convert } from "convert-gitmoji";
5
+ import { $fetch } from "ofetch";
6
+
7
+ //#region src/markdown.ts
8
+ function generateMarkdown(commits, options) {
9
+ const lines = [];
10
+ for (const [_, commit] of Object.entries(commits)) {
11
+ lines.push(`### ${commit.title}\n`);
12
+ for (const row of commit.commits) lines.push(`- ${row.message} - by **@${row.author.authorName}** [<samp>(${row.shortHash})</samp>](https://github.com/${options.owner}/${options.repo}/commit/${row.shortHash})\n`);
13
+ }
14
+ if (!lines.length) lines.push("*No significant changes*");
15
+ const url = `https://${options.baseUrl}/${options.owner}/${options.repo}/compare/${options.from}...${options.to}`;
16
+ lines.push("", `##### &nbsp;&nbsp;&nbsp;&nbsp;[View changes on GitHub](${url})`);
17
+ return convert(lines.join("\n").trim(), true);
18
+ }
19
+
20
+ //#endregion
21
+ //#region src/parse.ts
22
+ function parseCommits(commit, options) {
23
+ const commits = commit.split("\n").map((item) => {
24
+ const [commits$1, shortHash, body, authorName, authorEmail, date] = item.split("|");
25
+ return {
26
+ commits: commits$1,
27
+ shortHash,
28
+ body,
29
+ message: body?.split(": ").slice(1).join(""),
30
+ author: {
31
+ authorName,
32
+ authorEmail
33
+ },
34
+ date
35
+ };
36
+ });
37
+ return Object.entries(options.types).reduce((acc, [key, value]) => {
38
+ const list = commits.filter((commit$1) => commit$1.body.startsWith(`${key}`));
39
+ if (list.length) acc[key] = {
40
+ title: value.title,
41
+ commits: list
42
+ };
43
+ return acc;
44
+ }, {});
45
+ }
46
+
47
+ //#endregion
48
+ //#region src/generate.ts
49
+ async function generate(options) {
50
+ const config = await resolveConfig(options);
51
+ const rawCommits = await getCommitLogs(config.from, config.to, config.cwd);
52
+ const commits = parseCommits(rawCommits, config);
53
+ const markdown = generateMarkdown(commits, config);
54
+ return {
55
+ config,
56
+ commits,
57
+ markdown,
58
+ rawCommits: rawCommits.split("\n")
59
+ };
60
+ }
61
+
62
+ //#endregion
63
+ //#region src/github.ts
64
+ async function createRelease(options, markdown) {
65
+ const header = {
66
+ accept: "application/vnd.github.v3+json",
67
+ authorization: `token ${options.token}`
68
+ };
69
+ const url = `https://${options.baseUrlApi}/repos/${options.owner}/${options.repo}/releases`;
70
+ const result = await $fetch(url, {
71
+ method: "post",
72
+ headers: header,
73
+ body: JSON.stringify({
74
+ owner: options.owner,
75
+ repo: options.repo,
76
+ tag_name: options.version,
77
+ name: options.version,
78
+ body: markdown,
79
+ draft: false,
80
+ prerelease: false
81
+ })
82
+ });
83
+ console.log(green(`Released on ${result.html_url}`));
84
+ }
85
+
86
+ //#endregion
87
+ //#region package.json
88
+ var version = "0.0.1";
89
+
90
+ //#endregion
91
+ //#region src/cli.ts
92
+ const cli = cac("genereleaselog");
93
+ cli.command("").option("--token <token>", "Github Token").option("--from <ref>", "From tag").option("--to <ref>", "To tag").action(async (options) => {
94
+ console.log();
95
+ console.log(dim(`genereleaselog `) + dim(`v${version}`));
96
+ console.log();
97
+ const { config, rawCommits, markdown } = await generate(options);
98
+ const webUrl = `https://${config.baseUrl}/${config.owner}/${config.repo}/releases/new?title=${encodeURIComponent(String(config.version))}&body=${encodeURIComponent(String(markdown))}&tag=${encodeURIComponent(String(config.version))}`;
99
+ console.log(cyan(config.from) + dim(" -> ") + blue(config.to) + dim(` (${rawCommits.length} commits)`));
100
+ console.log(dim("--------------"));
101
+ console.log();
102
+ console.log(markdown.replace(/&nbsp;/g, ""));
103
+ console.log();
104
+ console.log(dim("--------------"));
105
+ const printWebUrl = () => {
106
+ console.log();
107
+ console.error(yellow("Using the following link to create it manually:"));
108
+ console.error(yellow(webUrl));
109
+ console.log();
110
+ };
111
+ if (!config.token) {
112
+ console.error(red("No GitHub token found, specify it via GITHUB_TOKEN env. Release skipped."));
113
+ printWebUrl();
114
+ process.exit(1);
115
+ }
116
+ await createRelease(config, markdown);
117
+ });
118
+ cli.help();
119
+ cli.version(version);
120
+ cli.parse();
121
+
122
+ //#endregion
123
+ export { };
124
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","names":["commits: IGitCommit","options: IChangelogOptions","lines: string[]","commit: string","options: IChangelogOptions","item: string","commits","commit","options: IOptions","options: IChangelogOptions","markdown: string","options: IOptions"],"sources":["../src/markdown.ts","../src/parse.ts","../src/generate.ts","../src/github.ts","../package.json","../src/cli.ts"],"sourcesContent":["import type { IChangelogOptions, IGitCommit } from '@/src/types.ts'\nimport { convert } from 'convert-gitmoji'\n\nexport function generateMarkdown(commits: IGitCommit, options: IChangelogOptions) {\n const lines: string[] = []\n\n for (const [_, commit] of Object.entries(commits)) {\n lines.push(`### ${commit.title}\\n`)\n for (const row of commit.commits) {\n lines.push(`- ${row.message} - by **@${row.author.authorName}** [<samp>(${row.shortHash})</samp>](https://github.com/${options.owner}/${options.repo}/commit/${row.shortHash})\\n`)\n }\n }\n\n if (!lines.length)\n lines.push('*No significant changes*')\n\n const url = `https://${options.baseUrl}/${options.owner}/${options.repo}/compare/${options.from}...${options.to}`\n\n lines.push('', `##### &nbsp;&nbsp;&nbsp;&nbsp;[View changes on GitHub](${url})`)\n\n return convert(lines.join('\\n').trim(), true)\n}\n","import type { IChangelogOptions, IGitCommit, IRawGitCommit } from '@/src/types.ts'\n\nexport function parseCommits(commit: string, options: IChangelogOptions): IGitCommit {\n const commits = commit.split('\\n').map((item: string) => {\n const [commits, shortHash, body, authorName, authorEmail, date] = item.split('|')\n\n return {\n commits,\n shortHash,\n body,\n message: body?.split(': ').slice(1).join(''),\n author: {\n authorName,\n authorEmail,\n },\n date,\n }\n }) as IRawGitCommit[]\n\n return Object.entries(options.types).reduce((acc, [key, value]) => {\n const list = commits.filter(commit => commit.body.startsWith(`${key}`))\n\n if (list.length) {\n acc[key] = {\n title: value.title,\n commits: list,\n }\n }\n\n return acc\n }, {} as IGitCommit)\n}\n","import type { IChangelogOptions, IGitCommit, IOptions } from '@/src/types.ts'\nimport { resolveConfig } from '@/src/config.ts'\nimport { getCommitLogs } from '@/src/git.ts'\nimport { generateMarkdown } from '@/src/markdown.ts'\nimport { parseCommits } from '@/src/parse.ts'\n\nexport async function generate(options: IOptions): Promise<{\n config: IChangelogOptions\n commits: IGitCommit\n markdown: string\n rawCommits: string[]\n}> {\n const config = await resolveConfig(options)\n const rawCommits = await getCommitLogs(config.from, config.to, config.cwd)\n const commits = parseCommits(rawCommits, config)\n const markdown = generateMarkdown(commits, config)\n\n return {\n config,\n commits,\n markdown,\n rawCommits: rawCommits.split('\\n'),\n }\n}\n","import type { IChangelogOptions } from '@/src/types.ts'\nimport { green } from 'ansis'\nimport { $fetch } from 'ofetch'\n\nexport async function createRelease(options: IChangelogOptions, markdown: string) {\n const header = {\n accept: 'application/vnd.github.v3+json',\n authorization: `token ${options.token}`,\n }\n\n const url = `https://${options.baseUrlApi}/repos/${options.owner}/${options.repo}/releases`\n\n const result = await $fetch(url, {\n method: 'post',\n headers: header,\n body: JSON.stringify({\n owner: options.owner,\n repo: options.repo,\n tag_name: options.version,\n name: options.version,\n body: markdown,\n draft: false,\n prerelease: false,\n }),\n })\n\n console.log(green(`Released on ${result.html_url}`))\n}\n","{\n \"name\": \"genereleaselog\",\n \"type\": \"module\",\n \"version\": \"0.0.1\",\n \"private\": true,\n \"description\": \"\",\n \"author\": \"lonewolfyx <olddrivero.king@qq.com>\",\n \"license\": \"MIT\",\n \"homepage\": \"https://github.com/ScaffoldCore/genereleaselog\",\n \"bugs\": {\n \"url\": \"https://github.com/ScaffoldCore/genereleaselog/issues\"\n },\n \"keywords\": [],\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.mjs\",\n \"types\": \"dist/index.d.ts\",\n \"bin\": {\n \"genereleaselog\": \"./src/bin/index.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"dev\": \"tsdown --watch\",\n \"build\": \"tsdown\",\n \"lint\": \"eslint\",\n \"lint:fix\": \"eslint --fix\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"dependencies\": {\n \"ansis\": \"^4.1.0\",\n \"c12\": \"^3.2.0\",\n \"cac\": \"^6.7.14\",\n \"convert-gitmoji\": \"^0.1.5\",\n \"ofetch\": \"^1.4.1\",\n \"tinyexec\": \"^1.0.1\"\n },\n \"devDependencies\": {\n \"@antfu/eslint-config\": \"^5.2.1\",\n \"@lonewolfyx/tsconfig\": \"^0.0.5\",\n \"@types/node\": \"^24.2.1\",\n \"eslint\": \"^9.33.0\",\n \"lint-staged\": \"^16.1.5\",\n \"simple-git-hooks\": \"^2.13.1\",\n \"tsdown\": \"^0.14.1\",\n \"tsx\": \"^4.20.4\",\n \"typescript\": \"^5.9.2\"\n },\n \"simple-git-hooks\": {\n \"pre-commit\": \"npx lint-staged\"\n },\n \"lint-staged\": {\n \"*\": \"eslint --fix\"\n }\n}\n","import type { IOptions } from '@/src/types.ts'\nimport { blue, cyan, dim, red, yellow } from 'ansis'\nimport cac from 'cac'\nimport { generate } from '@/src/generate.ts'\nimport { createRelease } from '@/src/github.ts'\nimport { version } from '../package.json'\n\nconst cli = cac('genereleaselog')\n\ncli.command('')\n .option('--token <token>', 'Github Token')\n .option('--from <ref>', 'From tag')\n .option('--to <ref>', 'To tag')\n .action(async (options: IOptions) => {\n console.log()\n console.log(dim(`genereleaselog `) + dim(`v${version}`))\n console.log()\n\n const { config, rawCommits, markdown } = await generate(options)\n const webUrl = `https://${config.baseUrl}/${config.owner}/${config.repo}/releases/new?title=${encodeURIComponent(String(config.version))}&body=${encodeURIComponent(String(markdown))}&tag=${encodeURIComponent(String(config.version))}`\n\n console.log(cyan(config.from) + dim(' -> ') + blue(config.to) + dim(` (${rawCommits.length} commits)`))\n console.log(dim('--------------'))\n console.log()\n console.log(markdown.replace(/&nbsp;/g, ''))\n console.log()\n console.log(dim('--------------'))\n\n const printWebUrl = () => {\n console.log()\n console.error(yellow('Using the following link to create it manually:'))\n console.error(yellow(webUrl))\n console.log()\n }\n\n if (!config.token) {\n console.error(red('No GitHub token found, specify it via GITHUB_TOKEN env. Release skipped.'))\n printWebUrl()\n process.exit(1)\n }\n\n await createRelease(config, markdown)\n })\n\ncli.help()\ncli.version(version)\ncli.parse()\n"],"mappings":"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"}
@@ -0,0 +1,158 @@
1
+ import * as process from "node:process";
2
+ import { x } from "tinyexec";
3
+
4
+ //#region src/git.ts
5
+ /**
6
+ * Get github repo
7
+ * @param cwd
8
+ */
9
+ async function getGithubRepo(cwd) {
10
+ const url = await execCommand("git", [
11
+ "config",
12
+ "--get",
13
+ "remote.origin.url"
14
+ ], cwd);
15
+ const { owner, repo } = JSON.parse(url.replace(/(git@|https:\/\/)github\.com[:/]([^/]+)\/([^/]+)\.git/, "{\"owner\":\"$2\",\"repo\":\"$3\"}"));
16
+ return {
17
+ owner,
18
+ repo
19
+ };
20
+ }
21
+ /**
22
+ * Get the last commit hash
23
+ * @param cwd
24
+ */
25
+ async function getLastTagCommit(cwd) {
26
+ return await execCommand("git", [
27
+ "rev-list",
28
+ "-1",
29
+ "HEAD"
30
+ ], cwd);
31
+ }
32
+ /**
33
+ * Get the prev tags commit
34
+ * @param cwd
35
+ */
36
+ async function getMatchingTagsCommit(cwd) {
37
+ const tag = await execCommand("git", [
38
+ "tag",
39
+ "--sort=-creatordate",
40
+ "|",
41
+ "sed",
42
+ "-n",
43
+ "2p"
44
+ ], cwd);
45
+ return await getCommitByTag(tag, cwd) || await getFirstGitCommit(cwd);
46
+ }
47
+ /**
48
+ * Get the latest tag
49
+ * @param cwd
50
+ */
51
+ async function getLatestTag(cwd) {
52
+ return await execCommand("git", [
53
+ "describe",
54
+ "--tags",
55
+ "--abbrev=0"
56
+ ], cwd);
57
+ }
58
+ /**
59
+ * Get all git tags
60
+ * @param cwd
61
+ */
62
+ async function getAllTags(cwd) {
63
+ return await execCommand("git", ["tag", "--sort=-creatordate"], cwd);
64
+ }
65
+ /**
66
+ * Get first git commit
67
+ * @param cwd
68
+ */
69
+ async function getFirstGitCommit(cwd) {
70
+ return await execCommand("git", [
71
+ "rev-list",
72
+ "--max-parents=0",
73
+ "HEAD"
74
+ ], cwd);
75
+ }
76
+ /**
77
+ * Get commit by tag
78
+ * @param tag
79
+ * @param cwd
80
+ */
81
+ async function getCommitByTag(tag, cwd) {
82
+ return await execCommand("git", [
83
+ "rev-list",
84
+ "-n",
85
+ "1",
86
+ `${tag}`
87
+ ], cwd);
88
+ }
89
+ /**
90
+ * Get commit logs
91
+ * @param from
92
+ * @param to
93
+ * @param cwd
94
+ */
95
+ async function getCommitLogs(from, to, cwd) {
96
+ return await execCommand("git", [
97
+ "log",
98
+ `${from}..${to}`,
99
+ "--pretty=format:\"%H|%h|%s|%an|%ae|%ad\"",
100
+ "--date=format:\"%Y-%m-%d %H:%M:%S\""
101
+ ], cwd);
102
+ }
103
+ async function execCommand(cmd, args, cwd) {
104
+ return (await x(cmd, args, { nodeOptions: {
105
+ cwd,
106
+ shell: true
107
+ } })).stdout.trim();
108
+ }
109
+
110
+ //#endregion
111
+ //#region src/config.ts
112
+ const defaultConfig = {
113
+ types: {
114
+ feat: { title: "🎉 Features" },
115
+ perf: { title: "🔥 Performance" },
116
+ fix: { title: "🐞 Bug Fixes" },
117
+ refactor: { title: "💅 Refactors" },
118
+ docs: { title: "📚 Documentation" },
119
+ build: { title: "📦 Build" },
120
+ types: { title: "🌊 Types" },
121
+ chore: { title: "🏡 Chore" },
122
+ examples: { title: "🏀 Examples" },
123
+ test: { title: "✅ Tests" },
124
+ style: { title: "🎨 Styles" },
125
+ ci: { title: "🤖 CI" }
126
+ },
127
+ from: "",
128
+ to: "",
129
+ cwd: "",
130
+ version: ""
131
+ };
132
+ async function resolveConfig(options) {
133
+ const { loadConfig } = await import("c12");
134
+ const config = await loadConfig({
135
+ name: "genereleaselog",
136
+ defaults: defaultConfig,
137
+ overrides: options
138
+ }).then((r) => {
139
+ return {
140
+ ...r.config || defaultConfig,
141
+ cwd: r.cwd || process.cwd()
142
+ };
143
+ });
144
+ config.baseUrl = config.baseUrl ?? "github.com";
145
+ config.baseUrlApi = config.baseUrlApi ?? "api.github.com";
146
+ config.token = config.token || process.env.GITHUB_TOKEN;
147
+ config.version = config.version || await getLatestTag(config.cwd);
148
+ config.from = config.from || await getMatchingTagsCommit(config.cwd);
149
+ config.to = config.to || await getLastTagCommit(config.cwd);
150
+ const remote = await getGithubRepo(config.cwd);
151
+ config.owner = remote.owner;
152
+ config.repo = remote.repo;
153
+ return config;
154
+ }
155
+
156
+ //#endregion
157
+ export { execCommand, getAllTags, getCommitByTag, getCommitLogs, getFirstGitCommit, getGithubRepo, getLastTagCommit, getLatestTag, getMatchingTagsCommit, resolveConfig };
158
+ //# sourceMappingURL=config-BY56Nhu0.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-BY56Nhu0.js","names":["cwd: string","tag: string","from: string","to: string","cmd: string","args: string[]","options: IOptions"],"sources":["../src/git.ts","../src/config.ts"],"sourcesContent":["import { x } from 'tinyexec'\n\n/**\n * Get github repo\n * @param cwd\n */\nexport async function getGithubRepo(cwd: string): Promise<{ owner: string, repo: string }> {\n // git config --get remote.origin.url | sed -E 's#(git@|https://)github.com[:/]([^/]+)/([^/]+)\\.git#{\"owner\":\"\\2\",\"repo\":\"\\3\"}#'\n const url = await execCommand('git', ['config', '--get', 'remote.origin.url'], cwd)\n const {\n owner,\n repo,\n } = JSON.parse(url.replace(/(git@|https:\\/\\/)github\\.com[:/]([^/]+)\\/([^/]+)\\.git/, '{\"owner\":\"$2\",\"repo\":\"$3\"}'))\n\n return {\n owner,\n repo,\n }\n}\n\n/**\n * Get the last commit hash\n * @param cwd\n */\nexport async function getLastTagCommit(cwd: string): Promise<string> {\n // git rev-list -1 HEAD\n return await execCommand('git', ['rev-list', '-1', 'HEAD'], cwd)\n}\n\n/**\n * Get the prev tags commit\n * @param cwd\n */\nexport async function getMatchingTagsCommit(cwd: string): Promise<string> {\n // git tag --sort=-creatordate | sed -n 2p\n const tag = await execCommand('git', ['tag', '--sort=-creatordate', '|', 'sed', '-n', '2p'], cwd)\n return await getCommitByTag(tag, cwd) || await getFirstGitCommit(cwd)\n}\n\n/**\n * Get the latest tag\n * @param cwd\n */\nexport async function getLatestTag(cwd: string): Promise<string> {\n // git describe --tags --abbrev=0\n return await execCommand('git', ['describe', '--tags', '--abbrev=0'], cwd)\n}\n\n/**\n * Get all git tags\n * @param cwd\n */\nexport async function getAllTags(cwd: string) {\n // git tag --sort=-creatordate\n return await execCommand('git', ['tag', '--sort=-creatordate'], cwd)\n}\n\n/**\n * Get first git commit\n * @param cwd\n */\nexport async function getFirstGitCommit(cwd: string): Promise<string> {\n // git rev-list --max-parents=0 HEAD\n return await execCommand('git', ['rev-list', '--max-parents=0', 'HEAD'], cwd)\n}\n\n/**\n * Get commit by tag\n * @param tag\n * @param cwd\n */\nexport async function getCommitByTag(tag: string, cwd: string): Promise<string> {\n // git rev-list -n 1 v0.0.4\n return await execCommand('git', ['rev-list', '-n', '1', `${tag}`], cwd)\n}\n\n/**\n * Get commit logs\n * @param from\n * @param to\n * @param cwd\n */\nexport async function getCommitLogs(from: string, to: string, cwd: string): Promise<string> {\n // git log <from>>..<to> --pretty=format:\"%H|%h|%s|%an|%ae|%ad\" --date=format:\"%Y-%m-%d %H:%M:%S\"\n return await execCommand('git', [\n 'log',\n `${from}..${to}`,\n '--pretty=format:\"%H|%h|%s|%an|%ae|%ad\"',\n '--date=format:\"%Y-%m-%d %H:%M:%S\"',\n ], cwd)\n}\n\nexport async function execCommand(cmd: string, args: string[], cwd: string): Promise<string> {\n return (await x(cmd, args, {\n nodeOptions: {\n cwd,\n shell: true,\n },\n })).stdout.trim()\n}\n","import type { IChangelogOptions, IOptions } from '@/src/types.ts'\nimport * as process from 'node:process'\nimport { getGithubRepo, getLastTagCommit, getLatestTag, getMatchingTagsCommit } from '@/src/git.ts'\n\nconst defaultConfig = {\n types: {\n feat: {\n title: '🎉 Features',\n },\n perf: {\n title: '🔥 Performance',\n },\n fix: {\n title: '🐞 Bug Fixes',\n },\n refactor: {\n title: '💅 Refactors',\n },\n docs: {\n title: '📚 Documentation',\n },\n build: {\n title: '📦 Build',\n },\n types: {\n title: '🌊 Types',\n },\n chore: {\n title: '🏡 Chore',\n },\n examples: {\n title: '🏀 Examples',\n },\n test: {\n title: '✅ Tests',\n },\n style: {\n title: '🎨 Styles',\n },\n ci: {\n title: '🤖 CI',\n },\n },\n from: '',\n to: '',\n cwd: '',\n version: '',\n} satisfies IChangelogOptions\n\n// 获取配置\nexport async function resolveConfig(options: IOptions) {\n const { loadConfig } = await import('c12')\n\n const config = await loadConfig<IChangelogOptions>({\n name: 'genereleaselog',\n defaults: defaultConfig,\n // eslint-disable-next-line ts/ban-ts-comment\n // @ts-expect-error\n overrides: options,\n }).then((r) => {\n return {\n ...r.config || defaultConfig,\n cwd: r.cwd || process.cwd(),\n }\n })\n config.baseUrl = config.baseUrl ?? 'github.com'\n config.baseUrlApi = config.baseUrlApi ?? 'api.github.com'\n\n config.token = config.token || process.env.GITHUB_TOKEN\n config.version = config.version || await getLatestTag(config.cwd)\n config.from = config.from || await getMatchingTagsCommit(config.cwd)\n config.to = config.to || await getLastTagCommit(config.cwd)\n\n const remote = await getGithubRepo(config.cwd)\n config.owner = remote.owner\n config.repo = remote.repo\n\n return config\n}\n"],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ //#region src/types.d.ts
2
+
3
+ interface IOptions {
4
+ '--': any[];
5
+ 'token'?: string;
6
+ 'from'?: string;
7
+ 'to'?: string;
8
+ }
9
+ //#endregion
10
+ //#region src/config.d.ts
11
+ declare function resolveConfig(options: IOptions): Promise<{
12
+ cwd: string;
13
+ types: Record<string, {
14
+ title: string;
15
+ }>;
16
+ from: string;
17
+ to: string;
18
+ owner?: string;
19
+ repo?: string;
20
+ baseUrl?: string;
21
+ baseUrlApi?: string;
22
+ version: string;
23
+ token?: string;
24
+ }>;
25
+ //#endregion
26
+ //#region src/git.d.ts
27
+ /**
28
+ * Get github repo
29
+ * @param cwd
30
+ */
31
+ declare function getGithubRepo(cwd: string): Promise<{
32
+ owner: string;
33
+ repo: string;
34
+ }>;
35
+ /**
36
+ * Get the last commit hash
37
+ * @param cwd
38
+ */
39
+ declare function getLastTagCommit(cwd: string): Promise<string>;
40
+ /**
41
+ * Get the prev tags commit
42
+ * @param cwd
43
+ */
44
+ declare function getMatchingTagsCommit(cwd: string): Promise<string>;
45
+ /**
46
+ * Get the latest tag
47
+ * @param cwd
48
+ */
49
+ declare function getLatestTag(cwd: string): Promise<string>;
50
+ /**
51
+ * Get all git tags
52
+ * @param cwd
53
+ */
54
+ declare function getAllTags(cwd: string): Promise<string>;
55
+ /**
56
+ * Get first git commit
57
+ * @param cwd
58
+ */
59
+ declare function getFirstGitCommit(cwd: string): Promise<string>;
60
+ /**
61
+ * Get commit by tag
62
+ * @param tag
63
+ * @param cwd
64
+ */
65
+ declare function getCommitByTag(tag: string, cwd: string): Promise<string>;
66
+ /**
67
+ * Get commit logs
68
+ * @param from
69
+ * @param to
70
+ * @param cwd
71
+ */
72
+ declare function getCommitLogs(from: string, to: string, cwd: string): Promise<string>;
73
+ declare function execCommand(cmd: string, args: string[], cwd: string): Promise<string>;
74
+ //#endregion
75
+ export { execCommand, getAllTags, getCommitByTag, getCommitLogs, getFirstGitCommit, getGithubRepo, getLastTagCommit, getLatestTag, getMatchingTagsCommit, resolveConfig };
76
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/config.ts","../src/git.ts"],"sourcesContent":[],"mappings":";;AEMsB,UFOL,QAAA,CEPkB;EAkBb,IAAA,EAAA,GAAA,EAAA;EASA,OAAA,CAAA,EAAA,MAAA;EAUA,MAAA,CAAA,EAAA,MAAY;EASZ,IAAA,CAAA,EAAA,MAAU;AAShC;;;AFhDiB,iBCqCK,aAAA,CDrCG,OAAA,ECqCoB,QDrCpB,CAAA,ECqC4B,ODrC5B,CAAA;;SCqC4B;;EAA/B,CAAA,CAAA;EAAa,IAAA,EAAA,MAAA;EAAA,EAAA,EAAU,MAAA;EAAQ,KAAA,CAAA,EAAA,MAAA;MAAA,CAAA,EAAA,MAAA;EAAA,OAAA,CAAA,EAAA,MAAA;;;;AC5CrD,CAAA,CAAA;;;;AFOA;;;iBEPsB,aAAA,eAA4B;ED4C5B,KAAA,EAAA,MAAA;EAAa,IAAA,EAAA,MAAA;CAAA,CAAA;;;AAAkB;;iBC1B/B,gBAAA,eAA+B;;AAlBrD;AAkBA;AASA;AAUsB,iBAVA,qBAAA,CAUkC,GAAA,EAAA,MAAA,CAAA,EAVE,OAUF,CAAA,MAAA,CAAA;AASxD;AASA;AAUA;AAWA;AAUsB,iBAjDA,YAAA,CAiD8D,GAAA,EAAA,MAAA,CAAA,EAjDnC,OAiDmC,CAAA,MAAA,CAAA;;;;;iBAxC9D,UAAA,eAAsB;;;;;iBAStB,iBAAA,eAAgC;;;;;;iBAUhC,cAAA,4BAA0C;;;;;;;iBAW1C,aAAA,yCAAsD;iBAUtD,WAAA,4CAAuD"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import { execCommand, getAllTags, getCommitByTag, getCommitLogs, getFirstGitCommit, getGithubRepo, getLastTagCommit, getLatestTag, getMatchingTagsCommit, resolveConfig } from "./config-BY56Nhu0.js";
2
+
3
+ export { execCommand, getAllTags, getCommitByTag, getCommitLogs, getFirstGitCommit, getGithubRepo, getLastTagCommit, getLatestTag, getMatchingTagsCommit, resolveConfig };
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "genereleaselog",
3
+ "type": "module",
4
+ "version": "0.0.1",
5
+ "description": "",
6
+ "author": "lonewolfyx <olddrivero.king@qq.com>",
7
+ "license": "MIT",
8
+ "homepage": "https://github.com/ScaffoldCore/genereleaselog",
9
+ "bugs": {
10
+ "url": "https://github.com/ScaffoldCore/genereleaselog/issues"
11
+ },
12
+ "keywords": [],
13
+ "main": "dist/index.js",
14
+ "module": "dist/index.mjs",
15
+ "types": "dist/index.d.ts",
16
+ "bin": {
17
+ "genereleaselog": "./src/bin/index.js"
18
+ },
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "scripts": {
23
+ "dev": "tsdown --watch",
24
+ "build": "tsdown",
25
+ "lint": "eslint",
26
+ "lint:fix": "eslint --fix"
27
+ },
28
+ "publishConfig": {
29
+ "registry": "https://registry.npmjs.org",
30
+ "access": "public"
31
+ },
32
+ "dependencies": {
33
+ "ansis": "^4.1.0",
34
+ "c12": "^3.2.0",
35
+ "cac": "^6.7.14",
36
+ "convert-gitmoji": "^0.1.5",
37
+ "eslint-plugin-yml": "^1.18.0",
38
+ "ofetch": "^1.4.1",
39
+ "tinyexec": "^1.0.1",
40
+ "yaml-eslint-parser": "^1.3.0"
41
+ },
42
+ "devDependencies": {
43
+ "@antfu/eslint-config": "^5.2.1",
44
+ "@lonewolfyx/tsconfig": "^0.0.5",
45
+ "@types/node": "^24.2.1",
46
+ "eslint": "^9.33.0",
47
+ "lint-staged": "^16.1.5",
48
+ "simple-git-hooks": "^2.13.1",
49
+ "tsdown": "^0.14.1",
50
+ "tsx": "^4.20.4",
51
+ "typescript": "^5.9.2"
52
+ },
53
+ "simple-git-hooks": {
54
+ "pre-commit": "npx lint-staged"
55
+ },
56
+ "lint-staged": {
57
+ "*": "eslint --fix"
58
+ }
59
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ import('../../dist/cli.js')