Skip to content

ci: build the iOS sample apps on Xcode 27 - #673

Merged
Shahroz16 merged 6 commits into
mainfrom
ci/xcode-27
Oct 23, 2026
Merged

Shahroz16 merged 6 commits into
mainfrom
ci/xcode-27

Conversation

@Shahroz16

@Shahroz16 Shahroz16 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Refs MBL-2397

Stacked on #667 (Node 24 actions): base branch ci/node24-actions. Retarget to main after #667 merges.

Implements the 2026-10-21 decision: regular CI moves to Xcode 27 now; an Xcode 26 PR check stays only where it's cheap; separate Xcode 27 nightlies go once the regular jobs pass.

1. Regular iOS builds → Xcode 27

build-sample-app.yml is the only workflow that builds iOS on every PR and on main:

  • runs-on: macos-26 → xcode-27, the runner the scene E2E lane already uses (GitHub-hosted public preview, [macOS] Xcode 27 is now available as a public preview actions/runner-images#14404). This covers every iOS sample build: PR verification (APN always, FCM when iOS paths change), signed distribution on main and ci:full, and the release sample apps after deploy.
  • Pins Xcode 27.0 (XCODE_VERSION) through mobile-ci-tools setup-ios. 27.0 is the image default; 27.1 RC and 27.2 beta are also installed.
  • Selects Xcode right after checkout. It used to run just before the final build, so the deep-link swiftc test and pod install ran on whatever the image defaulted to.
  • Asserts the toolchain with report-toolchain (Xcode and iOS SDK major 27), like the scene lane.
  • Adds timeout-minutes: 60 on execution. Builds take 20–35 minutes (measured on recent runs), and queue time doesn't count.
  • Job names are unchanged. main has no required status checks, so nothing needs a ruleset update either way.

2. Xcode 26 PR check: none

None of this repo's existing checks is a cheap Xcode 26 check. The only iOS PR jobs are full sample-app builds (npm, pod install, Release simulator build): 20–35 minutes each on macOS.

I considered keeping the FCM PR build on Xcode 26 as a zero-extra-job check, and rejected it on Codex's advice. FCM adds MessagingPushFCM / CioFirebaseWrapper and Firebase code paths that APN doesn't compile. Now that Xcode 27 is the primary compiler, losing FCM-on-27 on PRs costs more than losing APN-on-26.

Known gap: after this, nothing in this repo compiles the wrapper with Xcode 26 / Swift 6.2. Customers shipping to the App Store still build with Xcode 26 until Apple requires Xcode 27. If that matters, the cheapest add-on would be a separate macos-26 job compiling only the CocoaPods customerio-reactnative target. It still needs npm and pod install, so it's not free.

3. Scene E2E nightly: kept as the only scheduled iOS validation job (unchanged)

react-native-scene-e2e.yml already runs on xcode-27. It isn't folded into regular CI because:

  • It's too expensive for every PR. One run generates a fresh RN 0.88 template host, installs its pods, builds Release, and drives Maestro through warm, cold and declined notification flows plus ordinary links. That's about 25–40 minutes on the preview image, plus queueing (24 minutes on ci(e2e): stop pinning the scene E2E simulator model #668's last run).
  • It's already in regular CI where it matters. react-native-scene-e2e-full.yml runs the same lane on PRs that touch scene-routing paths, or that carry ci:full.
  • The nightly catches drift no PR touches. That's runner-image changes (like the iPhone 17 Pro removal) and new native SDK versions. ci(e2e): stop pinning the scene E2E simulator model #668's simulator fix comes first; this PR doesn't touch the scene workflows, so it doesn't trigger that lane.

It's the only scheduled iOS validation job (auto-update-native-sdks.yml has a schedule too, for SDK bump automation, unchanged).

4. Redundant after the move

Nothing; checked after the Xcode 27 jobs passed, so there's no cleanup commit. This repo has no Xcode 27-only nightly: the scene E2E nightly tests scene routing, not toolchain compatibility (section 3). The old late setup-ios step was moved, not duplicated.

Pre-existing, not changed here: the "Cache CocoaPods downloaded dependencies" step caches example/Pods, but pod install writes example/ios/Pods, so the cache never hits. That's a separate fix.

CI

All green (run 39535789047): 14 pass, 3 skipped by design (PR comment, scene lane, distribution).

Job Runner / toolchain Result
iOS APN sample app xcode-27, image macos27 20261012.0260.1, macOS 27.0.1, Xcode 27.0 (27A266a), iOS SDK 27.0 ✅ 21 min
iOS FCM sample app same ✅ 18 min
Android APN sample app ubuntu-latest ✅ 15 min

On the preview image these all worked: setup-xcode resolving 27.0, the Xcode 27 toolchain check, Homebrew sd/xcbeautify, Ruby 3.4 + bundler cache, pod install, and the deployment-target audit. Signed distribution (main / ci:full) hasn't run on Xcode 27 yet; it runs the same steps plus Fastlane gym and the Firebase upload.

Codex review

Approach consult:

  • Codex advised moving both APN and FCM PR builds to 27 rather than splitting them across 26 and 27. Adopted.
  • It advised selecting Xcode before any toolchain-dependent step, and asserting the Xcode and SDK majors. Adopted.
  • It advised an execution timeout. Adopted.
  • It advised keeping both scene workflows. Adopted.
  • It also raised the dead Pods cache path. Noted above.

Adversarial review: no confirmed findings. Codex found the step order with the job's working-directory default fine, as well as the runs-on expression, env inside a step's with: and the unchanged job name.

  • The timeout now also bounds Android (60 minutes); Android builds take 10–16 minutes, so that's harmless.
  • Codex couldn't verify these from git alone: report-toolchain@main inputs (checked: expected-xcode-major / expected-ios-sdk-major exist), setup-xcode resolving 27.0, and Homebrew / Ruby 3.4 on the macOS 27 image. CI on this PR is the check for those.

🤖 Generated with Claude Code

Shahroz16 and others added 3 commits October 20, 2026 12:44
GitHub removed the Node 20 Actions runtime on 2026-09-23; node20 actions now
run forced on Node 24 with a deprecation warning. Move every action this repo
pins to a release whose action.yml declares `runs.using: node24`:

- actions/checkout v4 -> v7, actions/setup-node v4 -> v7, actions/cache v4 -> v6,
  actions/upload-artifact v4.6.2 -> v7.0.2
- maierj/fastlane-action v3.1.0 -> v3.2.0
- cycjimmy/semantic-release-action v4.2.0 -> v6.0.0 (semantic_version stays
  25.0.9). v7/v8 shipped 10 releases in two weeks around an ESM rewrite; v6
  already runs on node24 and matches customerio-ios.
- slackapi/slack-github-action v1.26.0 -> v4.0.0, with the webhook URL and type
  moved from env to the `webhook`/`webhook-type` inputs v2+ require. v2+ no
  longer fails the step on a Slack error: the two failure alerts opt back in
  with `errors: true`; the success notices keep the default so a Slack outage
  cannot skip deploy-npm or report a published release as failed.
- ataylorme/eslint-annotate-action v3 -> 4.0.0, passing the token through
  `github-token` (the old `repo-token` input never existed)
- levibostian/action-conventional-pr-linter (no node24 release) ->
  amannn/action-semantic-pull-request v6.1.1
- kenji-miyake/setup-sd (no node24 release) -> local composite
  .github/actions/setup-sd that installs a checksum-verified sd 1.1.0

Refs MBL-2397

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Match the shared-CI choice for every mobile repo: the old linter commented on
invalid titles, so add marocchino/sticky-pull-request-comment v3.0.5 (node24)
to post fixed help text when amannn reports a title error, and to delete it
once the title passes. Both steps are best effort (`continue-on-error`): fork
and Dependabot runs get a read-only token.

Refs MBL-2397

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Move every iOS sample-app build (PR verification for APN and FCM, signed
distribution on main, ci:full and the release sample apps) from macos-26 to
the xcode-27 image, the runner the scene E2E lane already uses, and pin
Xcode 27.0 (the image default; 27.1 RC and 27.2 beta are also installed).

Select Xcode right after checkout instead of just before the build. The
deep-link swiftc test and `pod install` used to run with whatever the image
defaulted to. Then assert the toolchain with report-toolchain (Xcode and
iOS SDK major 27), as the scene E2E lane does.

Add a 60-minute execution timeout; the builds take 20-35 minutes, and queue
time on the preview image doesn't count against it.

Refs MBL-2397

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Shahroz16
Shahroz16 marked this pull request as ready for review October 21, 2026 03:21
@Shahroz16
Shahroz16 requested a review from a team as a code owner October 21, 2026 03:21
Base automatically changed from ci/node24-actions to main October 23, 2026 18:48
# Conflicts:
#	.github/workflows/react-native-scene-e2e.yml
@Shahroz16
Shahroz16 merged commit d4a0d7d into main Oct 23, 2026
10 checks passed
@Shahroz16
Shahroz16 deleted the ci/xcode-27 branch October 23, 2026 19:00
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.

2 participants