关于 changelog
changelog 是用于为当前分支创建、更新或修复变更日志条目的 Skill,面向需要按仓库约定记录分支变更的开发流程。它从 Git 信息和差异推导元数据,并提供确定性补全脚本与校验步骤。
主要功能
- 01从分支提交与差异提取元数据
- 02按包和类别分组生成正文
- 03支持幂等更新已有条目
- 04运行补全脚本添加链接等字段
- 05校验 frontmatter、文件名与内容
适用场景
- 01为当前功能分支撰写变更日志
- 02刷新已有分支对应的条目
- 03在提交推送前检查条目格式
- 04在单仓库或 monorepo 中记录变更
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ rheged-studio/ agent-skills --skill changelog安装后在 Claude Code 中输入/changelog确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
config.example.jsonpackage.jsonREADME.mdreferences/changelog-contract.mdscripts/add-links.mjsbackfill-commits.mjscheck-changelog-completeness.mjsenrich-changelog.mjsfinalise-changelog.mjspreflight-changelog-ci.mjsset-affected-packages.mjsvalidate-changelog.mjsscripts/lib/changelog.mjscli-entry.mjscommit-count.mjsconfig.mjsderive-packages.mjsenrich.mjsfrontmatter.mjsstamp.mjsscripts/lib/vendor/issue-keys.mjs详细介绍
变更日志
为当前分支生成或更新变更日志条目,路径为
changelog/YYYYMMDD-HHMMSS-<slug>.md:从 git 和差异中推导元数据,编写 frontmatter 和分组分类后的正文,运行确定性的补充脚本,然后验证结果。
此技能是有效变更日志条目规范的唯一事实来源——包括 frontmatter 架构、字段归属边界、幂等更新与创建规则,以及验证关卡。下游的使用方仓库 CI 和合并后补充程序也会执行相同约定,由后者填充合并后字段(@rheged-studio/changelog-core,在仓库内通过 reusable-changelog-enrich.yml 运行——不再是中央发布编排器的步骤),因此编写规则只需在此处定义一次。
此技能有两种调用方式:
- 独立运行(
/changelog)——编写、刷新或修复此分支的条目,并将其保留为工作区中未提交的文件以供审核。不提交、不推送,也不创建 PR。 - 在发布流程中运行(例如
/send-it)——在推送前执行的变更日志步骤;发布流程会提交条目、推送并创建 PR。
配置
配置位于此文件旁边的 config.json 中;随附脚本会自动读取它。请编辑你复制的 config.json,使其匹配使用方仓库(随附的中性 config.example.json 是一个模板)。issueKeys 和 linearWorkspaceSlug 是必填项——它们没有默认值,因此缺少 config.json 或缺少任一键都会导致脚本明确报错,而不会静默继承 ACME 的标识。其余配置项是结构性配置,具有通用且可覆盖的默认值:
| 键 | 含义 | 默认值 |
|---|---|---|
issueKeys | 用于识别分支和正文中问题 ID 的团队键前缀——仓库涉及的每个团队都要列出(例如,["R"];对于横跨 Cadogan 的仓库,可用 ["C", "R"])。问题 ID 正则表达式由这些前缀构建。 | 必填 |
linearWorkspaceSlug | 用于构建问题链接的 Linear 工作区 slug(https://linear.app/<slug>/issue/<id>)。 | 必填 |
baseBranch | 作为分支差异比较基准的主干分支(origin/<baseBranch>)。可通过每次运行的 BASE_REF 环境变量覆盖。 | "main" |
changelogDir | 存放按日期命名条目的目录(由补充和验证脚本扫描)。 | "changelog" |
packageRoots | 单仓库中用于将 <root>/<x>/… 映射为程序包 <x> 的目录前缀,推导 affected_packages 时使用。 | ["apps", "packages", "services"] |
fallbackPackage | 更改路径与任何 packageRoots 前缀都不匹配时使用的程序包名称。 | "infrastructure" |
affectedPackages | 是否生成 affected_packages 字段。单程序包仓库请保留为 false(该字段只写入且冗余,省略可使条目保持简洁);真正的单仓库请设为 true。rheged-skills-setup 检测到工作区配置时会启用此项。 | false |
所有随附脚本仅使用 Node 内置模块——无需 npm install,也无需构建步骤。它们会操作使用方仓库根目录下的 changelog/ 目录(请从仓库根目录运行)。
运行方式
步骤 1 — 检测现有条目(幂等性)
在 changelog/ 中搜索 frontmatter 包含 branch: "<current-branch>" 的文件。
如果恰好有一个匹配项,则进入更新模式:保留其 created_at 和文件名,重写其余内容。否则进入创建模式。
步骤 2 — 分析分支
git log origin/<base>..HEAD --pretty=full— 获取完整提交列表,包括正文和尾注。git diff origin/<base>...HEAD --name-only— 获取更改文件,用于按程序包对正文分组。
<base> 是 config.json 中的 baseBranch(默认值为 main)。请先获取该分支(git fetch origin <base>),确保差异准确——如果调用方已执行此操作,则跳过获取(例如,发布流程会在预检步骤中获取分支)。
多提交和合并提交安全性(R-825)
在多提交功能分支和合并合并(以及压缩合并/变基合并)中,编写和合并后补充信息都是安全的:
- 每个分支对应一个条目,而不是每个提交对应一个条目。 第 1 步会根据 frontmatter 中的
branch:查找;在中间提交后重新运行/changelog会更新同一个带日期的文件,不会为同一分支创建第二个条目。 - 分支分析涵盖整个 PR。 第 2 步使用
git log origin/<base>..HEAD(以及对称差异),因此无论合并前有多少个提交,功能分支上的每个提交都会参与元数据和正文内容的生成。 - 合并后,
commit是主干合并 SHA。 完成/补充信息时,会将commit设为已合并 PR 的mergeCommit.oid的前 7 个字符,也就是实际进入主干的提交。对于合并合并,这是一个双父合并提交;对于压缩合并,这是一个单独的压缩提交(与功能分支的顶端提交不同)。 stats.commits统计 PR 中编写的工作,不计合并产生的干扰。 系统会扫描 PR commits REST 端点,并排除父提交数超过 1 个的提交(分支main合并解决提交),因此即使多提交分支偶尔包含合并提交,统计结果也能正确反映编写的提交数。
步骤 3 — 推导元数据
| 字段 | 推导方式 |
|---|---|
issues | 根据 issueKeys 推导:仅取分支的开头 ID(转为大写;extractBranchIssueId 会忽略 -c-2- 这类 slug 标记),并纳入提交主题/正文中符合 issue ID 正则表达式的所有匹配项(buildIssueRe)。去重。 |
author | git config user.email。 |
co_authors | 解析分支所有提交中的 Co-authored-by: Name <email> 尾注。存储邮箱或 Name <email> 格式。若无,则为空数组。 |
category | 根据提交主题和 diff 推断:feature、fix、chore、docs、refactor、perf。如果无法明确判断,请用户确认。 |
breaking | 根据 BREAKING CHANGE: 尾注、符合 Conventional Commits 规范的提交主题中的 !,或公共接口的移除情况推断。如果不明确,请询问用户。默认值为 false。 |
release_note | 面向用户的一句话摘要,与 title 不同。可选;如果更改不会影响用户(如 chore、内部重构),则留空。 |
字段归属——此技能负责编写哪些字段、必须保留哪些字段,是契约的核心;完整规则请参阅
references/changelog-contract.md。
简而言之:
- 由此处编写:
title、release_note、category、breaking、issues、co_authors、author,以及——仅当启用affectedPackages时——affected_packages(由步骤 5 中的 enrichment 脚本写入,不要手动编辑)。单包仓库将affectedPackages: false(默认值)保留不变,并完全省略该字段。 created_at神圣不可改——创建时设置一次(首次运行的 UTC 时间);更新时,原样保留。- 此处绝不编写:
stats(files_changed、loc_added、loc_removed、commits)以及合并后字段merged_at/commit/pr。合并后 enrichment 程序会在合并后根据 GitHub PR 的权威数据完成这些字段——包括pr,它通过已合并 PR 的branch:解析得出(ship 流程绝不写入此字段)。commit是mergeCommit.oid的短 SHA(主干落地提交);stats.commits是 PR 分支上的非合并提交数(参见上文的多提交与合并提交安全性)。创建时,将合并后字段设为空白占位符;更新时,保留现有值不变。
此技能会输出推导得出的 issues 数组作为交接数据——ship 流程会将其用于 PR 正文和任何 Linear 回写(例如通过 linear-sync 技能)。
第 4 步——生成正文
按软件包分组列出要点,并归入 ## Added/## Changed/## Fixed。
只包含有条目的标题。涉及多个软件包时,使用
**<pkg-name>:** 作为子标题。
如果 breaking: true,正文必须以 ## Breaking 部分开头,说明
变更内容和迁移路径。
title、release_note 和正文描述应使用使用方仓库指定的
书面语言。本代码库范围内的语言为英式英语(colour、behaviour、
-ise/-yse)——仅限描述文字,标识符、依赖项名称或上游 API 字段名称除外。
第 5 步——编写或更新文件
文件名: changelog/YYYYMMDD-HHMMSS-<slug>.md,其中时间戳为
created_at(首次运行时的 UTC 时间),slug 根据 title 生成(小写,
非字母数字字符替换为 -,合并重复字符,长度约限制为 60 个字符,并在单词边界处截断)。
始终在 YAML 中为时间戳字符串加引号(created_at: "2026-04-26T13:24:00Z")。
不加引号的 ISO 时间戳会被解析为 Date 对象,并在往返写入时多出 .000Z 毫秒;
加引号可以保留原值。
**更新时:**保留 created_at 和文件名;重写 title、
release_note、category、breaking、co_authors、issues 和正文;
merged_at/commit/pr/stats 保持不变(后合并增强器会填充这些字段,pr 由分支解析)。
使用
references/changelog-contract.md 中指定的 frontmatter 字段顺序。只有在启用
affectedPackages 时,才输出 affected_packages: [] 作为占位符——脚本会原位填充。关闭时(默认的单软件包模式),省略此字段;set-affected-packages.mjs 不执行任何操作。
然后从使用方仓库根目录运行两个确定性增强脚本(两者均可幂等运行;它们会根据条目的 branch: frontmatter 匹配条目,并保留合并后字段为空):
node skills/changelog/scripts/set-affected-packages.mjs # writes affected_packages from the branch diff
node skills/changelog/scripts/add-links.mjs # rewrites bare issue IDs in the current branch's entry to Linear URLs
如果你将技能安装到了其他位置,请相应调整路径前缀。
两个增强脚本也支持 --check(别名为 --dry-run)——只读预览,会报告将要进行的更改但不会写入任何内容;如果条目已是最新状态则以 0 退出,需要重写则以 1 退出(风格类似 prettier 的 --check,因此 CI 可据此进行检查):
node skills/changelog/scripts/set-affected-packages.mjs --check # current branch's entry only
node skills/changelog/scripts/add-links.mjs --check # ALL entries in the changelog dir
默认情况下,两个增强器都按分支范围执行(R-603):不带参数运行 add-links.mjs 时,只会重写 branch: frontmatter 与当前 git 分支匹配的条目,因此编写新条目时不会反复改动其他已合并条目。仍有两种模式会扫描整个目录:--all(有意重写整个目录)和 --check/--dry-run(完整性检查,可因历史条目而以 1 退出)。使用 --check 确认目录中的条目都已完成增强;针对某个分支的单条目 PR,则使用默认模式。(git 不可用时,默认模式会退回到全量扫描。)
第 6 步——根据约定进行验证
这是检查关卡:
node skills/changelog/scripts/preflight-changelog-ci.mjs # optional: checks Node vs engines/.nvmrc, then pnpm install --frozen-lockfile
node skills/changelog/scripts/validate-changelog.mjs # validates frontmatter schema, filename format, field types, ISO timestamps, Breaking section, issue IDs
preflight-changelog-ci.mjs 是可选的,且仅适用于 pnpm——如果使用方仓库不使用 pnpm,请跳过。失败时,请停止并修复条目后再继续——不要将格式错误的条目交给发布流程。
独立运行与在发布流程中运行
- 独立运行(
/changelog)会执行第 1–6 步,然后报告结果,并将条目留在工作树中且不提交,供用户审阅和提交。它不会推送或创建 PR。 - 在发布流程中运行时,同样会在推送前执行这些步骤;之后发布流程会提交条目(
docs(changelog): <title>)、推送,并创建或更新 PR。它会将pr留空——后合并增强器会根据合并后的 PR 解析分支并填充此字段。
实现
变更日志生命周期所需的所有脚本都位于此捆绑包的 scripts/ 目录下,并可直接在 Node 上运行(无需 npm 依赖,也无需构建步骤)。这些脚本覆盖了此捆绑包负责的整个生命周期——编写(由此技能运行)以及合并后的最终处理/CI 逻辑(下文注释说明了该逻辑现在的运行位置)。每个脚本都支持 --help(显示用法,退出码为 0)和 --self-test(对纯逻辑进行离线冒烟测试);会写入文件的脚本还支持 --check/--dry-run(报告结果,不写入任何内容)。
编写——由此技能运行(/changelog 流程):
scripts/set-affected-packages.mjs— 根据分支差异写入affected_packages(仅适用于 monorepo 消费者;当affectedPackages关闭时不执行任何操作)。scripts/add-links.mjs— 将正文中的裸问题 ID 改写为 Linear URL。scripts/preflight-changelog-ci.mjs— 可选的 Node/锁文件 CI 一致性检查(pnpm)。scripts/validate-changelog.mjs— 根据约定验证条目。
合并后的最终处理和 CI 门禁——现在由 @rheged-studio/changelog-core 运行。
最终处理/丰富/完整性逻辑已提取到已发布的
@rheged-studio/changelog-core
软件包中(CLI:validate | enrich | finalise | set-affected-packages | add-links | backfill-commits | check-completeness)。仓库内的合并后丰富处理通过 shared-workflows 的 reusable-changelog-enrich.yml 运行(npm 目标使用 mode: finalise,部署目标使用 mode: enrich),该工作流会调用 changelog-core 并以 road-runner-bot[bot] 身份写回结果;CI validate 和完整性门禁则会调用 changelog-core validate/changelog-core check-completeness。这取代了旧版 release-orchestrator 内联最终处理步骤和已停用的每日 enrich-changelogs.yml 定时任务(R-801)——现在没有任何中央编排器或定时任务会运行这些逻辑。
以下对应的捆绑脚本是原始的零依赖实现。它们仍是已发布的技能源代码(并且仍会在此处接受 --help/--self-test 测试),因此使用者可以直接接入;但使用共享工作流的消费者获取这些逻辑的来源是 changelog-core,而非这些文件:
scripts/finalise-changelog.mjs— 在发布时为 npm 目标补充信息并标注版本。对于每条尚未完成最终处理的条目,它会通过gh/git查找已合并的 PR,填入合并后的字段(merged_at/commit/pr/stats,其中stats包含通过 PR commits API 获取的、不含合并提交的commits计数),将version标注为刚更新的package.json版本,并为裸 Linear ID 添加链接。它组合了lib/enrich.mjs(填入 PR 元数据)、lib/commit-count.mjs(获取不含合并提交的提交计数)和lib/stamp.mjs(标注版本)。scripts/enrich-changelog.mjs— 为 部署目标(octavo、shared-workflows)补充合并后信息。这些目标在发布流程中不会被检出,因此无法在发布时直接完成最终处理。它通过环境变量接口(BRANCH_NAME/MERGED_AT/MERGE_SHA/PR_NUMBER/ADDITIONS/DELETIONS/CHANGED_FILES)读取一个已合并 PR 的数据,根据branch:查找对应条目,并填入与最终处理脚本相同的合并后字段组(不含version,因为部署目标由自身的标签流程负责标注版本;也不含commits,因为补充信息流程不会获取该字段)。它是lib/enrich.mjs的轻量封装;只填充一次且具备幂等性,因此可安全地重复运行。若条目仍需补充信息,--check会以状态码 1 退出;--dry-run用于预览。scripts/check-changelog-completeness.mjs— CI 完整性检查:触发发布的 PR 标题(feat/fix/breaking)必须包含带日期的changelog/条目,否则构建会失败。scripts/backfill-commits.mjs— 一次性回填现有changelog/历史条目中的stats.commits(用于事后补充提交计数)。它通过gh查找每条记录对应的已合并 PR,只插入commits行(不重新序列化),并且具备幂等性;--dry-run用于预览。此脚本不属于编写或发布流程的一部分。
这些脚本共用 scripts/lib/ 下的辅助模块(changelog.mjs、derive-packages.mjs、
frontmatter.mjs、config.mjs、enrich.mjs、commit-count.mjs、stamp.mjs)。因此,这项技能本身只负责编写和验证,并将合并后字段留空;这些字段会在合并后由 changelog-core(通过
reusable-changelog-enrich.yml)填入,而不是由 /changelog 流程填入。
**采用者须知:**这些脚本的单元测试在
agent-skills仓库中维护(未随技能打包)。请参阅该技能的 README。