Repository navigation
263 lines (230 loc) · 10.9 KB
/
Copy pathe2e_ios.yml
File metadata and controls
263 lines (230 loc) · 10.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
name: e2e-ios
on:
pull_request:
branches:
- '**'
paths: &e2e-ios-paths
- '.github/workflows/e2e_ios.yml'
- '.github/actions/e2e-cache/**'
- '.github/actions/e2e-common/**'
- '.gitmodules'
# codegenConfig is copied into the linked package and drives codegen
- 'package.json'
- 'react-native-update.podspec'
- 'react-native.config.js'
- 'expo-module.config.json'
- 'src/**'
- 'ios/**'
- 'cpp/**'
- 'android/jni/**'
- 'Example/e2etest/**'
push:
branches:
- master
paths: *e2e-ios-paths
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
# Also part of every cache key/scope below: a new Xcode means new binaries.
XCODE_VERSION: '26.4'
jobs:
# Builds the release .app once (pod install + xcodebuild, or the cached app
# with a refreshed JS bundle) and prepares the local update artifacts; both
# test legs below install that same build instead of compiling it twice.
e2e-ios-build:
name: e2e-ios (build)
runs-on: macos-26
timeout-minutes: 45
steps:
- name: Checkout react-native-update
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
submodules: recursive
- name: Setup Xcode
uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0
with:
xcode-version: ${{ env.XCODE_VERSION }}
- name: Cache Homebrew downloads
# Bottle content addressing still controls reuse; only this job's
# master runs write the daily snapshot. applesimutils is installed
# here too (unused by the build) so the snapshot the test legs
# restore holds every bottle they need.
uses: ./.github/actions/e2e-cache
with:
path: ~/Library/Caches/Homebrew
scope: brew-xcode-${{ env.XCODE_VERSION }}
write: 'true'
- name: Install applesimutils and ccache
run: brew trust wix/brew && HOMEBREW_NO_AUTO_UPDATE=1 brew install wix/brew/applesimutils ccache
- name: Cache ccache
# Old content-addressed entries affect hit rate, not build correctness.
# PRs only restore; no per-commit duplicates.
uses: ./.github/actions/e2e-cache
with:
path: ~/Library/Caches/ccache
scope: ccache-xcode-${{ env.XCODE_VERSION }}
write: 'true'
- name: Set up e2e environment
# Node/Bun, e2etest dependencies, the local react-native-update link
# and react-native-update-cli (shared with the Android jobs).
uses: ./.github/actions/e2e-common
- name: Cache Metro transform cache
# Metro validates its own content keys; stale snapshots only recompile.
uses: ./.github/actions/e2e-cache
with:
path: Example/e2etest/.metro-cache
scope: metro-xcode-${{ env.XCODE_VERSION }}
write: 'true'
- name: Prepare local update artifacts
env:
E2E_PLATFORM: ios
RNU_CLI_ROOT: ${{ github.workspace }}/react-native-update-cli
run: cd Example/e2etest && bun run prepare:e2e
- name: Cache CocoaPods downloads
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/Library/Caches/CocoaPods
key: ${{ runner.os }}-cocoapods-e2e-${{ hashFiles('Example/e2etest/ios/Podfile.lock', 'Example/e2etest/ios/Podfile', 'Example/e2etest/bun.lock') }}
restore-keys: |
${{ runner.os }}-cocoapods-e2e-
- name: Cache built e2e app (keyed on native inputs)
# 命中 = native 输入(两个 ios 工程、cpp/jni、podspec、依赖锁、codegen 输入)
# 一字未改,跳过 pod install + xcodebuild,只重新注入 JS bundle(见下)。
# codegen 输入必须参与 key:TurboModule 胶水在 pod install 时由根
# package.json 的 codegenConfig + src/Native*.ts spec 生成,漏了它们
# 会在改 spec 后把新 JS 注入到旧胶水的二进制上。
# 故意不设 restore-keys:部分命中就是错的二进制,宁可全量重建。
id: cache-ios-app
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
Example/e2etest/ios/build/Build/Products/Release-iphonesimulator/AwesomeProject.app
Example/e2etest/ios/build/hermesc
key: ${{ runner.os }}-e2e-app-xcode-${{ env.XCODE_VERSION }}-${{ hashFiles('Example/e2etest/ios/**', 'Example/e2etest/package.json', 'Example/e2etest/bun.lock', 'react-native-update.podspec', 'react-native.config.js', 'expo-module.config.json', 'ios/**', 'cpp/**', 'android/jni/**', 'src/Native*.ts', 'package.json') }}
- name: Install CocoaPods dependencies
if: steps.cache-ios-app.outputs.cache-hit != 'true'
# USE_CCACHE=1 让 react_native_post_install 给所有 pod target 接上
# RN 自带的 ccache 编译器包装脚本
run: cd Example/e2etest/ios && USE_CCACHE=1 pod install
- name: Detox build (ios.sim.release)
if: steps.cache-ios-app.outputs.cache-hit != 'true'
env:
RNU_CLI_ROOT: ${{ github.workspace }}/react-native-update-cli
run: |
cd Example/e2etest && E2E_PLATFORM=ios bunx detox build --configuration ios.sim.release
# hermesc 进缓存区:命中 run 没有 Pods,注入脚本需要它编 HBC
cp ios/Pods/hermes-engine/destroot/bin/hermesc ios/build/hermesc
- name: Refresh JS bundle in cached app
if: steps.cache-ios-app.outputs.cache-hit == 'true'
run: cd Example/e2etest && ./scripts/refresh-ios-app-bundle.sh
- name: Pack app and update artifacts
# tar keeps the executable bits and symlinks that upload-artifact
# would drop. hermesc stays behind: only the bundle refresh above
# needs it.
run: |
tar -cf e2e-ios-build.tar \
Example/e2etest/ios/build/Build/Products/Release-iphonesimulator/AwesomeProject.app \
Example/e2etest/.e2e-artifacts/ios
- name: Upload app and update artifacts
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: e2e-ios-build
path: e2e-ios-build.tar
if-no-files-found: error
retention-days: 1
e2e-ios:
# 不带 matrix 值全量拼名,否则 check 叫 "e2e-ios (native, --config e2e/…)"
name: e2e-ios (${{ matrix.suite }})
needs: e2e-ios-build
runs-on: macos-26
# 绿色基线(不含构建)约 10 分钟。60 分钟覆盖最坏情况:一个用例等满 300s
# testTimeout,再叠一次 --retries 1 全量重试。40 分钟不够——实测重试跑到
# 一半被腰斩,把"慢但能恢复"的运行变成 cancelled,等于白开了 retries。
timeout-minutes: 60
strategy:
# 两条 leg 各自独立成败:一条超时不该掩盖另一条的结论
fail-fast: false
matrix:
include:
# 既有 suite(local-merge / bundle-hash),沿用默认 runner 配置
- suite: core
jest-config: ''
# 原生冷启动检测:每条断言都要真实重启 app,单独跑才不会把 core
# 顶过 40 分钟(拆分前实测 core 已占 36 分)
- suite: native
jest-config: '--config e2e/native/jest.config.js'
steps:
- name: Checkout react-native-update
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.4.0
- name: Cache Bun dependencies
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-e2e-${{ hashFiles('Example/e2etest/bun.lock', 'react-native-update-cli/bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-e2e-
- name: Setup Xcode
uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0
with:
xcode-version: ${{ env.XCODE_VERSION }}
- name: Boot iOS simulator in background
# 模拟器冷启动要 2-5 分钟,提前异步 boot,让它和依赖安装/下载并行。
# 型号必须用与 .detoxrc.js 完全同一份探测代码——此前 shell 里
# 另写一份选中了 detox 不用的设备,预热全部白费。
# 失败无害:detox 测试阶段会自己 boot。
run: |
udid=$(node Example/e2etest/scripts/detect-ios-simulator-type.js --udid)
if [ -n "$udid" ]; then
echo "pre-booting $(node Example/e2etest/scripts/detect-ios-simulator-type.js) ($udid)"
xcrun simctl boot "$udid" || true
else
echo "no matching simulator found, skipping pre-boot"
fi
- name: Cache Homebrew downloads
uses: ./.github/actions/e2e-cache
with:
path: ~/Library/Caches/Homebrew
scope: brew-xcode-${{ env.XCODE_VERSION }}
- name: Install applesimutils
run: brew trust wix/brew && HOMEBREW_NO_AUTO_UPDATE=1 brew install wix/brew/applesimutils
- name: Install e2etest dependencies
run: cd Example/e2etest && bun install --frozen-lockfile
- name: Download app and update artifacts
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: e2e-ios-build
- name: Unpack app and update artifacts
run: tar -xf e2e-ios-build.tar && rm e2e-ios-build.tar
- name: Cache Detox iOS framework
id: cache-detox-ios-framework
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/Library/Detox
key: ${{ runner.os }}-detox-ios-framework-xcode-${{ env.XCODE_VERSION }}-${{ hashFiles('Example/e2etest/bun.lock') }}
restore-keys: |
${{ runner.os }}-detox-ios-framework-xcode-${{ env.XCODE_VERSION }}-
- name: Build Detox iOS framework cache
if: steps.cache-detox-ios-framework.outputs.cache-hit != 'true'
run: cd Example/e2etest && bunx detox build-framework-cache
- name: Detox test (ios.sim.release)
env:
RNU_E2E_SKIP_PREPARE: 'true'
run: cd Example/e2etest && E2E_PLATFORM=ios bunx detox test --configuration ios.sim.release --retries 1 ${{ matrix.jest-config }}
- name: Upload Detox artifacts
# cancelled() 覆盖 job 超时被杀的场景,否则超时时拿不到现场
if: failure() || cancelled()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: e2e-ios-detox-artifacts-${{ matrix.suite }}
path: Example/e2etest/artifacts
if-no-files-found: ignore
retention-days: 7