Skip to content

Commit 75ab3ad

Browse files
abueideclaude
andauthored
refactor(ci): split E2E jobs into reusable workflows (#51)
Extract Android, iOS, and React Native E2E jobs from pr-checks.yml into separate reusable workflow files for better reviewability and reuse across pr-checks and e2e-full workflows. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f4461c2 commit 75ab3ad

5 files changed

Lines changed: 372 additions & 488 deletions

File tree

.github/workflows/e2e-android.yml

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
name: Android E2E
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
devices:
7+
description: 'JSON array of device names to test (e.g. ["max"] or ["min","max"])'
8+
type: string
9+
default: '["max"]'
10+
timeout-minutes:
11+
description: 'Job timeout in minutes'
12+
type: number
13+
default: 30
14+
boot-timeout:
15+
description: 'Emulator boot timeout in seconds'
16+
type: number
17+
default: 180
18+
test-timeout:
19+
description: 'Test timeout in seconds'
20+
type: number
21+
default: 300
22+
free-disk-space:
23+
description: 'Free disk space before build (recommended for single-device runs)'
24+
type: boolean
25+
default: true
26+
run-apk-detection-tests:
27+
description: 'Run APK detection tests before E2E'
28+
type: boolean
29+
default: false
30+
artifact-prefix:
31+
description: 'Prefix for artifact names'
32+
type: string
33+
default: 'android'
34+
35+
jobs:
36+
android-e2e:
37+
name: Android E2E - ${{ matrix.device }}
38+
runs-on: ubuntu-24.04
39+
timeout-minutes: ${{ inputs.timeout-minutes }}
40+
strategy:
41+
fail-fast: false
42+
matrix:
43+
device: ${{ fromJSON(inputs.devices) }}
44+
steps:
45+
- uses: actions/checkout@v6
46+
47+
- name: Enable KVM
48+
run: |
49+
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
50+
sudo udevadm control --reload-rules
51+
sudo udevadm trigger --name-match=kvm
52+
53+
- name: Setup Gradle cache
54+
uses: actions/cache@v5
55+
with:
56+
path: |
57+
~/.gradle/caches
58+
~/.gradle/wrapper
59+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
60+
restore-keys: |
61+
${{ runner.os }}-gradle-
62+
63+
- name: Free disk space
64+
if: inputs.free-disk-space
65+
run: |
66+
sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc \
67+
/usr/local/share/powershell /usr/local/share/chromium \
68+
/usr/local/share/boost /opt/hostedtoolcache
69+
sudo apt-get clean
70+
df -h /
71+
72+
- name: Install Devbox
73+
uses: jetify-com/devbox-install-action@v0.15.0
74+
with:
75+
enable-cache: true
76+
77+
- name: Rewrite plugin URLs to local
78+
run: bash scripts/dev/rewrite-plugin-urls.sh --to-local examples/
79+
80+
- name: Run Android apk-detection tests
81+
if: inputs.run-apk-detection-tests
82+
working-directory: examples/android
83+
run: devbox run bash ../../plugins/tests/android/test-apk-detection.sh
84+
85+
- name: Run Android E2E test
86+
working-directory: examples/android
87+
env:
88+
BOOT_TIMEOUT: ${{ inputs.boot-timeout }}
89+
TEST_TIMEOUT: ${{ inputs.test-timeout }}
90+
ANDROID_DEFAULT_DEVICE: ${{ matrix.device }}
91+
ANDROID_DEVICES: ${{ matrix.device }}
92+
TEST_TUI: false
93+
run: devbox run --pure -e EMU_HEADLESS=1 -e ANDROID_DEVICES=${{ matrix.device }} test:e2e
94+
95+
- name: Upload reports and logs
96+
if: always()
97+
uses: actions/upload-artifact@v7
98+
with:
99+
name: ${{ inputs.artifact-prefix }}-${{ matrix.device }}-reports
100+
path: |
101+
examples/android/reports/
102+
examples/android/app/build/outputs/
103+
retention-days: 7

.github/workflows/e2e-full.yml

Lines changed: 23 additions & 243 deletions
Original file line numberDiff line numberDiff line change
@@ -26,256 +26,36 @@ concurrency:
2626
jobs:
2727
# Android example E2E tests (min/max devices)
2828
android-e2e:
29-
name: Android E2E - ${{ matrix.device }}
3029
if: ${{ github.event_name == 'schedule' || inputs.run_android }}
31-
runs-on: ubuntu-24.04
32-
timeout-minutes: 45
33-
strategy:
34-
fail-fast: false
35-
matrix:
36-
device: [min, max]
37-
steps:
38-
- uses: actions/checkout@v6
39-
40-
- name: Enable KVM
41-
run: |
42-
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
43-
sudo udevadm control --reload-rules
44-
sudo udevadm trigger --name-match=kvm
45-
46-
- name: Setup Gradle cache
47-
uses: actions/cache@v5
48-
with:
49-
path: |
50-
~/.gradle/caches
51-
~/.gradle/wrapper
52-
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
53-
restore-keys: |
54-
${{ runner.os }}-gradle-
55-
56-
- name: Install Devbox
57-
uses: jetify-com/devbox-install-action@v0.15.0
58-
with:
59-
enable-cache: true
60-
61-
- name: Rewrite plugin URLs to local
62-
run: bash scripts/dev/rewrite-plugin-urls.sh --to-local examples/
63-
64-
- name: Run Android E2E test
65-
working-directory: examples/android
66-
env:
67-
BOOT_TIMEOUT: 240
68-
TEST_TIMEOUT: 600
69-
ANDROID_DEFAULT_DEVICE: ${{ matrix.device }}
70-
TEST_TUI: false
71-
run: devbox run --pure -e EMU_HEADLESS=1 test:e2e
72-
73-
- name: Upload reports and logs
74-
if: always()
75-
uses: actions/upload-artifact@v7
76-
with:
77-
name: android-${{ matrix.device }}-reports
78-
path: |
79-
examples/android/reports/
80-
examples/android/app/build/outputs/
81-
retention-days: 7
30+
uses: ./.github/workflows/e2e-android.yml
31+
with:
32+
devices: '["min","max"]'
33+
timeout-minutes: 45
34+
boot-timeout: 240
35+
test-timeout: 600
36+
free-disk-space: false
37+
run-apk-detection-tests: false
38+
artifact-prefix: android
8239

8340
# iOS example E2E tests (min/max devices)
8441
ios-e2e:
85-
name: iOS E2E - ${{ matrix.device }}
8642
if: ${{ github.event_name == 'schedule' || inputs.run_ios }}
87-
runs-on: ${{ matrix.os }}
88-
timeout-minutes: 45
89-
strategy:
90-
fail-fast: false
91-
matrix:
92-
include:
93-
- device: min
94-
os: macos-14
95-
- device: max
96-
os: macos-26
97-
steps:
98-
- uses: actions/checkout@v6
99-
100-
- name: Select pinned Xcode (max only)
101-
if: matrix.device == 'max'
102-
run: |
103-
XCODE_VERSION=$(jq -r '.env.IOS_XCODE_VERSION' plugins/ios/plugin.json)
104-
XCODE_APP=$(ls -d /Applications/Xcode_${XCODE_VERSION}*.app 2>/dev/null | head -1)
105-
if [ -z "$XCODE_APP" ]; then
106-
XCODE_APP="/Applications/Xcode.app"
107-
fi
108-
echo "Selecting: $XCODE_APP"
109-
sudo xcode-select -s "$XCODE_APP/Contents/Developer"
110-
xcodebuild -version
111-
xcrun simctl list runtimes | grep -i ios
112-
113-
- name: Setup CocoaPods cache
114-
uses: actions/cache@v5
115-
with:
116-
path: |
117-
~/.cocoapods/repos
118-
~/Library/Caches/CocoaPods
119-
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
120-
restore-keys: |
121-
${{ runner.os }}-pods-
122-
123-
- name: Setup Xcode build cache
124-
uses: actions/cache@v5
125-
with:
126-
path: |
127-
~/Library/Developer/Xcode/DerivedData
128-
key: ${{ runner.os }}-xcode-${{ hashFiles('**/*.xcodeproj/**', '**/*.xcworkspace/**') }}
129-
restore-keys: |
130-
${{ runner.os }}-xcode-
131-
132-
- name: Install Devbox
133-
uses: jetify-com/devbox-install-action@v0.15.0
134-
with:
135-
enable-cache: true
136-
137-
- name: Rewrite plugin URLs to local
138-
run: bash scripts/dev/rewrite-plugin-urls.sh --to-local examples/
139-
140-
- name: Run iOS E2E test
141-
working-directory: examples/ios
142-
env:
143-
BOOT_TIMEOUT: 180
144-
TEST_TIMEOUT: 600
145-
IOS_DEFAULT_DEVICE: ${{ matrix.device }}
146-
TEST_TUI: false
147-
run: devbox run --pure -e SIM_HEADLESS=1 test:e2e
148-
149-
- name: Upload reports and logs
150-
if: always()
151-
uses: actions/upload-artifact@v7
152-
with:
153-
name: ios-${{ matrix.device }}-reports
154-
path: |
155-
examples/ios/reports/
156-
~/Library/Logs/CoreSimulator/
157-
retention-days: 7
43+
uses: ./.github/workflows/e2e-ios.yml
44+
with:
45+
matrix-include: '[{"device":"min","os":"macos-14"},{"device":"max","os":"macos-26"}]'
46+
timeout-minutes: 45
47+
boot-timeout: 180
48+
test-timeout: 600
49+
artifact-prefix: ios
15850

15951
# React Native E2E tests (Android min/max, iOS min/max, Web)
16052
react-native-e2e:
161-
name: React Native E2E - ${{ matrix.platform }}-${{ matrix.device }}
16253
if: ${{ github.event_name == 'schedule' || inputs.run_react_native }}
163-
runs-on: ${{ matrix.os }}
164-
timeout-minutes: 60
165-
strategy:
166-
fail-fast: false
167-
matrix:
168-
include:
169-
# Android tests
170-
- platform: android
171-
device: min
172-
os: ubuntu-24.04
173-
- platform: android
174-
device: max
175-
os: ubuntu-24.04
176-
# iOS tests
177-
- platform: ios
178-
device: min
179-
os: macos-14
180-
- platform: ios
181-
device: max
182-
os: macos-26
183-
# Web test (fast, no device needed)
184-
- platform: web
185-
device: none
186-
os: ubuntu-24.04
187-
steps:
188-
- uses: actions/checkout@v6
189-
190-
- name: Setup Node.js with cache
191-
uses: actions/setup-node@v6
192-
with:
193-
node-version: '20'
194-
cache: 'npm'
195-
cache-dependency-path: examples/react-native/package-lock.json
196-
197-
- name: Select pinned Xcode (iOS max only)
198-
if: matrix.platform == 'ios' && matrix.device == 'max'
199-
run: |
200-
XCODE_VERSION=$(jq -r '.env.IOS_XCODE_VERSION' plugins/ios/plugin.json)
201-
XCODE_APP=$(ls -d /Applications/Xcode_${XCODE_VERSION}*.app 2>/dev/null | head -1)
202-
if [ -z "$XCODE_APP" ]; then
203-
XCODE_APP="/Applications/Xcode.app"
204-
fi
205-
echo "Selecting: $XCODE_APP"
206-
sudo xcode-select -s "$XCODE_APP/Contents/Developer"
207-
xcodebuild -version
208-
xcrun simctl list runtimes | grep -i ios
209-
210-
- name: Enable KVM (Android only)
211-
if: matrix.platform == 'android'
212-
run: |
213-
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
214-
sudo udevadm control --reload-rules
215-
sudo udevadm trigger --name-match=kvm
216-
217-
- name: Setup Gradle cache (Android only)
218-
if: matrix.platform == 'android'
219-
uses: actions/cache@v5
220-
with:
221-
path: |
222-
~/.gradle/caches
223-
~/.gradle/wrapper
224-
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
225-
restore-keys: |
226-
${{ runner.os }}-gradle-
227-
228-
- name: Setup CocoaPods cache (iOS only)
229-
if: matrix.platform == 'ios'
230-
uses: actions/cache@v5
231-
with:
232-
path: |
233-
~/.cocoapods/repos
234-
~/Library/Caches/CocoaPods
235-
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
236-
restore-keys: |
237-
${{ runner.os }}-pods-
238-
239-
- name: Setup Xcode build cache (iOS only)
240-
if: matrix.platform == 'ios'
241-
uses: actions/cache@v5
242-
with:
243-
path: |
244-
~/Library/Developer/Xcode/DerivedData
245-
key: ${{ runner.os }}-xcode-${{ hashFiles('**/*.xcodeproj/**', '**/*.xcworkspace/**') }}
246-
restore-keys: |
247-
${{ runner.os }}-xcode-
248-
249-
- name: Install Devbox
250-
uses: jetify-com/devbox-install-action@v0.15.0
251-
with:
252-
enable-cache: true
253-
254-
- name: Rewrite plugin URLs to local
255-
run: bash scripts/dev/rewrite-plugin-urls.sh --to-local examples/
256-
257-
- name: Run React Native E2E test
258-
working-directory: examples/react-native
259-
run: |
260-
if [ "${{ matrix.platform }}" = "android" ]; then
261-
devbox run --pure -e IOS_SKIP_SETUP=1 -e EMU_HEADLESS=1 test:e2e:android
262-
elif [ "${{ matrix.platform }}" = "ios" ]; then
263-
devbox run --pure -e ANDROID_SKIP_SETUP=1 -e SIM_HEADLESS=1 test:e2e:ios
264-
elif [ "${{ matrix.platform }}" = "web" ]; then
265-
devbox run --pure -e ANDROID_SKIP_SETUP=1 -e IOS_SKIP_SETUP=1 test:e2e:web
266-
fi
267-
268-
- name: Upload reports and logs
269-
if: always()
270-
uses: actions/upload-artifact@v7
271-
with:
272-
name: react-native-${{ matrix.platform }}-${{ matrix.device }}-reports
273-
path: |
274-
examples/react-native/reports/
275-
examples/react-native/android/app/build/outputs/
276-
examples/react-native/ios/build/
277-
~/Library/Logs/CoreSimulator/
278-
retention-days: 7
54+
uses: ./.github/workflows/e2e-react-native.yml
55+
with:
56+
matrix-include: '[{"platform":"android","device":"min","os":"ubuntu-24.04"},{"platform":"android","device":"max","os":"ubuntu-24.04"},{"platform":"ios","device":"min","os":"macos-14"},{"platform":"ios","device":"max","os":"macos-26"},{"platform":"web","device":"none","os":"ubuntu-24.04"}]'
57+
timeout-minutes: 60
58+
artifact-prefix: react-native
27959

28060
# Summary status check
28161
e2e-summary:
@@ -286,7 +66,7 @@ jobs:
28666
steps:
28767
- name: Check results
28868
run: |
289-
echo "📊 E2E Test Results:"
69+
echo "E2E Test Results:"
29070
echo " Android E2E: ${{ needs.android-e2e.result }}"
29171
echo " iOS E2E: ${{ needs.ios-e2e.result }}"
29272
echo " React Native E2E: ${{ needs.react-native-e2e.result }}"
@@ -301,4 +81,4 @@ jobs:
30181
exit 1
30282
fi
30383
304-
echo "::notice::All E2E tests passed successfully!"
84+
echo "::notice::All E2E tests passed successfully!"

0 commit comments

Comments
 (0)