Add Windows Electron desktop support (#1093)
* fix: make upstream sync actions target the selected remote Ensure fetch and pull actually honor upstream selection so fork maintenance works from the Git sidebar, and surface upstream branch status alongside the primary origin-tracking indicators. * feat: add Windows Electron desktop foundation * fix(electron): stabilize Windows desktop packaging * fix(electron): stabilize Windows desktop chrome Use native Windows titlebar behavior with an Alt-accessible hidden menu, and harden Windows dev command launching so the desktop app follows platform conventions. * fix(electron): stabilize Windows dev startup * fix(electron): clarify desktop artifact names * fix(electron): harden Windows desktop release and launch * fix(electron): address Windows release review * fix(electron): point updater and release links to org repo * Fix Windows settings persistence fallback * Fix Windows Electron dev startup * Add Windows Electron window controls * Fix Windows Electron install and opencode launch * fix: resolve git status for repositories without upstream Fixes repository detection stuck on Checking repository Handles git status when no upstream is configured Adds regression coverage for git status loading * Add Windows app menu button * fix: preserve file editor line endings * ci: add desktop release smoke workflow --------- Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
committed by
GitHub
co-authored by
Bohdan Triapitsyn
parent
cc7969ac00
commit
becd240168
@@ -0,0 +1,224 @@
|
||||
name: Desktop Release Build Smoke
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
repository:
|
||||
description: Repository to checkout, for example openchamber/openchamber or daveotero/openchamber
|
||||
required: false
|
||||
default: openchamber/openchamber
|
||||
type: string
|
||||
ref:
|
||||
description: Git ref to build (branch, tag, or sha)
|
||||
required: true
|
||||
default: feat/windows-desktop-app
|
||||
type: string
|
||||
build_macos:
|
||||
description: Build signed/notarized macOS Electron artifacts
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
build_windows:
|
||||
description: Build Windows Electron installer artifacts
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
retention_days:
|
||||
description: Artifact retention days
|
||||
required: false
|
||||
default: "7"
|
||||
type: choice
|
||||
options:
|
||||
- "1"
|
||||
- "3"
|
||||
- "7"
|
||||
- "14"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-macos-electron:
|
||||
if: ${{ inputs.build_macos }}
|
||||
name: Build macOS Electron (${{ matrix.arch }})
|
||||
runs-on: macos-26
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: aarch64-apple-darwin
|
||||
arch: arm64
|
||||
platform: darwin-aarch64
|
||||
- target: x86_64-apple-darwin
|
||||
arch: x64
|
||||
platform: darwin-x86_64
|
||||
steps:
|
||||
- name: Checkout selected ref
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ inputs.repository || github.repository }}
|
||||
ref: ${{ inputs.ref || github.ref }}
|
||||
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Install Apple Certificate
|
||||
env:
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
run: |
|
||||
KEYCHAIN_PATH=$RUNNER_TEMP/electron-signing.keychain-db
|
||||
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
|
||||
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||
|
||||
echo "$APPLE_CERTIFICATE" | base64 --decode > $RUNNER_TEMP/certificate.p12
|
||||
security import $RUNNER_TEMP/certificate.p12 \
|
||||
-P "$APPLE_CERTIFICATE_PASSWORD" \
|
||||
-A -t cert -f pkcs12 \
|
||||
-k "$KEYCHAIN_PATH"
|
||||
|
||||
security list-keychain -d user -s "$KEYCHAIN_PATH"
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: \
|
||||
-s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||
|
||||
- name: Build Electron app
|
||||
working-directory: packages/electron
|
||||
env:
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
ELECTRON_BUILDER_ARCH: ${{ matrix.arch }}
|
||||
run: |
|
||||
bun run build:web-assets
|
||||
bun run bundle:main
|
||||
# npmRebuild=false in package.json, so electron-builder won't
|
||||
# recompile native deps on its own. Rebuild against the target
|
||||
# Electron ABI before packaging, matching the release workflow.
|
||||
bun run rebuild:native
|
||||
bunx electron-builder --mac --${{ matrix.arch }} --publish=never
|
||||
|
||||
- name: Verify signature + entitlements + notarization
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
APP_DIR="packages/electron/dist/mac"
|
||||
[ -d "packages/electron/dist/mac-arm64" ] && APP_DIR="packages/electron/dist/mac-arm64"
|
||||
|
||||
APP_PATH=$(find "$APP_DIR" -maxdepth 2 -name "*.app" -print -quit)
|
||||
if [ -z "$APP_PATH" ]; then
|
||||
echo "Error: .app not found under packages/electron/dist/mac*"
|
||||
ls -la packages/electron/dist/
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Verifying $APP_PATH"
|
||||
codesign -vv --deep --strict "$APP_PATH"
|
||||
|
||||
CS_INFO=$(codesign -dv --verbose=4 "$APP_PATH" 2>&1)
|
||||
echo "$CS_INFO"
|
||||
if ! echo "$CS_INFO" | grep -q "flags=.*runtime"; then
|
||||
echo "Error: hardened runtime flag missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
xcrun stapler validate "$APP_PATH"
|
||||
|
||||
ENTITLEMENTS=$(codesign -d --entitlements :- "$APP_PATH" 2>&1 || true)
|
||||
if echo "$ENTITLEMENTS" | grep -q "com.apple.security.app-sandbox"; then
|
||||
echo "Error: app sandbox entitlement is present"
|
||||
exit 1
|
||||
fi
|
||||
for key in \
|
||||
com.apple.security.cs.allow-jit \
|
||||
com.apple.security.cs.allow-unsigned-executable-memory \
|
||||
com.apple.security.cs.disable-library-validation
|
||||
do
|
||||
if ! echo "$ENTITLEMENTS" | grep -q "<key>$key</key>"; then
|
||||
echo "Error: required entitlement missing: $key"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Upload macOS installable artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: desktop-release-smoke-macos-${{ matrix.arch }}
|
||||
path: |
|
||||
packages/electron/dist/*.dmg
|
||||
packages/electron/dist/*.zip
|
||||
packages/electron/dist/*.blockmap
|
||||
packages/electron/dist/latest-mac.yml
|
||||
if-no-files-found: error
|
||||
retention-days: ${{ fromJSON(inputs.retention_days) }}
|
||||
|
||||
build-windows-electron:
|
||||
if: ${{ inputs.build_windows }}
|
||||
name: Build Windows Electron (x64)
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- arch: x64
|
||||
target: x86_64-pc-windows-msvc
|
||||
platform: win32-x64
|
||||
steps:
|
||||
- name: Checkout selected ref
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ inputs.repository || github.repository }}
|
||||
ref: ${{ inputs.ref || github.ref }}
|
||||
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Build web assets
|
||||
working-directory: packages/electron
|
||||
run: bun run build:web-assets
|
||||
|
||||
- name: Bundle main process
|
||||
working-directory: packages/electron
|
||||
run: bun run bundle:main
|
||||
|
||||
- name: Rebuild native modules
|
||||
working-directory: packages/electron
|
||||
shell: bash
|
||||
# npmRebuild=false in package.json, so electron-builder won't
|
||||
# recompile native deps on its own. Rebuild against the target
|
||||
# Electron ABI before packaging, matching the release workflow.
|
||||
run: node ./scripts/rebuild-native.mjs
|
||||
|
||||
- name: Build Windows app
|
||||
working-directory: packages/electron
|
||||
shell: bash
|
||||
run: node ./scripts/package.mjs --win --${{ matrix.arch }} --publish=never
|
||||
|
||||
- name: Upload Windows installable artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: desktop-release-smoke-windows-${{ matrix.arch }}
|
||||
path: |
|
||||
packages/electron/dist/*.exe
|
||||
packages/electron/dist/*.blockmap
|
||||
packages/electron/dist/latest.yml
|
||||
if-no-files-found: error
|
||||
retention-days: ${{ fromJSON(inputs.retention_days) }}
|
||||
@@ -185,7 +185,7 @@ jobs:
|
||||
# target Electron ABI before packaging, otherwise better-sqlite3/
|
||||
# node-pty/bun-pty crash on require inside the packaged app.
|
||||
bun run rebuild:native
|
||||
./node_modules/.bin/electron-builder --mac --${{ matrix.arch }} --publish=never
|
||||
bunx electron-builder --mac --${{ matrix.arch }} --publish=never
|
||||
|
||||
- name: Verify signature + entitlements + notarization
|
||||
run: |
|
||||
@@ -275,6 +275,68 @@ jobs:
|
||||
path: packages/electron/dist/latest-mac.yml
|
||||
retention-days: 1
|
||||
|
||||
build-desktop-electron-windows:
|
||||
needs: create-release
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- arch: x64
|
||||
target: x86_64-pc-windows-msvc
|
||||
platform: win32-x64
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Build web assets
|
||||
working-directory: packages/electron
|
||||
run: bun run build:web-assets
|
||||
|
||||
- name: Bundle main process
|
||||
working-directory: packages/electron
|
||||
run: bun run bundle:main
|
||||
|
||||
- name: Rebuild native modules
|
||||
working-directory: packages/electron
|
||||
shell: bash
|
||||
# npmRebuild=false in package.json, so electron-builder won't
|
||||
# recompile native deps on its own — we must rebuild against the
|
||||
# target Electron ABI before packaging.
|
||||
run: node ./scripts/rebuild-native.mjs
|
||||
|
||||
- name: Build Windows app
|
||||
working-directory: packages/electron
|
||||
shell: bash
|
||||
run: node ./scripts/package.mjs --win --${{ matrix.arch }} --publish=never
|
||||
|
||||
- name: Upload installer to release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: v${{ needs.create-release.outputs.version }}
|
||||
files: |
|
||||
packages/electron/dist/*.exe
|
||||
packages/electron/dist/*.blockmap
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload update manifest as artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: latest-yml-${{ matrix.target }}
|
||||
path: packages/electron/dist/latest.yml
|
||||
retention-days: 1
|
||||
|
||||
repackage-electron-as-tauri-update:
|
||||
needs: [create-release, build-desktop-electron-macos]
|
||||
runs-on: macos-26
|
||||
@@ -449,7 +511,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
combine-electron-manifests:
|
||||
needs: [create-release, build-desktop-electron-macos]
|
||||
needs: [create-release, build-desktop-electron-macos, build-desktop-electron-windows]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -465,6 +527,12 @@ jobs:
|
||||
pattern: latest-yml-*-apple-darwin
|
||||
path: artifacts
|
||||
|
||||
- name: Download Windows latest.yml
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: latest-yml-*-pc-windows-*
|
||||
path: artifacts
|
||||
|
||||
- name: Finalize combined latest-mac.yml
|
||||
env:
|
||||
LATEST_YML_DIR: ${{ github.workspace }}/artifacts
|
||||
@@ -472,16 +540,18 @@ jobs:
|
||||
OPENCHAMBER_VERSION: ${{ needs.create-release.outputs.version }}
|
||||
run: node packages/electron/scripts/finalize-latest-yml.mjs
|
||||
|
||||
- name: Upload combined latest-mac.yml to release
|
||||
- name: Upload combined manifests to release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: v${{ needs.create-release.outputs.version }}
|
||||
files: ${{ runner.temp }}/latest-mac.yml
|
||||
files: |
|
||||
${{ runner.temp }}/latest-mac.yml
|
||||
${{ runner.temp }}/latest.yml
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
finalize-release:
|
||||
needs: [create-release, build-desktop-electron-macos, repackage-electron-as-tauri-update, publish-npm, combine-manifests, combine-electron-manifests]
|
||||
needs: [create-release, build-desktop-electron-macos, build-desktop-electron-windows, repackage-electron-as-tauri-update, publish-npm, combine-manifests, combine-electron-manifests]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
|
||||
Reference in New Issue
Block a user