From a45d3492b16605c8d49556847e212cd6f845d681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=91=98=E9=98=BF=E6=B1=9F=28Relakkes?= =?UTF-8?q?=29?= Date: Wed, 17 Jun 2026 03:38:46 +0800 Subject: [PATCH] fix(release): bound macOS notarization waits Add an outer watchdog around the signed macOS electron-builder step so hung notarytool waits return control to the retry loop instead of idling until the GitHub step timeout.\n\nTested: bun test scripts/pr/release-workflow.test.ts\nTested: git diff --check\nTested: bun run scripts/release.ts 0.4.3 --dry\nConfidence: medium\nScope-risk: narrow --- .github/workflows/release-desktop.yml | 41 +++++++++++++++++++++++++-- scripts/pr/release-workflow.test.ts | 7 ++++- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml index eb08758f..2b2add08 100644 --- a/.github/workflows/release-desktop.yml +++ b/.github/workflows/release-desktop.yml @@ -161,7 +161,7 @@ jobs: - name: Build signed macOS Electron release artifacts if: matrix.smoke_platform == 'macos' && needs.signing-preflight.outputs.macos_signed == 'true' working-directory: desktop - timeout-minutes: 90 + timeout-minutes: 80 env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} DEBUG: 'electron-builder,electron-osx-sign,electron-notarize*' @@ -184,10 +184,45 @@ jobs: security find-identity -v -p codesigning || true echo "::endgroup::" max_attempts=2 + build_timeout_seconds=2100 + + run_signed_electron_builder() { + local timeout_seconds="$1" + shift + "$@" & + local build_pid=$! + local start_epoch + start_epoch=$(date +%s) + + while true; do + if ! jobs -pr | grep -q "^${build_pid}$"; then + break + fi + + local now_epoch elapsed_seconds + now_epoch=$(date +%s) + elapsed_seconds=$((now_epoch - start_epoch)) + if [ "$elapsed_seconds" -ge "$timeout_seconds" ]; then + echo "::warning::Signed electron-builder timed out after ${elapsed_seconds}s; terminating process ${build_pid}" + pkill -TERM -P "$build_pid" 2>/dev/null || true + kill -TERM "$build_pid" 2>/dev/null || true + sleep 10 + pkill -KILL -P "$build_pid" 2>/dev/null || true + kill -KILL "$build_pid" 2>/dev/null || true + wait "$build_pid" 2>/dev/null || true + return 124 + fi + + sleep 15 + done + + wait "$build_pid" + } + for attempt in $(seq 1 "$max_attempts"); do - echo "Starting signed electron-builder attempt ${attempt}/${max_attempts} at $(date -u '+%Y-%m-%dT%H:%M:%SZ')" + echo "Starting signed electron-builder attempt ${attempt}/${max_attempts} at $(date -u '+%Y-%m-%dT%H:%M:%SZ') with ${build_timeout_seconds}s watchdog" rm -rf build-artifacts/electron - if node ./node_modules/electron-builder/out/cli/cli.js ${{ matrix.builder_args }} --publish never; then + if run_signed_electron_builder "$build_timeout_seconds" node ./node_modules/electron-builder/out/cli/cli.js ${{ matrix.builder_args }} --publish never; then echo "Finished signed electron-builder attempt ${attempt}/${max_attempts} at $(date -u '+%Y-%m-%dT%H:%M:%SZ')" exit 0 fi diff --git a/scripts/pr/release-workflow.test.ts b/scripts/pr/release-workflow.test.ts index ac38a072..1f44a50b 100644 --- a/scripts/pr/release-workflow.test.ts +++ b/scripts/pr/release-workflow.test.ts @@ -129,12 +129,17 @@ describe('release desktop workflow', () => { expect(signedBuildStep).toContain('APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}') expect(signedBuildStep).toContain('APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}') expect(signedBuildStep).not.toContain('CSC_IDENTITY_AUTO_DISCOVERY') - expect(signedBuildStep).toContain('timeout-minutes: 90') + expect(signedBuildStep).toContain('timeout-minutes: 80') expect(signedBuildStep).toContain("DEBUG: 'electron-builder,electron-osx-sign,electron-notarize*'") expect(signedBuildStep).toContain('macOS signing diagnostics') expect(signedBuildStep).toContain('xcrun --find notarytool') expect(signedBuildStep).toContain('security find-identity -v -p codesigning') expect(signedBuildStep).toContain('max_attempts=2') + expect(signedBuildStep).toContain('build_timeout_seconds=2100') + expect(signedBuildStep).toContain('run_signed_electron_builder') + expect(signedBuildStep).toContain('Signed electron-builder timed out') + expect(signedBuildStep).toContain('pkill -TERM -P "$build_pid"') + expect(signedBuildStep).toContain('with ${build_timeout_seconds}s watchdog') expect(signedBuildStep).toContain('rm -rf build-artifacts/electron') expect(signedBuildStep).toContain('Starting signed electron-builder attempt') expect(signedBuildStep).toContain('Finished signed electron-builder attempt')