Skip to content

CI: add SwiftPM iOS e2e workflows (RNTester, HelloWorld, new app)#57659

Open
chrfalch wants to merge 4 commits into
mainfrom
chrfalch/add-e2e-tests-for-swiftpm
Open

CI: add SwiftPM iOS e2e workflows (RNTester, HelloWorld, new app)#57659
chrfalch wants to merge 4 commits into
mainfrom
chrfalch/add-e2e-tests-for-swiftpm

Conversation

@chrfalch

Copy link
Copy Markdown
Collaborator

Summary:

Adds CI coverage for the SwiftPM (SPM) iOS path, which currently has none. Three standalone workflows scaffold + convert an app to SPM using the prebuilt XCFrameworks and compile it for the iOS simulator:

  • test-ios-spm-rntester.ymlpackages/rn-tester
  • test-ios-spm-helloworld.ymlprivate/helloworld
  • test-ios-spm-newapp.yml — a fresh copy of private/helloworld, wired to a Verdaccio-published build of this monorepo

None of them use @react-native-community/cli. The shared logic lives in two committed, locally-runnable scripts (scripts/e2e/spm-prime-artifacts.js, scripts/e2e/spm-ios-e2e.js); the workflows are thin wrappers. They run manually (workflow_dispatch) and nightly (schedule).

This also adds an optional slices input to prebuild-ios-dependencies.yml and prebuild-ios-core.yml. It defaults to the full platform set, so existing callers (test-all.yml, releases) are unchanged; the e2e workflows request only ios-simulator, since that is all they compile against.

Changelog:

[INTERNAL] [ADDED] - CI workflows validating the SwiftPM iOS build (RNTester, HelloWorld, new app)

Test Plan:

  • Trialed the HelloWorld workflow on this branch (temporary push trigger, since removed): full run green for both Debug and Release, incl. the real spm add + xcodebuild. The slices input correctly collapsed the prebuild matrices to the single ios-simulator slice per flavor.
  • node --check, prettier --check, and eslint clean on both scripts; all workflow YAML validated.

chrfalch and others added 2 commits July 24, 2026 08:53
Adds three standalone workflows that scaffold + convert an iOS app to
SwiftPM using the prebuilt XCFrameworks and compile it:

  - test-ios-spm-rntester.yml   (packages/rn-tester)
  - test-ios-spm-helloworld.yml (private/helloworld)
  - test-ios-spm-newapp.yml     (fresh copy of helloworld, wired to a
                                 Verdaccio-published local monorepo build)

None of these use @react-native-community/cli. Each workflow builds the
prebuilt dependencies + core XCFrameworks via the existing reusable
prebuild-ios-* workflows, primes both flavor slots, then runs the shared
logic in two committed, locally-runnable scripts:

  - scripts/e2e/spm-prime-artifacts.js  (lay CI tarballs + hermes into the
                                         --artifacts <dir>/<flavor>/ layout)
  - scripts/e2e/spm-ios-e2e.js          (scaffold -> spm add --deintegrate
                                         -> xcodebuild, per app)

Triggered manually (workflow_dispatch) and nightly (schedule).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an optional `slices` input to prebuild-ios-dependencies.yml and
prebuild-ios-core.yml, driving their build matrix from it. It defaults
to the full platform set, so existing callers (test-all.yml, releases)
are unchanged.

The three SwiftPM iOS e2e workflows only ever compile for the iOS
simulator, so they now request `["ios-simulator"]` from both prebuild
workflows — cutting the dependencies matrix from 8 slices to 1 and the
core matrix from 3 to 1 (per flavor), which is the dominant cost of
those e2e runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jul 24, 2026
@chrfalch
chrfalch requested a review from cipolleschi July 24, 2026 07:41
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Jul 24, 2026
chrfalch and others added 2 commits July 24, 2026 10:11
- spm-ios-e2e.js: build the execFileSync `env` from process.env's string
  entries only (process.env is Flow-typed to allow numbers, which the
  execFileSync `env` option rejects), and omit `env` entirely when there
  is no override so the child inherits process.env as-is.
- Both scripts: suppress the parseArgs [incompatible-type] error with the
  standard "Natural Inference rollout" $FlowFixMe, matching set-version.js
  and init-project-e2e.js.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
execFileSync's `env` option is invariantly typed {[string]: string |
number | void}, so neither a plain process.env spread ({[string]: string
| void}) nor a string-only object satisfies it. Build the env object
into a correctly-typed indexer instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@cipolleschi cipolleschi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for hardening our CI. However, I think that we are not quite there. This approach does not follow the patterns we are currently using in CI. I left a few comments to improve this approach.

Comment on lines +22 to +36
prebuild_apple_dependencies:
uses: ./.github/workflows/prebuild-ios-dependencies.yml
with:
# e2e only compiles for the iOS simulator — no need for device/catalyst/tv/xr slices.
slices: '["ios-simulator"]'
secrets: inherit

prebuild_react_native_core:
needs: [prebuild_apple_dependencies]
if: ${{ needs.prebuild_apple_dependencies.result == 'success' }}
uses: ./.github/workflows/prebuild-ios-core.yml
with:
use-hermes-prebuilt: ${{ !endsWith(github.ref_name, '-stable') }}
slices: '["ios-simulator"]'
secrets: inherit

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you have to depend on the job that creates the XCFramework and download the XCFramework directly and use that one. We don't want to run the prebuild for these jobs. We want to consume the prebuilds we are creating.

Comment on lines +80 to +89
- name: Download ReactCore (Debug)
uses: actions/download-artifact@v7
with:
name: ReactCoreDebug.xcframework.tar.gz
path: /tmp/rc-debug
- name: Download ReactCore (Release)
uses: actions/download-artifact@v7
with:
name: ReactCoreRelease.xcframework.tar.gz
path: /tmp/rc-release

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't have to download both. You can have a matrix and run Debug and Release in parallel.

Comment on lines +22 to +36
prebuild_apple_dependencies:
uses: ./.github/workflows/prebuild-ios-dependencies.yml
with:
# e2e only compiles for the iOS simulator — no need for device/catalyst/tv/xr slices.
slices: '["ios-simulator"]'
secrets: inherit

prebuild_react_native_core:
needs: [prebuild_apple_dependencies]
if: ${{ needs.prebuild_apple_dependencies.result == 'success' }}
uses: ./.github/workflows/prebuild-ios-core.yml
with:
use-hermes-prebuilt: ${{ !endsWith(github.ref_name, '-stable') }}
slices: '["ios-simulator"]'
secrets: inherit

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

Comment on lines +40 to +57
build_npm_package:
runs-on: 8-core-ubuntu
container:
image: reactnativecommunity/react-native-android:latest
env:
TERM: 'dumb'
LC_ALL: C.UTF8
GRADLE_OPTS: '-Dorg.gradle.daemon=false'
REACT_NATIVE_DOWNLOADS_DIR: /opt/react-native-downloads
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Build NPM Package
uses: ./.github/actions/build-npm-package
with:
release-type: dry-run
gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
skip-apple-prebuilts: 'true'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we rerun the build npm package when running the template app e2e tests. we should not do it here either.

@@ -0,0 +1,115 @@
name: Test iOS SwiftPM - Hello World

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would just create the workflow and call it from test-all. I would not add a cron job here. We should rely on the nightly trigger.

@@ -0,0 +1,155 @@
name: Test iOS SwiftPM - New App

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Comment on lines +111 to +120
- name: Download ReactCore (Debug)
uses: actions/download-artifact@v7
with:
name: ReactCoreDebug.xcframework.tar.gz
path: /tmp/rc-debug
- name: Download ReactCore (Release)
uses: actions/download-artifact@v7
with:
name: ReactCoreRelease.xcframework.tar.gz
path: /tmp/rc-release

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above, Debug and release should run in parallel.

@@ -0,0 +1,115 @@
name: Test iOS SwiftPM - RN Tester

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

@@ -0,0 +1,525 @@
/**

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this? can't we run the commands you show during the AppJS talk?

@@ -0,0 +1,185 @@
/**

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this for the testing. We know in advance what we are running and we can have two parallel jobs running one debug and one release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Expo Partner: Expo Partner Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants