ci: add quick iOS build+test pass and gate WASM deploy on every test - #24
Merged
Conversation
Adds a fourth CI job `ios-test` on `macos-26` that mirrors the iOS half of `mobile-release.yml` but stops at `xcodebuild build` (no archive, no IPA, no attest). Runs the same `commonTest` corpus on iosSimulatorArm64 that `test` already runs on Android, so common-code regressions surface on both mobile targets before a mobile release. * writeIosVersionXcconfig + generateDummyFramework, no appVersion flags * pod install with the same cache-hit --repo-update guard as release * compileTestKotlinIosSimulatorArm64 fast smoke * xcodebuild build against Simulator arch, signing disabled * :shared:iosSimulatorArm64Test * Upload iosSimulatorArm64 test reports on always() Shares the ~/.konan and CocoaPods cache keys with mobile-release.yml so PR runs pre-warm the release workflow (and vice versa). Also expands `build-wasm-image.needs` from `test` to `[test, desktop-test, integration-test, ios-test]` and updates the two rationale comments (above desktop-test and integration-test) so the design intent tracks the new gate. The `if: github.event_name == 'push'` guard is unchanged, so this only affects merged-to-main deploys — PRs still surface job failures as check-run signal without blocking anything. Expected cost: * cold cache first PR: ~20 min * warm cache: ~10-15 min Compare mobile-release iOS at ~30-40 min. Co-authored-by: Cursor <cursoragent@cursor.com>
Without ARCHS=arm64 ONLY_ACTIVE_ARCH=YES, xcodebuild's generic Simulator destination on Apple Silicon macos-26 tries to build a fat arm64+x86_64 slice. Compose Multiplatform's :shared:syncPodComposeResourcesForIos then aborts with 'Unknown iOS simulator arch: x86_64' because shared/build.gradle.kts only declares iosArm64 and iosSimulatorArm64 targets (no iosX64). Pinning to arm64 keeps the slice single-arch and matches the iosSimulatorArm64 KMP target the tests use. Co-authored-by: Cursor <cursoragent@cursor.com>
linkDebugTestIosSimulatorArm64 hit a Kotlin compiler assertion when consuming the incrementally-cached multiplatform-markdown-renderer klib: 'Lowering ReturnsInsertion: phases [Enums] are required, but not satisfied'. The compiler itself surfaces the workaround (kotlin.incremental.native=false) in the same message. Applied to both the smoke compile and the actual test step so the K/N linker uses a fresh build. This does NOT invalidate the ~/.konan cache (~1-2 GB, saves 5-10 min of Kotlin/Native compiler + platform-lib downloads per run) — that cache holds the compiler and platform bindings, which are project-independent. kotlin.incremental.native only controls per-module IR snapshots under each project's build/, which our CI does not cache across runs anyway. Mobile-release iOS is unaffected (uses linkReleaseFramework, a different phase pipeline that doesn't hit the [Enums] assertion). Kept as a per-invocation -P flag rather than editing gradle.properties so local dev + mobile-release both keep incremental. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a quick iOS build + test pass to the PR CI workflow so we get signal that a mobile release will still compile before we cut a tag, without paying the 30-40 min
xcodebuild archive-> IPA pack -> attest tail thatmobile-release.ymldoes.Also gates the WASM deploy on every test job, not just Android.
New job:
ios-testruns-on: macos-26for iOS 26 SDK parity with mobile-release (same runner class we picked to unblock the ComposeUIViewLayoutRegionlink).timeout-minutes: 40hard ceiling so a stuck simulator boot doesn't burn macOS minutes.~/.konan+ CocoaPods caches keyed to matchmobile-release.ymlverbatim so PR runs pre-warm the release workflow (and vice versa)../gradlew :shared:writeIosVersionXcconfig :shared:generateDummyFramework(no-PappVersion.*flags -- CI doesn't need release-shaped version stamps).pod installiniosApp/with the same cache-hit--repo-updateguard as release../gradlew :shared:compileTestKotlinIosSimulatorArm64-- analog to the Android job'sCompile instrumented testsfast pass at line 42; fails fast on source-set / cinterop / pod-drift issues before we pay simulator boot.xcodebuild buildagainst Simulator arch with signing disabled -- same Swift + KMP + linker surface as the release archive, just without the archive/IPA/signing wrapping../gradlew :shared:iosSimulatorArm64Test-- direct KMP analog of:shared:connectedAndroidDeviceTest; iterates the samecommonTestcorpus across both mobile targets, which is the "same tests that run on Android if possible" ask.always().Every test job now gates
build-wasm-imageChanged:
+++
build-wasm-image:
needs: [test, desktop-test, integration-test, ios-test]
if: github.event_name == 'push'
+++
The
if: github.event_name == 'push'guard is unchanged, so this only affects merged-to-maindeploys -- PRs still surface each job's failure as check-run signal without blocking anything.Trade-off: the old design kept the WASM deploy resilient to flakes in
desktop-test(Skia/AWT),integration-test(Testcontainers pulling ghcr.io), and nowios-test(simulator boot). Any of those flaking onmainnow holds up the WASM deploy until re-run. Standard mitigation is the "Re-run failed jobs" button; if any prove flaky in practice we can carve exceptions back out job-by-job. The two rationale comments abovedesktop-testandintegration-testhave been updated to reflect this so future readers don't work off stale intent.Expected cost
Known risks
iosSimulatorArm64Teststep fails with "Unable to boot device". Fallback is addingxcodes runtimes install "iOS 26"-- will add that only if the first cold run needs it.