-
Notifications
You must be signed in to change notification settings - Fork 280
238 lines (212 loc) · 9.93 KB
/
Copy pathe2e_ios.yml
File metadata and controls
238 lines (212 loc) · 9.93 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
name: e2e-ios
on:
pull_request:
branches:
- '**'
paths:
- '.github/workflows/e2e_ios.yml'
- '.gitmodules'
- 'package.json'
- 'bun.lock'
- 'react-native-update.podspec'
- 'react-native.config.js'
- 'expo-module.config.json'
- 'src/**'
- 'scripts/**'
- 'ios/**'
- 'cpp/**'
- 'android/jni/**'
- 'Example/e2etest/**'
push:
branches:
- master
paths:
- '.github/workflows/e2e_ios.yml'
- '.gitmodules'
- 'package.json'
- 'bun.lock'
- 'react-native-update.podspec'
- 'react-native.config.js'
- 'expo-module.config.json'
- 'src/**'
- 'scripts/**'
- 'ios/**'
- 'cpp/**'
- 'android/jni/**'
- 'Example/e2etest/**'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
e2e-ios:
# 不带 matrix 值全量拼名,否则 check 叫 "e2e-ios (native, --config e2e/…)"
name: e2e-ios (${{ matrix.suite }})
runs-on: macos-26
# 绿色基线 ~16 分钟。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@v7
with:
submodules: recursive
- name: Checkout react-native-update-cli
uses: actions/checkout@v7
with:
repository: reactnativecn/react-native-update-cli
path: react-native-update-cli
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 22
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Cache Bun dependencies
uses: actions/cache@v5.0.4
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@v1
with:
xcode-version: '26.4'
- name: Boot iOS simulator in background
# 模拟器冷启动要 2-5 分钟,提前异步 boot,让它和依赖安装/xcodebuild
# 并行。型号必须用与 .detoxrc.ts 完全同一份探测代码——此前 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
# bottle 按 URL 内容寻址,restore-keys 前缀命中即省下载(装/链接照常)
uses: actions/cache@v5.0.4
with:
path: ~/Library/Caches/Homebrew
key: ${{ runner.os }}-brew-e2e-${{ github.sha }}
restore-keys: |
${{ runner.os }}-brew-e2e-
- name: Install applesimutils and ccache
run: brew trust wix/brew && HOMEBREW_NO_AUTO_UPDATE=1 brew install wix/brew/applesimutils ccache
- name: Cache ccache
# ccache 按(预处理后)内容寻址,不受 fresh checkout 的 mtime 影响——
# 这是 DerivedData 缓存在 -UseNewBuildSystem=NO 下做不到的。
# 陈旧条目不影响正确性,只影响命中率,所以 restore-keys 用前缀即可。
uses: actions/cache@v5.0.4
with:
path: ~/Library/Caches/ccache
key: ${{ runner.os }}-ccache-e2e-xcode-26.4-${{ github.sha }}
restore-keys: |
${{ runner.os }}-ccache-e2e-xcode-26.4-
- name: Install e2etest dependencies
run: cd Example/e2etest && bun install --frozen-lockfile
- name: Link local react-native-update
run: |
set -euo pipefail
export LOCAL_RNU_VERSION="$(node -p "require('./Example/e2etest/node_modules/react-native-update/package.json').version")"
LOCAL_RNU_DIR="$PWD/Example/e2etest/.e2e-artifacts/local-react-native-update"
rm -rf "$LOCAL_RNU_DIR" Example/e2etest/node_modules/react-native-update
mkdir -p "$LOCAL_RNU_DIR"
cp package.json react-native-update.podspec react-native.config.js expo-module.config.json "$LOCAL_RNU_DIR"/
rsync -a --exclude='.git' src ios android cpp scripts "$LOCAL_RNU_DIR"/
node -e "const fs = require('fs'); const file = 'Example/e2etest/.e2e-artifacts/local-react-native-update/package.json'; const pkg = JSON.parse(fs.readFileSync(file, 'utf8')); pkg.version = process.env.LOCAL_RNU_VERSION; fs.writeFileSync(file, JSON.stringify(pkg, null, 2) + '\n');"
ln -s ../.e2e-artifacts/local-react-native-update Example/e2etest/node_modules/react-native-update
- name: Install react-native-update-cli dependencies
run: cd react-native-update-cli && bun install --frozen-lockfile && bun run build
- name: Cache Metro transform cache
# 内容寻址(等价 ccache 之于 clang):陈旧条目只影响命中率不影响正确性
uses: actions/cache@v5.0.4
with:
path: Example/e2etest/.metro-cache
key: ${{ runner.os }}-metro-e2e-${{ github.sha }}
restore-keys: |
${{ runner.os }}-metro-e2e-
- 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@v5.0.4
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@v5.0.4
with:
path: |
Example/e2etest/ios/build/Build/Products/Release-iphonesimulator/AwesomeProject.app
Example/e2etest/ios/build/hermesc
key: ${{ runner.os }}-e2e-app-xcode-26.4-${{ 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: Cache Detox iOS framework
id: cache-detox-ios-framework
uses: actions/cache@v5.0.4
with:
path: ~/Library/Detox
key: ${{ runner.os }}-detox-ios-framework-xcode-26.4-${{ hashFiles('Example/e2etest/bun.lock') }}
restore-keys: |
${{ runner.os }}-detox-ios-framework-xcode-26.4-
- 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 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: Detox test (ios.sim.release)
env:
RNU_CLI_ROOT: ${{ github.workspace }}/react-native-update-cli
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@v7
with:
name: e2e-ios-detox-artifacts-${{ matrix.suite }}
path: Example/e2etest/artifacts
if-no-files-found: ignore
retention-days: 7