news 2026/9/25 12:41:42

OpenCodex 双通道发布列车(Release Train)实战:从 dev 同步到 npm dist-tag 收敛

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpenCodex 双通道发布列车(Release Train)实战:从 dev 同步到 npm dist-tag 收敛

【免费下载链接】opencodex

Universal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code

项目地址:https://gitcode.com/gh_mirrors/ope/opencodex
点击查看免费下载

本文围绕 opencodex 仓库在 2026-07-22 执行的一次真实发布列车记录展开,完整讲解其dev → preview → main → npm四层分支发布模型、版本号决策规则(为什么 2.7.32 被跳过而直接发布 2.7.33)、由 scripts/release.ts 驱动的五步执行协议,以及ci.yml+service-lifecycle.yml双门禁、GitHub Release 与 npm dist-tag 的最终收敛验证。读完你可以直接理解并复用这套"预览线 + 稳定线"的发布流程。

一、发布列车背后的分支模型

opencodex 的发布体系由四个状态层构成,每次发版都要让它们严格收敛:

层职责本次训练前状态
dev集成开发线,承载社区 PR 与修复提交29763560(CI success、sol 敌对评审 PASS、部署 readiness READY)
preview预览发布线,仅包含 dev 之上的"发布 bump 提交"26fd5ea9,即release: v2.7.32-preview.20260722(未实际部署的 bump)
main稳定发布线,是 preview 的祖先304a1eab(对应 npmlatestv2.7.31)
npm dist-tags对外发布通道latest=2.7.31、preview=2.7.29-preview.20260721

值得注意的是,本次训练开始时preview分支上已经存在一个名为v2.7.32-preview.20260722的 bump 提交:release.yml的 run 虽然是 success,但那次只是dry-run——npm 上根本没有2.7.32-preview版本,npmpreview通道仍停留在2.7.29-preview.20260721。这正是发布列车要解决的典型状态:"本地/分支上版本号已前移,但对外通道没有实际发布"。

关于 readiness 如何判定,可参见同一工作流的前置记录 030_deploy_readiness.md:它通过本地门禁(3431 个隔离测试通过、tsc零错误、lint/privacy/locale 全绿)、远程门禁(Cross-platform CI success)以及 sol 敌对评审三轮(最终 PASS、无残留部署阻塞项)三层证据,判定 dev 达到READY,才允许进入本次发布列车。

二、版本决策:为什么跳过 2.7.32 直接走 2.7.33

发布前首先要确定本次要发布的版本号,而这里存在一个真实的分叉点:

  • preview分支的package.json已经是2.7.32-preview.20260722;
  • 若再次执行npm version 2.7.32-preview.20260722,npm 会报no-change 错误(版本未变化,无法生成新的 bump 提交);
  • 同时2.7.32-preview.20260722属于"未部署版本"——npm、Git 标签、GitHub Release 三处都不存在该版本的任何发布产物。

因此决策是放弃 2.7.32 线,沿2.7.33 线推进:

  • preview发布2.7.33-preview.20260722(带日期戳的预览版);
  • main发布2.7.33(稳定版,2.7.32 stable 被跳过——因为它从未在任何通道部署过)。

这一决策背后其实是 scripts/version-line.ts 中一整套版本解析与推演逻辑:

  • 稳定版走nextStableRelease:基于稳定通道 tip 做 patch/minor/major 递增,并检查"是否存在更高 core 的 preview 阻塞当前 patch 线";
  • 预览版走nextPreviewRelease:稳定线确定 core 后,追加-preview.YYYYMMDD日期戳;若同 core 已有预览,则用.序号递增(如-preview.20260722.2),并强制拒绝"stamp 时钟回退";
  • 所有候选版本最终都要通过assertAboveGlobalFloor——即必须严格高于已发布的所有版本(稳定 + 预览),防止把已发布的旧版本重新推到通道顶端。

从源码结构看,这套"阻塞检查 + 全局地板"机制,正是为了避免 dev 分支版本线落后于 main、导致发布回归通道 tip 的隐患。

三、五步执行协议(scripts/release.ts 规则)

原文档给出了本次发布列车的执行顺序,共五步:

  1. preview 检出 + 合并 dev:在 preview 上合并 dev(本次 base 之后 dev 未改版本号,因此预期package.json无冲突)。
  2. preview 发版:在 preview 分支执行bun scripts/release.ts 2.7.33-preview.20260722 --publish完整链路为:preflight → bump commit → push → 等待ci.yml+service-lifecycle.yml绿 → dispatchrelease.yml→ watch 运行结果。
  3. main 发版:将 main 快进到 preview tip,然后在 main 上执行bun scripts/release.ts 2.7.33 --publish。
  4. dev 收敛:将 dev 快进到 main tip 并 push,本地 HEAD 回到 dev。
  5. 验证:npm view @bitkyc08/opencodex dist-tags --json核对 dist-tags,并确认三个分支 tip 收敛。

release.ts的完整用法(见 scripts/release.ts 头部注释)为:

bun scripts/release.ts <version> [--tag latest|preview] [--publish] bun scripts/release.ts --bump patch|minor|major [--tag latest|preview] [--publish] bun scripts/release.ts watch

其中--bump模式会自动从远端标签 + npm 通道解析下一个版本号;watch模式只观察最近一次 Release run。release.ts还有几个硬性约束值得注意:

  • 分支与 dist-tag 绑定:preview分支只能发布preview通道,main只能发布latest,--tag传错会直接报错退出;
  • 版本形态绑定:preview 分支必须使用带-preview.的预发布版本,main 必须使用无预发布后缀的稳定 SemVer;
  • 工作区必须干净:git status --porcelain有任何输出都会中止。

3.1 preflight:发布前的五道本地关卡

每次release.ts运行(无论 dry-run 还是--publish)都会先执行完整的 preflight,按序为:

  1. release metadata preflight:assertUnusedReleaseVersion并行检查 npm 版本、远端 Git 标签(git ls-remote带 peeled 查询)与 GitHub Release 三处是否已存在同名版本,任一存在即拒绝;assertChannelVersionMovesForward保证候选版本严格高于当前通道 tip。
  2. dependency audit:bun run audit:high高危依赖审计。
  3. typecheck:bun x tsc --noEmit。
  4. test suite:bun test --isolate tests,并刻意与 CI 保持一致——把 Worker 密集的api-storage-policy*.test.ts、api-storage.test.ts、api-usage.test.ts从通用分片中剔除、单独隔离运行(源码注释明确记录了这个分组曾导致"CI 全绿但发布门禁失败"的教训,现在门禁与 CI 使用完全相同的分组)。
  5. privacy scan:bun run privacy:scan。

3.2 bump、push 与受保护分支的 SSH 钥匙

preflight 通过后,release.ts只修改package.json(npm version <v> --no-git-tag-version,版本标签由 Release 工作流在 npm 发布后创建),然后git add package.json && git commit -m "release: v${version}"并 push。

这里有一个关键设计:main和preview都配置了要求 PR 的分支保护 ruleset,管理员 bypass 是bypass_mode: "pull_request"——这只能合并 PR,不能直接 push(源码注释记录 v2.29.0 的发布正是死在这里)。因此 release.ts 提供了一个专门的写权限 deploy key 通道:

  • 设置OCX_RELEASE_SSH_KEY指向注册为该 rulesetDeployKeybypass actor 的私钥,仅 bump push 这一次改用 SSH 目标 push(通过GIT_SSH_COMMAND注入-o IdentitiesOnly=yes,防止 ssh 先尝试主维护者身份导致再次被拒);
  • OCX_RELEASE_SSH_REPO可覆盖目标仓库(发布 fork 时使用),且必须是非凭证形态的ssh://或git@host:owner/repo;
  • 源码中大量校验(拒绝带 userinfo 凭证的 HTTPS remote、拒绝 scp-like 密码形态、对 key 路径做 shell 引号转义)都是为了一个目标:fail-closed——进程即使中途崩溃,分支保护也从未被削弱,撤掉一把 key 就能关闭通道而不触碰仓库配置。

未设置OCX_RELEASE_SSH_KEY时,push 行为与普通推送完全一致,对贡献者/CI 克隆无影响。

3.3 双门禁等待与 dispatch

push 完成后,release.ts依次等待两个工作流在发布 commit 上变绿:

  • Cross-platform CI(ci.yml):轮询 20 分钟、10 秒间隔,成功或失败都会立即返回;
  • Service lifecycle(service-lifecycle.yml):因为 bump 必然触碰package.json(service-lifecycle 的触发路径),而release.yml的 service gate 要求同一 SHA 上已有成功的 Service lifecycle run,必须先等它,避免 dispatch 竞态。

等待之后还有一个live-remote 守卫:dispatch 前通过git ls-remote重新读取远端分支的真实 head,一旦发现"等待 CI 期间分支被移动"(本地 remote-tracking ref 可能已过期),立即中止发布——因为workflow_dispatch解析的是可变分支,这是拒绝发布未经审计新提交的最后机会。

随后执行 dispatch:

gh workflow run release.yml --ref <branch> \ -f version=<version> -f tag=<tag> \ -f expected-sha=<releaseSha> -f dry-run=<bool>

expected-sha参数把"必须发布哪个不可变 commit"传给 Release 工作流(release.yml 会在发布前校验版本与分支是否匹配,若分支移动则失败)。最后waitForReleaseWorkflowRun找到对应 SHA 的 run 并gh run watch --exit-status --interval 10跟踪到结束。

3.4 dry-run 与 --publish 的二阶段语义

release.ts的默认是dry-run(dryRun = !args.includes("--publish")),但 dry-run 也会真实 bump、commit、push,目的是让 Release 工作流在真实发布 commit上完整演练。因此对同一版本二次执行--publish时,package.json已处于目标版本,脚本会将其视为"已满足"(跳过npm version的 no-change 错误),commit 也已存在则直接复用——这正是 dry-run 后能无缝转正的原因。

四、本次训练的实际结果

按上述协议执行后的最终状态(均来自原文档记录,全部为 2026-07-22 的实况):

  • preview 线:dev(29763560)合并进 preview(9a140a20)→release.ts 2.7.33-preview.20260722 --publish→ bump 提交6c112450→ci.yml+service-lifecycle.yml双绿 → Release run29904313855success → npmpreview=2.7.33-preview.20260722,GitHub Releasev2.7.33-preview.20260722。
  • main 线:main 快进到 preview tip(6c112450)→release.ts 2.7.33 --publish→ bump 提交6d6bef8b→ 双门禁 success → Release success → npmlatest=2.7.33,tagv2.7.33。
  • 收敛:dev 快进到 main tip(6d6bef8b)并 push,preview 也 push 到6d6bef8b——远端dev/preview/main三个分支同一 SHA6d6bef8b,本地 HEAD 回到 dev,工作树干净。
  • 最终 npm dist-tags:latest=2.7.33、preview=2.7.33-preview.20260722。

dev 分支 push 后按协议惯例还确认了 dev-branch 的 CI run 结果(尽管同一 SHA 在 main 上已绿,仍按规矩单独确认 dev run)。

五、可复用的发布核对清单

综合原文档与源码,一次完整的 opencodex 发布列车可归纳为以下核对点:

  1. readiness 前置:dev 通过本地门禁(isolate 测试 + tsc + lint/privacy/locale)、远程 Cross-platform CI、敌对评审三层判定,参见 030_deploy_readiness.md。
  2. 版本决策:检查 previewpackage.json与 npm 实际 dist-tags 的差异;未部署的 bump 直接升线(本次即跳过 2.7.32 走 2.7.33);preview 用X.Y.Z-preview.YYYYMMDD形态,main 用稳定 SemVer。
  3. 顺序执行:preview 合并 dev → preview 发版 → main 快进 + 发版 → dev/preview 收敛到同一 SHA →npm view @bitkyc08/opencodex dist-tags --json终验。
  4. 门禁确认:ci.yml与service-lifecycle.yml必须在同一发布 commit 上双绿;dispatch 必须携带expected-sha;发布后核对 GitHub Release tag 与 npm dist-tag 一一对应。

参考文件

  • 发布列车执行记录(本文主体):040_release_train.md
  • 部署 readiness 判定:030_deploy_readiness.md
  • 发布辅助脚本:scripts/release.ts
  • 版本线与推演逻辑:scripts/version-line.ts
  • Release 工作流(dry-run 默认、dist-tag 选项、expected-sha守卫):release.yml
  • 双门禁:ci.yml、service-lifecycle.yml

【免费下载链接】opencodex

Universal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code

项目地址:https://gitcode.com/gh_mirrors/ope/opencodex
点击查看免费下载
上一篇:DeepLearnToolbox完整教程:如何在MATLAB中快速掌握深度学习算法
下一篇:终极Zotero检索引擎清单:一键提升学术研究效率300%

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 12:41:09

Atlas 300V 24G推理加速卡部署YOLO:从模型转换到性能优化

这两年只要跑AI推理任务的圈子&#xff0c;几乎绕不开一个名字&#xff1a;atlas。周围人也经常问&#xff1a;atlas 300v 24g 是运算加速卡吗&#xff1f;答案是肯定的&#xff0c;但它和你印象里的通用GPU加速卡不太一样。这篇文章我就结合自己实际部署YOLO的经验&#xff0c…

作者头像 李华
网站建设 2026/9/25 12:37:44

我与 AI 的“跨服聊天”:为了省那点 Token,我逼它学会了文言文

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 12:33:56

DeskcommCRM深度拆解:桌面端客户管理如何用沟通记录重塑销售流程

接手这个选题之前&#xff0c;我先说个现象&#xff1a;现在一提CRM&#xff0c;大家条件反射的就是一堆网页版SaaS&#xff0c;打开浏览器输入域名&#xff0c;登录之后看到一个花花绿绿的仪表盘。时间一长&#xff0c;通讯基本靠IM转发&#xff0c;客户资料散落在Excel、企业…

作者头像 李华