Skip to content

Commit ca388c5

Browse files
committed
Add GitHub Actions simulator provider workflow
1 parent 299381e commit ca388c5

2 files changed

Lines changed: 203 additions & 0 deletions

File tree

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
name: SimDeck Provider
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
preview_id:
7+
description: SimDeck Cloud preview deployment id
8+
required: true
9+
provider_token:
10+
description: One-time provider registration token
11+
required: true
12+
simdeck_cloud_url:
13+
description: SimDeck Cloud control plane URL
14+
required: true
15+
artifact_id:
16+
description: GitHub Actions artifact id containing a simulator .app
17+
required: false
18+
source_run_id:
19+
description: Source workflow run id that uploaded the simulator artifact
20+
required: false
21+
bundle_id:
22+
description: iOS app bundle id to launch after install
23+
required: false
24+
simdeck_artifact_url:
25+
description: Optional URL to a prebuilt simdeck binary tarball
26+
required: false
27+
28+
permissions:
29+
actions: read
30+
contents: read
31+
32+
jobs:
33+
provider:
34+
runs-on: macos-latest
35+
timeout-minutes: 360
36+
steps:
37+
- name: Check out repository
38+
uses: actions/checkout@v4
39+
40+
- name: Download simulator artifact
41+
if: ${{ inputs.artifact_id != '' }}
42+
uses: actions/download-artifact@v4
43+
with:
44+
artifact-ids: ${{ inputs.artifact_id }}
45+
run-id: ${{ inputs.source_run_id || github.run_id }}
46+
github-token: ${{ github.token }}
47+
path: simdeck-artifact
48+
49+
- name: Install cloudflared
50+
shell: bash
51+
run: |
52+
set -euo pipefail
53+
brew install cloudflare/cloudflare/cloudflared
54+
55+
- name: Register provider workflow
56+
shell: bash
57+
env:
58+
SIMDECK_CLOUD_URL: ${{ inputs.simdeck_cloud_url }}
59+
PREVIEW_ID: ${{ inputs.preview_id }}
60+
PROVIDER_TOKEN: ${{ inputs.provider_token }}
61+
run: |
62+
set -euo pipefail
63+
curl -fsS \
64+
-H 'content-type: application/json' \
65+
-d "{
66+
\"previewId\":\"$PREVIEW_ID\",
67+
\"providerToken\":\"$PROVIDER_TOKEN\",
68+
\"providerRunId\":\"$GITHUB_RUN_ID\",
69+
\"providerRunUrl\":\"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID\",
70+
\"status\":\"running\",
71+
\"simulatorName\":\"GitHub Actions macOS runner\"
72+
}" \
73+
"$SIMDECK_CLOUD_URL/api/actions/providers/register"
74+
75+
- name: Build or download SimDeck
76+
shell: bash
77+
env:
78+
SIMDECK_ARTIFACT_URL: ${{ inputs.simdeck_artifact_url }}
79+
run: |
80+
set -euo pipefail
81+
if [[ -n "${SIMDECK_ARTIFACT_URL:-}" ]]; then
82+
mkdir -p build
83+
curl -fsSL "$SIMDECK_ARTIFACT_URL" | tar -xz -C build
84+
chmod +x build/simdeck
85+
elif [[ -x ./scripts/build-client.sh && -x ./scripts/build-cli.sh ]]; then
86+
./scripts/build-client.sh
87+
./scripts/build-cli.sh
88+
else
89+
git clone --depth 1 https://github.com/DjDeveloperr/SimDeck.git simdeck-src
90+
./simdeck-src/scripts/build-client.sh
91+
./simdeck-src/scripts/build-cli.sh
92+
mkdir -p build
93+
cp simdeck-src/build/simdeck build/simdeck
94+
chmod +x build/simdeck
95+
fi
96+
97+
- name: Start simulator provider
98+
shell: bash
99+
env:
100+
SIMDECK_CLOUD_URL: ${{ inputs.simdeck_cloud_url }}
101+
PREVIEW_ID: ${{ inputs.preview_id }}
102+
PROVIDER_TOKEN: ${{ inputs.provider_token }}
103+
BUNDLE_ID: ${{ inputs.bundle_id }}
104+
SIMDECK_ALLOWED_ORIGINS: ${{ inputs.simdeck_cloud_url }}
105+
run: |
106+
set -euo pipefail
107+
108+
ios_udid="$(xcrun simctl list devices available --json | python3 -c '
109+
import json, sys
110+
data = json.load(sys.stdin)
111+
for runtime, devices in data.get("devices", {}).items():
112+
if "iOS" not in runtime:
113+
continue
114+
for device in devices:
115+
if device.get("isAvailable"):
116+
print(device["udid"])
117+
raise SystemExit(0)
118+
raise SystemExit("No available iOS simulator")
119+
')"
120+
121+
xcrun simctl boot "$ios_udid" || true
122+
xcrun simctl bootstatus "$ios_udid" -b
123+
124+
app_path=""
125+
if [[ -d simdeck-artifact ]]; then
126+
app_path="$(find simdeck-artifact -maxdepth 6 -type d -name '*.app' | head -n 1 || true)"
127+
fi
128+
if [[ -n "$app_path" ]]; then
129+
xcrun simctl install "$ios_udid" "$app_path"
130+
fi
131+
if [[ -n "${BUNDLE_ID:-}" ]]; then
132+
xcrun simctl launch "$ios_udid" "$BUNDLE_ID" || true
133+
fi
134+
135+
./build/simdeck serve \
136+
--port 4310 \
137+
--bind 127.0.0.1 \
138+
--access-token "$PROVIDER_TOKEN" \
139+
--video-codec h264-software \
140+
> simdeck.log 2>&1 &
141+
simdeck_pid="$!"
142+
143+
for _ in {1..120}; do
144+
if curl -fsS http://127.0.0.1:4310/api/health >/dev/null; then
145+
break
146+
fi
147+
sleep 1
148+
done
149+
150+
cloudflared tunnel --url http://127.0.0.1:4310 \
151+
> cloudflared.log 2>&1 &
152+
cloudflared_pid="$!"
153+
154+
tunnel_url=""
155+
for _ in {1..120}; do
156+
tunnel_url="$(grep -Eo 'https://[-a-zA-Z0-9.]+\.trycloudflare\.com' cloudflared.log | head -n 1 || true)"
157+
if [[ -n "$tunnel_url" ]]; then
158+
break
159+
fi
160+
sleep 1
161+
done
162+
163+
if [[ -z "$tunnel_url" ]]; then
164+
echo "cloudflared did not print a trycloudflare.com URL"
165+
cat cloudflared.log || true
166+
exit 1
167+
fi
168+
169+
register() {
170+
curl -fsS \
171+
-H 'content-type: application/json' \
172+
-d "{
173+
\"previewId\":\"$PREVIEW_ID\",
174+
\"providerToken\":\"$PROVIDER_TOKEN\",
175+
\"providerRunId\":\"$GITHUB_RUN_ID\",
176+
\"providerRunUrl\":\"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID\",
177+
\"baseUrl\":\"$tunnel_url/?simdeckToken=$PROVIDER_TOKEN&transport=webrtc&device=$ios_udid\",
178+
\"simulatorUdid\":\"$ios_udid\",
179+
\"simulatorName\":\"GitHub Actions macOS runner\",
180+
\"runtimeName\":\"$(xcrun simctl getenv "$ios_udid" SIMULATOR_RUNTIME_VERSION 2>/dev/null || true)\",
181+
\"status\":\"ready\",
182+
\"simulatorCount\":1
183+
}" \
184+
"$SIMDECK_CLOUD_URL/api/actions/providers/register"
185+
}
186+
187+
register
188+
echo "SimDeck tunnel: $tunnel_url"
189+
while true; do
190+
sleep 30
191+
if ! kill -0 "$simdeck_pid" 2>/dev/null; then
192+
echo "simdeck exited"
193+
cat simdeck.log || true
194+
exit 1
195+
fi
196+
if ! kill -0 "$cloudflared_pid" 2>/dev/null; then
197+
echo "cloudflared exited"
198+
cat cloudflared.log || true
199+
exit 1
200+
fi
201+
register
202+
done

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ packages/nativescript-inspector/dist/
1111
packages/react-native-inspector/dist/
1212
docs/.vitepress/dist/
1313
docs/.vitepress/cache/
14+
cloud/
1415
.playwright-mcp/
1516
simdeck-snapshot.md
1617

0 commit comments

Comments
 (0)