跳转至

Preview 频道:版本化 + 回滚 —— 设计规范

  • 日期: 2026-06-01
  • 状态: Phase A 已实现;Phase B = 提案设计,待评审
  • 随版本发布: v0.3.0 系列

问题

Preview 更新频道(设置 → 关于 → 更新频道 → Preview)从 main 构建,并发布到滚动更新的 preview GitHub prerelease。但两个缺口使其实际上无法作为更新频道工作:

  1. 没有版本化。 每个 preview 构建都打上了静态的 tauri.conf.json 版本(0.3.0)。Tauri 的 updater 只在清单版本比已安装版本 semver 更大 时才提供更新,因此 0.3.0 == 0.3.0 →“没有更新”。Preview 用户安装一次后就再也收不到下一个 preview。
  2. 没有回滚。 Tauri 的 updater 只会向前移动。没有任何方式可以回到更早的 preview 构建(例如,当新的 main 构建出现回归时),除非手动重新安装。

Phase A —— 前向版本化(已完成)

release.yml 仅在 workflow_dispatch + publish_preview 路径上为每个 preview 构建打上唯一且单调递增的 semver 预发布版本:

<base>-preview.<github.run_number>     e.g. 0.3.0-preview.42

通过一个临时、永不提交的 tauri.conf.json 的 version 重写(Tauri 从那里读取 bundle 与 updater 版本)。性质:

  • 单调递增(run_number 只增不减)→ …preview.43 > …preview.42,因此 updater 会提供每个较新的 preview。
  • 当前目标的预发布 → 当稳定版 0.3.0 发布时,0.3.0 > 0.3.0-preview.N,所以 preview 用户收敛到稳定版(符合频道 preview→stable 的回退语义)。
  • 无 +build 元数据 —— 特意排除,以避免文件名 / MSI 中出现 + 的边界情况。提交可追溯性保留在发布说明中(preview-notes 任务已渲染提交范围 + 贡献者)。

已知注意点(Windows MSI)

Windows MSI 的 ProductVersion 是 4 段数字(a.b.c.d),并且会剥离 semver 预发布部分 → 每个 preview MSI 都报告为 0.3.0。Tauri updater 比较来自 latest.json 的完整 semver(因此它仍然提供新的 preview 并运行新的 MSI),但 msiexec 安装一个 ProductVersion 未变化的 MSI 时,属于“重新安装”,而不是“升级”。行动项: 在测试中验证 Windows preview→preview 是否真的替换了文件。macOS/Linux 会整体替换 bundle,不受影响。如果 Windows 行为异常,回退方案是数字方案(0.3.<run_number>),代价是无法干净地收敛到稳定版——在实际 Windows 测试后再决定。

Phase B —— 版本目录 + 回滚(提案)

发布模型:按版本发布预发布版

每个 preview 构建发布一个独立的预发布版,标签为 preview-<version>(例如 preview-0.3.0-preview.42),内容自包含:签名构件 + 各自的 latest.json。另外,滚动更新的 preview 标签的 latest.json 镜像最新版本,使默认前向更新始终读取稳定的 URL(releases/download/preview/latest.json)。

  • 保留策略: 保留最近约 10 个 preview-* 发布;清理步骤会删除更旧的发布和标签。这些发布就是回滚目录——因此与 Phase A 的清理倾向相反,我们刻意保留旧构件。

应用侧:“Preview builds” 选择器

在 设置 → 关于 → 更新频道 中(当处于 Preview 时显示):

  • 从 GitHub Releases API 列出可用构建(匹配 preview-* 的 prerelease):版本、日期、提交范围,以及 alembic-head 标记(见数据安全)。
  • 每一行 → Install。选择更旧的构建即为回滚。
  • 安装路径复用 #199 中的 Rust updater 命令,并扩展:
  • 显式端点(…/preview-<chosen>/latest.json),以及
  • allow_downgrades(Tauri UpdaterBuilder::version_comparator,例如 |current, candidate| candidate != current),使它即使在目标版本旧于当前运行版本时也能安装。
  • 每个构建均经过 minisign 签名 → 回滚安装同样经过验证。

⚠️ 数据安全:DB schema + 回滚

Alembic 迁移是仅前向的,并且只针对升级经过测试。将应用回滚跨越某个迁移,意味着更旧的应用会遇到 schema head 比它预期更新的 omnivoice_data DB——这可能会出问题(与“向后兼容数据”约束正好相反)。按工作量递增的缓解措施:

  1. 为每个 preview 标记其 alembic head(在构建时将 alembic heads 捕获到发布说明 / sidecar 字段)。选择器将构建标记为“可安全回滚到”(相同 head)或“数据不兼容(较新 schema)”。
  2. 在选择器中针对跨 schema 回滚给出警告,并要求明确确认。
  3. (后续)为受影响的修订实现并测试 alembic downgrade 路径,使回滚真正安全。

Phase B 至少应完成 (1)+(2);(3) 是随各个迁移进行的后续工作。

实现大纲(Phase B)

  • release.yml:按版本发布 preview-<version>,并镜像最新版本到滚动 preview/latest.json;保留/清理步骤;捕获 alembic head。
  • backend:增加一个小端点,暴露当前运行的 alembic head(供选择器的安全检查使用),或由客户端从发布元数据中读取。
  • frontend/src-tauri(updater_channel.rs):install_specific(version),带端点覆盖 + allow_downgrades;通过 GH API 调用 list_preview_builds()。
  • frontend(设置):“Preview builds” 选择器 + 回滚确认对话框;i18n(en + zh-CN,然后补齐其余语言)。

待定决策

  1. 基础方案:0.3.0-preview.N(已选)vs 0.3.1-preview.N。
  2. 保留数量(建议 10)。
  3. 是否将跨越 alembic head 的回滚设为硬阻止,还是设为“警告后确认”(建议:警告后确认 + 明确标记)。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 om/VoiceStudio