Skip to content

Commit 387bc99

Browse files
chrfalchclaude
andcommitted
CI: add SwiftPM iOS e2e workflows (RNTester, HelloWorld, new app)
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>
1 parent 8f5fa1c commit 387bc99

5 files changed

Lines changed: 1066 additions & 0 deletions

File tree

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
name: Test iOS SwiftPM - Hello World
2+
3+
permissions:
4+
contents: read
5+
6+
on:
7+
workflow_dispatch:
8+
inputs:
9+
flavor:
10+
description: 'Which build configuration(s) to test'
11+
type: choice
12+
options:
13+
- both
14+
- Debug
15+
- Release
16+
default: both
17+
schedule:
18+
# Nightly at 07:00 UTC (low-traffic hour).
19+
- cron: '0 7 * * *'
20+
21+
jobs:
22+
prebuild_apple_dependencies:
23+
uses: ./.github/workflows/prebuild-ios-dependencies.yml
24+
secrets: inherit
25+
26+
prebuild_react_native_core:
27+
needs: [prebuild_apple_dependencies]
28+
if: ${{ needs.prebuild_apple_dependencies.result == 'success' }}
29+
uses: ./.github/workflows/prebuild-ios-core.yml
30+
with:
31+
use-hermes-prebuilt: ${{ !endsWith(github.ref_name, '-stable') }}
32+
secrets: inherit
33+
34+
set_flavors:
35+
runs-on: ubuntu-latest
36+
outputs:
37+
flavors: ${{ steps.compute.outputs.flavors }}
38+
steps:
39+
- id: compute
40+
env:
41+
FLAVOR: ${{ github.event.inputs.flavor }}
42+
run: |
43+
case "$FLAVOR" in
44+
Debug) echo 'flavors=["Debug"]' >> "$GITHUB_OUTPUT" ;;
45+
Release) echo 'flavors=["Release"]' >> "$GITHUB_OUTPUT" ;;
46+
*) echo 'flavors=["Debug","Release"]' >> "$GITHUB_OUTPUT" ;;
47+
esac
48+
49+
test:
50+
needs: [prebuild_react_native_core, set_flavors]
51+
if: ${{ needs.prebuild_react_native_core.result == 'success' }}
52+
runs-on: macos-15-large
53+
strategy:
54+
fail-fast: false
55+
matrix:
56+
flavor: ${{ fromJSON(needs.set_flavors.outputs.flavors) }}
57+
steps:
58+
- name: Checkout
59+
uses: actions/checkout@v6
60+
- name: Setup xcode
61+
uses: ./.github/actions/setup-xcode
62+
- name: Setup node.js
63+
uses: ./.github/actions/setup-node
64+
- name: Run yarn install
65+
uses: ./.github/actions/yarn-install
66+
- name: Set Hermes prebuilt version
67+
shell: bash
68+
run: node ./scripts/releases/use-hermes-prebuilt.js
69+
- name: Run yarn install again, with the correct hermes version
70+
uses: ./.github/actions/yarn-install
71+
- name: Ensure CocoaPods (needed by `spm add --deintegrate`)
72+
shell: bash
73+
run: pod --version || sudo gem install cocoapods --no-document
74+
# `spm add --artifacts` validates BOTH the debug/ and release/ slots, so
75+
# download both flavors regardless of which one this cell builds.
76+
- name: Download ReactCore (Debug)
77+
uses: actions/download-artifact@v7
78+
with:
79+
name: ReactCoreDebug.xcframework.tar.gz
80+
path: /tmp/rc-debug
81+
- name: Download ReactCore (Release)
82+
uses: actions/download-artifact@v7
83+
with:
84+
name: ReactCoreRelease.xcframework.tar.gz
85+
path: /tmp/rc-release
86+
- name: Download ReactNativeDependencies (Debug)
87+
uses: actions/download-artifact@v7
88+
with:
89+
name: ReactNativeDependenciesDebug.xcframework.tar.gz
90+
path: /tmp/deps-debug
91+
- name: Download ReactNativeDependencies (Release)
92+
uses: actions/download-artifact@v7
93+
with:
94+
name: ReactNativeDependenciesRelease.xcframework.tar.gz
95+
path: /tmp/deps-release
96+
- name: Prime SPM artifacts (Debug + Release)
97+
shell: bash
98+
run: |
99+
node scripts/e2e/spm-prime-artifacts.js --artifacts /tmp/spm-artifacts --flavor Debug \
100+
--core-tarball /tmp/rc-debug/ReactCoreDebug.xcframework.tar.gz \
101+
--deps-tarball /tmp/deps-debug/ReactNativeDependenciesDebug.xcframework.tar.gz
102+
node scripts/e2e/spm-prime-artifacts.js --artifacts /tmp/spm-artifacts --flavor Release \
103+
--core-tarball /tmp/rc-release/ReactCoreRelease.xcframework.tar.gz \
104+
--deps-tarball /tmp/deps-release/ReactNativeDependenciesRelease.xcframework.tar.gz
105+
- name: Convert to SwiftPM + build
106+
shell: bash
107+
run: |
108+
node scripts/e2e/spm-ios-e2e.js \
109+
--app helloworld \
110+
--flavor "${{ matrix.flavor }}" \
111+
--artifacts /tmp/spm-artifacts
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
name: Test iOS SwiftPM - New App
2+
3+
permissions:
4+
contents: read
5+
6+
on:
7+
workflow_dispatch:
8+
inputs:
9+
flavor:
10+
description: 'Which build configuration(s) to test'
11+
type: choice
12+
options:
13+
- both
14+
- Debug
15+
- Release
16+
default: both
17+
schedule:
18+
# Nightly at 08:00 UTC (low-traffic hour).
19+
- cron: '0 8 * * *'
20+
21+
jobs:
22+
prebuild_apple_dependencies:
23+
uses: ./.github/workflows/prebuild-ios-dependencies.yml
24+
secrets: inherit
25+
26+
prebuild_react_native_core:
27+
needs: [prebuild_apple_dependencies]
28+
if: ${{ needs.prebuild_apple_dependencies.result == 'success' }}
29+
uses: ./.github/workflows/prebuild-ios-core.yml
30+
with:
31+
use-hermes-prebuilt: ${{ !endsWith(github.ref_name, '-stable') }}
32+
secrets: inherit
33+
34+
# Produces the `react-native-package` artifact (a local react-native .tgz) the
35+
# fresh app installs. Mirrors test-all.yml's build_npm_package (dry-run upload).
36+
build_npm_package:
37+
runs-on: 8-core-ubuntu
38+
container:
39+
image: reactnativecommunity/react-native-android:latest
40+
env:
41+
TERM: 'dumb'
42+
LC_ALL: C.UTF8
43+
GRADLE_OPTS: '-Dorg.gradle.daemon=false'
44+
REACT_NATIVE_DOWNLOADS_DIR: /opt/react-native-downloads
45+
steps:
46+
- name: Checkout
47+
uses: actions/checkout@v6
48+
- name: Build NPM Package
49+
uses: ./.github/actions/build-npm-package
50+
with:
51+
release-type: dry-run
52+
gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
53+
skip-apple-prebuilts: 'true'
54+
55+
set_flavors:
56+
runs-on: ubuntu-latest
57+
outputs:
58+
flavors: ${{ steps.compute.outputs.flavors }}
59+
steps:
60+
- id: compute
61+
env:
62+
FLAVOR: ${{ github.event.inputs.flavor }}
63+
run: |
64+
case "$FLAVOR" in
65+
Debug) echo 'flavors=["Debug"]' >> "$GITHUB_OUTPUT" ;;
66+
Release) echo 'flavors=["Release"]' >> "$GITHUB_OUTPUT" ;;
67+
*) echo 'flavors=["Debug","Release"]' >> "$GITHUB_OUTPUT" ;;
68+
esac
69+
70+
test:
71+
needs: [prebuild_react_native_core, build_npm_package, set_flavors]
72+
if: ${{ needs.prebuild_react_native_core.result == 'success' && needs.build_npm_package.result == 'success' }}
73+
runs-on: macos-15-large
74+
strategy:
75+
fail-fast: false
76+
matrix:
77+
flavor: ${{ fromJSON(needs.set_flavors.outputs.flavors) }}
78+
steps:
79+
- name: Checkout
80+
uses: actions/checkout@v6
81+
- name: Setup xcode
82+
uses: ./.github/actions/setup-xcode
83+
- name: Setup node.js
84+
uses: ./.github/actions/setup-node
85+
- name: Run yarn install
86+
uses: ./.github/actions/yarn-install
87+
- name: Set Hermes prebuilt version
88+
shell: bash
89+
run: node ./scripts/releases/use-hermes-prebuilt.js
90+
- name: Run yarn install again, with the correct hermes version
91+
uses: ./.github/actions/yarn-install
92+
- name: Ensure CocoaPods (needed by `spm add --deintegrate`)
93+
shell: bash
94+
run: pod --version || sudo gem install cocoapods --no-document
95+
- name: Configure git (Verdaccio publish + build)
96+
shell: bash
97+
run: |
98+
git config --global user.email "react-native-bot@meta.com"
99+
git config --global user.name "React Native Bot"
100+
- name: Download React Native package
101+
uses: actions/download-artifact@v7
102+
with:
103+
name: react-native-package
104+
path: /tmp/react-native-tmp
105+
# `spm add --artifacts` validates BOTH the debug/ and release/ slots, so
106+
# download both flavors regardless of which one this cell builds.
107+
- name: Download ReactCore (Debug)
108+
uses: actions/download-artifact@v7
109+
with:
110+
name: ReactCoreDebug.xcframework.tar.gz
111+
path: /tmp/rc-debug
112+
- name: Download ReactCore (Release)
113+
uses: actions/download-artifact@v7
114+
with:
115+
name: ReactCoreRelease.xcframework.tar.gz
116+
path: /tmp/rc-release
117+
- name: Download ReactNativeDependencies (Debug)
118+
uses: actions/download-artifact@v7
119+
with:
120+
name: ReactNativeDependenciesDebug.xcframework.tar.gz
121+
path: /tmp/deps-debug
122+
- name: Download ReactNativeDependencies (Release)
123+
uses: actions/download-artifact@v7
124+
with:
125+
name: ReactNativeDependenciesRelease.xcframework.tar.gz
126+
path: /tmp/deps-release
127+
- name: Prime SPM artifacts (Debug + Release)
128+
shell: bash
129+
run: |
130+
node scripts/e2e/spm-prime-artifacts.js --artifacts /tmp/spm-artifacts --flavor Debug \
131+
--core-tarball /tmp/rc-debug/ReactCoreDebug.xcframework.tar.gz \
132+
--deps-tarball /tmp/deps-debug/ReactNativeDependenciesDebug.xcframework.tar.gz
133+
node scripts/e2e/spm-prime-artifacts.js --artifacts /tmp/spm-artifacts --flavor Release \
134+
--core-tarball /tmp/rc-release/ReactCoreRelease.xcframework.tar.gz \
135+
--deps-tarball /tmp/deps-release/ReactNativeDependenciesRelease.xcframework.tar.gz
136+
- name: Convert to SwiftPM + build
137+
shell: bash
138+
run: |
139+
mapfile -t RN_PKGS < <(find /tmp/react-native-tmp -type f -name "*.tgz")
140+
if [[ ${#RN_PKGS[@]} -ne 1 ]]; then
141+
echo "Expected exactly one react-native .tgz in /tmp/react-native-tmp, found ${#RN_PKGS[@]}:" >&2
142+
printf ' %s\n' "${RN_PKGS[@]}" >&2
143+
exit 1
144+
fi
145+
REACT_NATIVE_PKG="${RN_PKGS[0]}"
146+
echo "react-native tarball: $REACT_NATIVE_PKG"
147+
node scripts/e2e/spm-ios-e2e.js \
148+
--app newapp \
149+
--flavor "${{ matrix.flavor }}" \
150+
--artifacts /tmp/spm-artifacts \
151+
--rn-tarball "$REACT_NATIVE_PKG"
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
name: Test iOS SwiftPM - RN Tester
2+
3+
permissions:
4+
contents: read
5+
6+
on:
7+
workflow_dispatch:
8+
inputs:
9+
flavor:
10+
description: 'Which build configuration(s) to test'
11+
type: choice
12+
options:
13+
- both
14+
- Debug
15+
- Release
16+
default: both
17+
schedule:
18+
# Nightly at 06:00 UTC (low-traffic hour).
19+
- cron: '0 6 * * *'
20+
21+
jobs:
22+
prebuild_apple_dependencies:
23+
uses: ./.github/workflows/prebuild-ios-dependencies.yml
24+
secrets: inherit
25+
26+
prebuild_react_native_core:
27+
needs: [prebuild_apple_dependencies]
28+
if: ${{ needs.prebuild_apple_dependencies.result == 'success' }}
29+
uses: ./.github/workflows/prebuild-ios-core.yml
30+
with:
31+
use-hermes-prebuilt: ${{ !endsWith(github.ref_name, '-stable') }}
32+
secrets: inherit
33+
34+
set_flavors:
35+
runs-on: ubuntu-latest
36+
outputs:
37+
flavors: ${{ steps.compute.outputs.flavors }}
38+
steps:
39+
- id: compute
40+
env:
41+
FLAVOR: ${{ github.event.inputs.flavor }}
42+
run: |
43+
case "$FLAVOR" in
44+
Debug) echo 'flavors=["Debug"]' >> "$GITHUB_OUTPUT" ;;
45+
Release) echo 'flavors=["Release"]' >> "$GITHUB_OUTPUT" ;;
46+
*) echo 'flavors=["Debug","Release"]' >> "$GITHUB_OUTPUT" ;;
47+
esac
48+
49+
test:
50+
needs: [prebuild_react_native_core, set_flavors]
51+
if: ${{ needs.prebuild_react_native_core.result == 'success' }}
52+
runs-on: macos-15-large
53+
strategy:
54+
fail-fast: false
55+
matrix:
56+
flavor: ${{ fromJSON(needs.set_flavors.outputs.flavors) }}
57+
steps:
58+
- name: Checkout
59+
uses: actions/checkout@v6
60+
- name: Setup xcode
61+
uses: ./.github/actions/setup-xcode
62+
- name: Setup node.js
63+
uses: ./.github/actions/setup-node
64+
- name: Run yarn install
65+
uses: ./.github/actions/yarn-install
66+
- name: Set Hermes prebuilt version
67+
shell: bash
68+
run: node ./scripts/releases/use-hermes-prebuilt.js
69+
- name: Run yarn install again, with the correct hermes version
70+
uses: ./.github/actions/yarn-install
71+
- name: Ensure CocoaPods (needed by `spm add --deintegrate`)
72+
shell: bash
73+
run: pod --version || sudo gem install cocoapods --no-document
74+
# `spm add --artifacts` validates BOTH the debug/ and release/ slots, so
75+
# download both flavors regardless of which one this cell builds.
76+
- name: Download ReactCore (Debug)
77+
uses: actions/download-artifact@v7
78+
with:
79+
name: ReactCoreDebug.xcframework.tar.gz
80+
path: /tmp/rc-debug
81+
- name: Download ReactCore (Release)
82+
uses: actions/download-artifact@v7
83+
with:
84+
name: ReactCoreRelease.xcframework.tar.gz
85+
path: /tmp/rc-release
86+
- name: Download ReactNativeDependencies (Debug)
87+
uses: actions/download-artifact@v7
88+
with:
89+
name: ReactNativeDependenciesDebug.xcframework.tar.gz
90+
path: /tmp/deps-debug
91+
- name: Download ReactNativeDependencies (Release)
92+
uses: actions/download-artifact@v7
93+
with:
94+
name: ReactNativeDependenciesRelease.xcframework.tar.gz
95+
path: /tmp/deps-release
96+
- name: Prime SPM artifacts (Debug + Release)
97+
shell: bash
98+
run: |
99+
node scripts/e2e/spm-prime-artifacts.js --artifacts /tmp/spm-artifacts --flavor Debug \
100+
--core-tarball /tmp/rc-debug/ReactCoreDebug.xcframework.tar.gz \
101+
--deps-tarball /tmp/deps-debug/ReactNativeDependenciesDebug.xcframework.tar.gz
102+
node scripts/e2e/spm-prime-artifacts.js --artifacts /tmp/spm-artifacts --flavor Release \
103+
--core-tarball /tmp/rc-release/ReactCoreRelease.xcframework.tar.gz \
104+
--deps-tarball /tmp/deps-release/ReactNativeDependenciesRelease.xcframework.tar.gz
105+
- name: Convert to SwiftPM + build
106+
shell: bash
107+
run: |
108+
node scripts/e2e/spm-ios-e2e.js \
109+
--app rntester \
110+
--flavor "${{ matrix.flavor }}" \
111+
--artifacts /tmp/spm-artifacts

0 commit comments

Comments
 (0)