Switchyard发布工作流揭秘:从git tag到PyPI/crates.io的完整流水线
【免费下载链接】SwitchyardSwitchyard lets LLM applications route traffic across models and providers while preserving native OpenAI and Anthropic API compatibility - enabling flexible model selection, benchmarking, and cost/performance optimization.项目地址: https://gitcode.com/GitHub_Trending/switch/Switchyard
Switchyard 是一个让 LLM 应用跨多个模型与提供商路由流量的控制平面,同时保持 OpenAI 与 Anthropic 原生 API 兼容。那么这样一个 Rust 工作区 + Python 包双栈项目,是如何仅凭一条 git tag,就把 1 Python 包和 7 个 Rust crate 安全送达 PyPI 与 crates.io 的?本文揭秘其完整的发布工作流:零手动上传、版本号零失误、中途失败还能安全重跑。
🧭 发布流水线总览:一条 tag,两个注册表
Switchyard 的发布体系遵循「常规 CI 把关质量、tag 驱动正式出版、手动构建只产 artifact」的 OSS 标准路径,完整说明见 docs/internal/release_workflow.md:
| 触发方式 | 做什么 | 产物去向 |
|---|---|---|
| PR / 推送 main 分支 | 测试、lint、类型检查、Rust 检查、瘦身安装冒烟(.github/workflows/ci.yml) | 无,纯质量门禁 |
| 手动触发 dev 构建 | 构建 1 个或全套.dev版本 wheel | GitHub Actions artifact(仅 1 天保留期) |
推送vMAJOR.MINOR.PATCHtag | 完整发布校验 + 构建矩阵 + 正式出版 | PyPI + crates.io + GitHub Release |
这里藏着一个关键设计:PyPI 版本一旦上传事实上不可变更,所以正式发布只允许由根目录 tag 触发;而分支状态的手动构建绝不允许污染公共索引。版本号的唯一真相来源则是 pyproject.toml(Python 包)与 Cargo.toml(Rust 工作区),两者必须完全一致。
🔍 第一关:tag 与版本号三重绑定
推送 tag 后,publish工作流(.github/workflows/publish.yml)的第一个 job 就做一次「三重绑定」校验:
- 格式校验—— tag 必须严格形如
v数字.数字.数字,任何v0.2.0-rc1之类的变体都会被拒绝; - Python 绑定—— tag 必须与
pyproject.toml的version精确匹配(包版本0.2.0只能配v0.2.0); - Rust 绑定—— Cargo 工作区版本必须与 Python 包版本相等。
三重校验保证了「tag 即版本」,从源头杜绝了 tag 与代码版本错位这种经典事故。
🧪 第二关:Python 与 Rust 双语言质量门禁
tag 通过后,两条独立的检查流水线并行展开(.github/workflows/publish.yml):
- Python 矩阵:在 3.10 到 3.14 共5 个版本上逐一执行
ruff check与完整测试套件; - Rust 工作区:
cargo fmt --check格式检查、cargo clippy以-D warnings零容忍运行、cargo test --workspace全量测试。
任何一条失败都会让发布在出版之前终止——质量门禁全部位于「出版」上游,顺序不可逆。
📦 第三关:构建 7 件套发布物
校验通过后进入构建阶段,产出 1 个 sdist + 6 个平台 wheel:
源码包(sdist)用 maturin 构建 sdist 后,工作流还会解包检查LICENSE与NOTICE是否齐全,并在/tmp隔离目录做一次真实安装冒烟——确保用户pip install源码包时真的能装起来。
wheel 矩阵(6 平台)
| 平台 | 构建方式 |
|---|---|
| Linux x86_64 / aarch64 | manylinux2014 容器内构建,兼容主流 Linux 发行版 |
| macOS x86_64 / arm64 | 原生构建 |
| Windows x86_64 / arm64 | 原生构建 |
所有 wheel 均为abi3格式,一份 wheel 通吃多个 Python 版本。在可执行的平台上,工作流还会分别在Python 3.10 和 3.14两个端点做强制重装冒烟导入,验证switchyard、switchyard_rust及原生扩展均可正常加载(.github/workflows/publish.yml)。
🚀 第四关:零 Token 发布 PyPI(Trusted Publishing)
注意 PyPI 的包名是nemo-switchyard,而 Python 导入名与 CLI 仍叫switchyard。正式出版由publishjob 执行(.github/workflows/publish.yml):
uv publish --trusted-publishing always dist/*它不依赖任何存储的 API 密钥,而是使用PyPI Trusted Publishing:GitHub 凭 tag 事件 + 匹配的待发布出版方(项目nemo-switchyard、工作流publish.yml、环境pypi)自动换取临时凭证。凭证不落库、不轮换、不泄露——这是目前最安全的 PyPI 发布姿势。发布成功后,工作流还会顺手创建 GitHub Release。
📚 第五关:7 个 Rust crate 按依赖顺序发布
同一个 tag 还会把 Rust 工作区的 7 个 crate 依序送上 crates.io,顺序严格遵循依赖方向(.github/workflows/publish.yml):
switchyard-protocol(协议契约)switchyard-translation(格式转换)switchyard-libsy(可组合路由算法库)switchyard-llm-client(模型客户端)prefill-router(预填充路由)switchyard-runner(运行器)switchyard-server(独立服务端)
三个工程细节值得借鉴:
- 版本再确认:发布前用
cargo metadata核对 7 个 crate 的版本都与 tag 一致,防止漏改; - 等待索引同步:每发一个 crate 后轮询 crates.io 索引(最长 30 × 10 秒),确认它可见后才发布依赖它的下一个;
- 幂等可重跑:若某 crate 已存在则直接跳过。因此中途失败时,只需在 GitHub 上点击Re-run failed jobs,已成功发布的 crate 不会被重复推送。
🛠️ 番外:不发 PyPI 的 dev 构建
想在正式切 tag 之前验证发布矩阵?publish.yml提供了两个手动开关(docs/internal/release_workflow.md):
| 开关 | 效果 |
|---|---|
build_dev_artifact = true | 仅构建 1 个 Linux x86_64 dev wheel,artifact 保留 1 天,随后下载回来核对Name/Version元数据 |
build_dev_matrix = true | 构建完整 sdist + wheel 矩阵,仅作为 artifact 保存,绝不发布 |
dev 版本号遵循 PEP 440 的.dev规范(如0.0.1.dev0),由 scripts/release/set_dev_wheel_version.py 打戳到pyproject.toml,本地也能预览:
python scripts/release/set_dev_wheel_version.py 0.0.1.dev0 --print-version(提示:除非发布流程明确要求,不要把打戳后的元数据提交回仓库。)
💡 核心要点速记
- 3 处版本号强绑定:git tag ==
pyproject.toml== Cargo 工作区版本,任何一处不符立即失败; - 2 种发布凭证策略:PyPI 用 Trusted Publishing(零密钥),crates.io 用
CARGO_REGISTRY_TOKEN仓库 Secret; - 6 平台 wheel + 5 个 Python 版本测试,全部通过才允许出版;
- 失败可恢复:crate 发布幂等设计 + GitHub「Re-run failed jobs」,成功步骤不重跑;
- 版本记录:每个正式版的变更说明统一沉淀在 CHANGELOG.md,遵循 Keep a Changelog 与语义化版本规范。
整套流水线的精髓一句话:让「出版」成为整条链路中唯一不可逆的动作,它之前的每一步都是可重复、可验证、可失败的。对任何同时维护 Python 与 Rust 双栈的项目来说,这套从 tag 到 PyPI/crates.io 的完整发布工作流都值得直接抄作业。
【免费下载链接】SwitchyardSwitchyard lets LLM applications route traffic across models and providers while preserving native OpenAI and Anthropic API compatibility - enabling flexible model selection, benchmarking, and cost/performance optimization.项目地址: https://gitcode.com/GitHub_Trending/switch/Switchyard
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考