feat(FN-5607): add cross-platform updater feeds for desktop releases

Add multi-platform updater feed configuration for the desktop app, including Windows, Mac, and Linux feed files with a collector, wired into the release and test-release workflows, plus corresponding tests and documentation.

Fusion-Task-Id: FN-5607

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fusion-Task-Id: FN-5607
This commit is contained in:
gsxdsm
2026-05-27 03:10:21 -07:00
parent a0d30f18f8
commit 9504c31a85
5 changed files with 19 additions and 3 deletions

View File

@@ -259,7 +259,8 @@ The desktop shell installs a native menu with standard shortcuts.
- `triggerUpdateCheck(mainWindow?)` performs on-demand checks (manual menu/IPC trigger) and returns `checking`/`unavailable`/`error` status.
- `startUpdateCheckInterval(mainWindow, intervalMs?)` schedules periodic background checks (default every 4 hours) and returns a disposer for quit cleanup.
- Events forwarded to renderer include `update-available`, `update-downloaded`, `update-not-available`, and `update-error`.
- Failures are logged and treated as non-fatal (important for unsigned/local dev builds).
- Auto-update feed metadata is published as GitHub Release assets by `.github/workflows/release.yml` (`latest.yml`, `latest-mac.yml`, `latest-linux.yml`) and is what updater checks resolve against.
- Failures are logged and treated as non-fatal (important for unsigned/local dev builds, which typically surface `update-not-available` or the guarded error path).
- **Window state persistence**
- `loadWindowState()` reads `window-state.json` from `app.getPath("userData")`.
- `saveWindowState(mainWindow)` writes bounds/maximized state atomically (`.tmp` + rename).
@@ -353,6 +354,7 @@ Desktop packaging is configured in `electron-builder.yml`.
- Targets: macOS (`dmg`, `zip`), Windows (`nsis`, `portable`), Linux (`AppImage`, `deb`, `tar.gz`)
- Windows artifacts: `Fusion-<version>-win-x64.exe` and `Fusion-<version>-win-arm64.exe` (both NSIS + portable variants) in `packages/desktop/dist-electron/`
- Binary GitHub Release workflow (`.github/workflows/release.yml`) now attaches desktop artifacts for all supported platforms:
- Electron-updater feed files are also published per platform: `latest.yml` (Windows), `latest-mac.yml` (macOS), and `latest-linux.yml` (Linux). `setupAutoUpdater` / `triggerUpdateCheck` resolve these feeds from the GitHub Release channel.
- Windows: x64 + arm64 outputs (NSIS + portable), matching `.exe.sha256` sidecars, and `.blockmap` files.
- macOS: `Fusion-<version>-mac-arm64.dmg`, `Fusion-<version>-mac-x64.dmg`, matching `.zip` variants, `.sha256` sidecars, and `.blockmap` files.
- Linux: `Fusion-<version>-linux-x64.AppImage` with `.sha256`, plus best-effort `.deb` and `.tar.gz` outputs (and sidecars) when available on the runner image.

View File

@@ -41,6 +41,9 @@ describe("electron-builder desktop config", () => {
expect(builderConfig).toMatch(/artifactName:\s*"\$\{productName\}-\$\{version\}-\$\{os\}-\$\{arch\}\.\$\{ext\}"/m);
expect(builderConfig).toMatch(/appId:\s*com\.gsxdsm\.fusion\.desktop/m);
expect(builderConfig).toMatch(/productName:\s*Fusion/m);
expect(builderConfig).toMatch(/publish:\s*[\s\S]*?provider:\s*github/m);
expect(builderConfig).toMatch(/publish:\s*[\s\S]*?owner:\s*gsxdsm/m);
expect(builderConfig).toMatch(/publish:\s*[\s\S]*?repo:\s*fusion/m);
});
it("locks windows signing policy without baked certificate paths", async () => {

View File

@@ -21,16 +21,19 @@ describe("desktop release workflow wiring", () => {
expect(workflow).toContain("runs-on: windows-latest");
expect(workflow).toMatch(/pnpm --filter @fusion\/desktop dist:win|electron-builder --win/);
expect(workflow).toContain("name: fusion-desktop-windows");
expect(workflow).toContain("packages/desktop/dist-electron/latest.yml");
expect(workflow).toContain("build-desktop-macos:");
expect(workflow).toContain("runs-on: macos-latest");
expect(workflow).toMatch(/pnpm --filter @fusion\/desktop dist:mac|electron-builder --mac/);
expect(workflow).toContain("name: fusion-desktop-macos");
expect(workflow).toContain("packages/desktop/dist-electron/latest-mac.yml");
expect(workflow).toContain("build-desktop-linux:");
expect(workflow).toContain("runs-on: ubuntu-latest");
expect(workflow).toMatch(/pnpm --filter @fusion\/desktop dist:linux|electron-builder --linux/);
expect(workflow).toContain("name: fusion-desktop-linux");
expect(workflow).toContain("packages/desktop/dist-electron/latest-linux.yml");
}
});
@@ -49,6 +52,7 @@ describe("desktop release workflow wiring", () => {
expect(release).toContain('-name "*.AppImage"');
expect(release).toContain('-name "*.deb"');
expect(release).toContain('-name "*.tar.gz"');
expect(release).toContain('-name "latest*.yml"');
});
it("wires test-release collect job to wait for all desktop build jobs", async () => {
@@ -57,6 +61,7 @@ describe("desktop release workflow wiring", () => {
expect(testRelease).toContain(
"needs: [build-binaries, build-desktop-windows, build-desktop-macos, build-desktop-linux]",
);
expect(testRelease).toContain('-name "latest*.yml"');
});
});