应用更新 — 手动测试清单
针对"检测更新 → 用户同意 → 自行下载/安装/重启"流程的端到端验证,覆盖全部三种部署模式。每节独立可用:在目标平台按先决条件准备好后执行。
单元测试(
UpdateCheckServiceTest、portable-updater.test.ts、auto-updater.test.ts)已覆盖版本比较与检测逻辑。本清单验证的是真实的"下载 → 校验 → 替换 → 重启"流水线——这部分必须在目标 OS 上对着真实的 GitHub release 或 FY-Proxy 内网仓库运行。
通用先决条件(所有模式)
- GitHub 上必须存在两个 release,这样"旧版"才能检测到"新版":
- 一个较旧的 tagged release,你要安装/运行它(如
v4.0.0-beta.1)。 - 一个较新的 tagged release,已发布在 Releases 页(如
v4.0.0-beta.4)。 - 较新的 release 必须是在本次改动合入之后由
fengyu-release.yml构建的(这样latest*.yml、*.blockmap、checksums.txt才会发布——electron-updater 和便携自更新都需要)。
- 一个较旧的 tagged release,你要安装/运行它(如
- 确认较新 release 包含你所在模式需要的产物(见下)。
- 先把旧版装好/解压好并跑起来,再触发检查。
如何确认较新 release 有必需的 feed 文件
打开 https://github.com/MuskStark/FengYu/releases/tag/v<新版本>,确认下列产物存在(任一缺失都说明 CI 改动未生效,自动更新无法工作):
| 产物 | 谁需要 |
|---|---|
latest.yml(Windows)/ latest-mac.yml(macOS) | electron-updater(NSIS 安装版 + macOS) |
*.blockmap | electron-updater 增量下载 |
Infinia-<版本>-win32-x64-portable.zip | Windows 便携自更新 |
Infinia.jar + checksums.txt | 便携 Web(java -jar)自更新 |
内网 / 离线商店通道(商店取代 FY-Proxy)
在设置 → 更新通道 → 升级渠道地址填写 Infinia 商店源地址,例如 http://10.0.0.5:8080(独立部署的商店平台——它取代了旧的 FY-Proxy 分发中心,同一地址 也承载插件安装与云账号登录),并打开同页的**「允许私有网络(自建商店)」开关**——自建 渠道(含 localhost 调试商店)只在开关开启时生效,关闭时地址休眠、商店与更新回退官方 线上商店与 GitHub。该值会被持久化,并在桌面窗口创建前加载,因此启动自动 探测与关于 → 检查更新都会绕过 GitHub。
商店通道当前支持以下产物:
| 平台/包类型 | 必须的产物 | 发现端点(相对商店基址) |
|---|---|---|
| Windows x64 便携版 | STABLE 渠道 APP 发布,含 Infinia-<版本>-win32-x64-portable.zip 产物 | /api/v1/compat/fengyu/fengyu-releases/api/releases/latest?channel=windows-portable |
| Debian/Ubuntu lite x64 | 暂仍为 FY-Proxy 旧契约(待商店提供 electron-updater feed) | /fengyu-updates/deb/latest-linux.yml(FY-Proxy 契约) |
应用发布改走商店的发布者流程(APP listing + 按版本上传产物),不再使用 FY-Proxy 的 文件上传页。便携 ZIP 的 release 响应包含强制 SHA-256,Infinia 会在解压前校验;deb feed 由 electron-updater 执行 SHA-512 校验。手动下载页变为商店 Web 应用(/web)。启动后确认 自动发现,再用关于 → 重新检查确认手动发现。NSIS、AppImage、macOS、JRE 和便携 Web/JAR 在商店通道下均不受支持。
模式 1:Windows NSIS 安装版(*-setup.exe)
平台: Windows 10/11 · 更新机制: electron-updater
仅支持公共 GitHub 通道;FY-Proxy 会拒绝 NSIS 产物。
准备
- 下载并安装旧版
*-win-x64-setup.exe。 - 从开始菜单/桌面快捷方式启动 Infinia。
步骤
- 打开关于(侧边栏)。几秒后"更新"行应显示
Version <新版本> is available(StatusBar 也会出现徽标)。 - 点击立即更新。弹出未签名风险确认框。
- 点击继续。
- 下载进度条填充(
update:progressIPC 事件在流动)。 - 完成后应用退出,NSIS 安装器静默运行,然后 Infinia 重新启动。
- Windows SmartScreen 可能弹警告(未签名构建)——点"更多信息"→"仍要运行"。未签名构建出现这个是预期行为。
- 重启后再次打开关于——版本应已变为
<新版本>,"更新"行应显示"已是最新版本"。
通过标准
- [ ] 旧版能检测到更新
- [ ] 能看到下载进度
- [ ] 应用退出、安装器运行、应用重启
- [ ] 重启后关于页确认是新版本
- [ ] 更新后 StatusBar 徽标消失
常见失败
| 症状 | 可能原因 |
|---|---|
| 关于页显示"检查更新失败" | release 上没有发布 latest.yml(CI glob 漏了) |
| 下载一直不开始 | signedRelease 门控——同意 IPC 路径应该绕过它;检查 update:download-install 是否被调到(DevTools → Network/Console) |
| 应用退出但不重启 | NSIS --updated 流程失败;查 %TEMP% 里的安装器日志 |
模式 2:Windows 便携版(*-portable.zip)
平台: Windows 10 1803+ · 更新机制: 自定义流水线(portable-updater.ts)
electron-updater 不能更新便携 zip——此模式用的是自定义的"下载 → tar 解压 → robocopy 替换 → 重启"流水线。这是最容易出现文件锁或单实例问题的模式,务必仔细测试。
准备
- 下载并解压旧版
*-win-x64-portable.zip到某个文件夹,如C:\Users\<你>\Infinia\。 - 运行
C:\Users\<你>\Infinia\Infinia.exe。
步骤
- 打开关于 → "更新"行检测到
<新版本>(走 GitHub API 或已配置 FY-Proxy 的windows-portablerelease 端点,不走latest.yml)。 - 点击立即更新 → 继续(未签名警告)。
- 下载进度填充(便携 zip 较大,留意百分比)。
- 应用退出。一个 detached 的
.bat(在%TEMP%)接管:- 等待旧
Infinia.exe的 PID + backend JVM 进程树退出(tasklist 轮询)。 - 清扫仍从安装目录运行的进程(残留的插件 worker 会锁住内置
resources\jre的映像文件)。 - 用
robocopy把解压出的新目录树覆盖到安装目录(目标文件仍被锁时重试一次)。 - 重启
Infinia.exe。
- 等待旧
- Infinia 自动重新启动。
通过标准
- [ ] 便携检测生效(关于页显示更新,不是静默失败)
- [ ] 能看到下载进度
- [ ] 旧进程完全退出后才替换文件(无"文件被占用"错误)
- [ ]
Infinia.exe+resources\binaries\FengYu.jar+resources\app.asar全部被替换 - [ ] 应用以新版本重启(关于页显示
<新版本>) - [ ] 重启时不报第二实例错误(单实例锁已干净释放)
失败时如何排查
- detached 脚本日志:
%TEMP%\fengyu-portable-update-<pid>.log - 脚本本身(自删前):
%TEMP%\fengyu-portable-update-<pid>.bat - 暂存目录:
%TEMP%\fengyu-portable-update-*\(解压出的新目录树) - 从 cmd 窗口运行以看控制台输出:
Infinia.exe日志在<runtime>\.fengyu\logs\。
常见失败
| 症状 | 可能原因 |
|---|---|
tar extraction failed | Windows 版本低于 10 1803(无 bsdtar);或 zip 产物名不含 -portable.zip |
| robocopy 报"文件被占用" | 安装目录下仍有进程在运行(残留的插件 worker 锁住内置 JRE)。替换脚本复制前会清扫应用目录内的进程并重试一次 robocopy;仍失败时查看 .fengyu/logs/update.log 里的清扫输出与 robocopy 退出码 |
| 应用重启后立即退出 | 单实例锁未释放(旧进程还活着);或新 exe 路径不一致 |
| 关于页一直不显示更新 | isWindowsPortable() 返回了 false——确认便携解压目录里 resources\app-update.yml 不存在 |
模式 3:便携 Web(java -jar,run.sh / run.bat)
平台: 任意(macOS/Linux/Windows) · 更新机制: 后端 SelfUpdateService (JAR 下载 → SHA256 校验 → detached 重启脚本 → JVM 退出 → 替换 → 重启)
这是唯一能在 macOS/Linux 上端到端测试的模式。它只替换 JAR(启动脚本和插件保持原位)。 此模式只支持 GitHub;FY-Proxy 会拒绝 JAR 产物。
准备
- 下载并解压旧版
Infinia-<旧版本>-web.zip(或.tar.gz)。 - 启动:
- macOS/Linux:
./run.sh - Windows:
run.bat
- macOS/Linux:
- 记下输出到 stderr 的生成 token(
Generated per-launch token ...: zf-...)。 - 在浏览器打开打印出的 URL(或用带 token 的 curl)。
步骤
- 打开关于 → "更新"行显示
<新版本>可用。- 该 release 必须有
Infinia.jar产物和checksums.txt产物(都由 release 工作流发布)。没有checksums.txt,SHA256 校验步骤会失败。
- 该 release 必须有
- 点击立即更新 → 继续。
- 后端:
- 从 release 下载
Infinia.jar到暂存文件。 - 下载
checksums.txt,解析Infinia.jar那一行,校验 SHA256。 - 在
<runtime>\runtime-files\下生成self-update.sh(POSIX)或self-update.bat(Windows)。 - detached 派生脚本,然后退出 JVM(
System.exit,延迟 1 秒让响应刷新)。
- 从 release 下载
- detached 脚本:
- 等待旧 JVM PID 退出(POSIX 用
tail --pid=,Windows 用tasklist)。 - 备份旧 JAR 到
Infinia.jar.bak。 - 把下载的 JAR 移到位。
- 用
java -jar Infinia.jar <原始参数>重新启动。
- 等待旧 JVM PID 退出(POSIX 用
- 新 backend 起来;浏览器重连(StatusBar 圆点变回绿色)。
通过标准
- [ ] 检测到更新(关于页显示
<新版本>) - [ ] 下载 + SHA256 校验成功(查 backend 日志里的
[self-update] checksum verified) - [ ] 旧 JVM 干净退出(backend 日志显示 context close + shutdown hook)
- [ ] JAR 已替换:
Infinia.jar是新版本,Infinia.jar.bak是旧版本 - [ ] 新 JVM 以相同端口/token 重启(UI 无需手动操作即重连)
- [ ] 关于页现在显示
<新版本>且"已是最新版本"
失败时如何排查
- backend 日志:
<解压目录>\data\logs\(即-Dfengyu.runtime.dir=$ROOT/data指向的位置)。 - 重启脚本:
<解压目录>\data\runtime-files\self-update.sh(或.bat)。 - 重启脚本日志:
<解压目录>\data\runtime-files\self-update-*.log。 - 暂存下载文件:
<解压目录>\data\runtime-files\update-staging-*.jar。
常见失败
| 症状 | 可能原因 |
|---|---|
SHA-256 mismatch for Infinia.jar | release 上的 checksums.txt 过期或与发布的 JAR 不匹配 |
checksums.txt has no entry for Infinia.jar | 该 release 是在 checksums.txt 加入 CI 收集步骤之前构建的 |
| 旧 JAR 没被替换(重启后还是旧版本) | detached 脚本并未真正脱离(随 JVM 一起死了);或 java.class.path 没解析到 JAR 路径 |
| JVM 退出但没重启 | 脚本的重启命令有误——检查 self-update.sh,看 exec java ... 那行是否带了正确的 -D 标志和 --token |
| 重启了但端口变了 | 重启没把 --port=<n> 传过去;SelfUpdateService.buildRelaunchCommand 对 sun.java.command 的解析漏掉了 |
模式 4:macOS 桌面(*-mac-arm64.dmg)
平台: macOS(Apple Silicon) · 更新机制: 手动下载(未签名 Gatekeeper 降级路径)
macOS 未签名构建在
quitAndInstall替换后无法重启(Gatekeeper 会拦截被替换的 bundle)。应用降级为"下载 + 打开发布页"。在实现代码签名 + 公证之前,这是有意为之。FY-Proxy 内网模式不支持 macOS。
准备
- 下载并安装旧版
*-mac-arm64.dmg(把 Infinia 拖进应用程序)。 - 首次启动时右键 → 打开(绕过 Gatekeeper 对未签名旧构建的拦截)。
- 运行 Infinia。
步骤
- 打开关于 → "更新"行检测到
<新版本>。- 注意:关于页会检测到 macOS,显示的是**"打开页面"**按钮,而不是"立即更新"(因为外壳的
update:download-installIPC 在 darwin 上返回{action:'manual'})。
- 注意:关于页会检测到 macOS,显示的是**"打开页面"**按钮,而不是"立即更新"(因为外壳的
- 点击打开页面 → 浏览器打开 GitHub releases 页。
- 手动下载较新的
*-mac-arm64.dmg。 - 替换 /Applications 里的旧 Infinia.app(把新的拖进去,同意替换)。
- 右键 → 打开新的 Infinia(又是 Gatekeeper 警告——未签名)。
通过标准
- [ ] 检测到更新
- [ ] 显示"打开页面"按钮(不是"立即更新"——确认走了 darwin 分支)
- [ ] 打开正确的 releases URL
- [ ] 手动替换后关于页确认是新版本
未来:代码签名落地后
在签名 + 公证的构建之后重新跑模式 4:ipc/update.ts 的 darwin 分支应改为调 downloadUpdate() + quitAndInstall()(同 Windows NSIS),关于页按钮应切换为"立即更新"。到那时完整的自动流程才适用。
跨模式通用检查(任意模式成功更新后快速过一遍)
无论哪种模式,成功更新后都要验证应用是功能完整的,而不只是"版本号变了":
- [ ] 插件仍能加载:打开工具页——4 个官方插件(markdown/excel/email/offlinepython)都出现 (浏览器自动化是宿主内嵌能力,不是插件)。更新后的 JAR/asar 必须带了配套的插件包。
- [ ] AI 对话可用:在对话页发条消息——有响应流回。
- [ ] 数据库完好:打开设置——DB 配置在重启后还在(
data/运行目录没被更新清掉)。 - [ ] 再次检查显示"已是最新":关于 → "重新检查" → 现在显示"已是最新版本"(新构建版本号等于最新 release tag)。