1010
1111env :
1212 PYTHON_VERSION : " 3.11"
13+ DISABLE_MACOS_DMG : " true" # Flag to disable DMG creation for macOS
14+ DISABLE_MACOS_NOTARIZATION : " true" # Flag to disable notarization for macOS
1315
1416jobs :
1517 build :
2527 executable-name : " Jumperless"
2628 icon-path : " assets/icons/icon.png"
2729
30+ - os : ubuntu-latest
31+ platform : linux
32+ arch : x86
33+ artifact-name : " Jumperless-Linux-x86"
34+ executable-name : " Jumperless"
35+ icon-path : " assets/icons/icon.png"
36+
2837 # macOS builds (Intel)
2938 - os : macos-13
3039 platform : macos
4857 artifact-name : " Jumperless-Windows-x64"
4958 executable-name : " Jumperless"
5059 icon-path : " assets/icons/icon.ico"
60+
61+ - os : windows-latest
62+ platform : windows
63+ arch : x86
64+ artifact-name : " Jumperless-Windows-x86"
65+ executable-name : " Jumperless"
66+ icon-path : " assets/icons/icon.ico"
5167
5268 runs-on : ${{ matrix.os }}
5369
@@ -84,7 +100,10 @@ jobs:
84100 - name : Install system dependencies (macOS)
85101 if : matrix.platform == 'macos'
86102 run : |
87- brew install create-dmg
103+ # Only install create-dmg if DMG creation is enabled
104+ if [ "${{ env.DISABLE_MACOS_DMG }}" != "true" ]; then
105+ brew install create-dmg
106+ fi
88107
89108 - name : Install Python dependencies
90109 run : |
@@ -128,6 +147,92 @@ jobs:
128147 # Use PyInstaller with direct command line arguments for consistent builds
129148 echo "Building with PyInstaller"
130149 python -m PyInstaller --clean --windowed --name "Jumperless" --distpath dist/macos --workpath build/macos --icon "assets/icons/icon.icns" JumperlessWokwiBridge.py
150+
151+ - name : Code Sign macOS App
152+ if : matrix.platform == 'macos'
153+ env :
154+ MACOS_CERTIFICATE : ${{ secrets.MACOS_CERTIFICATE }}
155+ MACOS_CERTIFICATE_PASSWORD : ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
156+ run : |
157+ # Only proceed if certificate is available
158+ if [ -z "$MACOS_CERTIFICATE" ]; then
159+ echo "No signing certificate provided, skipping code signing"
160+ exit 0
161+ fi
162+
163+ # Create temporary keychain
164+ security create-keychain -p temp_keychain_password temp_keychain
165+ security default-keychain -s temp_keychain
166+ security unlock-keychain -p temp_keychain_password temp_keychain
167+
168+ # Decode and import certificate
169+ echo "$MACOS_CERTIFICATE" | base64 --decode > certificate.p12
170+ security import certificate.p12 -k temp_keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
171+
172+ # Enable codesign to access the keychain
173+ security set-key-partition-list -S apple-tool:,apple: -s -k temp_keychain_password temp_keychain
174+
175+ # Find the app bundle
176+ APP_PATH="dist/macos/Jumperless.app"
177+ if [ -d "$APP_PATH" ]; then
178+ echo "Signing $APP_PATH"
179+ # Sign the app bundle
180+ codesign --force --sign "Developer ID Application" --deep --options runtime "$APP_PATH"
181+
182+ # Verify the signature
183+ codesign --verify --verbose "$APP_PATH"
184+ echo "Code signing completed successfully"
185+ else
186+ echo "App bundle not found at $APP_PATH"
187+ exit 1
188+ fi
189+
190+ # Clean up
191+ rm certificate.p12
192+ security delete-keychain temp_keychain
193+
194+ - name : Notarize macOS App
195+ if : matrix.platform == 'macos'
196+ env :
197+ MACOS_CERTIFICATE : ${{ secrets.MACOS_CERTIFICATE }}
198+ APPLE_ID : ${{ secrets.APPLE_ID }}
199+ APPLE_ID_PASSWORD : ${{ secrets.APPLE_ID_PASSWORD }}
200+ APPLE_TEAM_ID : ${{ secrets.APPLE_TEAM_ID }}
201+ DISABLE_MACOS_NOTARIZATION : ${{ env.DISABLE_MACOS_NOTARIZATION }}
202+ run : |
203+ # Check if notarization is disabled
204+ if [ "$DISABLE_MACOS_NOTARIZATION" = "true" ]; then
205+ echo "Notarization disabled by DISABLE_MACOS_NOTARIZATION flag"
206+ exit 0
207+ fi
208+
209+ # Only proceed if both signing certificate and Apple ID are available
210+ if [ -z "$MACOS_CERTIFICATE" ] || [ -z "$APPLE_ID" ]; then
211+ echo "No signing certificate or Apple ID provided, skipping notarization"
212+ exit 0
213+ fi
214+
215+ APP_PATH="dist/macos/Jumperless.app"
216+ if [ -d "$APP_PATH" ]; then
217+ echo "Creating archive for notarization"
218+ ditto -c -k --keepParent "$APP_PATH" "Jumperless.zip"
219+
220+ echo "Submitting for notarization"
221+ xcrun notarytool submit "Jumperless.zip" \
222+ --apple-id "$APPLE_ID" \
223+ --password "$APPLE_ID_PASSWORD" \
224+ --team-id "$APPLE_TEAM_ID" \
225+ --wait
226+
227+ echo "Stapling notarization"
228+ xcrun stapler staple "$APP_PATH"
229+
230+ echo "Notarization completed successfully"
231+ rm "Jumperless.zip"
232+ else
233+ echo "App bundle not found for notarization"
234+ exit 1
235+ fi
131236
132237 - name : Build with PyInstaller (Windows)
133238 if : matrix.platform == 'windows'
@@ -147,11 +252,15 @@ jobs:
147252 if : matrix.platform == 'linux'
148253 run : |
149254 python Scripts/package_app.py --platform linux --arch ${{ matrix.arch }}
255+ env :
256+ PREFER_TARGZ : " true" # Signal to prefer tar.gz over zip for Linux
150257
151258 - name : Create platform-specific package (macOS)
152259 if : matrix.platform == 'macos'
153260 run : |
154261 python Scripts/package_app.py --platform macos --arch ${{ matrix.arch }}
262+ env :
263+ DISABLE_MACOS_DMG : ${{ env.DISABLE_MACOS_DMG }}
155264
156265 - name : Create platform-specific package (Windows)
157266 if : matrix.platform == 'windows'
@@ -220,10 +329,22 @@ jobs:
220329 Multi-platform release of the Jumperless Wokwi Bridge application.
221330
222331 ### Downloads
223- - **Linux x64**: Jumperless-Linux-x64 (AppImage + Python fallback)
224- - **macOS Intel**: Jumperless-macOS-Intel (DMG + Python fallback)
225- - **macOS Apple Silicon**: Jumperless-macOS-Apple-Silicon (DMG + Python fallback)
332+ - **Linux x64**: Jumperless-Linux-x64 (tar.gz + Python fallback)
333+ - **Linux x86**: Jumperless-Linux-x86 (tar.gz + Python fallback)
334+ - **macOS Intel**: Jumperless-macOS-Intel (App bundle + Python fallback)
335+ - **macOS Apple Silicon**: Jumperless-macOS-Apple-Silicon (App bundle + Python fallback)
226336 - **Windows x64**: Jumperless-Windows-x64 (EXE + Python fallback)
337+ - **Windows x86**: Jumperless-Windows-x86 (EXE + Python fallback)
338+
339+ ### macOS Users - Important Note
340+ If the app is code-signed with a Developer ID, you should be able to run it directly.
341+
342+ **If you get a security warning, try these steps:**
343+ 1. Right-click the app and select "Open" to bypass Gatekeeper
344+ 2. Or remove the quarantine attribute:
345+ ```bash
346+ xattr -d com.apple.quarantine Jumperless.app
347+ ```
227348
228349 ### Installation Methods
229350 Each package includes multiple ways to run Jumperless:
@@ -239,10 +360,12 @@ jobs:
239360 See the README.md in each package for detailed instructions.
240361
241362 ### What's New
242- - Multi-platform CI/CD pipeline
363+ - Multi-platform CI/CD pipeline with x86 support
364+ - macOS code signing support (notarization disabled by default for faster builds)
243365 - Improved packaging with modern tools
244366 - Better error handling and logging
245367 - Enhanced platform-specific optimizations
368+ - Linux packages now use tar.gz format
246369
247370 draft : false
248371 prerelease : ${{ !startsWith(github.ref, 'refs/tags/') }}
0 commit comments