Setup

()
首页博客あさき命MomentLive Log关于我数据统计
首页
首页博客あさき命MomentLive Log关于我数据统计

应用

GITADORA Skill RecorderFog of World HelperDTX Player宝可梦个体/努力值倒推
© 2014-2026Sean白熱All Rights Reserved.

为什么我不再使用 release-it 了

发布2026年7月31日
更新2026年8月15日
阅读时间5 min
分类Dev/开发
标签#Release#Monorepo#Rust#Open Source

我在 Univer 的相关仓库里用了接近三年的 release-it。标准配置是 release-it@17.1.1,配上 @release-it-plugins/workspaces@4.2.0 和 conventional changelog 插件。它们替我创建新版本号、changelog、commit、tag 和 push,长期用下来并没有出现过任何致命问题。

随着 npm 生态日益猖獗的供应链投毒攻击,我开始把工作重心放在了依赖安全上。

Dependabot 在近几年内,每隔上一阵就会报告 release-it 依赖树里出现了漏洞。作为核心,release-it 通常很快就会得到修复并更新,而我所需要的 @release-it-plugins/workspaces 社区插件却经常跟不上。

release-it 其实修得很快

2026 年 3 月 13 日,undici 6.23.0 同时命中五份安全公告。这个版本是 release-it 19.2.4 的直接运行时依赖。站在业务仓库里看,它则是依赖图里的次级依赖。

公告类型当前等级
GHSA-f269-vfmq-vjvj恶意 WebSocket 长度导致客户端崩溃High
GHSA-2mjp-6q6p-2qxm重复 Content-Length 引起请求走私Moderate
GHSA-vrm6-8vpv-qv8qWebSocket 解压炸弹耗尽内存High
GHSA-v9p9-hfj2-hcw8非法压缩参数触发未捕获异常High
GHSA-4992-7rv2-5pvqupgrade 参数 CRLF 注入Moderate

release-it 的响应确实比较及时。与之相关的修复 PR #1285 在第二天就被提了上来,3 月 24 日合入,把 undici 从 6.23.0 升到 7.24.3。大约两小时后,release-it@20.0.0-0 发布。稳定版 20.0.0 在 4 月 15 日发布,距离公告公开 33 天。

这里需要补充说明下前面也提到过的实际风险问题。release-it 实际上只从 undici 引入了 Agent,用于处理 GitLab 的自定义 TLS。它压根没使用 WebSocket,也没有把不可信输入传给 upgrade 或底层的 headers 数组。也就是说,对于 Univer 的开发者和其用户来说,这些漏洞并没有真实影响。

虽然无关痛痒,但暴露出来的核心问题是,release-it 的一些扩展能力来自另一个维护节奏不同的项目。只要安全修复跨了主版本,最慢的 peerDependencies 或者生态插件就会决定整个发布链能不能升级。

2026 年:核心修好了,插件的版本上限没有跟上
  1. 2026-03-13
    Undici 公布 5 个告警
    release-it 19.2.4 固定在 Undici 6.23.0
  2. 2026-03-24
    release-it 给出修复预发布版
    20.0.0-0 升至 Undici 7.24.3
  3. 2026-04-15
    release-it 20.0.0 稳定版
    距离告警公布 33 天
  4. 2026-06-19
    workspaces 6.0.0
    peer range 仍停在 release-it 19
  5. 2026-07-31
    v20 支持仍未落地
    release-it 20 已发布 107 天

当时使用的 @release-it-plugins/workspaces@5.0.3 只接受 release-it ^17 || ^18 || ^19。2026 年 6 月 19 日,插件时隔 364 天发布 6.0.0,peerDependencies 仍然停在 19。即使到了 7 月 31 日,支持 release-it@20 的 issue #159 依旧没有关闭,你无法在不 override 的情况下把 release-it 升到 20。

并且这不是偶发的一次:

release-it 主版本核心发布时间workspaces 首个支持版本等待时间
172023-11-114.1.0(2024-01-15)65 天
182025-01-065.0.0(2025-06-18)163 天
192025-04-185.0.0(2025-06-18)61 天
202026-04-15截至 2026-07-31 仍无107 天以上

仓库历史也留下了蛛丝马迹。2025 年,Univer Presets 曾把 release-it 19 降回 17,等 @release-it-plugins/workspaces@5 发布后才重新升级。我维护的另一个仓库在 2026 年 4 月 15 日升到 release-it@20,三天后又回到 19.2.4。当时 lockfile 里的 @release-it-plugin/workspaces@5.0.3 又明确只支持到 19。

插件自己的依赖也有相同的问题。PR #158 记录了 walk-sync 链上的 minimatch 和 brace-expansion 漏洞,相关公告公布后 85 至 122 天,插件才在 6.0.0 中更新生产依赖。用户可以靠刷新 lockfile 或 override 提前修,不必等插件发版,但这也意味着发布工具的依赖卫生最后落到了使用者手里。

与其再维护一个插件,不如推倒重来

我最初考虑过 fork @release-it-plugins/workspaces 插件。问题是,fork 之后我要继续追随 release-it 的插件 API、依赖变化和发布行为,维护面并不会缩小。

于是我写了 Verso。它不是一个更通用的 release-it,只处理我真正用到的发布流程:更新 monorepo 里各个 packages 的共享版本号并推送 tag。仓库里如果混有 Rust 项目,也可以把指定的 Cargo.toml 和 Cargo.lock 一起更新。

安装只需要一个开发依赖:

sh
pnpm add -D @amamo/verso
json
{
  "scripts": {
    "release": "verso"
  }
}

大多数 pnpm workspace 甚至不需要写 package glob。Verso 会读取 pnpm-workspace.yaml。需要混合 Cargo 时,再加一份很短的配置:

toml
[version]
cargo_manifest_paths = [
  "path/to/foo/Cargo.toml",
  "path/to/bar/Cargo.toml",
]

[changelog]
enabled = false

[git]
push = "atomic"

这里的 Cargo manifest 路径只是占位。verso doctor --json 会检查配置、工作区版本和 Git upstream,下面是精简后的示意输出:

json
{
  "ok": true,
  "checks": [
    {
      "name": "git upstream",
      "status": "pass",
      "message": "ready to push to origin/main"
    }
  ],
  "packageCount": 4,
  "currentVersion": "1.2.3"
}

Verso 能做什么

Verso 的主要功能都围绕这条流水线:

  • 自动发现 npm、pnpm 和 Yarn workspaces,也支持单包仓库;
  • 检查所有发布单元是否使用同一版本,并按需更新 package.json、JSON5 或 YAML manifest;
  • 更新显式配置的 Cargo manifest 和最近的 Cargo.lock;
  • 从 conventional commits 生成 Angular 风格 changelog;
  • 提供 patch、minor、major、alpha、beta、rc 和自定义 semver 选择;
  • 支持 init、doctor --json、--dry-run --json,以及发布步骤之间的 hooks;
  • 创建发布 commit 和 annotated tag,再用 git push --atomic <remote> <branch> <exact-tag> 一次推送。

--dry-run 不会写文件,也不会执行会修改状态的 Git 命令。正式执行时,commit 前出错就恢复文件和原有暂存状态。如果 git push --atomic 失败,本地的 commit 和 tag 会保留下来,处理完问题后可以直接重试。

push 成功以后,npm 包和 GitHub Release 都交给 CI,其中 npm 使用 trusted publishing。本地不需要保存 npm token 或 GitHub token。

我没有做的功能

Verso 并不是任何一个现有发布工具的平替,也有很明确的边界:

  • 只支持统一版本,不计算独立 package 的 bump;
  • 不改写 workspace 内部依赖范围;
  • changelog 只有 Angular conventional preset;
  • 不直接 publish registry,也不创建 GitHub Release;
  • Cargo manifest 必须显式列出。

这些限制有一天可能会变化,就目前来说,它们是为了让工具更小、更专注、更容易维护。

参考资料

  • release-it 20.0.0-0 发布记录
  • release-it monorepo recipe
  • workspaces 5.0.3 npm 元数据
  • workspaces 6.0.0 npm 元数据
  • Verso 源码与文档

相关文章

Dev/开发

CSS Custom Highlight API 的机制与实践

不改写 DOM 结构,直接在渲染层实现文本高亮与标注。

2026年2月27日

Dev/开发

使用 Promise.try() 优雅地同时处理同步与异步错误

Just try it.

2026年2月25日

Dev/开发

同形异码:Unicode 正规化、编码与文件系统的隐形分岔

从 URL 编码到文件系统,解释为何“看起来相同”的字符串会走向不同字节路径。

2026年2月14日
台风天BAND-MAID WORLD TOUR 2026 HONG KONG