diff --git a/.claude/rules/ci.md b/.claude/rules/ci.md index 7afaaebb5c..b31b145c0f 100644 --- a/.claude/rules/ci.md +++ b/.claude/rules/ci.md @@ -55,9 +55,8 @@ The required check names are in `AGENTS.md` (CI). Reading a red check: `.claude/ ## iOS and Package Tests (`ios-tests.yml`) - Triggers and concurrency as macOS Tests. `Changes (iOS)` outputs `run` (detector `ios`) and `oracle` (detector `oracle`). -- 50 minutes on `xcode-27`, simulator `iPhone 18 Pro` on the newest iOS runtime that has it. The iOS platform is downloaded only when that simulator is missing. -- Right after setup-xcode the job boots that simulator by UDID, so its first boot overlaps the build. `xcodebuild test` names it with `-destination id=`. -- `TableProMobileTests` runs with `-parallel-testing-enabled NO` on that one simulator: a second booted simulator killed runs with "(ipc/mig) server died" on the 3-core runner. `TableProMobile/project.yml` says `parallelizable: true`, which every run overrides. +- 50 minutes on `xcode-27`, simulator `iPhone 18 Pro`. The iOS platform is downloaded only when that simulator is missing. +- `TableProMobileTests` runs with `-parallel-testing-enabled NO`: a second booted simulator killed runs with "(ipc/mig) server died" on the 3-core runner. `TableProMobile/project.yml` says `parallelizable: true`, which every run overrides. - `swift test --package-path Packages/TableProCore --parallel`, then TableProOracle with `--force-resolved-versions` when its detector is not false. Each step has `if: !cancelled()`, so one red step never hides the next. - The summary step always runs. Evidence uploads only on failure. diff --git a/.github/workflows/ios-tests.yml b/.github/workflows/ios-tests.yml index fb57826deb..64b1690e62 100644 --- a/.github/workflows/ios-tests.yml +++ b/.github/workflows/ios-tests.yml @@ -46,38 +46,12 @@ jobs: runs-on: xcode-27 timeout-minutes: 50 env: - SIMULATOR: iPhone 18 Pro + DESTINATION: platform=iOS Simulator,name=iPhone 18 Pro steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: ./.github/actions/setup-xcode - # Booted ahead of the build so the first boot overlaps the compile instead of following it. - # The image ships the iOS 27.0 runtime; downloading the one for Xcode's newer SDK costs minutes. - # A destination by name takes the newest runtime, so the lookup does too. - - name: Boot the simulator - id: simulator - run: | - set -euo pipefail - find_simulator() { - xcrun simctl list devices available -j | jq -r --arg name "$SIMULATOR" ' - [.devices | to_entries[] | select(.key | test("\\.iOS-[0-9-]+$")) - | {version: (.key | capture("iOS-(?[0-9-]+)$").v | split("-") | map(tonumber)), - udid: (.value[] | select(.name == $name) | .udid)}] - | sort_by(.version) | last | .udid // empty' - } - udid="$(find_simulator)" - if [ -z "$udid" ]; then - xcodebuild -downloadPlatform iOS - udid="$(find_simulator)" - fi - if [ -z "$udid" ]; then - echo "No $SIMULATOR simulator, even after downloading the iOS platform." >&2 - exit 1 - fi - xcrun simctl boot "$udid" - echo "udid=$udid" >> "$GITHUB_OUTPUT" - - uses: ./.github/actions/setup-xcodegen - name: Download static libraries @@ -88,16 +62,21 @@ jobs: - name: Generate the Xcode project run: scripts/generate-project.sh ios + # The image ships the iOS 27.0 runtime. Downloading the one for Xcode's newer SDK costs minutes. + - name: Make sure the simulator exists + run: | + if ! xcrun simctl list devices available | grep -F "iPhone 18 Pro (" > /dev/null; then + xcodebuild -downloadPlatform iOS + fi + # One simulator, not clones: on a 3-core runner a second booted simulator killed runs with # "(ipc/mig) server died", and TableProMobileTests is one bundle that never split anyway. - name: Run the iOS tests - env: - SIMULATOR_UDID: ${{ steps.simulator.outputs.udid }} run: | set -o pipefail xcodebuild test \ -project TableProMobile/TableProMobile.xcodeproj -scheme TableProMobile \ - -destination "platform=iOS Simulator,id=$SIMULATOR_UDID" -only-testing:TableProMobileTests \ + -destination "$DESTINATION" -only-testing:TableProMobileTests \ -parallel-testing-enabled NO \ -skipPackagePluginValidation -resultBundlePath iOS.xcresult \ CODE_SIGNING_ALLOWED=NO COMPILER_INDEX_STORE_ENABLE=NO COMPILATION_CACHE_ENABLE_CACHING=NO \