每次发版前最烦人的事情是什么写 changelog。翻一个月的 commit history对着一堆fix typo、update readme、wip、asdf这样的 commit message欲言又止。release-management 仓库里的 changelog 自动化模块解决的就是这个问题。为什么手动写 changelog 是浪费时间想象一个典型场景ops-transformer 要从 1.2.0 发到 2.0.0这两个月里仓库有 300 多次 commit。如果手动整理打开 git log从第一个 commit 翻到最后一个每次 commit 都要点进去看 diff判断是 feature 还是 fix把内容归类到不同 section检查有没有 breaking change 要特别标注反复确认有没有遗漏的重要改动这活儿熟练工也要干两个小时。而且人整理的东西容易有主观偏差比如觉得自己写的update比fix更重要就把它归到 New Features 里——其实只是改了变量名。自动化生成的基本原理changelog 生成的本质是从结构化的 commit message 里提取信息按版本聚合按类别分组。核心逻辑其实不复杂fromrelease_managementimportChangeLog# 从指定 tag 范围生成 changelogchangelogChangeLog.generate(repoops-transformer,from_tagv1.2.0,to_tagv2.0.0,# conventional commit 格式解析categories{feat:New Features,# feat: 开头的 commitfix:Bug Fixes,# fix: 开头的 commitperf:Performance,# perf: 开头的 commitdocs:Documentation,# docs: 开头的 commitrefactor:Refactoring,# refactor: 开头的 commit},# 过滤掉哪些类型的 commit 不出现在 changelog 里exclude[style,test,chore])print(changelog)输出的前提是 commit message 符合 Conventional Commits 规范比如feat(flash-attention): add v2 implementation supporting 32k context fix(moe-router): correct topk overflow when experts is odd perf(mc2-allgather): reduce communication overhead by 15% docs: update README for v2 migration guidefeat:后面括号里的 scope 会被保留下来用于标注是哪个子模块的改动。changelog 里会显示flash-attention: add v2 implementation...阅读体验好很多。自定义过滤规则怎么过滤噪音 commit自动生成有一个问题仓库里有很多没有意义的 commit比如依赖升级、CI 配置更新、merge branch 这些。直接放进 changelog 会显得很业余。# 定义过滤规则正则匹配排除噪音 commitchangelogChangeLog.generate(repoops-transformer,from_tagv1.2.0,to_tagv2.0.0,filters{# 排除所有依赖相关的 commitexclude_patterns:[r^chore(deps):,r^chore\(ci\):,r^style:,r^test:,rMerge branch,r^Update .*lock,],# 只保留超过 N 个字符的 commit message# 太短的 commit 往往是 typo fix 或者无关紧要的改动min_message_length:20,# merge commit 通常不包含实质内容exclude_merges:True,})有一个容易忽略的细节breaking change 不会自动标注。Conventional Commits 规范里 breaking change 要在 footer 里写BREAKING CHANGE:或者在 message 末尾加!:。但很多开发者不知道这个约定代码写完了才发现有个 API 不兼容。# 自动扫描 breaking changechangelogChangeLog.generate(repoops-transformer,from_tagv1.2.0,to_tagv2.0.0,# 扫描常见的不兼容模式breaking_patterns[r^BREAKING CHANGE:,rremove.*parameter,rrename.*argument,rchange.*return.*type,],# 识别到 breaking change 自动提升到 Breaking Changes sectionauto_breakingTrue)生成后人工 review 的几个检查点自动化生成之后人工 review 仍然必要但重点变了——不是从头整理而是检查生成结果有没有明显错误。我一般会过这几个点第一大功能有没有被漏掉。如果某个 commit 加了新的融合模式但在 changelog 里找不到那八成是被 filter 规则误杀了。去 commit history 里搜一下关键词确认是漏掉了还是确实被过滤了。第二分组是否合理。有时候同一个 commit 改了多个文件conventional commit 的 scope 只能标一个其他子模块的改动容易被忽略。这种情况要手动拆分成多条。第三语气是否一致。自动化生成的是add xxx和fix xxx但 changelog 作为一个对外文档应该统一人称和时态。我一般会用脚本做一次批量替换# 统一 changelog 语气第三人称、一般过去时changelogChangeLog.generate(...)normalizedchangelog.replace(add,Added).replace(fix,Fixed).replace(update,Updated)和 CI 集成每次 PR 合入自动更新最理想的使用方式是让 changelog 生成成为 CI 流程的一部分而不是发版前临时抱佛脚。# .github/workflows/changelog.ymlname:Changelog Updateon:pull_request:types:[closed]branches:[main]jobs:update-changelog:if:github.event.pull_request.merged trueruns-on:ubuntu-lateststeps:-uses:actions/checkoutv3-name:Generate changelog entryrun:|python -m release_management.changelog \ --repo ${{ github.event.pull_request.head.repo.name }} \ --sha ${{ github.event.pull_request.head.sha }} \ --output changelog_entry.txt-name:Create PR for changelog updateuses:peter-evans/create-pull-requestv4with:title:docs: update changelogbody-file:changelog_entry.txtbranch:changelog/${{github.event.pull_request.number}}这样每次 PR 合并都会自动生成一条 changelog entry后续发版的时候直接合并这些 entry 就行了changelog 内容早就准备好了。工具不是万能的最后说一个反直觉的点changelog 工具再好也解决不了根本问题——commit message 质量。如果团队里 commit message 写得很随意update、fix、wip满天飞那 changelog 生成出来也是一堆噪音。工具只是放大镜能放大好的规范也能放大乱规范。所以在用 release-management 的 changelog 模块之前先把 commit message 规范建起来。Conventional Commits 不难学团队里约定一个 scope 列表比如flash-attention、moe-router、mc2-allgather每次 commit 前花 30 秒想清楚这条 commit 改了什么——之后写 changelog 能省两小时。仓库在 https://atomgit.com/cann/release-managementchangelog 相关的 API 文档可以直接看源码里的changelog.py逻辑很清晰。