From a517a5d96c2f3cf99038f1d56b2ca5d257d0eb48 Mon Sep 17 00:00:00 2001 From: matt Date: Fri, 13 Feb 2026 01:34:31 +0900 Subject: [PATCH] feat(release): enhance CI workflow for macOS and Windows builds - Added build and verification steps for both macOS and Windows in the GitHub Actions workflow. - Included checks to ensure the necessary packaged inputs are present after the build process. This commit improves the CI workflow by ensuring that builds are properly verified across platforms, enhancing reliability and consistency in the release process. --- .github/workflows/release.yml | 19 ++++++++++++++++ src/main/index.ts | 43 ++++++++++++++++++++++++++++------- 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 47576708..4fe91ef9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -83,6 +83,15 @@ jobs: VERSION="${GITHUB_REF#refs/tags/v}" pnpm pkg set version="$VERSION" + - name: Build app (macOS) + run: pnpm build + + - name: Verify packaged inputs (macOS) + run: | + test -f dist-electron/main/index.cjs + test -f dist-electron/preload/index.js + test -f out/renderer/index.html + - name: Package & Release (macOS) env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -130,6 +139,16 @@ jobs: VERSION="${GITHUB_REF#refs/tags/v}" pnpm pkg set version="$VERSION" + - name: Build app (Windows) + run: pnpm build + + - name: Verify packaged inputs (Windows) + shell: bash + run: | + test -f dist-electron/main/index.cjs + test -f dist-electron/preload/index.js + test -f out/renderer/index.html + - name: Package & Release (Windows) env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/src/main/index.ts b/src/main/index.ts index 97913421..c5a22bfd 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -23,13 +23,19 @@ import { join } from 'path'; import { initializeIpcHandlers, removeIpcHandlers } from './ipc/handlers'; -// Icon path - works for both dev and production -const getIconPath = (): string => { +// Window icon path for non-mac platforms. +const getWindowIconPath = (): string | undefined => { const isDev = process.env.NODE_ENV === 'development'; - if (isDev) { - return join(process.cwd(), 'resources/icon.png'); + const candidates = isDev + ? [join(process.cwd(), 'resources/icon.png')] + : [join(process.resourcesPath, 'resources/icon.png'), join(__dirname, '../../resources/icon.png')]; + + for (const candidate of candidates) { + if (existsSync(candidate)) { + return candidate; + } } - return join(__dirname, '../../resources/icon.png'); + return undefined; }; const logger = createLogger('App'); @@ -40,6 +46,14 @@ const HTTP_SERVER_START = 'httpServer:start'; const HTTP_SERVER_STOP = 'httpServer:stop'; const HTTP_SERVER_GET_STATUS = 'httpServer:getStatus'; +process.on('unhandledRejection', (reason) => { + logger.error('Unhandled promise rejection in main process:', reason); +}); + +process.on('uncaughtException', (error) => { + logger.error('Uncaught exception in main process:', error); +}); + import { HttpServer } from './services/infrastructure/HttpServer'; import { configManager, @@ -349,10 +363,11 @@ function syncTrafficLightPosition(win: BrowserWindow): void { */ function createWindow(): void { const isMac = process.platform === 'darwin'; + const iconPath = isMac ? undefined : getWindowIconPath(); mainWindow = new BrowserWindow({ width: DEFAULT_WINDOW_WIDTH, height: DEFAULT_WINDOW_HEIGHT, - icon: getIconPath(), + ...(iconPath ? { icon: iconPath } : {}), webPreferences: { preload: join(__dirname, '../preload/index.js'), nodeIntegration: false, @@ -383,6 +398,18 @@ function createWindow(): void { } }); + // Log top-level renderer load failures (helps diagnose blank/black window issues in packaged apps) + mainWindow.webContents.on( + 'did-fail-load', + (_event, errorCode, errorDescription, validatedURL, isMainFrame) => { + if (isMainFrame) { + logger.error( + `Failed to load renderer (code=${errorCode}): ${errorDescription} - ${validatedURL}` + ); + } + } + ); + // Sync traffic light position when zoom changes (Cmd+/-, Cmd+0) // zoom-changed event doesn't fire in Electron 40, so we detect zoom keys directly. // Also keeps zoom bounds within a practical readability range. @@ -467,8 +494,8 @@ void app.whenReady().then(() => { if (!config.general.showDockIcon) { app.dock?.hide(); } - // Set dock icon - app.dock?.setIcon(getIconPath()); + // macOS app icon is already provided by the signed bundle (.icns) + // so we avoid runtime setIcon calls that can fail and block startup. } // Then create window