Mole Release Flow 详解:Tag 驱动的 V* 发布流水线、三条分发渠道与再发布避坑指南
本文以 Mole 仓库中的发布流程技能文档 .claude/skills/release-flow/SKILL.md 为主体,完整拆解 Mole CLI 的发布体系:从大写 V 前缀 tag 如何触发 release.yml 构建 macOS 双架构二进制并生成带 provenance 的 GitHub Release,到 Nightly、GitHub stable、Homebrew core 三条分发渠道各自的触发条件与自动化边界,再到精选 release notes 的手动跟进流程和已知发布陷阱。读完本文,你能够按仓库现行规范独立完成一次 Mole 版本的发布前检查、打 tag 发布、资产验证、脚本通道自更新冒烟测试与 release notes 发布。
发布架构总览:Tag 驱动 + 三条分发渠道
Mole 的发布是纯粹的 tag 驱动流程。release.yml 工作流监听 'V*'(大写 V)tag push 事件,在 macOS 上构建 amd64 和 arm64 二进制,生成 SHA256SUMS,附加构建溯源(build provenance),创建一个不带 notes 的 GitHub Release,随后自动向 Homebrew core 发起 PR。release notes 是工作流之后的手动跟进动作。
技能文档将仓库的三条分发渠道定义如下:
| 渠道 | 发布内容 | 触发条件 | 自动化程度 |
|---|---|---|---|
Nightly(mo update --nightly) |
通过 install.sh 安装 main HEAD |
任意 commit push 到 main |
全自动;不涉及 tag 和 release |
| GitHub stable release | amd64/arm64 二进制 + SHA256SUMS |
push 大写 V 前缀 tag |
release.yml 构建并创建 release;精选 notes 为手动跟进 |
| Homebrew core | 版本更新 PR 提交到 Homebrew/homebrew-core |
同一个 V* tag 工作流 |
PR 自动发起;合并时机由上游决定 |
文档同时规定了一条人机协作纪律:在任何 release 相关任务开始时,必须先复述本次会触及哪些渠道、不会触及哪些渠道,并与 maintainer 确认后再行动。渠道范围只能由 maintainer 指定,禁止自行推断。 这条纪律防止了"顺手把 Nightly/Homebrew 也带上了"这类越界操作。
工作流 release.yml 的源码级拆解
结合 .github/workflows/release.yml 的实际内容,可以确认技能文档描述的每个环节都有对应实现:
1. 大小写敏感的 tag 过滤与版本一致性校验
工作流入口仅匹配 V* 前缀(见 release.yml#L3-L6)。tag push 后,Verify release tag matches source version 步骤会用 sed -n 's/^VERSION="\([^"]*\)"$/\1/p' mole 从入口脚本提取版本号,再断言 tag == "V" + 源码版本(见 release.yml#L29-L38)。当前仓库入口脚本 mole 中的版本声明为 VERSION="1.53.0"(mole#L57),因此下一次 stable 发布必须先把这一行 bump 到目标版本,否则 tag 校验会直接失败——这正是预检清单第 1 条 grep '^VERSION=' mole 的工程含义:本地 grep 与 CI 的 sed 校验针对同一行源码。
2. 双架构构建:纯 Go 交叉编译
构建矩阵在 macos-latest 上分别执行 make release-amd64 和 make release-arm64。这两个 Makefile 目标(见 Makefile#L60-L70)刻意保持纯 Go 构建:CGO_ENABLED=0 加 GOOS=darwin 交叉编译,链接参数 -s -w 去符号表。源码注释给出了原因:保持 pure-Go 是为了防止 macOS SDK 在 release runner 上通过 cgo 抬升 Mach-O 的最低 OS 版本。构建完成后还会执行 scripts/check_release_minos.sh 校验二进制的最小 OS 版本约束。
3. SHA256SUMS 与构建溯源
release job 汇总两个矩阵产物后,用 sha256sum 对所有资产生成 SHA256SUMS(release.yml#L90-L99),随后通过 actions/attest-build-provenance 对 analyze-darwin-*、status-darwin-*、binaries-darwin-*.tar.gz 与 SHA256SUMS 统一附加 provenance(release.yml#L101-L108)。
这一步在技能文档里被赋予了发布阻断级的重要性:安装器是 fail-closed 的,一个缺少可读 SHA256SUMS 资产的 release 会让所有安装与 mo update 按设计中止——"missing checksums file is a release blocker, not a cosmetic gap"。仓库中对应的行为测试见 tests/install_checksum.bats。
4. 创建无 notes 的 Release + 自动 Homebrew PR
Create Release 步骤显式设置 generate_release_notes: false、draft: false、prerelease: false(release.yml#L110-L118)。这就是"notes 必须在后续步骤用 gh release edit 补上、且绝不能用 create"的根因。
紧随其后的 update-homebrew-core job 则实现了文档表格中"Automatic PR"一栏:它下载 tag 的源码 tarball 计算 sha256,在 fork 上仅改写 formula 的 url 与其后的 sha256(bottle 块不动,因为 Homebrew 的 check-bottle-block CI 会拒绝改动它的 PR),复用既有分支则拒绝覆盖,最后用 Homebrew 模板正文创建或 PATCH 更新 Homebrew/homebrew-core PR,并轮询确认 PR 处于 open 状态(release.yml#L120-L269)。文档因此强调:Homebrew 是独立的下游闸门,只能在 core formula 更新后才验证,绝不能把脚本通道冒烟当作 Homebrew 就绪的证明。
发布前预检清单(Pre-flight Checklist)
技能文档给出的六条预检必须全部通过:
grep '^VERSION=' mole匹配新版本号;- SECURITY_AUDIT.md 首行反映新版本号与日期;
git status -s为空,或只包含有意暂存的发布工作;git log origin/main..HEAD --oneline只包含你打算随版本发布的 commit;./scripts/check.sh --format与MOLE_TEST_NO_AUTH=1 MOLE_TEST_JOBS=2 BATS_FORMATTER=tap ./scripts/test.sh均以 0 退出;go test ./cmd/...与make build均通过。
前两条对应仓库中真实存在的文件:scripts/check.sh(格式检查)与 scripts/test.sh(Bats 套件入口,BATS_FORMATTER=tap 输出机器可读结果,MOLE_TEST_NO_AUTH=1 关闭需要授权的测试)。关联的 release-notes 技能还补充了一句关键判据:"If any fail, stop. The notes can wait; a bad release tag cannot."——预检失败时 tag 不能推,notes 可以等。
打 Tag 与发布:命令、资产验证、脚本自更新冒烟
打 tag 的命令序列
git push origin main
git tag V<version> # 大写 V;release workflow 忽略小写 v
git push origin V<version>
等待工作流完成后,在任何公告之前先验证 release 资产:
gh release view V<version> --json assets --jq '.assets[].name'
结果必须同时列出两个架构的二进制和 SHA256SUMS。如前所述,由于安装验证是 fail-closed 的,缺少 checksums 文件意味着该 release 对脚本通道用户而言根本不可用。
脚本自更新冒烟(Script self-update smoke)
在发布 notes 或对外公告之前,技能文档要求执行一次脚本通道自更新冒烟:通过脚本渠道安装上一个 stable 版本,运行 mo update,确认 mo --version 输出候选版本。其原理在"发布陷阱"一节有呼应:脚本安装的客户端执行的是新 tag 里的 install.sh,因此这是唯一一条能真正验证存量用户升级路径的闸门——预检套件在 release 存在之前无法覆盖它。若冒烟失败,必须在任何人被告知"可以更新"之前先撤回 release(见下文"撤回并重新发布")。
精选 Release Notes:职责边界与格式纪律
职责边界:flow 管节奏,notes 管格式
release-flow 技能明确声明,精选 notes 流程(双语格式、用 gh release edit 而非 create、致谢块、六连 reaction)归 .claude/skills/release-notes/SKILL.md 所有;.agents/skills/release-notes 是指向该规范目录的 symlink(供 Codex 发现),其 Codex 专用调用策略在 agents/openai.yaml 中——文档特别警告不要用复制的镜像替换这个 symlink。flow 技能只保留引用,不复制格式细节,让 release-notes 技能保持 notes 格式的唯一事实来源。
从 release-notes/SKILL.md 的内容可以印证这套分工。发布动作是:
gh release edit V<version> --repo tw93/Mole \
--title "V<version> <CodeName> <emoji>" \
--notes-file <path-to-draft>
其"Format rules"一节列出的每条规则都注明"all are documented bugs that have shipped before"(每一条都是曾经真实上线过的事故),包括:
- 正文 h1 只有
Mole:版本号、代号、emoji 只进--title(如V1.45.0 Quiet 🤫这样的标题惯例),重复进正文标题此前已被明确否决; - 全篇禁用 em dash,改用逗号、句号、冒号、分号或括号;
- 默认不放赞助者名单,只致谢本周期的 issue 报告者与 PR 贡献者(排除
tw93和 bot); - 除标题的版本 emoji 外正文禁用 emoji,小节标题保持纯文本;
- 不放内联 PR 引用、不放内联 @handle 致谢,人与 PR 只进专门的 Thanks 块;
- 英文块在前、中文块在后,两个块编号顺序与条目数完全一致;
- 条目按用户感知影响排序,而非 commit 时间序:headline 级变化在前,内部安全加固、性能、bugfix 在后;
- 逐条验证 notes 中提到的命令在 HEAD 上真实存在——已删除的
mo check/mo doctor曾险些作为"新功能"写进 notes; - 事故/排障类说明只允许"一句症状 + 一条命令"。
仓库内 docs/release-notes/V1.42.0.md 保存了历史版本 notes 的成稿,可作为上述结构的对照样本。
仪式锚点(Ritual anchors)
flow 技能保留了三个流程锚点:起草前,把最新 stable release 的正文当作硬性格式模板读取(gh release view <latest-tag> --json body);标题按仓库惯例取"代号 + emoji";发布后运行技能自带脚本补六连 reaction 并复读确认:
bash .claude/skills/release-notes/scripts/post-reactions.sh V<version>
注意该脚本位于技能目录内,不在顶层 scripts/ 下。查看 post-reactions.sh 源码可以看到它的防御性:拒绝小写 v 前缀的 tag(第 13–16 行,与 release.yml 过滤规则同构),依赖 gh CLI,通过 release ID 依次 POST +1、laugh、hooray、heart、rocket、eyes 六个 reaction(第 29–32 行)。
发布专属陷阱(Release-only Pitfalls)
技能文档最后汇总的四条陷阱是本文的核心避坑清单,每一条都有仓库内的实现依据:
-
gh release create与工作流创建的 release 冲突:tag push 后 release 已存在,补 notes 必须用gh release edit,永远不能用create。依据见 release.yml#L110-L118 与 release-notes 技能"Publish"节的同一警告。 -
tag 前缀大小写敏感:
release.yml只过滤'V*',推一个v1.38.0不会触发任何构建。release-notes 技能更进一步:小写vtag 甚至可能指示一次打坏了的发布(botched tag)。 -
旧客户端从 release tag 而非 main 拉取
install.sh:自更新的 Mole 下载的是形如raw.githubusercontent.com/tw93/mole/V<tag>/install.sh的路径,而 tag 内容不可变。因此安装器/更新器 bug 只能通过新 tag 触达存量 stable 用户;修 main 只改变 Nightly,无法修复已发布的 stable 更新器。这条结论也解释了为什么"脚本自更新冒烟"必须放在新 tag 发布之后执行。 -
撤回并重新发布一个版本:完整步骤为
gh release delete V<old> --cleanup-tag(删除 release 与远端 tag)→ 删除本地 tag → 在推替代 tag 之前先关闭被取代的 Homebrew core PR 并附一行 supersede 评论(同一 formula 的 open PR 可能阻塞brew bump-formula-pr)→ bumpVERSION与 SECURITY_AUDIT.md → 提交release: V<new>→ 打 tag → 走正常发布流程。新的 Homebrew core PR 会随新 tag 自动重新生成。
文档末尾还给出交叉引用:当发布工作触及 Shell 代码或测试时,应阅读 .claude/skills/bugs/references/shell-and-test-pitfalls.md 了解 Bash 3.2 数组、heredoc 输入、mock 绕过与 CI runner 的怪癖——这与仓库测试中大量 Bash 3.2 兼容性用例(如 tests/uninstall_scan_bash32.bats)相呼应。
小结:一次标准发布的时间线
把上述内容串起来,Mole 一次 stable 发布的完整时间线是:
- 渠道确认:与 maintainer 复述本次触及/不触及的渠道;
- 预检:bump mole 的
VERSION与 SECURITY_AUDIT.md 首行,跑齐六条预检; - 打 tag:
git tag V<version>并推送,等待release.yml的 build → release → update-homebrew-core 三 job 完成; - 资产验证:
gh release view确认双架构二进制与SHA256SUMS齐全; - 脚本冒烟:旧版脚本安装 →
mo update→ 确认mo --version; - 补 notes:按 release-notes 技能格式起草,
gh release edit发布,跑六连 reaction 脚本并复读确认; - 下游观察:等待 Homebrew core PR 合并后再验证 brew 渠道,不手工重跑工作流。
这套流程的设计取向在源码中清晰可见:能用 CI 强制的(tag 与版本一致性、checksums、provenance、Homebrew formula 只改 url/sha)都在 release.yml 里失败即停;只能由人判断的(渠道范围、notes 措辞、reaction)则由两个技能文档以"单一事实来源 + 交叉引用"的方式约束,避免规则在多处漂移。
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