Skip to content

ci: pair the simulator test job's Xcode with an installed iOS runtime - #218

Merged
KevinTCoughlin merged 1 commit into
mainfrom
fix/ci-simulator-selection
Sep 24, 2026
Merged

KevinTCoughlin merged 1 commit into
mainfrom
fix/ci-simulator-selection

Conversation

@KevinTCoughlin

Copy link
Copy Markdown
Contributor

Summary

The Test app (iOS Simulator) job has failed on every push to main since the xcode-27-arm64 runner image updated from 20260912.0186.1 to 20260921.0210.1.

Root cause: the new image adds Xcode 27.1 and Xcode 27.2 beta, but still ships only the iOS 27.0 simulator runtime. The build job picked Xcode with ls -d /Applications/Xcode*.app | sort -V | tail -1, which now lands on Xcode_27.2_beta.app. The app built with 27.2 launches on the 27.0 simulator, but the test bundle fails to load (Symbol not found: _$s21AppIntentsTypeSupport24PropertyContainerElement…). xcodebuild then waits out a 600-second diagnostics timeout before reporting Failed to load the test bundle. For comparison: failing run 35958089959, last green run 35659238433.

The ::error::No available iPhone simulator line in the failing log is the step echoing its own script source. The simulator step itself passed.

Changes

  • New .github/scripts/select_xcode_and_simulator.py:
    • Resolves the iOS Simulator SDK version of each installed Xcode (symlinks deduplicated).
    • Picks the newest Xcode whose SDK major.minor matches an installed iOS runtime that has an available iPhone. The tie-break by device name stays the same, so the pick is stable between runs.
    • If nothing matches, falls back to /Applications/Xcode.app with a ::warning::.
    • Still fails with ::error:: when no iPhone is available at all.
  • ci.yml build job: the separate "Select latest Xcode" and "Select an iOS Simulator" steps are merged into one step, toolchain. It outputs id (the cache key, computed the same way as before) and udid.

On today's image this selects Xcode 27.0, which is the pairing from the last green run. It moves up to 27.2 on its own once a 27.2 runtime ships.

Not changed

host-tests, release-checks, codeql.yml and pages.yml still use the newest Xcode, so they now build with the 27.2 beta. They pass because they never load a test bundle into a simulator. They can switch to this script if we want every job off betas.

Validation

  • Tested on Linux with a fake xcrun, fake Xcode bundles and sample simctl JSON:
    • The failing image's layout selects 27.0 and iPhone Air.
    • With a 27.2 runtime installed, it selects 27.2.
    • With no matching runtime, it falls back with a warning.
    • With no iPhone, it exits 1.
  • actionlint shows no new findings.
  • Not yet verified on a real macOS runner. This PR's CI run is the real test.

🤖 Generated with Claude Code

The xcode-27-arm64 image rolled from 20260912.0186 to 20260921.0210 and
added Xcode 27.1 and Xcode 27.2 beta alongside 27.0, but still installs
only the iOS 27.0 simulator runtime. The build job selected Xcode with
`ls -d /Applications/Xcode*.app | sort -V | tail -1`, which now lands on
Xcode_27.2_beta.app, and then ran the tests on an iOS 27.0 iPhone. The
app built and launched, but HolmdelTests links Xcode 27.2's
AppIntentsTesting, which needs a symbol only the 27.2 runtime has:

  Symbol not found: _$s21AppIntentsTypeSupport24PropertyContainerElement...
  Referenced from: .../Xcode_27.2_beta.app/.../AppIntentsTesting.framework
  Expected in:     .../iOS 27.0.simruntime/.../AppIntentsTypeSupport

xcodebuild then waited out a 600s diagnostics timeout before reporting
"Failed to load the test bundle" (run 35958089959, ~21 billed minutes).
The last green run on main (35659238433) used Xcode 27.0 with the same
iOS 27.0 iPhone Air, on the previous image.

The build job now selects Xcode and simulator in one step through
.github/scripts/select_xcode_and_simulator.py: the newest Xcode whose
iOS Simulator SDK major.minor has an installed runtime with an available
iPhone. On today's image that is Xcode 27.0. When a 27.2 runtime ships,
it moves up by itself. If nothing matches, it falls back to the image
default /Applications/Xcode.app with a warning rather than failing. The
toolchain-id cache key and UDID-based destination are unchanged.

The compile-only jobs (host-tests, release-checks, CodeQL, Pages) still
take the newest Xcode. They passed on 27.2 beta and load no test bundle
into a simulator.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@KevinTCoughlin
KevinTCoughlin merged commit a57dd0b into main Sep 24, 2026
10 checks passed
@KevinTCoughlin
KevinTCoughlin deleted the fix/ci-simulator-selection branch September 24, 2026 22:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant