首页
/ Remotion 版本发布全流程解析:release Skill 清单背后的 set-version 与 publish 实现

Remotion 版本发布全流程解析:release Skill 清单背后的 set-version 与 publish 实现

2026-09-06 11:25:35作者:蔡丛锟

本文基于 Remotion 仓库内的智能体技能文档 .agents/skills/release/SKILL.md,完整拆解一次 Remotion 4.x 版本发布的标准作业流程:从环境校验、NPM 令牌创建、版本号递增、Lambda 烟雾测试,到多包并发发布、模板仓库同步与 Changelog 生成。读完后,你既能拿到一份可直接执行的发布检查单,也能理解每个步骤背后 set-version.tspublish.tsrelease-package-policy.ts 等源码的实现细节与失败中止条件。

一、release Skill 是什么:给 AI Agent 的发布检查单

.agents/skills/release/SKILL.md 是 Remotion 仓库为 AI 编码代理(如 Codex)定义的"发布新 Remotion 版本"技能,frontmatter 仅两行元信息:

---
name: release
description: Release a new Remotion version
---

正文是一条按顺序执行的操作清单。它的设计思路很典型:把人类发布工程师脑子里的"发布肌肉记忆"固化为可被 Agent 逐步执行的确定性步骤,每一步都明确了失败时的处理策略(立即中止 / 等待修复 / 等待人工审批)。整个流程可以归纳为七个阶段:

阶段 核心命令 失败策略
环境清理与校验 杀掉 turbo 进程、gcloud auth print-access-token 校验失败则不继续
NPM 凭证准备 npm login + 1Password 取密码/OTP + npm token create 人工完成 2FA
构建 bun ibun run build
版本号递增 bun set-version.ts <version> 退出码非 0 立即中止
Lambda 烟雾测试 cd packages/example && sh runlambda.sh 失败则中止
发布 NPM_CONFIG_TOKEN=<token> bun run releasebun run publishtemplates 模板发布失败则停止并上报
Changelog 生成 git log + gh CLI 发布前必须人工审批

二、阶段一:环境清理与三项前置校验

2.1 杀掉残留的 turbo 进程

清单第一步要求:以 SIGKILL 杀掉任何可能正在运行的 turbo 进程。仓库根 package.json 中大量脚本基于 Turborepo(如 "build": "turbo run make --no-update-notifier"),构建进程如果残留,可能占用 dist 产物或缓存目录,干扰发布构建,因此必须先清理。

2.2 校验 gcloud 登录态

发布流程涉及 Cloud Run 相关包的构建与部署验证,清单要求在开始发布前运行:

gcloud auth print-access-token >/dev/null

若失败则执行 gcloud auth login 后重新检查,检查不通过就不得继续发布。这是一个典型的"前置依赖显式断言"写法,避免流程进行到一半才发现云凭据过期。

2.3 Codex 环境的 Ruby 版本陷阱

这是清单中最有针对性的一条。Codex 可能以非交互式 shell 启动,PATH/usr/bin 排在 ~/.rbenv/shims 之前,导致即使用户终端用的是 Ruby 3.3.x,发布命令里调用 Ruby/Bundler 时实际走的是系统的 Ruby 2.6。修复方式是显式把 rbenv 的 shims 目录提到 PATH 最前:

PATH="$HOME/.rbenv/shims:$HOME/.rbenv/bin:$PATH" <command>

并用同样的方式验证 ruby --version 输出的是 rbenv 的 Ruby。

这条限制在仓库中有直接依据:packages/lambda-ruby/remotion_lambda.gemspec 声明了运行时依赖 json> 2.0.0)、rexml 等 gem,其中 json 2.x 系列要求 Ruby >= 2.7。若发布链路中 Ruby 回落到 2.6,lambda-ruby 包的 gem 解析会直接失败。从 gemspec 与 packages/lambda-ruby/package.json 的版本号(均为 4.0.520)一致也可看出:Ruby SDK 的 gem 版本与 npm 包版本是锁定的,同一次发布必须同时满足两个生态的要求。

三、阶段二:NPM 凭证准备(登录、取密、建令牌)

3.1 登录与二次认证

清单要求先运行 npm login(2FA 由人工在浏览器中完成),然后通过 1Password CLI 获取两样东西:

# 密码
op item get "Npmjs" --fields password --reveal --account remotiondev.1password.com
# 一次性密码 OTP
op item get "Npmjs" --otp --account remotiondev.1password.com

把密码存进 shell 变量(如 $PASSWORD),后面用管道喂给 npm。

3.2 创建专用发布令牌

令牌创建命令是清单里信息密度最高的一条,参数逐项解释:

npm token create \
  --name="PublishRemotionXXXXXX" \
  --packages "remotion" \
  --packages "create-video" \
  --packages-and-scopes-permission read-write \
  --bypass-2fa \
  --scopes "@remotion" \
  --otp=<otp>
  • --name 中的 XXXXXX 要替换成随机字符串,保证每次发布生成的令牌名唯一,便于事后审计与吊销;
  • --packages "remotion" --packages "create-video" 加上 --scopes "@remotion",把写权限收敛到核心包 remotioncreate-video 与整个 @remotion scope——即覆盖 monorepo 内所有以 @remotion/* 发布的包;
  • --bypass-2fa 配合 --otp 实现非交互式的 2FA 通过,因为 npm token create 过程中还需要输入密码,清单指定用 echo "$PASSWORD" | 管道传入;
  • 记好生成的 token 值,阶段六发布时要用。

四、阶段三:构建与版本号递增

4.1 安装与构建

bun i
bun run build

对照根 package.json 可见,build 实际是 turbo run make --no-update-notifier,即通过 Turborepo 对全部 workspace 包执行各自的 make 任务(仓库根 packageManagerbun@1.3.3)。

4.2 查询当前版本并递增

npm view remotion version        # 得到线上最新版本号
bun set-version.ts <version>     # <version> = 当前版本 + 1

清单明确:set-version.ts 退出码非 0 时,立即中止整个发布流程。以当前仓库为例,packages/core/package.json"version": "4.0.520",下一次发布就应传入 4.0.521

4.3 深入 set-version.ts:一个"递增版本号"命令到底改了什么

set-version.ts 并不只是改一行 version 字段,它是一条完整的"版本一致性"流水线:

  1. 分支断言:执行 git rev-parse --abbrev-ref HEAD,不在 main 分支直接抛错(set-version.ts#L29-L36)。

  2. 遍历 packages/ 下所有含 package.json 的目录(以及 cloudrun/container),跳过 FEATURED_TEMPLATES 中声明的模板目录——模板有独立的版本同步机制(见第六节);同时删除各包的 tsconfig.tsbuildinfo 旧构建信息。

  3. 发布策略过滤:对每个包调用 release-package-policy.tsshouldReleasePackage()。该策略维护了一个"v5 将移除的包"名单:

    export const packagesRemovedInV5 = [
      '@remotion/light-leaks',
      '@remotion/media-parser',
      '@remotion/starburst',
      '@remotion/webcodecs',
    ] as const;
    

    逻辑是:若发布主版本号 < 5,这些包照常发布;一旦进入 v5,它们将被排除出发布范围。配套地,moveRemovedDependenciesToDevDependencies() 会把其他包 dependencies 中指向这些包的依赖降级移入 devDependencies,避免用户项目继续安装即将停发的包。

  4. 写回 version 字段,并对非 private 包执行第 3 步的依赖调整。

  5. 同步 Agent 技能版本:遍历 packages/skills/skills/*/SKILL.md,在 frontmatter 中替换(或补写)version: <version> 行(set-version.ts#L99-L119)。这也是本文档所在目录的技能们会随版本一起更新版本号的机制。

  6. 同步插件清单:更新 agent-plugin/plugin.jsonagent-plugin/.codex-plugin/plugin.jsonclaude-code-plugin/.claude-plugin/plugin.jsonkimi-code-plugin/.kimi-plugin/plugin.json 中的 version 字段(set-version.ts#L121-L137)。

  7. 核心包版本固化:分别进入 packages/corepackages/media-parser 执行 bun ensure-correct-version.ts。以 packages/core/ensure-correct-version.ts 为例,它会:

    • package.json 读取新版本,生成 src/version.ts(导出 VERSION 常量,标注"Automatically generated on publish");
    • 重新执行 bun run makebun x tsgo -d
    • 验证产物:检查 dist/esm/version.mjsdist/cjs/version.js 中确实包含新版本号,否则 process.exit(1);并断言不存在的错误产物(如 dist/index.js)。

    这解释了清单中"退出码非 0 即中止"的原因——该脚本内置了产物级断言,退出码非 0 意味着构建产物与版本号不一致,此时发布必然出错。

  8. 重建与回归:清理 packages/studiodist,重新 bun run build,重新生成 Google Fonts 数据(packages/google-fonts),运行 packages/it-testssrc/monorepo 集成测试,构建 compositor(bun build.ts --all),最后再执行一次 bun i 刷新锁定依赖。

  9. 提交与打标签git add .、提交信息为 v<version> 的 commit,删除本地与远端可能存在的同名旧 tag 后重新打 v<version>set-version.ts#L173-L183),支持 --no-commit 参数跳过本步。

可以看到,清单里一句简单的"运行 bun set-version.ts <version>",背后是横跨全部 workspace 包的版本一致性校验与一次回归测试。

五、阶段四:Lambda 烟雾测试(发布前最后一道闸门)

cd packages/example && sh runlambda.sh && cd ../..

清单要求:此步失败则中止发布。packages/example/runlambda.sh 的内容是一次真实的"部署 + 渲染"端到端验证:

set -e
cd ../..
bunx turbo run make --filter=@remotion/lambda   # 构建 @remotion/lambda 包
cd packages/lambda && bun run makeruntime        # 构建 Lambda 运行时
cd ../example
bunx remotion lambda functions rmall -f          # 清空旧函数
bunx remotion lambda functions deploy --memory=2048 --disk=10000
bunx remotion lambda sites create --site-name=testbed-v6 --log=verbose --enable-folder-expiry
bunx remotion lambda render testbed-v6 NewVideo --log=verbose --delete-after="1-day" --api-key=<api-key>

它在 AWS 上用真实凭据重建 Lambda 函数、创建测试站点 testbed-v6 并渲染示例视频 NewVideo。由于 set -e 的存在,任一子命令失败都会使整个脚本非 0 退出,从而触发清单中的中止策略。对发布流程而言,这一步的意义是:验证"即将发布到 npm 的 @remotion/lambda 及运行时"在真实云环境中可部署、可渲染,把问题挡在用户下载之前。

六、阶段五:npm 多包并发发布

NPM_CONFIG_TOKEN=<token> bun run release

对照根 package.json#L48release 脚本是一条三段式命令:

"release": "bun publish.ts && turbo run publishprivate --concurrency=1 && git push --tags && git push"
  • 第一段 bun publish.ts:发布全部公开 npm 包;
  • 第二段 turbo run publishprivate --concurrency=1:串行执行各包声明的 publishprivate 任务(如 Ruby gem、Go/Python SDK 等其他生态产物);
  • 第三段:推送 tag 与分支,使 v<version> tag 到达远端。

6.1 publish.ts 的实现细节

根目录 publish.ts 的发布逻辑值得逐条拆解:

  1. 版本号来源:从 packages/core/package.json 读取 version(当前为 4.0.520)——即"core 包的版本就是本次发布版本"的单一事实源,与 set-version.ts 全仓统一改号的设计呼应。
  2. 包筛选:遍历 packages/ 下含 package.json 的目录,跳过 FEATURED_TEMPLATES 模板目录、跳过 private: true 的包、再经 shouldReleasePackage() 过滤(v5 名单中的包在 v5+ 不再发布)。
  3. LICENSE 自动补齐:若某包的 license 字段引用了 LICENSE.md 但包内没有该文件,先临时复制根目录 LICENSE.md 进去,bun publish 完成后再删除——保证 npm 上每个包都带许可证文件。
  4. 并发控制与幂等:用 p-limit 把并发限制在 4(const p = limit(4)),每个包执行 bun publish --tolerate-republish——--tolerate-republish 使重复发布同一版本不报错,这为"发布中断后重跑"提供了幂等性保障。

6.2 阶段六:模板仓库同步(publishtemplates)

bun run publishtemplates

对应根 package.json#L51cd packages/it-tests && bun src/templates/publish.ts。清单要求:任一模板发布失败,就停止发布工作流并上报失败

packages/it-tests/src/templates/publish.ts 实现了这件事,核心机制:

  • 同步目标FEATURED_TEMPLATES 中每个 templateInMonorepo 非空的模板,克隆对应的独立 GitHub 模板仓库,清空旧文件后把 monorepo 内的模板目录整体拷入并推送;
  • 版本改写:拷贝 package.json 时把所有 workspace:* 替换为 ^4.0.0publish.ts#L75-L79),因为模板在 monorepo 外用 workspace 协议引用本地包,发布到独立仓库后必须换成真实 npm 版本范围——这正是"用新发布的包重新发布所有模板"的落地点;
  • 范围不止模板:同一脚本还会构建并同步 Agent 插件仓库(Codex 插件、Cursor 插件、Claude Code 插件、Kimi Code 插件),把 plugin.json 的版本号同步为 monorepo 包版本并打 v<version> tag,以及同步 Canvas Capture 浏览器扩展仓库;
  • 失败即非 0 退出:脚本收集所有 Promise.allSettled 结果,只要有 rejected 就打印失败清单并 process.exit(1)publish.ts#L431-L442)——与 SKILL.md"停止并报告失败"的指令严格对应。

七、阶段七:Changelog 生成规范(逐条继承)

清单最后一大段定义了 Changelog 的生成规则,产物保存到 /tmp/release-<version>.md。完整规则如下:

  1. 取提交范围git log v<prev>..v<new> --oneline 获取两个 tag 之间全部提交;

  2. 提取 PR:从 merge commit 中解析 PR 号,对每个 PR 执行:

    gh pr view <number> --json title,author,number,url \
      --jq '"* \(.title) by @\(.author.login) in \(.url)"'
    
  3. 分节归类:PR 归入 "What's Changed"、"Templates"、"Docs"、"Internal" 四节;所有 template-* 相关变更单独进 "Templates" 节;

  4. 排序规则:"What's Changed" 内按包分组使同包条目相邻(不加子标题,只调整顺序),且 remotion 核心包的变更必须排在最前——这与第六节中 core 包作为版本事实源的地位一致;

  5. 标题清洗:去掉冗余前缀,例如 Docs 节条目去掉 "Docs:" 字样;

  6. 新文档页加链接:运行

    git diff --diff-filter=A --name-only v<prev>..v<new> \
      -- 'packages/docs/docs/**/*.mdx' 'packages/docs/docs/**/*.md'
    

    列出本版本新增的文档页,把每个新增页映射回引入它的 PR,将该条目标题包成指向文档站的 markdown 链接;页面 URL 优先取 mdx frontmatter 中的 slug: 字段,否则按文件相对 packages/docs/docs/ 的路径推导;没有新文档页的条目保持纯文本不加链接;

  7. 识别新贡献者gh api repos/remotion-dev/remotion/contributors --paginate --jq '.[].login' 拉取历史贡献者列表,与本版本 PR 作者比对,只有真正的新面孔才写入 "New Contributors" 节;

  8. 收尾:底部固定追加一行 **Full Changelog**: 并附 v<prev>...v<new> 的 compare 链接;

  9. 格式对齐:使用与上一次 GitHub Release 完全相同的格式(可用 gh release view v<prev> 查看对照);

  10. 人工审批:changelog 未经作者批准不得发布,并允许作者在发布前直接编辑。

八、失败策略总览与流程特点

把散落在清单各处的中止条件集中起来,可以画出这个发布流水线的"安全边界":

检查点 触发条件 动作
gcloud 认证 token 打印失败 登录重试,不通过则不发布
Ruby 版本 发布命令走错 ruby 前置修正 PATH(仅预防,运行前验证)
set-version.ts 退出码非 0 立即中止整个发布
runlambda.sh 任一步失败(set -e 中止发布
publishtemplates 任一模板/插件同步失败(process.exit(1) 停止工作流并上报
Changelog 未获人工批准 不发布

从这套流程的源码结构可以看出几个设计取向:单一版本事实源(core 包版本驱动全仓改号)、产物级验证ensure-correct-version.ts 校验 dist 内容而非只看源码)、幂等发布--tolerate-republish + tag 先删后建)、以及把验证前移到发布之前(Lambda 端到端渲染、monorepo 集成测试都在 bun run release 之前跑完)。对于维护多包 monorepo 的团队,.agents/skills/release/SKILL.md 与其背后的 set-version.tspublish.tsrelease-package-policy.ts 构成了一套值得参考的"版本一致性 + 发布闸门"工程范式。

需要注意的适用前提:以上流程基于当前仓库的 4.x 版本线(core 当前为 4.0.520)与 Bun/Turborepo 工具链;npm token create、1Password、ghgcloud 等外部工具与真实云账号凭据仅发布负责人可用,读者在非发布环境中只能查看这些脚本与配置,不应实际执行发布命令。

登录后查看全文
热门项目推荐
相关项目推荐