Traefik 版本发布准备流程详解:/release 技能的分支策略、git-cliff 变更日志生成与 PR 约定
2026/9/7 3:11:04 网站建设 项目流程

Traefik 版本发布准备流程详解:/release 技能的分支策略、git-cliff 变更日志生成与 PR 约定

【免费下载链接】traefikThe Cloud Native Application Proxy项目地址: https://gitcode.com/GitHub_Trending/tr/traefik

Traefik 仓库将版本发布准备(Preparing a release)沉淀为一个可被 Claude Code 直接调用的技能(.claude/skills/release/SKILL.md),通过/release <new-tag>一键完成“判定发布类型 → 预检 → 建分支 → 生成 changelog → 提交推送 → 开 PR”的完整流程。读完本文,你将掌握 Traefik 三类发布(patch、minor RC1、RC2+)的分支与上一版本 tag 推导规则、git cliff与 cliff.toml 的分组机制,以及发布分支命名、提交信息与 PR 标签的完整约定,并了解 PR 合入后 .github/workflows/release.yaml 如何自动构建并发布多平台二进制。

1. 技能概览:调用方式与发布类型判定

该技能以标准 frontmatter 声明:name: releasedescription: Prepare a Traefik release (patch, minor RC1, minor RC2+, major RC) — generates changelog, bumps versions, commits, pushes, opens PR,并标记user-invocable: true。调用形式为:

/release <new-tag>

文档给出的示例:

  • /release v2.11.51— patch release
  • /release v3.8.0-rc.1— minor RC1(从 master 出发)
  • /release v3.8.0-rc.2— minor RC2+(从 v3.8 分支出发)
  • /release v4.0.0-rc.1— major RC1(从 master 出发)

1.1 解析 tag:Step 1

技能的第一步(Parse tag and detect release type)从NEW_TAG中提取以下变量:

  • MAJORMINORPATCH,以及RC_NUM(非 RC 时为 0)
  • IS_RC:tag 包含-rc.时为 true
  • IS_RC1RC_NUM == 1时为 true

发布类型与分支、上一 tag(Prev tag)的对应关系如下表(直接继承自文档):

类型示例分支 (BRANCH)Prev tag 判定方式
Patchv2.11.51v{major}.{minor}最后一个v{major}.{minor}.*正式版 tag
RC1v3.8.0-rc.1master最后一个v{major}.{minor-1}.0-rc.*ea.*tag
RC2+v3.8.0-rc.2v{major}.{minor}v{major}.{minor}.0-rc.{RC_NUM-1}

随后设置BRANCHRELEASE_BRANCH=prepare-release-${NEW_TAG},即发布准备分支统一采用prepare-release-<tag>命名。

PREV_TAG的探测命令:

  • Patch

    git tag --sort=-version:refname | grep "^v${MAJOR}\.${MINOR}\." | grep -v "^${NEW_TAG}$" | grep -v "\-rc\." | head -1
  • RC1

    git tag --sort=-version:refname | grep -E "^v${MAJOR}\.$(( MINOR - 1 ))\.0-(rc|ea)\." | head -1

    注意这里同时匹配-rc.-ea.(early access)tag,用于兜底上一个 minor 没有 RC 而只有 EA 版的场景。

  • RC2+:直接构造v${MAJOR}.${MINOR}.0-rc.$(( RC_NUM - 1 )),无需查询。

PREV_TAG为空,技能会停下来询问用户:“Could not auto-detect previous tag. What is the previous tag?”,避免在错误区间上生成 changelog。

1.2 cliff.toml 如何决定 CHANGELOG 的结构

cliff.toml 是 git-cliff 的配置,它决定了第 6 步 changelog 输出的最终形态:

  • conventional_commits = falsefilter_unconventional = false:Traefik 不采用 Conventional Commits 规范,条目分组完全依赖PR 标签而非提交前缀。

  • commit_parsers先过滤噪音:带area/infrastructure标签的 PR、消息以Prepare release开头的提交(即上一次发布准备产生的提交,避免自我引用)、merge commit 全部跳过;剩余 PR 按标签分组到四个 section:

    PR 标签分组(CHANGELOG 中的 section)
    area/documentationDocumentation
    kind/bug/fixBug fixes
    kind/enhancementEnhancement
    其他(.*Misc

    分组值中的<!-- 0 --><!-- 1 -->等 HTML 注释用于控制 section 的排序,最终在 CHANGELOG.md 中呈现为Bug fixes:/Enhancement:/Documentation:/Misc:

  • extract_areas模板宏会从 PR 标签中提取**[area]**前缀:只取area/platform/前缀的标签,去掉area/provider/area/middleware/前缀后合并输出,且排除以documentation结尾的标签。例如 PR 标签为area/middlewarekind/bug/fix时,条目会渲染成**[middleware]** Fix panic in retry middleware with Websockets ([#13520]… @juliens)——这正是 CHANGELOG.md 中每个条目的实际格式。

  • [git]部分:tag_pattern = "v3\\.7.*"限定 changelog 版本头只匹配当前主线 v3.7 系列 tag,ignore_tags = "v2\\..*"忽略 v2 遗留 tag;[remote.github]指定owner = "traefik"repo = "traefik",并以.git/cliff-cache缓存 PR 远程数据(commit_range = true启用按 tag 区间查询)。也就是说,git-cliff 在生成时会访问 GitHub API 拉取 PR 标题、编号与标签,这也是 Step 2 要求导出GITHUB_TOKEN的原因。

  • 版本头模板渲染为## vX.Y.Z (YYYY-MM-DD)All Commits对比链接,与 CHANGELOG.md 现存条目的格式一致。

2. 预检清单(Step 2):快速失败与清晰报错

在动任何文件之前,技能按顺序执行 6 项检查(fail fast, clear messages):

  1. 当前分支git branch --show-current必须等于BRANCH。否则报错:Error: must be on branch ${BRANCH}, currently on <current>.
  2. 发布分支不存在git branch --list ${RELEASE_BRANCH}必须为空,否则:Error: branch ${RELEASE_BRANCH} already exists.
  3. 与上游同步:先git fetch upstream,再git rev-list HEAD..upstream/${BRANCH} --count。若计数大于 0:Error: branch is N commits behind upstream/${BRANCH}. Run: git pull upstream ${BRANCH}
  4. CODENAME(发布代号):读取 .github/workflows/release.yaml,提取CODENAME:后的值;若缺失则询问用户当前发布代号。当前仓库中该值为CODENAME: langres,位于 workflow 的env:段,PR 正文与发布流程都会引用它。
  5. GITHUB_TOKEN:优先使用已设置的$GITHUB_TOKEN,否则执行gh auth token获取,并导出供 git-cliff 使用(对应 cliff.toml 中[remote.github]的远程查询需求)。
  6. Fork 远端:通过git remote -vgh api user --jq .login找出 push URL 中包含自己 GitHub 用户名的 remote(即自己的 fork);若有歧义则询问 “Which remote is your fork?”

全部通过后,技能打印确认摘要并要求用户输入y继续:

Release type: <Patch | Minor RC1 | Minor RC2+ | Major RC1> New tag: ${NEW_TAG} Prev tag: ${PREV_TAG} Branch: ${BRANCH} → ${RELEASE_BRANCH} Codename: ${CODENAME}

3. 建分支与 RC1 专属操作(Step 3–5)

3.1 创建发布分支

git checkout -b ${RELEASE_BRANCH}

3.2 RC1 专属:升级文档中的版本号

仅 RC1 执行。先计算OLD_MINOR=v${MAJOR}.$(( MINOR - 1 ))NEW_MINOR=v${MAJOR}.${MINOR},然后用seddocs/下所有 git 跟踪文件(排除构建产物docs/dist/)中的${OLD_MINOR}批量替换为${NEW_MINOR}

git ls-files docs/ | grep -v '^docs/dist/' | xargs sed -i '' "s/${OLD_MINOR}/${NEW_MINOR}/g"

同时更新cmd/traefik/traefik.go——该文件包含带版本号的文档 URL。从源码看,cmd/traefik/traefik.go 第 103 行有一条日志引用的https://doc.traefik.io/traefik/v3.7/migrate/v3/…迁移指南链接正是此类“版本绑定字符串”,RC1 时需要随主线小版本一起滚动,保证新版本二进制提示的用户指向对应大版本的文档。

技能随后展示改动文件列表并进入Pause 1a(“Review the version bump changes in your editor. (y to commit)”),确认后再提交:

git add $(git ls-files docs/ | grep -v '^docs/dist/') cmd/traefik/traefik.go git commit -m "Bump documentation references from ${OLD_MINOR} to ${NEW_MINOR}"

3.3 RC1 专属:更新 CODENAME

询问用户 “What is the new codename for ${NEW_MINOR}?”,然后修改 .github/workflows/release.yaml 中CODENAME:行的值。经Pause 1b确认后提交:

git add .github/workflows/release.yaml git commit -m "Update release codename to <new_codename>"

4. 变更日志:git-cliff 生成、排序与入库(Step 6–7)

4.1 生成

GITHUB_TOKEN=${GITHUB_TOKEN} git cliff --config script/release/cliff.toml --tag ${NEW_TAG} ${PREV_TAG}..${BRANCH}

区间取PREV_TAG..BRANCH(而非两个 tag),保证包含主干上尚未打 tag 的最新提交;--tag ${NEW_TAG}则让模板以新 tag 渲染版本头。

4.2 后处理规则(Process changelog output)

对 git-cliff 的原始输出施加两条规范化规则:

  1. 分节内按字母排序:带**[area]**前缀的条目按**[...]**内的标签文本排序;无标签的条目按整行文本排序,并统一放在带标签条目之后。
  2. 去掉分节内部的空行(分节与分节之间的空行保留)。

处理后的内容前置插入(prepend)到 CHANGELOG.md 顶部,随后展示新增块的前约 30 行供审阅,进入Pause 2(“CHANGELOG.md updated. Review in your editor, adjust if needed. (y to commit)”),确认后提交:

git add CHANGELOG.md git commit -m "Prepare release ${NEW_TAG}"

5. 推送与创建 PR(Step 8–9)

5.1 推送到 fork

Pause 3确认(“Ready to push branch ${RELEASE_BRANCH} to ${FORK_REMOTE}. (y to push)”)后:

git push ${FORK_REMOTE} ${RELEASE_BRANCH}

5.2 向 traefik/traefik 开 PR

Pause 4确认(“Ready to open PR against traefik/traefik:${BRANCH}. (y to open PR)”)后执行:

gh pr create \ --repo traefik/traefik \ --base ${BRANCH} \ --head ${GITHUB_USER}:${RELEASE_BRANCH} \ --title "Prepare release ${NEW_TAG}" \ --label "area/documentation" \ --label "size/S" \ --body "$(cat <<'PRBODY' ### What does this PR do? Prepare release ${NEW_TAG}. aka `${CODENAME}` ### Motivation To create a new release. ### More - [ ] Added/updated tests - [x] Added/updated documentation PRBODY )"

注意 PR 目标分支是BRANCH(patch/RC2+ 为维护分支如v2.11,RC1 为master),标题固定为Prepare release ${NEW_TAG},标签固定area/documentation+size/S;PR 正文会附上当前代号(如aka 'langres')。仓库中还保留了同构的 PR 模板 .github/PULL_REQUEST_TEMPLATE/release.md,内容即“Prepare release v{{.Version}}”格式。执行完毕后技能打印 PR URL,整个准备流程结束。

6. 发布 PR 合入之后:tag 触发的自动化流水线

发布准备 PR 合入并打上 tag 后,后续全部由 CI 完成。从 .github/workflows/release.yaml 可以看到:

  • 触发条件为push且 tag 匹配v*.*.*,且仅限traefik/traefik仓库本体;VERSIONgithub.ref_name
  • build-webui复用template-webui.yaml构建仪表盘前端产物(webui.tar.gz artifact);buildjob 在 17 个os/arch矩阵(linux-amd64/386/arm/arm64/ppc64le/s390x/riscv64、darwin-amd64/arm64、windows-amd64/arm64/386、freebsd-amd64/386、openbsd-amd64/386/riscv64)上分别执行go generate,通过go run ./internal/release <os>基于 .goreleaser.yml.tmpl 模板渲染出 goreleaser 配置(见 internal/release/release.go:按GOOS/GOARCH替换模板占位符并输出临时配置文件路径),再用 goreleaser 产出tar.gz/zip与校验和文件,以*-binariesartifact 形式保留 1 天。
  • releasejob 下载全部平台产物后,合并所有平台校验和到traefik_${VERSION}_checksums.txt,打包源码traefik-${VERSION}.src.tar.gz(排除.githubdist.idea等),以gh release create … --latest=false创建 GitHub Release(注意--latest=false:只有正式 tag 之外由维护者手动标记 latest,RC 不会被误标)。
  • 最后执行 script/deploy.sh:使用 secret 中的 SSH 私钥,向traefik/traefik-library-image仓库推送对应版本的官方 Docker 镜像更新提交与 tag。

7. 手工替代流程与参考文件

当 Claude Code 技能不可用时,script/release/README.md 提供了等价的手工流程,前置条件为:已安装git-cliffcargo install git-cliff或包管理器安装)、ghCLI 已认证、当前分支即发布分支且与上游同步。其三类操作与本技能一一对应:

  • Patch(如 v2.11.51)git fetch upstream && git checkout v2.11 && git pull upstream v2.11 && git checkout -b prepare-release-v2.11.51,然后export GITHUB_TOKEN=$(gh auth token) && git cliff --config script/release/cliff.toml --tag v2.11.51 v2.11.50..v2.11,前置插入 CHANGELOG.md(排序规则同第 4.2 节),git commit -m "Prepare release v2.11.51"后推送,PR base 为v2.11
  • Minor/Major RC1(如 v3.8.0-rc.1):在master上建prepare-release-v3.8.0-rc.1,先sed -i '' 's/v3\.7/v3\.8/g'批量替换docs/(排除docs/dist/)与cmd/traefik/traefik.go并单独提交,再更新release.yaml中的 CODENAME,最后以上一个 RC tag 为区间生成 changelog,PR base 为master
  • Minor/Major RC2+(如 v3.8.0-rc.2):等价于 patch 流程,仅分支为v3.8PREV_TAGv3.8.0-rc.1、git-cliff 区间为v3.8.0-rc.1..v3.8,且只改 CHANGELOG.md(不做文档版本替换、不改 codename)。

需要留意的适用前提:本文描述的流程以当前仓库状态为准——cliff.tomltag_pattern当前锚定为v3\.7.*主线,release.yamlCODENAME当前为langres,文档版本字符串为v3.7;切换到下一条主线(如 v3.8)发布 RC1 时,这些值会由维护者随发布节奏同步调整。

小结

Traefik 的发布准备被收敛为一套强约束的流程:prepare-release-<tag>分支命名、按发布类型精确推导PREV_TAG与目标分支、git-cliff 基于 PR 标签的 changelog 分组与排序规范化、以及固定格式的提交信息与 PR 模板。掌握/release技能的这九个步骤后,无论自动还是手工,都可以按照 script/release/README.md 与 .claude/skills/release/SKILL.md 对同一 tag 复现出完全一致的发布准备提交。

【免费下载链接】traefikThe Cloud Native Application Proxy项目地址: https://gitcode.com/GitHub_Trending/tr/traefik

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询