Skip to content

Build the iOS test apps with SwiftPM in CI - #59742

Open
chrfalch wants to merge 2 commits into
mainfrom
chrfalch/spm-ci-default
Open

chrfalch wants to merge 2 commits into
mainfrom
chrfalch/spm-ci-default

Conversation

@chrfalch

@chrfalch chrfalch commented Nov 2, 2026

Copy link
Copy Markdown
Collaborator

Summary:

The iOS CI jobs that build our test apps still use CocoaPods: RNTester, HelloWorld, and the template app that the Maestro end-to-end tests run. SwiftPM is becoming the default way to build React Native apps on iOS, so CI should build these apps with SwiftPM.

This PR changes those jobs to SwiftPM:

  1. HelloWorld is converted to SwiftPM and checked in. Its Podfile, workspace and Ruby files are removed. yarn bootstrap ios and yarn build ios now use SwiftPM.
  2. RNTester stays a CocoaPods project in git, so developers can still build React Native from source in it. CI converts it to SwiftPM before each build (spm scaffold, then spm add --deintegrate).
  3. The RNTester app that the Maestro tests use keeps its artifact name, RNTesterApp-NewArch-{Debug,Release}, so the Maestro jobs do not change.
  4. The template app for the Maestro tests is converted to SwiftPM in its build job.
  5. A new action, setup-spm-artifacts, gives each job the prebuilt frameworks from the same CI run.
  6. test_ios_rntester now blocks a merge. It replaces the blocking test_ios_spm_rntester job.
  7. These jobs and workflows are removed: the Ruby 3.2 jobs, the dynamic-frameworks job, the use_frameworks matrix axis, and test-ios-spm-rntester.yml / test-ios-spm-helloworld.yml (the jobs above now cover them).

Things reviewers should know:

  • After this PR, no CI job builds an app with CocoaPods. A separate PR will add a test for the CocoaPods opt-out.
  • The check names change, for example test_ios_rntester (Debug, false) becomes test_ios_rntester (Debug). If branch protection lists the old names, it must be updated.
  • The RNTester and HelloWorld unit-test targets are not built by any CI job today. They do not build after the SwiftPM conversion. A follow-up PR will fix them.

Changelog:

[INTERNAL] [CHANGED] - Build the iOS test apps with SwiftPM in CI

Test Plan:

Local, Xcode, iPhone simulator:

  • RNTester, starting from the CocoaPods project in git, with the same commands as the CI action: spm scaffold, spm add --deintegrate, then xcodebuild -project RNTesterPods.xcodeproj -scheme RNTester. Debug and Release: BUILD SUCCEEDED. The embedded React.framework has the matching flavor (nm | grep getDebugProps: 81 symbols in Debug, 0 in Release).
  • HelloWorld, from a clean checkout: yarn bootstrap ios && yarn build ios in private/helloworld: BUILD SUCCEEDED. yarn bundle ios: passes. Before this change, all three commands failed on the converted project ("No Podfile found").
  • yarn flow-check: 0 errors. npx eslint --max-warnings 0 on the changed JavaScript files: clean.

Not run locally: the template-app job and test-ios-spm-newapp.yml. The CI run on this PR tests them.

@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 Nov 2, 2026
The iOS CI jobs that build RNTester, HelloWorld and the template app used
by the Maestro end-to-end tests still built them with CocoaPods. SwiftPM
is becoming the default way to build React Native apps on iOS, so these
jobs now build with SwiftPM.

- HelloWorld is converted to SwiftPM and checked in. Its Podfile,
  workspace and Ruby files are removed. `yarn bootstrap ios` and
  `yarn build ios` use SwiftPM.
- RNTester stays a CocoaPods project in git, so developers keep building
  React Native from source. CI converts it to SwiftPM before each build.
  The app uploaded for the Maestro tests keeps its name.
- The template app is converted to SwiftPM in its build job.
- A new action, setup-spm-artifacts, gives every job the prebuilt
  frameworks from the same CI run.
- test_ios_rntester now blocks a merge.
- The CocoaPods-only jobs (Ruby 3.2, dynamic frameworks, use_frameworks)
  and the separate SwiftPM workflows for RNTester and HelloWorld are
  removed.

Verify locally: `yarn bootstrap ios && yarn build ios` in
private/helloworld prints BUILD SUCCEEDED.
`spm add --deintegrate` keeps the Podfile since #59368, so the RNTester
check now looks for CocoaPods references in RNTesterPods.xcodeproj, as the
SwiftPM workflows on main do.
@chrfalch
chrfalch force-pushed the chrfalch/spm-ci-default branch from 14f423f to 54ca50f Compare November 3, 2026 11:58
@chrfalch
chrfalch marked this pull request as ready for review November 3, 2026 16:13
@chrfalch
chrfalch requested a review from cipolleschi November 3, 2026 16:14
@chrfalch

chrfalch commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator Author

@cipolleschi This PR changes the iOS CI jobs to build our test apps with SwiftPM instead of CocoaPods. SwiftPM becomes the default in 0.89, so CI should test that setup. The PR is ready for your review.

What changes:

  • HelloWorld is checked in as a SwiftPM project.
  • RNTester stays CocoaPods in git, so developers can still build from source. CI converts it to SwiftPM before each build.
  • The template app for the Maestro tests is converted in its build job.
  • CI is green on the current commit. All iOS jobs pass in Debug and Release.

Things that need your attention:

  • Check names change. For example, test_ios_rntester (Debug, false) becomes test_ios_rntester (Debug). If branch protection lists the old names, it needs an update.
  • test_ios_rntester now blocks a merge.
  • After this PR, no CI job builds an app with CocoaPods. The CocoaPods opt-out landed in Let spm deinit take an app back to CocoaPods #59368. A follow-up PR adds a CI test that builds an app with that opt-out.
  • The RNTester and HelloWorld unit-test targets do not build after the conversion. No CI job builds them today. A follow-up PR fixes them.

@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 Nov 3, 2026

@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 working on this.
I left some questions and I think we need to keep cover at least RNTester with cocoapods to ensure the opt-out mechanism does not break.

path: /tmp/ReactCore
- name: Print ReactCore folder
if: ${{ steps.prebuilds.outputs.enabled == 'true' }}
run: pod --version || sudo gem install cocoapods --no-document

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.

if we need to run this, we still need ruby. Mac machines should come with cocoapods already installed no?

This step should not be necessary.

- name: Install CocoaPods dependencies
working-directory: packages/rn-tester
run: |
# pod deintegrate fails on non-ASCII strings without a UTF-8 locale.

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.

whch non-ASCII strings we have in RNTester?? I don't think this locale thing is needed.

fail-on-error: true
secrets: inherit

test_ios_spm_rntester:

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.

on the other side, we might want to keep a couple of jobs to test the build with Cocoapods, to make sure we maintain it working while we have the dual setup.
SwiftPM will be the official setup, but we need to ensure that the opt-out path keeps working. For this scenario, we don't need the full matrix.

<PreActions>
<ExecutionAction
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent

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.

shouldn't this action be injected by our scripts? 😕
This looks scary.

@@ -0,0 +1,43 @@
#!/bin/bash

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 see that this is generated. Why are we committing it? Generated files should be gitignored and not committed.

@@ -0,0 +1,226 @@
#!/bin/bash

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 see that this is generated. Why are we committing it? Generated files should be gitignored and not committed.

@@ -0,0 +1,68 @@
// Generated by React Native on every `spm add` and `spm update`.

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 see that this is generated. Why are we committing it? Generated files should be gitignored and not committed.

Comment on lines -43 to -45
# Ruby / CocoaPods
ios/Pods/
vendor/bundle/

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.

we can keep these.

This branch has not been deployed

No deployments
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. 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