feat(desktop): Tauri → Electron migration release kit (#1526)

Ships the last-missing piece of the Electron migration. After this PR
merges there are three one-shot scripts under scripts/migration/ that
carry the whole lifecycle from "cut v0.12.0" through "delete src-tauri":

  01-cut-migration-release.mjs   # bumps versions, writes the release env
                                 # fragment, tags, pushes.
  02-validate-migration.mjs      # guided smoke test against a cut release.
  03-post-migration-cleanup.mjs  # deletes src-tauri, flips defaults,
                                 # scrubs Tauri docs (dry-run by default).

Code landing in the same PR (dormant until a release sets
VITE_OPENWORK_MIGRATION_RELEASE=1):

- apps/desktop/src-tauri/src/commands/migration.rs gains
  migrate_to_electron() — downloads the matching Electron .zip, verifies
  the Apple signature, swaps the .app bundle in place via a detached
  shell script, relaunches, and exits. Windows + Linux branches are
  stubbed with clear TODOs for the follow-up.
- apps/app/src/app/lib/migration.ts grows migrateToElectron() + a
  "later" defer helper.
- apps/app/src/react-app/shell/migration-prompt.tsx adds the one-time
  "OpenWork is moving to a new engine" modal. Mounted from
  providers.tsx. Gated on isTauriRuntime() AND the build-time flag, so
  Electron users and all non-migration-release builds never render it.
- apps/app/vite.config.ts loads apps/app/.env.migration-release when
  present so the prompt gets the release-specific download URLs.
- .gitignore allows the migration-release fragment to be committed only
  on the tagged migration-release commit (removed in cleanup step).

Release workflow:
- .github/workflows/release-macos-aarch64.yml gains a publish-electron
  job alongside the Tauri jobs. Gated on RELEASE_PUBLISH_ELECTRON repo
  var OR the new publish_electron workflow_dispatch input (default
  false). Uses the existing Apple Dev ID secrets — no new credential
  story. Produces latest-mac.yml alongside Tauri's latest.json so a
  v0.12.0 release serves both updaters.

Verified:
  pnpm --filter @openwork/app typecheck   ✓
  cargo check --manifest-path apps/desktop/src-tauri/Cargo.toml   ✓
  node --check on all mjs scripts   ✓
  python yaml parse of release-macos-aarch64.yml   ✓

Not verified (needs a real release cycle):
  end-to-end migration from a signed Tauri .app to a signed Electron
  .app through the detached-script install swap.

Co-authored-by: Benjamin Shafii <benjamin@openworklabs.com>
This commit is contained in:
ben
2026-04-22 18:52:30 -07:00
committed by GitHub
parent 921ddbd13d
commit 7a53c2964c
12 changed files with 1219 additions and 2 deletions

View File

@@ -53,6 +53,11 @@ on:
required: false
type: boolean
default: true
publish_electron:
description: "Build + publish Electron desktop artifacts (macOS) alongside Tauri"
required: false
type: boolean
default: false
permissions:
contents: write
@@ -605,7 +610,58 @@ jobs:
--repo "$GITHUB_REPOSITORY" \
--clobber
release-orchestrator-sidecars:
publish-electron:
name: Build + publish Electron desktop (macOS)
# Runs alongside the Tauri jobs so the same release carries both
# latest.json (Tauri updater) AND latest-mac.yml (electron-updater).
# Gated on RELEASE_PUBLISH_ELECTRON=true (repo var) OR the workflow
# input of the same name so opt-in during rollout, opt-out if a
# non-migration release doesn't want Electron artifacts.
needs: [resolve-release, verify-release]
if: ${{ vars.RELEASE_PUBLISH_ELECTRON == 'true' || github.event.inputs.publish_electron == 'true' }}
runs-on: macos-14
env:
RELEASE_TAG: ${{ needs.resolve-release.outputs.release_tag }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ env.RELEASE_TAG }}
fetch-depth: 0
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.27.0
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.9
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build + package Electron app
env:
# electron-builder reads these to codesign + notarize the .app.
# Reuses the same secrets the Tauri path already uses.
CSC_LINK: ${{ secrets.APPLE_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
# electron-builder needs this to upload artifacts + the updater
# feed manifest (latest-mac.yml) to the GitHub release.
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
pnpm --filter @openwork/desktop package:electron --publish always
name: Build + Upload openwork-orchestrator Sidecars
needs: [resolve-release, verify-release]
if: needs.resolve-release.outputs.publish_sidecars == 'true'