mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-25 17:54:34 +08:00
feat(changelog): generate per-language markdown from JSON
Add scripts/changelog-to-markdown.mjs that renders changelogs/{cn,en,tw,ja}.json
into readable Markdown files. Runs idempotently; output passes Prettier without
changes.
Wire the script into the sync-changelog skill (step 4, before the release commit)
and update commit_release_changelogs.sh to include the four .md files in the
release: v<version> commit, with a preflight guard that errors if the md files
are missing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
2f8591fb8c
commit
f09d40f436
7 files changed
+4352
-7
No files matched your search
+1055
File diff suppressed because it is too large.
Load diff
+1055
File diff suppressed because it is too large.
Load diff
+1055
File diff suppressed because it is too large.
Load diff
+1055
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* changelog-to-markdown.mjs
|
||||
*
|
||||
* 将 changelogs/{cn,en,tw,ja}.json 全量渲染为同名 .md 文件。
|
||||
* 幂等:每次全量重写,md 始终与 json 保持一致。
|
||||
*
|
||||
* 用法:
|
||||
* node scripts/changelog-to-markdown.mjs
|
||||
*/
|
||||
|
||||
import { readFileSync, writeFileSync } from 'fs'
|
||||
import { resolve, dirname } from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const ROOT = resolve(__dirname, '..')
|
||||
|
||||
// ── 本地化配置 ──────────────────────────────────────────────────────────────
|
||||
|
||||
const LOCALES = [
|
||||
{ key: 'cn', h1: '更新日志' },
|
||||
{ key: 'en', h1: 'Changelog' },
|
||||
{ key: 'tw', h1: '更新日誌' },
|
||||
{ key: 'ja', h1: '変更履歴' },
|
||||
]
|
||||
|
||||
/** type → 各语言的标题(含 emoji)。缺失 type 回退为原始字符串,兼容未来扩展。 */
|
||||
const TYPE_LABELS = {
|
||||
feat: { cn: '✨ 新功能', en: '✨ Features', tw: '✨ 新功能', ja: '✨ 新機能' },
|
||||
fix: { cn: '🐛 修复', en: '🐛 Bug Fixes', tw: '🐛 修復', ja: '🐛 バグ修正' },
|
||||
refactor: { cn: '♻️ 重构', en: '♻️ Refactoring', tw: '♻️ 重構', ja: '♻️ リファクタリング' },
|
||||
perf: { cn: '⚡ 性能', en: '⚡ Performance', tw: '⚡ 效能', ja: '⚡ パフォーマンス' },
|
||||
docs: { cn: '📝 文档', en: '📝 Documentation', tw: '📝 文件', ja: '📝 ドキュメント' },
|
||||
style: { cn: '💄 样式', en: '💄 Styles', tw: '💄 樣式', ja: '💄 スタイル' },
|
||||
ci: { cn: '👷 CI', en: '👷 CI', tw: '👷 CI', ja: '👷 CI' },
|
||||
chore: { cn: '🔧 杂项', en: '🔧 Chores', tw: '🔧 雜項', ja: '🔧 雑務' },
|
||||
}
|
||||
|
||||
// ── 渲染函数 ────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* 将单个语言的 changelog 数组渲染为 Markdown 字符串。
|
||||
* @param {string} h1 - H1 标题文字
|
||||
* @param {string} langKey - 'cn' | 'en' | 'tw' | 'ja'(用于 type 标题查表)
|
||||
* @param {Array} entries - changelog 数组
|
||||
*/
|
||||
function renderMarkdown(h1, langKey, entries) {
|
||||
const lines = [`# ${h1}`, '']
|
||||
|
||||
for (const entry of entries) {
|
||||
const { version, date, summary, changes } = entry
|
||||
|
||||
lines.push(`## v${version} (${date})`)
|
||||
lines.push('')
|
||||
|
||||
if (summary) {
|
||||
lines.push(`> ${summary}`)
|
||||
lines.push('')
|
||||
}
|
||||
|
||||
if (Array.isArray(changes)) {
|
||||
for (const group of changes) {
|
||||
const { type, items } = group
|
||||
const typeMap = TYPE_LABELS[type]
|
||||
const label = typeMap ? typeMap[langKey] : type
|
||||
lines.push(`### ${label}`)
|
||||
lines.push('')
|
||||
for (const item of items) {
|
||||
lines.push(`- ${item}`)
|
||||
}
|
||||
lines.push('')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 确保文件以单个换行结尾
|
||||
return lines.join('\n').trimEnd() + '\n'
|
||||
}
|
||||
|
||||
// ── 主流程 ──────────────────────────────────────────────────────────────────
|
||||
|
||||
let hasError = false
|
||||
|
||||
for (const { key, h1 } of LOCALES) {
|
||||
const jsonPath = resolve(ROOT, 'changelogs', `${key}.json`)
|
||||
const mdPath = resolve(ROOT, 'changelogs', `${key}.md`)
|
||||
|
||||
let entries
|
||||
try {
|
||||
entries = JSON.parse(readFileSync(jsonPath, 'utf8'))
|
||||
} catch (err) {
|
||||
console.error(`✗ 读取 ${jsonPath} 失败:${err.message}`)
|
||||
hasError = true
|
||||
continue
|
||||
}
|
||||
|
||||
const md = renderMarkdown(h1, key, entries)
|
||||
writeFileSync(mdPath, md, 'utf8')
|
||||
console.log(`✓ changelogs/${key}.md (${entries.length} 版本)`)
|
||||
}
|
||||
|
||||
if (hasError) process.exit(1)
|
||||
@@ -54,20 +54,29 @@ scripts/preflight_main_clean.sh . "package.json,changelogs/cn.json"
|
||||
5. 翻译时必须逐条对应当前中文条目:`summary` 与 `changes.items` 的语义都应来自最新中文文件内容,不得沿用旧版本措辞。
|
||||
6. 写入后执行格式化(若项目有 Prettier,优先使用 Prettier)。
|
||||
|
||||
## 4. 在当前仓库创建发布提交
|
||||
## 4. 生成多语言 Markdown
|
||||
|
||||
在提交前,将 4 个 JSON 渲染为可读的 Markdown 文件:
|
||||
|
||||
```bash
|
||||
node scripts/changelog-to-markdown.mjs
|
||||
prettier --write changelogs/*.md
|
||||
```
|
||||
|
||||
生成结果:`changelogs/cn.md`、`en.md`、`tw.md`、`ja.md`(全量幂等,每次重写)。
|
||||
|
||||
## 5. 在当前仓库创建发布提交
|
||||
|
||||
1. 提交文件必须包含:
|
||||
- `package.json`
|
||||
- `changelogs/cn.json`
|
||||
- `changelogs/en.json`
|
||||
- `changelogs/tw.json`
|
||||
- `changelogs/ja.json`
|
||||
- `changelogs/cn.json`、`en.json`、`tw.json`、`ja.json`
|
||||
- `changelogs/cn.md`、`en.md`、`tw.md`、`ja.md`
|
||||
2. commit message:`release: v<version>`(示例:`release: v0.9.6`)。
|
||||
3. 仅创建 commit,不 push。
|
||||
|
||||
可复用脚本:`scripts/commit_release_changelogs.sh`
|
||||
|
||||
## 5. 输出结果
|
||||
## 6. 输出结果
|
||||
|
||||
输出以下信息给用户:
|
||||
|
||||
@@ -82,3 +91,4 @@ scripts/preflight_main_clean.sh . "package.json,changelogs/cn.json"
|
||||
- `references/japanese-release-style.md`
|
||||
- `scripts/preflight_main_clean.sh`
|
||||
- `scripts/commit_release_changelogs.sh`
|
||||
- `scripts/changelog-to-markdown.mjs`
|
||||
@@ -13,6 +13,10 @@ CN_FILE="$REPO_PATH/changelogs/cn.json"
|
||||
EN_FILE="$REPO_PATH/changelogs/en.json"
|
||||
TW_FILE="$REPO_PATH/changelogs/tw.json"
|
||||
JA_FILE="$REPO_PATH/changelogs/ja.json"
|
||||
CN_MD="$REPO_PATH/changelogs/cn.md"
|
||||
EN_MD="$REPO_PATH/changelogs/en.md"
|
||||
TW_MD="$REPO_PATH/changelogs/tw.md"
|
||||
JA_MD="$REPO_PATH/changelogs/ja.md"
|
||||
PKG_FILE="$REPO_PATH/package.json"
|
||||
|
||||
if [[ ! -f "$CN_FILE" || ! -f "$EN_FILE" || ! -f "$TW_FILE" || ! -f "$JA_FILE" || ! -f "$PKG_FILE" ]]; then
|
||||
@@ -20,6 +24,11 @@ if [[ ! -f "$CN_FILE" || ! -f "$EN_FILE" || ! -f "$TW_FILE" || ! -f "$JA_FILE" |
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$CN_MD" || ! -f "$EN_MD" || ! -f "$TW_MD" || ! -f "$JA_MD" ]]; then
|
||||
echo "错误: Markdown 文件不完整,请先运行 node scripts/changelog-to-markdown.mjs" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERSION="$(node -e "const fs=require('fs');const arr=JSON.parse(fs.readFileSync(process.argv[1],'utf8'));process.stdout.write(arr?.[0]?.version||'');" "$CN_FILE")"
|
||||
if [[ -z "$VERSION" ]]; then
|
||||
echo "错误: 无法从 $CN_FILE 读取当前版本" >&2
|
||||
@@ -33,7 +42,11 @@ git -C "$REPO_PATH" add \
|
||||
changelogs/cn.json \
|
||||
changelogs/en.json \
|
||||
changelogs/tw.json \
|
||||
changelogs/ja.json
|
||||
changelogs/ja.json \
|
||||
changelogs/cn.md \
|
||||
changelogs/en.md \
|
||||
changelogs/tw.md \
|
||||
changelogs/ja.md
|
||||
|
||||
# 若没有差异则不提交,避免空提交失败。
|
||||
if git -C "$REPO_PATH" diff --cached --quiet; then
|
||||
|
||||
Reference in new issue
Block a user