Skip to content

Commit d056820

Browse files
committed
ci: add manual iOS runner prebuild cache for iOS workflow
1 parent 733bd8d commit d056820

2 files changed

Lines changed: 155 additions & 20 deletions

File tree

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
name: iOS Runner Prebuild (CI-only)
2+
3+
on:
4+
workflow_dispatch:
5+
6+
permissions:
7+
contents: read
8+
9+
concurrency:
10+
group: ci-${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
prebuild-ios-runner:
15+
name: Build iOS 26.2 Prebuilt
16+
runs-on: macos-26
17+
timeout-minutes: 60
18+
env:
19+
IOS_RUNTIME_VERSION: '26.2'
20+
IOS_DEVICE_NAME: 'iPhone 17 Pro'
21+
PREBUILT_DIR: ${{ runner.temp }}/ios-runner-prebuilt
22+
DERIVED_DATA_PATH: ${{ runner.temp }}/ios-runner-derived
23+
steps:
24+
- name: Checkout
25+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
26+
27+
- name: Setup toolchain
28+
uses: ./.github/actions/setup-node-pnpm
29+
30+
- name: Resolve Xcode cache key
31+
id: xcode
32+
run: |
33+
set -euo pipefail
34+
XCODE_VERSION="$(xcodebuild -version | tr '\n' ' ' | sed -E 's/[[:space:]]+/ /g; s/[[:space:]]$//')"
35+
XCODE_KEY="$(echo "$XCODE_VERSION" | tr ' ' '-' | tr -cd '[:alnum:]._-')"
36+
echo "version=$XCODE_VERSION" >> "$GITHUB_OUTPUT"
37+
echo "key=$XCODE_KEY" >> "$GITHUB_OUTPUT"
38+
39+
- name: Restore prebuilt cache
40+
id: restore-prebuilt
41+
uses: actions/cache/restore@v4
42+
with:
43+
path: ${{ env.PREBUILT_DIR }}
44+
key: ios-runner-prebuilt-${{ steps.xcode.outputs.key }}-ios-${{ env.IOS_RUNTIME_VERSION }}
45+
46+
- name: Resolve iOS runtime 26.2
47+
if: steps.restore-prebuilt.outputs.cache-hit != 'true'
48+
id: runtime
49+
run: |
50+
set -euo pipefail
51+
RUNTIME_ID="$(
52+
xcrun simctl list runtimes -j | node -e "
53+
const fs = require('node:fs');
54+
const payload = JSON.parse(fs.readFileSync(0, 'utf8'));
55+
const targetVersion = process.env.IOS_RUNTIME_VERSION;
56+
const runtime = (payload.runtimes ?? [])
57+
.filter((item) => item.isAvailable)
58+
.find((item) => item.platform === 'iOS' && item.version === targetVersion);
59+
if (!runtime?.identifier) process.exit(1);
60+
process.stdout.write(runtime.identifier);
61+
"
62+
)"
63+
64+
if [ -z "$RUNTIME_ID" ]; then
65+
echo "Could not find available iOS runtime ${IOS_RUNTIME_VERSION}" >&2
66+
exit 1
67+
fi
68+
69+
echo "runtime_id=$RUNTIME_ID" >> "$GITHUB_OUTPUT"
70+
71+
- name: Create simulator for runtime
72+
if: steps.restore-prebuilt.outputs.cache-hit != 'true'
73+
id: simulator
74+
run: |
75+
set -euo pipefail
76+
UDID="$(xcrun simctl create "agent-device-prebuild-${GITHUB_RUN_ID}" "$IOS_DEVICE_NAME" "${{ steps.runtime.outputs.runtime_id }}")"
77+
echo "udid=$UDID" >> "$GITHUB_OUTPUT"
78+
xcrun simctl boot "$UDID" || true
79+
80+
- name: Build ios-runner for testing
81+
if: steps.restore-prebuilt.outputs.cache-hit != 'true'
82+
run: |
83+
set -euo pipefail
84+
rm -rf "$DERIVED_DATA_PATH" "$PREBUILT_DIR"
85+
xcodebuild build-for-testing \
86+
-project ios-runner/AgentDeviceRunner/AgentDeviceRunner.xcodeproj \
87+
-scheme AgentDeviceRunner \
88+
-destination "id=${{ steps.simulator.outputs.udid }}" \
89+
-derivedDataPath "$DERIVED_DATA_PATH"
90+
91+
- name: Package prebuilt artifact
92+
if: steps.restore-prebuilt.outputs.cache-hit != 'true'
93+
run: |
94+
set -euo pipefail
95+
mkdir -p "$PREBUILT_DIR"
96+
cp -R "$DERIVED_DATA_PATH" "$PREBUILT_DIR/derived-data"
97+
cat > "$PREBUILT_DIR/metadata.txt" <<EOF
98+
runtime_version=${IOS_RUNTIME_VERSION}
99+
runtime_id=${{ steps.runtime.outputs.runtime_id }}
100+
device_name=${IOS_DEVICE_NAME}
101+
simulator_udid=${{ steps.simulator.outputs.udid }}
102+
xcode_version=${{ steps.xcode.outputs.version }}
103+
github_run_id=${GITHUB_RUN_ID}
104+
github_sha=${GITHUB_SHA}
105+
EOF
106+
107+
- name: Save prebuilt cache
108+
if: steps.restore-prebuilt.outputs.cache-hit != 'true'
109+
uses: actions/cache/save@v4
110+
with:
111+
path: ${{ env.PREBUILT_DIR }}
112+
key: ios-runner-prebuilt-${{ steps.xcode.outputs.key }}-ios-${{ env.IOS_RUNTIME_VERSION }}
113+
114+
- name: Report prebuild cache status
115+
run: |
116+
set -euo pipefail
117+
if [ "${{ steps.restore-prebuilt.outputs.cache-hit }}" = "true" ]; then
118+
echo "Reused existing prebuild cache."
119+
else
120+
echo "Created/updated prebuild cache."
121+
fi
122+
123+
- name: Cleanup simulator
124+
if: always() && steps.restore-prebuilt.outputs.cache-hit != 'true'
125+
run: |
126+
set -euo pipefail
127+
xcrun simctl delete "${{ steps.simulator.outputs.udid }}" || true

.github/workflows/ios.yml

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,43 +19,51 @@ jobs:
1919
runs-on: macos-26
2020
timeout-minutes: 80
2121
continue-on-error: true
22+
env:
23+
IOS_RUNTIME_VERSION: '26.2'
24+
PREBUILT_DIR: ${{ runner.temp }}/ios-runner-prebuilt
2225
steps:
2326
- name: Checkout
2427
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2528

2629
- name: Setup toolchain
2730
uses: ./.github/actions/setup-node-pnpm
2831

32+
- name: Resolve Xcode cache key
33+
id: xcode
34+
run: |
35+
set -euo pipefail
36+
XCODE_VERSION="$(xcodebuild -version | tr '\n' ' ' | sed -E 's/[[:space:]]+/ /g; s/[[:space:]]$//')"
37+
XCODE_KEY="$(echo "$XCODE_VERSION" | tr ' ' '-' | tr -cd '[:alnum:]._-')"
38+
echo "key=$XCODE_KEY" >> "$GITHUB_OUTPUT"
39+
40+
- name: Restore iOS runner prebuilt cache
41+
id: restore-prebuilt
42+
uses: actions/cache/restore@v4
43+
with:
44+
path: ${{ env.PREBUILT_DIR }}
45+
key: ios-runner-prebuilt-${{ steps.xcode.outputs.key }}-ios-${{ env.IOS_RUNTIME_VERSION }}
46+
47+
- name: Hydrate derived data from prebuilt cache
48+
if: steps.restore-prebuilt.outputs.cache-hit == 'true'
49+
run: |
50+
set -euo pipefail
51+
mkdir -p "$HOME/.agent-device/ios-runner"
52+
rm -rf "$HOME/.agent-device/ios-runner/derived"
53+
cp -R "$PREBUILT_DIR/derived-data" "$HOME/.agent-device/ios-runner/derived"
54+
2955
- name: Resolve agent-device home
3056
id: ios-agent-home
3157
run: echo "dir=$HOME/.agent-device" >> "$GITHUB_OUTPUT"
3258

33-
- name: Select and start iOS simulator
34-
run: |
35-
UDID="$(
36-
xcrun simctl list devices -j | node -e "
37-
const fs = require('node:fs');
38-
const payload = JSON.parse(fs.readFileSync(0, 'utf8'));
39-
const all = Object.values(payload.devices ?? {}).flat();
40-
const available = all.filter((d) => d.isAvailable);
41-
const preferred =
42-
available.find((d) => d.state === 'Booted') ??
43-
available.find((d) => d.name === 'iPhone 17 Pro') ??
44-
available[0];
45-
if (!preferred?.udid) process.exit(1);
46-
process.stdout.write(preferred.udid);
47-
"
48-
)"
49-
xcrun simctl boot "$UDID" || true
50-
echo "IOS_UDID=$UDID" >> "$GITHUB_ENV"
51-
5259
- name: Build iOS integration artifacts
60+
if: steps.restore-prebuilt.outputs.cache-hit != 'true'
5361
run: pnpm build:xcuitest
5462

5563
- name: Boot preflight via agent-device
5664
run: |
5765
set -euo pipefail
58-
node --experimental-strip-types src/bin.ts boot --platform ios --udid "$IOS_UDID" --json
66+
node --experimental-strip-types src/bin.ts boot --platform ios --device "iPhone 17 Pro" --json
5967
env:
6068
AGENT_DEVICE_IOS_BOOT_TIMEOUT_MS: "180000"
6169
AGENT_DEVICE_RETRY_LOGS: "1"

0 commit comments

Comments
 (0)