Skip to content

Commit 0ec1835

Browse files
Merge branch 'main' into cocoon/feature-duplicate-annotation
2 parents 501c4f2 + e85d07b commit 0ec1835

115 files changed

Lines changed: 9034 additions & 809 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
APP_NAME=Openscreen
2+
BUNDLE_ID=com.siddharthvaddem.openscreen
3+
4+
APPLE_ID=
5+
TEAM_ID=
6+
SIGN_IDENTITY="Developer ID Application: Samir Patil ()"
7+
CSC_NAME="Samir Patil ()"
8+
9+
NOTARY_PROFILE=OpenScreen-notary
10+
APPLE_APP_SPECIFIC_PASSWORD=

.envrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
use flake

.github/workflows/build.yml

Lines changed: 165 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ name: Build Electron App
33

44
on:
55
workflow_dispatch:
6+
inputs:
7+
arch:
8+
description: 'Architecture to build'
9+
required: true
10+
default: 'both'
11+
type: choice
12+
options:
13+
- arm64
14+
- x64
15+
- both
616

717
jobs:
818
build-windows:
@@ -36,38 +46,180 @@ jobs:
3646

3747
build-macos:
3848
runs-on: macos-latest
49+
strategy:
50+
matrix:
51+
arch: ${{ github.event.inputs.arch == 'both' && fromJSON('["arm64", "x64"]') || fromJSON(format('["{0}"]', github.event.inputs.arch)) }}
52+
3953
steps:
54+
# ─── Checkout ─────────────────────────────────────────────
4055
- name: Checkout code
41-
uses: actions/checkout@v3
56+
uses: actions/checkout@v4
4257

58+
# ─── Setup Node.js ────────────────────────────────────────
4359
- name: Setup Node.js
44-
uses: actions/setup-node@v3
60+
uses: actions/setup-node@v4
4561
with:
46-
node-version: '22'
62+
node-version: 22
63+
cache: npm
4764

65+
# ─── Setup Python (needed by some native deps) ────────────
4866
- name: Setup Python
49-
uses: actions/setup-python@v4
67+
uses: actions/setup-python@v5
5068
with:
5169
python-version: '3.11'
5270

71+
# ─── Install Dependencies ─────────────────────────────────
5372
- name: Install dependencies
5473
run: npm ci
5574

56-
- name: Install app dependencies
57-
run: npx electron-builder install-app-deps
58-
59-
- name: Build macOS app
60-
run: npm run build:mac
75+
# ─── Import Code Signing Certificate ──────────────────────
76+
# This is the KEY step that makes CI signing work.
77+
# We create a temporary keychain, import the .p12 cert into it,
78+
# and set it as the default so codesign can find it.
79+
- name: Import code signing certificate
6180
env:
81+
MAC_CERTIFICATE_P12: ${{ secrets.MAC_CERTIFICATE_P12 }}
82+
MAC_CERTIFICATE_PASSWORD: ${{ secrets.MAC_CERTIFICATE_PASSWORD }}
83+
run: |
84+
# Create a temporary keychain
85+
KEYCHAIN_PATH=$RUNNER_TEMP/build.keychain-db
86+
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
87+
88+
# Create and configure keychain
89+
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
90+
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
91+
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
92+
93+
# Decode and import certificate
94+
echo "$MAC_CERTIFICATE_P12" | base64 --decode > $RUNNER_TEMP/certificate.p12
95+
security import $RUNNER_TEMP/certificate.p12 \
96+
-k "$KEYCHAIN_PATH" \
97+
-P "$MAC_CERTIFICATE_PASSWORD" \
98+
-T /usr/bin/codesign \
99+
-T /usr/bin/security
100+
101+
# Allow codesign to access the keychain without UI prompt
102+
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
103+
104+
# Add to keychain search path (makes it the default)
105+
security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"')
106+
107+
# Verify the identity is available
108+
security find-identity -v -p codesigning "$KEYCHAIN_PATH"
109+
110+
# Clean up the .p12 file
111+
rm -f $RUNNER_TEMP/certificate.p12
112+
113+
# ─── Build Vite + Electron ────────────────────────────────
114+
- name: Build Vite + Electron
115+
run: npx tsc && npx vite build
116+
117+
# ─── Package with electron-builder ────────────────────────
118+
# electron-builder handles deep codesigning the .app bundle
119+
# "notarize: false" in electron-builder.json5 prevents it from
120+
# trying its own notarization flow
121+
- name: Package .app bundle
122+
run: npx electron-builder --mac --${{ matrix.arch }} --dir
123+
env:
124+
CSC_NAME: "Samir Patil (N26FZ4GW28)"
62125
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63126

64-
- name: Upload macOS build
127+
# ─── Read version from package.json ───────────────────────
128+
- name: Get version
129+
id: version
130+
run: echo "version=$(node -p 'require(\"./package.json\").version')" >> $GITHUB_OUTPUT
131+
132+
# ─── Locate the .app bundle ───────────────────────────────
133+
- name: Find .app bundle
134+
id: find_app
135+
run: |
136+
VERSION="${{ steps.version.outputs.version }}"
137+
echo "=== Release directory contents ==="
138+
ls -laR "release/${VERSION}/" || echo "release/${VERSION}/ not found"
139+
echo "=== Searching for .app bundle ==="
140+
APP_BUNDLE=$(find "release/${VERSION}" -maxdepth 4 -name "*.app" -type d | head -n1)
141+
if [ -z "$APP_BUNDLE" ]; then
142+
echo "::error::No .app bundle found in release/${VERSION}/"
143+
exit 1
144+
fi
145+
echo "app_bundle=$APP_BUNDLE" >> $GITHUB_OUTPUT
146+
echo "Found: $APP_BUNDLE"
147+
148+
# ─── Verify .app signature ────────────────────────────────
149+
- name: Verify .app code signature
150+
run: codesign --verify --deep --strict "${{ steps.find_app.outputs.app_bundle }}"
151+
152+
# ─── Create DMG ───────────────────────────────────────────
153+
- name: Create DMG
154+
id: dmg
155+
run: |
156+
VERSION="${{ steps.version.outputs.version }}"
157+
ARCH="${{ matrix.arch }}"
158+
DMG_NAME="Openscreen-Mac-${ARCH}-${VERSION}.dmg"
159+
RELEASE_DIR="release/${VERSION}"
160+
DMG_OUTPUT="${RELEASE_DIR}/${DMG_NAME}"
161+
STAGING="${RELEASE_DIR}/dmg-staging"
162+
163+
mkdir -p "$STAGING"
164+
cp -R "${{ steps.find_app.outputs.app_bundle }}" "$STAGING/"
165+
ln -s /Applications "$STAGING/Applications"
166+
167+
hdiutil create \
168+
-srcfolder "$STAGING" \
169+
-volname "Openscreen" \
170+
-fs HFS+ \
171+
-fsargs "-c c=64,a=16,e=16" \
172+
-format UDBZ \
173+
"$DMG_OUTPUT"
174+
175+
rm -rf "$STAGING"
176+
177+
echo "dmg_path=$DMG_OUTPUT" >> $GITHUB_OUTPUT
178+
echo "dmg_name=$DMG_NAME" >> $GITHUB_OUTPUT
179+
180+
# ─── Sign DMG ─────────────────────────────────────────────
181+
- name: Sign DMG
182+
run: |
183+
codesign --force \
184+
--sign "Developer ID Application: Samir Patil (N26FZ4GW28)" \
185+
--timestamp \
186+
"${{ steps.dmg.outputs.dmg_path }}"
187+
188+
# ─── Notarize DMG ────────────────────────────────────────
189+
# On CI we can't use keychain profiles for notarytool, so we
190+
# pass credentials directly via env vars / flags
191+
- name: Notarize DMG
192+
run: |
193+
xcrun notarytool submit "${{ steps.dmg.outputs.dmg_path }}" \
194+
--apple-id "${{ secrets.APPLE_ID }}" \
195+
--team-id "${{ secrets.APPLE_TEAM_ID }}" \
196+
--password "${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}" \
197+
--wait
198+
timeout-minutes: 15
199+
200+
# ─── Staple ───────────────────────────────────────────────
201+
- name: Staple notarization ticket
202+
run: xcrun stapler staple "${{ steps.dmg.outputs.dmg_path }}"
203+
204+
# ─── Validate ─────────────────────────────────────────────
205+
- name: Validate stapled DMG
206+
run: |
207+
xcrun stapler validate "${{ steps.dmg.outputs.dmg_path }}"
208+
spctl -a -vv -t install "${{ steps.dmg.outputs.dmg_path }}"
209+
210+
# ─── Upload Artifact ──────────────────────────────────────
211+
- name: Upload notarized DMG
65212
uses: actions/upload-artifact@v4
66213
with:
67-
name: macos-installer
68-
path: release/**/*.dmg
214+
name: openscreen-mac-${{ matrix.arch }}
215+
path: ${{ steps.dmg.outputs.dmg_path }}
69216
retention-days: 30
70217

218+
# ─── Cleanup Keychain ─────────────────────────────────────
219+
- name: Cleanup keychain
220+
if: always()
221+
run: security delete-keychain $RUNNER_TEMP/build.keychain-db || true
222+
71223
build-linux:
72224
runs-on: ubuntu-latest
73225
steps:
@@ -97,4 +249,5 @@ jobs:
97249
path: |
98250
release/**/*.AppImage
99251
release/**/*.zsync
252+
release/**/*.deb
100253
retention-days: 30

.github/workflows/ci.yml

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ jobs:
3131
- run: npm ci
3232
- run: npx tsc --noEmit
3333

34-
build:
35-
name: Build
34+
test:
35+
name: Test
3636
runs-on: ubuntu-latest
3737
steps:
3838
- uses: actions/checkout@v4
@@ -41,10 +41,11 @@ jobs:
4141
node-version: 22
4242
cache: npm
4343
- run: npm ci
44-
- run: npx vite build
44+
- run: npm run test:browser:install
45+
- run: npm run test:browser
4546

46-
e2e:
47-
name: E2E Tests
47+
build:
48+
name: Build
4849
runs-on: ubuntu-latest
4950
steps:
5051
- uses: actions/checkout@v4
@@ -53,15 +54,4 @@ jobs:
5354
node-version: 22
5455
cache: npm
5556
- run: npm ci
56-
- run: npx playwright install --with-deps chromium
57-
# Install Electron system dependencies not covered by Playwright's chromium deps
58-
- run: npx electron . --version || sudo apt-get install -y libgbm-dev
59-
- run: npm run build-vite
60-
# xvfb provides a virtual display; Electron needs one on Linux even with show:false
61-
- run: xvfb-run --auto-servernum npm run test:e2e
62-
- uses: actions/upload-artifact@v4
63-
if: failure()
64-
with:
65-
name: playwright-report
66-
path: playwright-report/
67-
retention-days: 7
57+
- run: npx vite build

0 commit comments

Comments
 (0)