Kong 变更日志自动化实践:changelog 目录的工具链、生成流程与 PR 校验脚本
本篇围绕 Kong 仓库中的 changelog/README.md 展开,讲解 Kong 官方如何把"发版变更日志"从手工维护变成一套可重复执行的工具链:如何配置 changelog CLI 工具,如何用一条 make 命令自动生成版本变更日志并创建 PR,以及如何使用 verify-prs 脚本对比任意两个修订版本、找出缺少变更日志条目的 PR。读完本文,你可以完整复现 Kong 的变更日志生成与核对流程,并理解其 Makefile 各阶段与校验脚本的底层调用逻辑。
一、changelog 目录的结构约定
理解工具链之前,先看一下 changelog/ 目录的组织方式,这是整套流程的数据基础:
-
changelog/unreleased/kong/、changelog/unreleased/kong-manager/:尚未发布的变更条目。每个 PR 合入时附带一个.yml文件,记录该 PR 的变更描述。例如当前仓库中 unreleased/kong/add-cp-connectivity-metric-prometheus.yml:message: | **Prometheus**: Added gauge to expose connectivity state to controlplane. type: feature scope: Plugin -
changelog/<版本号>/kong/:某个版本发布后,unreleased下的条目被移入对应的版本目录。例如 changelog/3.9.0/kong/ 下共有 60 个.yml条目。 -
changelog/<版本号>/<版本号>.md:由工具从.yml条目自动汇编出的 Markdown 变更日志,如 changelog/3.9.0/3.9.0.md。 -
changelog/Makefile、changelog/create_pr、changelog/verify-prs:驱动整个流程的自动化脚本。
变更条目的字段格式由 changelog/changelog-template.yaml 定义:
message: # "Description of your change" (required)
type: # One of "feature", "bugfix", "dependency", "deprecation", "breaking_change", "performance" (required)
scope: # One of "Core", "Plugin", "PDK", "Admin API", "Performance", "Configuration", "Clustering", "Portal", "CLI Command" (optional)
其中 message 必填,type 必填且取值限于六种(特性、缺陷修复、依赖升级、弃用、破坏性变更、性能优化),scope 可选并用于在生成的 Markdown 中做二级分组。
生成后的 Markdown 按 type 分节、再按 scope 分子节。以 3.9.0.md 为例,可以看到 ### Deprecations、### Dependencies、### Features 等章节,每个条目下面还附带对应的 GitHub Issue 链接(由 --github-issue-repo 参数生成)以及 Jira 链接(由 --with-jiras 参数生成)。根目录的 CHANGELOG.md 在发布时会把这些条目汇编进去,其 ## Unreleased 小节也明确指向 changelog/unreleased。
二、环境准备:changelog 二进制与 GITHUB_TOKEN
根据 changelog/README.md 的 Setup 章节,需要准备两样东西:
-
changelog二进制工具。从 Kong 官方的 gateway-changelog 项目 0.0.2 版本 release 下载(README 同时给出了 release-helper 中的脚本来源作为替代),并将其所在目录加入PATH:~ $ PATH="/path/to/changelog:$PATH" ~ $ changelog changelog version 0.0.2 -
GITHUB_TOKEN环境变量,供后续所有 GitHub API 调用鉴权:~ $ echo $GITHUB_TOKEN
注意版本约束:Makefile 中定义了 REQUIRED_VERSION := 0.0.2,check_version 目标会把 changelog -v 输出的版本号解析出来,若仍为旧的 0.0.1 会直接报错要求升级——这意味着 0.0.1 的旧二进制无法驱动本流程。
三、一条 make 命令生成变更日志 PR
3.1 命令与参数
在仓库的 changelog/ 子目录下执行:
~ $ pwd
/Users/zachary/workspace/kong/changelog
~ $ make BASE_BRANCH="release/3.6.x" VERSION="3.6.0"
README 对三个参数的解释:
BASE_BRANCH:变更日志 PR 所基于的远端分支,同时作为 merge base。本地仓库不要求检出在该分支上——Makefile 会自己git fetch --prune后基于origin/$(BASE_BRANCH)创建分支。VERSION:要生成变更日志 PR 的目标版本号。README 说明它"可以是任意字符串,只要你清楚自己在做什么(例如测试用途)"。DEBUG:显示调试输出,默认false,最终以--debug=$(DEBUG)传给changelog generate。
此外 Makefile 中还定义了默认值 BASE_BRANCH ?= release/3.6.x、VERSION ?= 3.6.0,以及固定的 OWNER_REPO := Kong/kong、UNRELEASED_DIR ?= unreleased。
3.2 Makefile 的五个阶段
all 目标按序执行五个阶段:check_tools check_version create_branch generate push_changelog create_pr。此外还有一个 no_pr 目标,跳过最后一步 PR 创建(只推送分支),适合只想本地验证生成结果、不立即开 PR 的场景。逐阶段看源码实现:
check_tools —— 依赖自检。REQUIRED_TOOLS := git changelog curl jq,用 command -v 逐个检查,任一缺失即 $(error ...) 终止;同时检查 GITHUB_TOKEN 是否设置。这对应 README 中"依赖 curl、jq 等工具,任一不满足则拒绝创建或更新变更日志 PR"的说法。
check_version —— 版本自检。前面提到的 0.0.1/0.0.2 判断逻辑。
create_branch —— 准备分支:
@git fetch --prune
@git submodule update --init --recursive
@git checkout -B $(BRANCH_NAME) $(ORIGIN_BRANCH)
其中 BRANCH_NAME := generate-$(VERSION)-changelog,例如 generate-3.6.0-changelog。checkout -B 保证该分支存在则重置、不存在则新建,起点是 origin/$(BASE_BRANCH)——这就是"本地不要求检出 base 分支"的原因。
generate —— 汇编 Markdown。核心命令(针对 kong 部分,kong-manager 同理):
changelog --debug=$(DEBUG) generate \
--repo-path . \
--changelog-paths 3.6.0/kong,unreleased/kong \
--title Kong \
--github-issue-repo Kong/kong \
--github-api-repo Kong/kong \
--with-jiras \
>> 3.6.0.md
几个参数值得注意:
--changelog-paths同时指向"版本目录 + unreleased 目录",即先把VERSION/kong下已有条目和unreleased/kong下全部新条目一起纳入汇编;--github-issue-repo决定条目中的 Issue/PR 链接指向哪个仓库(kong部分指向Kong/kong);- Makefile 中有个细节:
kong-manager部分的生成使用--title Kong-Manager且--github-issue-repo Kong/kong-manager(条目归属 kong-manager 仓库),但--github-api-repo仍统一为Kong/kong; - 只有当对应目录下确实存在
.yml文件时(nullglob判断)才执行生成,避免产出空标题。
push_changelog —— 移动条目并推送。这一步完成了"未发布条目已发布"的落库动作:
@mkdir -p $(VERSION)
@mv -f $(VERSION).md $(VERSION)/
@for i in kong kong-manager ; do \
mkdir -p $(UNRELEASED_DIR)/$$i ; mkdir -p $(VERSION)/$$i ; \
git mv -k $(UNRELEASED_DIR)/$$i/*.yml $(VERSION)/$$i/ ; \
touch $(UNRELEASED_DIR)/$$i/.gitkeep ; touch $(VERSION)/$$i/.gitkeep ; \
done
@git add .
@git commit -m "docs(release): generate $(VERSION) changelog"
@git push -fu origin HEAD
即:把 3.6.0.md 移入 3.6.0/ 目录,把所有 unreleased/{kong,kong-manager}/*.yml 用 git mv 迁入 3.6.0/{kong,kong-manager}/,留下 .gitkeep 保证空目录可被 git 跟踪,最后以固定提交信息 docs(release): generate <VERSION> changelog 提交并推送。
create_pr —— 创建或复用 PR,调用 create_pr 脚本。该脚本的逻辑很清晰:先查询 repos/<owner>/pulls?state=open&base=<BASE_BRANCH>&head=<BRANCH_NAME>,若已存在同 head 分支的 open PR 则打印 "Updated existing PR"(因为刚推送过新提交,PR 自动更新);否则调用创建 PR 接口,标题为 docs(release): generate <VERSION> changelog。这正好解释了 README 中"该命令会创建新的变更日志 PR 或更新已有 PR;若之后又有带 changelog 的功能 PR 合入,请再次重复执行该命令"的说明——重复执行时 unreleased 目录里积累了新条目,generate 会重新汇编并更新同一个 PR。
四、verify-prs:开发 PR 的批量校验脚本
verify-prs 是同一 README 的第二个工具。给定两个任意修订(tag、分支或 commit hash),它会列出:全部提交、全部 PR、缺少 changelog 条目的 PR,以及疑似未同步到 EE 的 CE PR(CE2EE 检查,实验性)。
4.1 用法与参数
~ $ changelog/verify-prs -h
README 给出的示例:
changelog/verify-prs --org-repo kong/kong --base-commit 3.4.2 --head-commit 3.4.3 [--strict-filter] [--bulk 5] [--safe-mode] [-v]
# 或
ORG_REPO=kong/kong BASE_COMMIT=3.4.2 HEAD_COMMIT=3.4.3 changelog/verify-prs
从脚本源码 changelog/verify-prs 整理完整参数表(比 README 更全):
| 参数 | 说明 |
|---|---|
-h, --help |
打印帮助信息并退出 |
-v, --verbose |
打印调试信息(开启 set -x) |
--org-repo <repo> |
GitHub 仓库,如 kong/kong 或 kong/kong-ee,也可用环境变量 ORG_REPO 指定 |
--base-commit <rev> |
起始修订(tag、分支或 hash) |
--head-commit <rev> |
结束修订 |
--strict-filter |
CE2EE 检查启用更严格过滤:关联的 EE PR 标题必须包含 cherry 关键词(源码中标注 Recommended) |
--safe-mode |
CE2EE 的交叉引用检查改为逐个串行执行,覆盖 --bulk(源码中标注 Recommended) |
--bulk N |
parallel 的并发任务数,默认 5;源码提示应结合 CPU 核数调整,过高可能触发 GitHub API 限速 |
硬性环境要求(check_tools 函数):必须导出 GITHUB_TOKEN;Bash 版本不低于 5;系统装有 jq 和 GNU parallel。另外注意两点源码中的保护逻辑:--bulk 必须为正整数,且 ≥ 8 时会打印"并发过高、可能触及 GitHub API rate limit"的警告。
4.2 执行流程与输出
脚本的 main 按四步执行:get_commits → get_prs → check_changelog → check_ce2ee,对应输出五类结果(控制台与本地文件双份):
- Commits:通过 GitHub Compare API(
repos/<repo>/compare/<base>...<head>)分页拉取全部提交,README 示例输出显示"number of commits: 280 / number of pages: 6"。 - PRs:将提交 SHA 作为搜索条件批量查询 Search Issues API(
repo:<repo> type:pr is:merged <sha...>),每个查询最多拼 17 个 SHA,避免搜索串过长。 - PRs without changelog:对每个 PR 调用
pulls/<n>/files接口取文件列表,若 PR 修改的文件中没有匹配changelog/unreleased/kong*/*.yml的条目,则列入"缺 changelog"名单——这正是与第三节的"每个 PR 附带.yml"约定形成闭环的核对手段。 - CE PRs without cherry-pick label / cross-referenced EE PRs:仅当
--org-repo kong/kong时执行。检查 PR 是否带cherry-pick kong-ee标签(issues/<n>/labels),或 timeline 中是否交叉引用了已合入的 EE 仓库 PR(issues/<n>/timeline);--strict-filter时额外要求 EE PR 标题含cherry。README 也明确提示:这只是实验性的快捷校验,"开发者可能并未遵循 CE2EE 规范",因此结果用于快速核对多数 PR 而非绝对判定。
所有结果写入 mktemp -d 创建的临时目录(commits.txt、prs.txt、prs_no_changelog.txt 等),脚本结尾会提醒"记得删除临时目录";异常退出时 cleanup trap 会自动清理,Ctrl-C 可随时中断。README 给出的运行示例(--base-commit 3.4.0 --head-commit 3.5.0)展示了完整的输出形态:统计信息 → PR 列表 → 三类待核实 PR 列表 → 五个结果文件路径。
五、实践建议与小结
- 执行时机:变更日志 PR 应在"功能 PR 陆续合入 base 分支之后"重复执行
make,因为每次执行都会把当时unreleased/下的全部条目汇编进 PR;新条目合入后再跑一次即可增量更新同一 PR。 - 可重复性:
create_branch使用git checkout -B、create_pr先查后建,整个流程幂等,可安全重试。 - 依赖清单:
git、changelog(≥0.0.2)、curl、jq、GITHUB_TOKEN;verify-prs额外要求 Bash ≥ 5 与 GNUparallel。 - 核对闭环:
unreleased约定(changelog-template.yaml)→ 生成(Makefile)→ 校验(verify-prs)构成一个完整闭环:约定决定.yml格式,生成把.yml汇编为版本 Markdown 并迁移文件,校验则回溯两个修订之间的所有 PR、揪出漏写条目的 PR。
这套流程让 Kong 每个版本的变更日志(如 3.9.0.md)既保持逐条可追溯到 PR/Issue/Jira,又无需发布时手工拼写——所有条目在开发阶段就随 PR 进入仓库,发布只是"汇编 + 移动文件"两步机械操作。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00