-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from mmdapl/feat/add-changelog
feat(changelog): 新增脚手架支持自动记录变更日志
- Loading branch information
Showing
14 changed files
with
922 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
# @142vip/changelog | ||
|
||
根据git提交记录,自动生成changelog文档 | ||
|
||
[![NPM version](https://img.shields.io/npm/v/@142vip/changelog?color=a1b858&label=version)](https://www.npmjs.com/package/@142vip/changelog) | ||
|
||
Generate changelog for GitHub releases from [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/), | ||
powered by [changelogen](https://github.com/unjs/changelogen). | ||
|
||
[👉 使用示例](https://github.com/unocss/unocss/releases/tag/v0.39.0) | ||
|
||
## 新功能 | ||
|
||
- Support exclamation mark as breaking change, e.g. `chore!: drop node v10` | ||
- Grouped scope in changelog | ||
- Create the release note, or update the existing one | ||
- List contributors | ||
|
||
## 使用 | ||
|
||
### 生成CHANGELOG.md文档 | ||
|
||
```bash | ||
# output参数可以配置,支持做本地文档更新 | ||
npx changelog --output CHANGELOG.md | ||
``` | ||
|
||
### 配合Github Actions使用 | ||
|
||
```yml | ||
# .github/workflows/release.yml | ||
|
||
name: Release | ||
|
||
permissions: | ||
contents: write | ||
|
||
on: | ||
push: | ||
tags: | ||
- 'v*' | ||
|
||
jobs: | ||
release: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
with: | ||
fetch-depth: 0 | ||
|
||
# 安装node版本,大于16 | ||
- uses: actions/setup-node@v3 | ||
with: | ||
node-version: 16.x | ||
|
||
# Github发布版本,并更新Release信息 | ||
- run: npx changelog | ||
env: | ||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} | ||
``` | ||
向 GitHub 推送以“v”开头的标签时,`github actions`会被触发。 | ||
|
||
在142vip所有的开源仓库中,都可以通过`@142vip/changelog`模块来实现发布,例如: | ||
|
||
```yaml | ||
# CD持续交付 | ||
# - 部署到Github Pages | ||
# - 部署到Vercel托管平台 | ||
# - 发布新的Github Release | ||
# 参考:https://v2.vuepress.vuejs.org/zh/guide/deployment.html#github-pages | ||
# | ||
name: CD | ||
on: | ||
push: | ||
branches: | ||
- next | ||
workflow_dispatch: | ||
jobs: | ||
# 版本发布 | ||
release: | ||
name: 创建Github发布 | ||
runs-on: ubuntu-latest | ||
# 主库next且执行release更新时执行 | ||
if: github.repository == '142vip/core-x' && startsWith(github.event.head_commit.message, 'chore(release):') | ||
steps: | ||
- name: Checkout Code | ||
uses: actions/checkout@v4 | ||
with: | ||
token: ${{ secrets.TOKEN }} | ||
persist-credentials: false | ||
# “最近更新时间” 等 git 日志相关信息,需要拉取全部提交记录 | ||
fetch-depth: 0 | ||
# 安装node版本,大于16 | ||
- uses: actions/setup-node@v3 | ||
with: | ||
node-version: 16.x | ||
# Github发布版本,并更新Release信息 | ||
- run: npx changelog | ||
env: | ||
GITHUB_TOKEN: ${{secrets.TOKEN}} | ||
# 提取版本号 | ||
- name: Get New Version Number | ||
id: releaseVersion | ||
run: | | ||
echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT | ||
# 更新资源 区分压缩包上传 | ||
- name: Upload Resource Assets | ||
uses: actions/upload-release-asset@latest | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.TOKEN }} | ||
with: | ||
upload_url: ${{ steps.createRelease.outputs.upload_url }} | ||
asset_path: ./142vip-oauth.zip | ||
asset_name: 142vip-oauth.zip | ||
asset_content_type: application/zip | ||
``` | ||
|
||
## 配置 | ||
|
||
You can put a configuration file in the project root, named | ||
as `changelogithub.config.{json,ts,js,mjs,cjs}`, `.changelogithubrc` or use the `changelogithub` field | ||
in `package.json`. | ||
|
||
## 本地预览y | ||
|
||
```bash | ||
# 只本地生成创建版本的URL | ||
npx changelogithub --dry | ||
``` | ||
|
||
## 感谢 | ||
|
||
- changelogen: <https://github.com/unjs/changelogen> | ||
- changelogithub: <https://github.com/antfu/changelogithub> | ||
|
||
## 证书 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { defineBuildConfig } from 'unbuild' | ||
|
||
export default defineBuildConfig({ | ||
entries: [ | ||
'src/index', | ||
'src/changelog', | ||
], | ||
declaration: true, | ||
clean: true, | ||
rollup: { | ||
emitCJS: true, | ||
inlineDependencies: true, | ||
}, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#!/usr/bin/env node | ||
// eslint-disable-next-line antfu/no-import-dist | ||
import './dist/changelog.mjs' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
{ | ||
"name": "@142vip/changelog", | ||
"version": "0.0.1", | ||
"private": false, | ||
"type": "module", | ||
"description": "公众号搜:储凡", | ||
"author": "mmdapl <[email protected]>", | ||
"license": "MIT", | ||
"keywords": [ | ||
"公众号搜:储凡", | ||
"142vip", | ||
"@142vip/changelog", | ||
"github", | ||
"release", | ||
"releases", | ||
"conventional", | ||
"changelog" | ||
], | ||
"sideEffects": false, | ||
"exports": { | ||
".": { | ||
"types": "./dist/index.d.ts", | ||
"import": "./dist/index.mjs", | ||
"require": "./dist/index.cjs" | ||
} | ||
}, | ||
"main": "./dist/index.mjs", | ||
"module": "./dist/index.mjs", | ||
"types": "./dist/index.d.ts", | ||
"bin": "./cli.mjs", | ||
"files": [ | ||
"*.mjs", | ||
"dist" | ||
], | ||
"engines": { | ||
"node": ">=16.0.0" | ||
}, | ||
"scripts": { | ||
"dev": "unbuild --stub", | ||
"build": "unbuild", | ||
"typecheck": "tsc --noEmit" | ||
}, | ||
"dependencies": { | ||
"@antfu/utils": "^0.7.10", | ||
"c12": "^1.11.1", | ||
"cac": "^6.7.14", | ||
"changelogen": "0.5.5", | ||
"convert-gitmoji": "^0.1.5", | ||
"dayjs": "^1.11.11", | ||
"execa": "^8.0.1", | ||
"kolorist": "^1.8.0", | ||
"ofetch": "^1.3.4", | ||
"semver": "^7.6.2" | ||
}, | ||
"devDependencies": { | ||
"@antfu/eslint-config": "^2.22.0", | ||
"@types/debug": "^4.1.12", | ||
"@types/fs-extra": "^11.0.4", | ||
"@types/minimist": "^1.2.5", | ||
"@types/semver": "^7.5.8", | ||
"bumpp": "^9.4.1", | ||
"eslint": "^9.7.0", | ||
"esno": "^4.7.0", | ||
"fs-extra": "^11.2.0", | ||
"typescript": "^5.5.3", | ||
"unbuild": "^2.0.0", | ||
"vitest": "^2.0.2" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
#!/usr/bin/env node | ||
|
||
/* eslint-disable no-console */ | ||
import process from 'node:process' | ||
import { blue, bold, cyan, dim, red, yellow } from 'kolorist' | ||
import cac from 'cac' | ||
import { version } from '../package.json' | ||
import { generate, isRepoShallow, sendRelease, updateChangelog } from './index' | ||
|
||
const cli = cac('changelog') | ||
|
||
// 参数 | ||
cli | ||
.version(version) | ||
.option('-t, --tokens <path>', 'GitHub Token') | ||
.option('--from <ref>', 'From tag') | ||
.option('--to <ref>', 'To tag') | ||
.option('--github <path>', 'GitHub Repository, e.g. @142vip/core-x') | ||
.option('--name <name>', 'Name of the release') | ||
.option('--prerelease', 'Mark release as prerelease') | ||
.option('--output <path>', 'Output to file instead of sending to GitHub') | ||
.option('--dry', 'Dry run') | ||
.help() | ||
|
||
// 命令 | ||
cli | ||
.command('') | ||
.action(async (args) => { | ||
args.token = args.token || process.env.GITHUB_TOKEN | ||
|
||
let webUrl = '' | ||
|
||
try { | ||
console.log() | ||
console.log(dim(`${bold('@142vip/changelog')} `) + dim(`v${version}`)) | ||
|
||
const { config, markdown, commits } = await generate(args) | ||
webUrl = `https://${config.baseUrl}/${config.repo}/releases/new?title=${encodeURIComponent(String(config.name || config.to))}&body=${encodeURIComponent(String(markdown))}&tag=${encodeURIComponent(String(config.to))}&prerelease=${config.prerelease}` | ||
|
||
console.log(cyan(config.from) + dim(' -> ') + blue(config.to) + dim(` (${commits.length} commits)`)) | ||
console.log(dim('--------------')) | ||
console.log() | ||
console.log(markdown.replace(/ /g, '')) | ||
console.log() | ||
console.log(dim('--------------')) | ||
|
||
function printWebUrl() { | ||
console.log() | ||
console.error(yellow('使用以下链接手动发布新的版本:')) | ||
console.error(yellow(webUrl)) | ||
console.log() | ||
} | ||
|
||
if (config.dry) { | ||
console.log(yellow('试运行。已跳过版本发布。')) | ||
printWebUrl() | ||
return | ||
} | ||
|
||
// 更新changelog文档 | ||
if (typeof config.output === 'string') { | ||
await updateChangelog(config.output, markdown, config.to) | ||
return | ||
} | ||
|
||
// 带token上传 | ||
if (!config.tokens) { | ||
console.error(red('未找到 GitHub 令牌,请通过 GITHUB_TOKEN 环境变量指定。已跳过版本发布。')) | ||
printWebUrl() | ||
return | ||
} | ||
|
||
if (!commits.length && await isRepoShallow()) { | ||
console.error(yellow('存储库似乎克隆得很浅,这使得更改日志无法生成。您可能希望在 CI 配置中指定 \'fetch-depth: 0\'。')) | ||
printWebUrl() | ||
return | ||
} | ||
|
||
// 调用api 直接发布 | ||
await sendRelease(config, markdown) | ||
} | ||
catch (e: any) { | ||
console.error(red(String(e))) | ||
if (e?.stack) | ||
console.error(dim(e.stack?.split('\n').slice(1).join('\n'))) | ||
|
||
// 手动执行,创建release | ||
if (webUrl) { | ||
console.log() | ||
console.error(red('无法创建发布。使用以下链接手动创建它:')) | ||
console.error(yellow(webUrl)) | ||
console.log() | ||
} | ||
} | ||
finally { | ||
process.exitCode = 1 | ||
} | ||
}) | ||
|
||
cli.parse() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import process from 'node:process' | ||
import { | ||
getCurrentGitBranch, | ||
getFirstGitCommit, | ||
getGitHubRepo, | ||
getLastMatchingTag, | ||
isPrerelease, | ||
} from './git' | ||
import type { ChangelogOptions, ResolvedChangelogOptions } from './types' | ||
|
||
// const defaultOutput = 'CHANGELOG.md' | ||
const defaultConfig: ChangelogOptions = { | ||
scopeMap: {}, | ||
types: { | ||
feat: { title: '✨ Features', semver: 'minor' }, | ||
perf: { title: '🔥 Performance', semver: 'patch' }, | ||
fix: { title: '🐛 Bug Fixes', semver: 'patch' }, | ||
refactor: { title: '💅 Refactors', semver: 'patch' }, | ||
docs: { title: '📖 Documentation', semver: 'patch' }, | ||
build: { title: '📦 Build', semver: 'patch' }, | ||
types: { title: '🌊 Types', semver: 'patch' }, | ||
}, | ||
titles: { | ||
breakingChanges: '🚨 Breaking Changes', | ||
}, | ||
tokens: { | ||
github: process.env.GITHUB_TOKEN || process.env.TOKEN, | ||
}, | ||
contributors: true, | ||
capitalize: true, | ||
group: true, | ||
emoji: true, | ||
// output: defaultOutput, | ||
} | ||
|
||
export async function resolveConfig(options: ChangelogOptions) { | ||
const { loadConfig } = await import('c12') | ||
const config = await loadConfig<ChangelogOptions>({ | ||
name: '@142vip/changelog', | ||
defaults: defaultConfig, | ||
overrides: options, | ||
packageJson: '@142vip/changelog', | ||
}).then(r => r.config || defaultConfig) | ||
|
||
config.baseUrl = config.baseUrl ?? 'github.com' | ||
config.baseUrlApi = config.baseUrlApi ?? 'api.github.com' | ||
config.to = config.to || await getCurrentGitBranch() | ||
config.from = config.from || await getLastMatchingTag(config.to) || await getFirstGitCommit() | ||
// @ts-expect-error backward compatibility | ||
config.repo = config.repo || config.github || await getGitHubRepo(config.baseUrl) | ||
config.prerelease = config.prerelease ?? isPrerelease(config.to) | ||
|
||
if (typeof config.repo !== 'string') | ||
throw new Error(`Invalid GitHub repository, expected a string but got ${JSON.stringify(config.repo)}`) | ||
|
||
return config as ResolvedChangelogOptions | ||
} |
Oops, something went wrong.