From 3dfad1e75178c87f7c13ea2150a1691a88f8d3e2 Mon Sep 17 00:00:00 2001 From: DjDeveloperr Date: Sat, 16 May 2026 16:25:51 -0400 Subject: [PATCH] Delay iOS PR comments until public simulator access is ready --- actions/run-ios-comment-session/action.yml | 52 ++++++++++++++++++++++ docs/guide/github-actions.md | 2 +- package.json | 3 +- scripts/github-actions.test.mjs | 52 ++++++++++++++++++++++ 4 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 scripts/github-actions.test.mjs diff --git a/actions/run-ios-comment-session/action.yml b/actions/run-ios-comment-session/action.yml index 58a1737a..10c02629 100644 --- a/actions/run-ios-comment-session/action.yml +++ b/actions/run-ios-comment-session/action.yml @@ -545,6 +545,58 @@ runs: fi date +%s > /tmp/sim-boot-end + - name: Wait for public SimDeck iOS session access + shell: bash + run: | + set -euo pipefail + + udid="${SIMULATOR_UDID}" + public_simulators_url="${{ steps.stream.outputs.url }}/api/simulators?simdeckToken=${{ steps.stream.outputs.access_token }}" + tunnel_host="${{ steps.stream.outputs.url }}" + tunnel_host="${tunnel_host#https://}" + tunnel_host="${tunnel_host%%/*}" + + fetch_public_simulators() { + curl -fsS "${public_simulators_url}" -o public-simulators.json || + curl -fsS --resolve "${tunnel_host}:443:104.16.230.132" "${public_simulators_url}" -o public-simulators.json || + curl -fsS --resolve "${tunnel_host}:443:104.16.231.132" "${public_simulators_url}" -o public-simulators.json + } + + verify_selected_simulator() { + SIMDECK_READY_UDID="${udid}" python3 - <<'PY' + import json + import os + + with open("public-simulators.json", "r", encoding="utf-8") as handle: + data = json.load(handle) + + udid = os.environ["SIMDECK_READY_UDID"] + simulators = data.get("simulators", data if isinstance(data, list) else []) + for simulator in simulators: + if simulator.get("udid") == udid and simulator.get("isBooted") is True: + raise SystemExit(0) + + raise SystemExit(1) + PY + } + + for attempt in {1..120}; do + if fetch_public_simulators && verify_selected_simulator; then + echo "Public SimDeck URL lists booted simulator ${udid}." + exit 0 + fi + echo "Waiting for public SimDeck simulator list (${attempt}/120)." + sleep 1 + done + + echo "SimDeck public simulator list did not become accessible for ${udid}" >&2 + if [[ -f public-simulators.json ]]; then + cat public-simulators.json >&2 || true + fi + cat cloudflared.log >&2 || true + cat simdeck-daemon.log >&2 || true + exit 1 + - name: Update status comment with booted simulator URL shell: bash run: | diff --git a/docs/guide/github-actions.md b/docs/guide/github-actions.md index 13ccde5b..705403ce 100644 --- a/docs/guide/github-actions.md +++ b/docs/guide/github-actions.md @@ -192,5 +192,5 @@ Supported quality values include `tiny`, `low`, `economy`, `fast`, `smooth`, `ba - Picks or creates an iOS Simulator or Android emulator. - Downloads the app artifact for the PR head commit. - Installs and launches the app. -- Posts a browser URL back to the pull request after the simulator or emulator is booted. +- Posts a browser URL back to the pull request after the simulator or emulator is booted. The iOS action waits until the public URL can load the selected booted simulator from `/api/simulators`. - Stops after the configured keepalive window. diff --git a/package.json b/package.json index 1d87cea2..427e6828 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "format": "prettier --write . && cargo fmt --manifest-path server/Cargo.toml", "format:check": "prettier --check . && cargo fmt --manifest-path server/Cargo.toml --check", "lint": "npm run format:check && cargo clippy --manifest-path server/Cargo.toml --all-targets -- -D warnings && npm run --prefix client typecheck", - "test": "cargo test --manifest-path server/Cargo.toml && npm run --prefix client test", + "test": "cargo test --manifest-path server/Cargo.toml && npm run --prefix client test && npm run test:github-actions", "test:integration:cli": "node scripts/integration/cli.mjs", "test:integration:cli:verbose": "SIMDECK_INTEGRATION_VERBOSE=1 SIMDECK_INTEGRATION_SHOW_SIMULATOR=1 node scripts/integration/cli.mjs", "test:integration:fixture": "node scripts/integration/prebuild-fixture.mjs", @@ -77,6 +77,7 @@ "test:e2e:webrtc:headed": "SIMDECK_E2E_HEADFUL=1 node scripts/e2e-webrtc-reliability.mjs", "test:e2e:webrtc:stress": "node scripts/e2e-webrtc-stress.mjs", "test:studio-provider": "node --test scripts/studio-provider-bridge.test.mjs scripts/studio-host-provider.test.mjs", + "test:github-actions": "node --test scripts/github-actions.test.mjs", "test:stress": "node scripts/stress/simdeck.mjs", "bench:encoder:build": "scripts/bench/build-encoder-benchmark.sh", "ci": "npm run lint && npm run build:all && npm run test && npm run package:vscode-extension", diff --git a/scripts/github-actions.test.mjs b/scripts/github-actions.test.mjs new file mode 100644 index 00000000..8a974e08 --- /dev/null +++ b/scripts/github-actions.test.mjs @@ -0,0 +1,52 @@ +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import { test } from "node:test"; + +const iosAction = readFileSync( + new URL("../actions/run-ios-comment-session/action.yml", import.meta.url), + "utf8", +); + +test("iOS PR comment waits for public simulator list access", () => { + const prebootIndex = iosAction.indexOf( + "- name: Select and preboot simulator", + ); + const readinessIndex = iosAction.indexOf( + "- name: Wait for public SimDeck iOS session access", + ); + const commentIndex = iosAction.indexOf( + "- name: Update status comment with booted simulator URL", + ); + + assert.notEqual(prebootIndex, -1, "preboot step should exist"); + assert.notEqual( + commentIndex, + -1, + "booted simulator comment step should exist", + ); + assert( + readinessIndex > prebootIndex, + "readiness check should run after simulator preboot", + ); + assert( + readinessIndex < commentIndex, + "readiness check should run before posting the PR URL", + ); + + const readinessStep = iosAction.slice(readinessIndex, commentIndex); + assert.match( + readinessStep, + /\$\{\{ steps\.stream\.outputs\.url \}\}\/api\/simulators\?simdeckToken=/, + "readiness check should use the public tunnel URL", + ); + assert.match( + readinessStep, + /SIMULATOR_UDID/, + "readiness check should look for the selected simulator", + ); + assert.match( + readinessStep, + /isBooted/, + "readiness check should require the selected simulator to be booted", + ); +});