[build-tools] Restore maestro-runner WDA cache - #4195
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4195 +/- ##
==========================================
+ Coverage 63.73% 63.77% +0.04%
==========================================
Files 1030 1032 +2
Lines 47448 47508 +60
Branches 9977 9989 +12
==========================================
+ Hits 30237 30292 +55
+ Misses 17110 17101 -9
- Partials 101 115 +14 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR restores a prebuilt WebDriverAgent (WDA) cache for maestro-runner on macOS build runtimes to avoid the first-run WDA compilation cost, by downloading an archive from turtle-v2 (optionally via a proxy) and materializing per-iOS-runtime cache directories. It also factors out shared proxy URL rewriting logic and adds small iOS/Xcode utility helpers with tests.
Changes:
- Add WDA cache installation to
eas/install_maestroformaestro-runneron Darwin (download + extract + copy to runtime-specific cache paths). - Add utilities to detect Xcode version and available iOS simulator runtime versions (with unit tests).
- Extract
getProxiedDownloadUrlinto a shared utility and reuse it from xcactivitylog parsing.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/build-tools/src/utils/IosSimulatorUtils.ts | Adds a helper to list available iOS runtime versions via xcrun simctl. |
| packages/build-tools/src/utils/download.ts | Introduces shared proxy URL rewriting helper for GCS downloads. |
| packages/build-tools/src/utils/tests/IosSimulatorUtils.test.ts | Adds unit coverage for the new runtime-version helper. |
| packages/build-tools/src/steps/utils/ios/xcactivitylog.ts | Reuses shared proxy URL helper instead of local implementation. |
| packages/build-tools/src/steps/functions/installMaestro.ts | Implements optimistic WDA cache download/extract/copy for maestro-runner on macOS. |
| packages/build-tools/src/steps/functions/tests/installMaestro.test.ts | Adds tests validating WDA cache installation + fallback behavior. |
| packages/build-tools/src/ios/xcode.ts | Adds a helper to parse Xcode version from xcodebuild -version. |
| packages/build-tools/src/ios/tests/xcode.test.ts | Adds unit tests for Xcode version parsing + error case. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
d7a1aaa to
9890a1e
Compare
|
⏩ The changelog entry check has been skipped since the "no changelog" label is present. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.
Suppressed comments (1)
packages/build-tools/src/ios/xcode.ts:11
getXcodeVersionAsynconly throws aSystemErrorwhen parsing fails; ifxcodebuild -versionfails to spawn (missing binary, non-zero exit, permission issues), the raw spawn error will bubble up and may not be handled consistently by callers. The previous inlined implementation wrapped spawn failures in aSystemErrorwith a cause, which provides clearer and more uniform error reporting.
export async function getXcodeVersionAsync({ env }: { env: NodeJS.ProcessEnv }): Promise<string> {
const { stdout } = await spawn('xcodebuild', ['-version'], { stdio: 'pipe', env });
const version = /^Xcode\s+(\d+(?:\.\d+)*)$/m.exec(stdout)?.[1];
if (!version) {
throw new SystemError(`Failed to determine Xcode version from: ${stdout.trim()}`);
}
return version;
hSATAC
left a comment
There was a problem hiding this comment.
Looks good overall, approving. Left a few questions inline — I may be missing some context around the WDA/turtle-v2 side.
| maestroRunnerHome, | ||
| 'cache', | ||
| 'wda-builds', | ||
| `sim-ios${runtimeVersion}-iphone`, |
There was a problem hiding this comment.
I think this may miss the cache on patched runtimes.
simctl list runtimes --json gives us the full version (e.g. 26.3.1), but maestro-runner derives the cache key from the runtime identifier (iOS-26-3 → 26.3). So we'd write sim-ios26.3.1-iphone here while runner looks for sim-ios26.3-iphone.
I haven't checked what versions we currently have on the images, so maybe I'm missing something there. Should we derive this from identifier too, to match runner?
| const archivePath = path.join(tempDirectory, 'wda-cache.tar.gz'); | ||
| const directArchiveUrl = | ||
| `https://storage.googleapis.com/turtle-v2/maestro-runner-wda-cache/` + | ||
| `xcode-${encodeURIComponent(xcodeVersion)}-wda-${encodeURIComponent(wdaVersion)}.tar.gz`; |
There was a problem hiding this comment.
I'm not sure I understand how this lines up with the turtle-v2 upload side.
This looks for xcode-<xcodeVersion>-wda-<wdaVersion>.tar.gz, but turtle-v2#2603 seems to upload image-keyed artifacts like macos-sequoia-15.6-xcode-26.0-wda-11.1.3.tar.gz.
The existing xcode-* objects are there, so I assume there's another step I'm missing. Are we planning to change the turtle-v2 naming to match this?
If so, I think the two Xcode 16.4 images would also collapse to the same object name, so the artifact count/check there may need an update too.
| logger.info(`Downloading the prebuilt WebDriverAgent cache for Xcode ${xcodeVersion}`); | ||
| if (proxiedArchiveUrl) { | ||
| try { | ||
| await downloadFile(proxiedArchiveUrl, archivePath, { retry: 3 }); |
There was a problem hiding this comment.
Should we add a timeout to these downloads?
AFAICT @expo/downloader passes this through to got, and got doesn't have a default timeout. If the connection stalls after being established, this best-effort cache download could hang until the build timeout instead of falling back.
xcactivitylog.ts uses timeout: 20_000 for the same proxied-download pattern.
| import spawn from '@expo/turtle-spawn'; | ||
|
|
||
| export async function getXcodeVersionAsync({ env }: { env: NodeJS.ProcessEnv }): Promise<string> { | ||
| const { stdout } = await spawn('xcodebuild', ['-version'], { stdio: 'pipe', env }); |
There was a problem hiding this comment.
Was dropping the SystemError wrapping around the xcodebuild -version spawn intentional?
Previously a spawn failure was wrapped as SystemError('Failed to get Xcode version', { cause }). Now only the parse failure is a SystemError, so things like a bad DEVELOPER_DIR would propagate as the raw spawn error at the maestro-runner version-selection call site.
The WDA cache path catches this anyway, so I think this only affects the other caller. Maybe intentional, just wanted to check.
Why
maestro-runnerneeds WDA driver to run tests. By default it compiles it on first run which takes a minute.How
Compiled WDA on all images, uploaded to
turtle-v2GCS and added optimistic download toeas/install_maestro. See https://github.com/expo/turtle-v2/pull/2603.Test plan
https://staging.expo.dev/accounts/expo-services/projects/workflows-testing/workflows/01a0009e-b171-7497-9335-af1fc470a8d5