@@ -26,6 +26,9 @@ permissions:
2626jobs :
2727 build-macos :
2828 runs-on : macos-latest
29+ strategy :
30+ matrix :
31+ arch : [x64, arm64]
2932 steps :
3033 - name : Checkout code
3134 uses : actions/checkout@v4
4144 working-directory : apps/desktop
4245 run : npm ci
4346
44- - name : Build macOS app
47+ - name : Build macOS app (${{ matrix.arch }})
4548 working-directory : apps/desktop
46- run : npm run build:mac
49+ run : npm run build:mac -- --${{ matrix.arch }}
4750 env :
4851 # Skip notarization in CI (requires Apple Developer credentials)
4952 CSC_IDENTITY_AUTO_DISCOVERY : false
@@ -52,10 +55,21 @@ jobs:
5255 working-directory : apps/desktop
5356 run : ls -lah dist/
5457
58+ - name : Rename artifacts with architecture
59+ working-directory : apps/desktop/dist
60+ run : |
61+ for file in *.dmg; do
62+ if [ -f "$file" ]; then
63+ base="${file%.dmg}"
64+ mv "$file" "${base}-${{ matrix.arch }}.dmg"
65+ fi
66+ done
67+ ls -lah
68+
5569 - name : Upload macOS artifacts
5670 uses : actions/upload-artifact@v4
5771 with :
58- name : kortix-macos-${{ github.sha }}
72+ name : kortix-macos-${{ matrix.arch }}-${{ github.sha }}
5973 path : |
6074 apps/desktop/dist/*.dmg
6175 retention-days : 30
@@ -96,9 +110,187 @@ jobs:
96110 apps/desktop/dist/*.exe
97111 retention-days : 30
98112
99- create-release :
113+ upload-to-r2 :
100114 needs : [build-macos, build-windows]
101115 runs-on : ubuntu-latest
116+ if : github.ref == 'refs/heads/main' || github.ref == 'refs/heads/PRODUCTION'
117+ steps :
118+ - name : Checkout code
119+ uses : actions/checkout@v4
120+
121+ - name : Get version from package.json
122+ id : version
123+ run : |
124+ VERSION=$(node -p "require('./apps/desktop/package.json').version")
125+ echo "version=$VERSION" >> $GITHUB_OUTPUT
126+
127+ - name : Download macOS x64 artifacts
128+ uses : actions/download-artifact@v4
129+ with :
130+ name : kortix-macos-x64-${{ github.sha }}
131+ path : ./artifacts/macos-x64
132+
133+ - name : Download macOS ARM64 artifacts
134+ uses : actions/download-artifact@v4
135+ with :
136+ name : kortix-macos-arm64-${{ github.sha }}
137+ path : ./artifacts/macos-arm64
138+
139+ - name : Download Windows artifacts
140+ uses : actions/download-artifact@v4
141+ with :
142+ name : kortix-windows-${{ github.sha }}
143+ path : ./artifacts/windows
144+
145+ - name : Configure AWS CLI for R2
146+ uses : aws-actions/configure-aws-credentials@v4
147+ with :
148+ aws-access-key-id : ${{ secrets.R2_ACCESS_KEY_ID }}
149+ aws-secret-access-key : ${{ secrets.R2_SECRET_ACCESS_KEY }}
150+ aws-region : auto
151+
152+ - name : Upload to Cloudflare R2
153+ env :
154+ R2_ENDPOINT : ${{ secrets.R2_ENDPOINT }}
155+ R2_BUCKET : ${{ secrets.R2_BUCKET }}
156+ VERSION : ${{ steps.version.outputs.version }}
157+ run : |
158+ # Set environment prefix (staging vs production)
159+ if [[ "${{ github.ref }}" == "refs/heads/PRODUCTION" ]]; then
160+ ENV_PREFIX="production"
161+ else
162+ ENV_PREFIX="staging"
163+ fi
164+
165+ echo "📦 Uploading to R2 bucket: $R2_BUCKET"
166+ echo "🏷️ Version: $VERSION"
167+ echo "🌍 Environment: $ENV_PREFIX"
168+
169+ # Upload macOS Intel (x64)
170+ for file in ./artifacts/macos-x64/*.dmg; do
171+ if [ -f "$file" ]; then
172+ filename=$(basename "$file")
173+ aws s3 cp "$file" \
174+ "s3://$R2_BUCKET/desktop/$ENV_PREFIX/$VERSION/macos/$filename" \
175+ --endpoint-url "$R2_ENDPOINT" \
176+ --content-type "application/x-apple-diskimage"
177+
178+ # Also upload as "latest" for easy access
179+ aws s3 cp "$file" \
180+ "s3://$R2_BUCKET/desktop/$ENV_PREFIX/latest/macos/$filename" \
181+ --endpoint-url "$R2_ENDPOINT" \
182+ --content-type "application/x-apple-diskimage"
183+
184+ echo "✅ Uploaded macOS x64: $filename"
185+ fi
186+ done
187+
188+ # Upload macOS Apple Silicon (ARM64)
189+ for file in ./artifacts/macos-arm64/*.dmg; do
190+ if [ -f "$file" ]; then
191+ filename=$(basename "$file")
192+ aws s3 cp "$file" \
193+ "s3://$R2_BUCKET/desktop/$ENV_PREFIX/$VERSION/macos/$filename" \
194+ --endpoint-url "$R2_ENDPOINT" \
195+ --content-type "application/x-apple-diskimage"
196+
197+ # Also upload as "latest"
198+ aws s3 cp "$file" \
199+ "s3://$R2_BUCKET/desktop/$ENV_PREFIX/latest/macos/$filename" \
200+ --endpoint-url "$R2_ENDPOINT" \
201+ --content-type "application/x-apple-diskimage"
202+
203+ echo "✅ Uploaded macOS ARM64: $filename"
204+ fi
205+ done
206+
207+ # Upload Windows
208+ for file in ./artifacts/windows/*.exe; do
209+ if [ -f "$file" ]; then
210+ filename=$(basename "$file")
211+ aws s3 cp "$file" \
212+ "s3://$R2_BUCKET/desktop/$ENV_PREFIX/$VERSION/windows/$filename" \
213+ --endpoint-url "$R2_ENDPOINT" \
214+ --content-type "application/x-msdownload"
215+
216+ # Also upload as "latest"
217+ aws s3 cp "$file" \
218+ "s3://$R2_BUCKET/desktop/$ENV_PREFIX/latest/windows/$filename" \
219+ --endpoint-url "$R2_ENDPOINT" \
220+ --content-type "application/x-msdownload"
221+
222+ echo "✅ Uploaded Windows: $filename"
223+ fi
224+ done
225+
226+ echo "🎉 All files uploaded to R2!"
227+
228+ - name : Generate download URLs
229+ env :
230+ R2_PUBLIC_URL : ${{ secrets.R2_PUBLIC_URL }}
231+ VERSION : ${{ steps.version.outputs.version }}
232+ run : |
233+ if [[ "${{ github.ref }}" == "refs/heads/PRODUCTION" ]]; then
234+ ENV_PREFIX="production"
235+ else
236+ ENV_PREFIX="staging"
237+ fi
238+
239+ echo "## 📥 Download URLs" >> $GITHUB_STEP_SUMMARY
240+ echo "" >> $GITHUB_STEP_SUMMARY
241+ echo "### Version $VERSION" >> $GITHUB_STEP_SUMMARY
242+ echo "" >> $GITHUB_STEP_SUMMARY
243+
244+ # List all uploaded files and create URLs
245+ for file in ./artifacts/macos-x64/*.dmg; do
246+ if [ -f "$file" ]; then
247+ filename=$(basename "$file")
248+ echo "- **macOS Intel (x64)**: ${R2_PUBLIC_URL}/desktop/${ENV_PREFIX}/${VERSION}/macos/${filename}" >> $GITHUB_STEP_SUMMARY
249+ fi
250+ done
251+
252+ for file in ./artifacts/macos-arm64/*.dmg; do
253+ if [ -f "$file" ]; then
254+ filename=$(basename "$file")
255+ echo "- **macOS Apple Silicon (ARM64)**: ${R2_PUBLIC_URL}/desktop/${ENV_PREFIX}/${VERSION}/macos/${filename}" >> $GITHUB_STEP_SUMMARY
256+ fi
257+ done
258+
259+ for file in ./artifacts/windows/*.exe; do
260+ if [ -f "$file" ]; then
261+ filename=$(basename "$file")
262+ echo "- **Windows**: ${R2_PUBLIC_URL}/desktop/${ENV_PREFIX}/${VERSION}/windows/${filename}" >> $GITHUB_STEP_SUMMARY
263+ fi
264+ done
265+
266+ echo "" >> $GITHUB_STEP_SUMMARY
267+ echo "### Latest (always current)" >> $GITHUB_STEP_SUMMARY
268+ echo "" >> $GITHUB_STEP_SUMMARY
269+
270+ for file in ./artifacts/macos-x64/*.dmg; do
271+ if [ -f "$file" ]; then
272+ filename=$(basename "$file")
273+ echo "- **macOS Intel (x64)**: ${R2_PUBLIC_URL}/desktop/${ENV_PREFIX}/latest/macos/${filename}" >> $GITHUB_STEP_SUMMARY
274+ fi
275+ done
276+
277+ for file in ./artifacts/macos-arm64/*.dmg; do
278+ if [ -f "$file" ]; then
279+ filename=$(basename "$file")
280+ echo "- **macOS Apple Silicon (ARM64)**: ${R2_PUBLIC_URL}/desktop/${ENV_PREFIX}/latest/macos/${filename}" >> $GITHUB_STEP_SUMMARY
281+ fi
282+ done
283+
284+ for file in ./artifacts/windows/*.exe; do
285+ if [ -f "$file" ]; then
286+ filename=$(basename "$file")
287+ echo "- **Windows**: ${R2_PUBLIC_URL}/desktop/${ENV_PREFIX}/latest/windows/${filename}" >> $GITHUB_STEP_SUMMARY
288+ fi
289+ done
290+
291+ create-release :
292+ needs : [build-macos, build-windows, upload-to-r2]
293+ runs-on : ubuntu-latest
102294 if : |
103295 github.event_name == 'workflow_dispatch' &&
104296 github.event.inputs.create_release == 'true' ||
@@ -109,17 +301,22 @@ jobs:
109301
110302 - name : Get version from package.json
111303 id : version
112- working-directory : apps/desktop
113304 run : |
114- VERSION=$(node -p "require('./package.json').version")
305+ VERSION=$(node -p "require('./apps/desktop/ package.json').version")
115306 echo "version=$VERSION" >> $GITHUB_OUTPUT
116307 echo "tag=v$VERSION" >> $GITHUB_OUTPUT
117308
118- - name : Download macOS artifacts
309+ - name : Download macOS x64 artifacts
119310 uses : actions/download-artifact@v4
120311 with :
121- name : kortix-macos-${{ github.sha }}
122- path : ./artifacts/macos
312+ name : kortix-macos-x64-${{ github.sha }}
313+ path : ./artifacts/macos-x64
314+
315+ - name : Download macOS ARM64 artifacts
316+ uses : actions/download-artifact@v4
317+ with :
318+ name : kortix-macos-arm64-${{ github.sha }}
319+ path : ./artifacts/macos-arm64
123320
124321 - name : Download Windows artifacts
125322 uses : actions/download-artifact@v4
@@ -129,8 +326,10 @@ jobs:
129326
130327 - name : List all artifacts
131328 run : |
132- echo "=== macOS artifacts ==="
133- ls -lah ./artifacts/macos/
329+ echo "=== macOS x64 artifacts ==="
330+ ls -lah ./artifacts/macos-x64/
331+ echo "=== macOS ARM64 artifacts ==="
332+ ls -lah ./artifacts/macos-arm64/
134333 echo "=== Windows artifacts ==="
135334 ls -lah ./artifacts/windows/
136335
@@ -142,22 +341,28 @@ jobs:
142341 draft : false
143342 prerelease : false
144343 files : |
145- ./artifacts/macos/*
344+ ./artifacts/macos-x64/*
345+ ./artifacts/macos-arm64/*
146346 ./artifacts/windows/*
147347 body : |
148348 ## Kortix Desktop App ${{ steps.version.outputs.version }}
149349
150350 ### Downloads
151351
152- - **macOS**: Download the `.dmg` file
153- - **Windows**: Download the `.exe` file
352+ **macOS:**
353+ - **Apple Silicon (M1/M2/M3)**: Download the `-arm64.dmg` file
354+ - **Intel**: Download the `-x64.dmg` file
355+
356+ **Windows:**
357+ - Download the `.exe` installer
154358
155359 ### Installation
156360
157361 **macOS:**
158- 1. Download and open the `.dmg` file
159- 2. Drag Kortix to your Applications folder
160- 3. Open Kortix from Applications
362+ 1. Download the appropriate `.dmg` file for your Mac (Apple Silicon or Intel)
363+ 2. Open the `.dmg` file
364+ 3. Drag Kortix to your Applications folder
365+ 4. Open Kortix from Applications
161366
162367 **Windows:**
163368 1. Download and run the `.exe` installer
@@ -171,17 +376,53 @@ jobs:
171376 GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
172377
173378 notify :
174- needs : [build-macos, build-windows]
379+ needs : [build-macos, build-windows, upload-to-r2 ]
175380 runs-on : ubuntu-latest
176381 if : always()
177382 steps :
178383 - name : Build Status
179384 run : |
180- if [ "${{ needs.build-macos.result }}" == "success" ] && [ "${{ needs.build-windows.result }}" == "success" ]; then
181- echo "✅ All desktop builds completed successfully!"
385+ MACOS_STATUS="${{ needs.build-macos.result }}"
386+ WINDOWS_STATUS="${{ needs.build-windows.result }}"
387+ R2_STATUS="${{ needs.upload-to-r2.result }}"
388+
389+ echo "## 🏗️ Build Status" >> $GITHUB_STEP_SUMMARY
390+ echo "" >> $GITHUB_STEP_SUMMARY
391+
392+ if [ "$MACOS_STATUS" == "success" ]; then
393+ echo "✅ macOS (Intel + Apple Silicon): Success" >> $GITHUB_STEP_SUMMARY
394+ echo "✅ macOS builds completed successfully!"
395+ else
396+ echo "❌ macOS (Intel + Apple Silicon): $MACOS_STATUS" >> $GITHUB_STEP_SUMMARY
397+ echo "❌ macOS builds failed: $MACOS_STATUS"
398+ fi
399+
400+ if [ "$WINDOWS_STATUS" == "success" ]; then
401+ echo "✅ Windows: Success" >> $GITHUB_STEP_SUMMARY
402+ echo "✅ Windows build completed successfully!"
403+ else
404+ echo "❌ Windows: $WINDOWS_STATUS" >> $GITHUB_STEP_SUMMARY
405+ echo "❌ Windows build failed: $WINDOWS_STATUS"
406+ fi
407+
408+ if [ "$R2_STATUS" == "success" ] || [ "$R2_STATUS" == "skipped" ]; then
409+ if [ "$R2_STATUS" == "success" ]; then
410+ echo "✅ Cloudflare R2 Upload: Success" >> $GITHUB_STEP_SUMMARY
411+ echo "✅ Files uploaded to R2!"
412+ else
413+ echo "⏭️ Cloudflare R2 Upload: Skipped (not main/PRODUCTION branch)" >> $GITHUB_STEP_SUMMARY
414+ fi
415+ else
416+ echo "❌ Cloudflare R2 Upload: $R2_STATUS" >> $GITHUB_STEP_SUMMARY
417+ echo "❌ R2 upload failed: $R2_STATUS"
418+ fi
419+
420+ if [ "$MACOS_STATUS" == "success" ] && [ "$WINDOWS_STATUS" == "success" ]; then
421+ echo ""
422+ echo "🎉 All desktop builds completed successfully!"
423+ exit 0
182424 else
183- echo "❌ Some builds failed:"
184- echo " macOS: ${{ needs.build-macos.result }}"
185- echo " Windows: ${{ needs.build-windows.result }}"
425+ echo ""
426+ echo "❌ Some builds failed"
186427 exit 1
187428 fi
0 commit comments