Skip to content

Commit 73ca89c

Browse files
rabanspiegelrokt-clayschubiner
authored andcommitted
fix: native module architecture mismatch in x64 builds (generalaction#709)
* fix: build each mac architecture separately to fix native module mismatch (generalaction#706) * fix: fail verification if no app bundles found
1 parent a2ed2fe commit 73ca89c

1 file changed

Lines changed: 113 additions & 43 deletions

File tree

.github/workflows/release.yml

Lines changed: 113 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -62,28 +62,6 @@ jobs:
6262
- name: Build app (ts + vite)
6363
run: npm run build
6464

65-
- name: Rebuild native modules (per-arch)
66-
run: |
67-
set -euo pipefail
68-
ELECTRON_VERSION=$(node -p "require('electron/package.json').version")
69-
ARCH_INPUT="${{ github.event.inputs.arch }}"
70-
if [ -z "$ARCH_INPUT" ] || [ "$ARCH_INPUT" = "both" ]; then ARGS=(x64 arm64); else ARGS=("$ARCH_INPUT"); fi
71-
echo "Rebuilding sqlite3,node-pty,keytar for Electron $ELECTRON_VERSION: ${ARGS[*]}"
72-
for A in "${ARGS[@]}"; do
73-
npm_config_build_from_source=true npx @electron/rebuild -f -a "$A" -v "$ELECTRON_VERSION" -w sqlite3,node-pty,keytar
74-
done
75-
76-
- name: Rebuild native modules (per-arch)
77-
run: |
78-
set -euo pipefail
79-
ELECTRON_VERSION=$(node -p "require('electron/package.json').version")
80-
ARCH_INPUT="${{ github.event.inputs.arch }}"
81-
if [ -z "$ARCH_INPUT" ] || [ "$ARCH_INPUT" = "both" ]; then ARGS=(x64 arm64); else ARGS=("$ARCH_INPUT"); fi
82-
echo "Rebuilding sqlite3,node-pty,keytar for Electron $ELECTRON_VERSION: ${ARGS[*]}"
83-
for A in "${ARGS[@]}"; do
84-
npm_config_build_from_source=true npx @electron/rebuild -f -a "$A" -v "$ELECTRON_VERSION" -w sqlite3,node-pty,keytar
85-
done
86-
8765
- name: Inject PostHog config (dev build job)
8866
env:
8967
PH_KEY: ${{ secrets.POSTHOG_PROJECT_API_KEY }}
@@ -109,18 +87,71 @@ jobs:
10987
env:
11088
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
11189
run: |
90+
set -euo pipefail
11291
ARCH_INPUT="${{ github.event.inputs.arch }}"
11392
if [ -z "$ARCH_INPUT" ] || [ "$ARCH_INPUT" = "both" ]; then
114-
FLAGS="--x64 --arm64"
93+
ARCHS=(x64 arm64)
11594
elif [ "$ARCH_INPUT" = "arm64" ]; then
116-
FLAGS="--arm64"
95+
ARCHS=(arm64)
11796
elif [ "$ARCH_INPUT" = "x64" ]; then
118-
FLAGS="--x64"
97+
ARCHS=(x64)
11998
else
12099
echo "Unknown arch input: $ARCH_INPUT" && exit 1
121100
fi
122-
echo "Building for: $FLAGS"
123-
npx electron-builder --mac dmg $FLAGS --publish never --config.npmRebuild=false
101+
ELECTRON_VERSION=$(node -p "require('electron/package.json').version")
102+
# Build each architecture separately to ensure native modules match.
103+
# Building both at once with --x64 --arm64 would use the same node_modules/
104+
# for both, causing architecture mismatches (issue #706).
105+
for A in "${ARCHS[@]}"; do
106+
echo "=== Building for $A ==="
107+
echo "Rebuilding native modules for $A (Electron $ELECTRON_VERSION)"
108+
npm_config_build_from_source=true npx @electron/rebuild -f -a "$A" -v "$ELECTRON_VERSION" -w sqlite3,node-pty,keytar
109+
echo "Packaging $A DMG"
110+
npx electron-builder --mac dmg --$A --publish never --config.npmRebuild=false
111+
done
112+
113+
- name: Verify native module architectures match Electron
114+
run: |
115+
set -euo pipefail
116+
# Verify that each build has native modules matching its Electron binary architecture.
117+
# This catches issues like #706 where x64 builds had arm64 native modules.
118+
VERIFIED_COUNT=0
119+
for APP_DIR in release/mac-*/emdash.app; do
120+
[ -d "$APP_DIR" ] || continue
121+
ARCH_DIR=$(basename "$(dirname "$APP_DIR")")
122+
case "$ARCH_DIR" in
123+
mac-arm64) EXPECTED_ARCH="arm64" ;;
124+
mac-x64|mac) EXPECTED_ARCH="x86_64" ;;
125+
*) echo "Unknown arch dir: $ARCH_DIR"; continue ;;
126+
esac
127+
echo "=== Checking $APP_DIR (expected: $EXPECTED_ARCH) ==="
128+
ELECTRON_BIN="$APP_DIR/Contents/MacOS/emdash"
129+
SQLITE_NODE="$APP_DIR/Contents/Resources/app.asar.unpacked/node_modules/sqlite3/build/Release/node_sqlite3.node"
130+
# Check Electron binary architecture
131+
ELECTRON_ARCH=$(file "$ELECTRON_BIN" | grep -o 'arm64\|x86_64' | head -1)
132+
echo "Electron binary: $ELECTRON_ARCH"
133+
if [ "$ELECTRON_ARCH" != "$EXPECTED_ARCH" ]; then
134+
echo "::error::Electron arch mismatch: got $ELECTRON_ARCH, expected $EXPECTED_ARCH"
135+
exit 1
136+
fi
137+
# Check sqlite3 native module architecture
138+
if [ -f "$SQLITE_NODE" ]; then
139+
SQLITE_ARCH=$(file "$SQLITE_NODE" | grep -o 'arm64\|x86_64' | head -1)
140+
echo "sqlite3 native module: $SQLITE_ARCH"
141+
if [ "$SQLITE_ARCH" != "$EXPECTED_ARCH" ]; then
142+
echo "::error::sqlite3 arch mismatch: got $SQLITE_ARCH, expected $EXPECTED_ARCH"
143+
exit 1
144+
fi
145+
else
146+
echo "::warning::sqlite3 native module not found at $SQLITE_NODE"
147+
fi
148+
VERIFIED_COUNT=$((VERIFIED_COUNT + 1))
149+
done
150+
if [ "$VERIFIED_COUNT" -eq 0 ]; then
151+
echo "::error::No app bundles found to verify"
152+
exit 1
153+
fi
154+
echo "Verified $VERIFIED_COUNT app bundle(s)"
124155
125156
- name: Smoke test sqlite3 in packaged app (arm64)
126157
if: ${{ github.event.inputs.arch == '' || github.event.inputs.arch == 'arm64' || github.event.inputs.arch == 'both' }}
@@ -322,6 +353,7 @@ jobs:
322353
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
323354
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
324355
run: |
356+
set -euo pipefail
325357
# Guard against legacy env vars overriding cert-import flow
326358
unset CSC_LINK CSC_KEY_PASSWORD CSC_NAME
327359
# Force Apple ID notarization for the app build to avoid bad APPLE_API_KEY paths
@@ -331,30 +363,68 @@ jobs:
331363
echo "App notarization method: Apple ID (TEAM_ID=$TEAM_ID)"
332364
ARCH_INPUT="${{ github.event.inputs.arch }}"
333365
if [ -z "$ARCH_INPUT" ] || [ "$ARCH_INPUT" = "both" ]; then
334-
FLAGS="--x64 --arm64"
366+
ARCHS=(x64 arm64)
335367
elif [ "$ARCH_INPUT" = "arm64" ]; then
336-
FLAGS="--arm64"
368+
ARCHS=(arm64)
337369
elif [ "$ARCH_INPUT" = "x64" ]; then
338-
FLAGS="--x64"
370+
ARCHS=(x64)
339371
else
340372
echo "Unknown arch input: $ARCH_INPUT" && exit 1
341373
fi
342-
# Rebuild native modules per-arch before packaging
343374
ELECTRON_VERSION=$(node -p "require('electron/package.json').version")
344-
for flag in $FLAGS; do
345-
case "$flag" in
346-
--x64) A=x64 ;;
347-
--arm64) A=arm64 ;;
348-
*) continue ;;
349-
esac
350-
echo "electron-rebuild for $A (Electron $ELECTRON_VERSION)"
375+
# Build each architecture separately to ensure native modules match.
376+
# Building both at once with --x64 --arm64 would use the same node_modules/
377+
# for both, causing architecture mismatches (issue #706).
378+
for A in "${ARCHS[@]}"; do
379+
echo "=== Building for $A ==="
380+
echo "Rebuilding native modules for $A (Electron $ELECTRON_VERSION)"
351381
npm_config_build_from_source=true npx @electron/rebuild -f -a "$A" -v "$ELECTRON_VERSION" -w sqlite3,node-pty,keytar
382+
echo "Packaging $A DMG and ZIP"
383+
npx electron-builder --mac dmg zip --$A --publish never --config.npmRebuild=false
352384
done
353-
echo "Building signed for: $FLAGS"
354-
# Build signed + notarized artifacts locally but DO NOT publish yet.
355-
# We will staple and validate before uploading to the GitHub Release.
356-
# Build both dmg (for manual download) and zip (for auto-update)
357-
npx electron-builder --mac dmg zip $FLAGS --publish never --config.npmRebuild=false
385+
386+
- name: Verify native module architectures match Electron
387+
run: |
388+
set -euo pipefail
389+
# Verify that each build has native modules matching its Electron binary architecture.
390+
# This catches issues like #706 where x64 builds had arm64 native modules.
391+
VERIFIED_COUNT=0
392+
for APP_DIR in release/mac-*/emdash.app; do
393+
[ -d "$APP_DIR" ] || continue
394+
ARCH_DIR=$(basename "$(dirname "$APP_DIR")")
395+
case "$ARCH_DIR" in
396+
mac-arm64) EXPECTED_ARCH="arm64" ;;
397+
mac-x64|mac) EXPECTED_ARCH="x86_64" ;;
398+
*) echo "Unknown arch dir: $ARCH_DIR"; continue ;;
399+
esac
400+
echo "=== Checking $APP_DIR (expected: $EXPECTED_ARCH) ==="
401+
ELECTRON_BIN="$APP_DIR/Contents/MacOS/emdash"
402+
SQLITE_NODE="$APP_DIR/Contents/Resources/app.asar.unpacked/node_modules/sqlite3/build/Release/node_sqlite3.node"
403+
# Check Electron binary architecture
404+
ELECTRON_ARCH=$(file "$ELECTRON_BIN" | grep -o 'arm64\|x86_64' | head -1)
405+
echo "Electron binary: $ELECTRON_ARCH"
406+
if [ "$ELECTRON_ARCH" != "$EXPECTED_ARCH" ]; then
407+
echo "::error::Electron arch mismatch: got $ELECTRON_ARCH, expected $EXPECTED_ARCH"
408+
exit 1
409+
fi
410+
# Check sqlite3 native module architecture
411+
if [ -f "$SQLITE_NODE" ]; then
412+
SQLITE_ARCH=$(file "$SQLITE_NODE" | grep -o 'arm64\|x86_64' | head -1)
413+
echo "sqlite3 native module: $SQLITE_ARCH"
414+
if [ "$SQLITE_ARCH" != "$EXPECTED_ARCH" ]; then
415+
echo "::error::sqlite3 arch mismatch: got $SQLITE_ARCH, expected $EXPECTED_ARCH"
416+
exit 1
417+
fi
418+
else
419+
echo "::warning::sqlite3 native module not found at $SQLITE_NODE"
420+
fi
421+
VERIFIED_COUNT=$((VERIFIED_COUNT + 1))
422+
done
423+
if [ "$VERIFIED_COUNT" -eq 0 ]; then
424+
echo "::error::No app bundles found to verify"
425+
exit 1
426+
fi
427+
echo "Verified $VERIFIED_COUNT app bundle(s)"
358428
359429
- name: Smoke test sqlite3 in packaged app (arm64, signed)
360430
if: ${{ github.event.inputs.arch == '' || github.event.inputs.arch == 'arm64' || github.event.inputs.arch == 'both' }}

0 commit comments

Comments
 (0)