Skip to content

Commit b32ab51

Browse files
committed
Merge remote-tracking branch 'origin/main' into codex/make-libimobiledevice-optional
# Conflicts: # packages/platform-ios/src/__tests__/instance.test.ts
2 parents 0a73592 + 96021a6 commit b32ab51

68 files changed

Lines changed: 5859 additions & 1458 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/e2e-tests.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ jobs:
110110
timeout-minutes: 30
111111
if: ${{ (github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'main') || (github.event_name == 'workflow_dispatch' && (github.event.inputs.platform == 'all' || github.event.inputs.platform == 'ios')) }}
112112
env:
113+
HARNESS_DEBUG: true
113114
DEBUG: 'Metro:*'
114115
steps:
115116
- name: Checkout code
@@ -349,6 +350,7 @@ jobs:
349350
timeout-minutes: 30
350351
if: ${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.platform == 'all' || github.event.inputs.platform == 'ios') }}
351352
env:
353+
HARNESS_DEBUG: true
352354
DEBUG: 'Metro:*'
353355
steps:
354356
- name: Checkout code
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
__default__: patch
3+
---
4+
5+
Physical iOS app launches now pass Harness launch arguments to `xcrun devicectl` without breaking JSON output collection. This prevents app launch arguments from being misinterpreted as `devicectl` flags and keeps device launches working when custom arguments are provided.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
__default__: patch
3+
---
4+
5+
Harness now queues concurrent runs before starting Metro when they target the same locked resource, such as the same simulator, device, or browser. Queueing is keyed by the platform resource lock rather than the configured Metro port, so runs using different ports still wait if they target the same resource.

action.yml

Lines changed: 22 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ runs:
5252
env:
5353
INPUT_RUNNER: ${{ inputs.runner }}
5454
INPUT_PROJECTROOT: ${{ inputs.projectRoot }}
55+
HARNESS_AVD_CACHING: ${{ inputs.cacheAvd }}
5556
run: |
5657
node ${{ github.action_path }}/actions/shared/index.cjs
5758
- name: Verify native app input
@@ -72,34 +73,20 @@ runs:
7273
${{ runner.os }}-metro-cache-
7374
7475
# ── iOS ──────────────────────────────────────────────────────────────────
75-
- uses: futureware-tech/simulator-action@v4
76-
if: fromJson(steps.load-config.outputs.config).platformId == 'ios'
77-
with:
78-
model: ${{ fromJson(steps.load-config.outputs.config).config.device.name }}
79-
os: iOS
80-
os_version: ${{ fromJson(steps.load-config.outputs.config).config.device.systemVersion }}
81-
wait_for_boot: true
82-
erase_before_boot: false
83-
- name: Install app
84-
if: fromJson(steps.load-config.outputs.config).platformId == 'ios'
85-
shell: bash
86-
working-directory: ${{ steps.load-config.outputs.projectRoot }}
87-
run: |
88-
xcrun simctl install booted ${{ inputs.app }}
76+
# iOS simulator boot and app installation are handled by Harness itself.
8977
# ── Android ──────────────────────────────────────────────────────────────
9078
- name: Verify Android config
91-
if: fromJson(steps.load-config.outputs.config).platformId == 'android'
79+
if: ${{ fromJson(steps.load-config.outputs.config).platformId == 'android' && fromJson(steps.load-config.outputs.config).config.device.type == 'emulator' }}
9280
shell: bash
9381
run: |
94-
CONFIG='${{ steps.load-config.outputs.config }}'
95-
if [ -z "$CONFIG.config.device.avd" ] || [ "$CONFIG.config.device.avd" = "null" ]; then
82+
if [ '${{ fromJson(steps.load-config.outputs.config).config.device.avd }}' = 'null' ]; then
9683
echo "Error: AVD config is required for Android emulators"
9784
echo "Please define the 'avd' property in the runner config"
9885
exit 1
9986
fi
10087
- name: Get architecture of the runner
10188
id: arch
102-
if: fromJson(steps.load-config.outputs.config).platformId == 'android'
89+
if: ${{ fromJson(steps.load-config.outputs.config).platformId == 'android' && fromJson(steps.load-config.outputs.config).config.device.type == 'emulator' }}
10390
shell: bash
10491
run: |
10592
case "${{ runner.arch }}" in
@@ -117,7 +104,7 @@ runs:
117104
;;
118105
esac
119106
- name: Enable KVM group perms
120-
if: fromJson(steps.load-config.outputs.config).platformId == 'android'
107+
if: ${{ fromJson(steps.load-config.outputs.config).platformId == 'android' && fromJson(steps.load-config.outputs.config).config.device.type == 'emulator' }}
121108
shell: bash
122109
run: |
123110
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
@@ -126,47 +113,24 @@ runs:
126113
ls /dev/kvm
127114
- name: Compute AVD cache key
128115
id: avd-key
129-
if: ${{ fromJson(steps.load-config.outputs.config).platformId == 'android' && fromJSON(inputs.cacheAvd) }}
116+
if: ${{ fromJson(steps.load-config.outputs.config).platformId == 'android' && fromJson(steps.load-config.outputs.config).config.device.type == 'emulator' && fromJson(steps.load-config.outputs.config).action.avdCachingEnabled }}
130117
shell: bash
131118
run: |
132-
CONFIG='${{ steps.load-config.outputs.config }}'
133-
AVD_CONFIG=$(echo "$CONFIG" | jq -c '.config.device.avd')
134-
AVD_CONFIG_HASH=$(echo "$AVD_CONFIG" | sha256sum | cut -d' ' -f1)
119+
CACHE_CONFIG='${{ toJson(fromJson(steps.load-config.outputs.config).action.avdCacheConfig) }}'
120+
AVD_CONFIG_HASH=$(printf '%s' "$CACHE_CONFIG" | sha256sum | cut -d' ' -f1)
121+
AVD_NAME='${{ fromJson(steps.load-config.outputs.config).config.device.name }}'
135122
ARCH="${{ steps.arch.outputs.arch }}"
136-
CACHE_KEY="avd-$ARCH-$AVD_CONFIG_HASH"
123+
CACHE_KEY="avd-$AVD_NAME-$ARCH-$AVD_CONFIG_HASH"
137124
echo "key=$CACHE_KEY" >> $GITHUB_OUTPUT
138125
- name: Restore AVD cache
139126
uses: actions/cache/restore@v4
140127
id: avd-cache
141-
if: ${{ fromJson(steps.load-config.outputs.config).platformId == 'android' && fromJSON(inputs.cacheAvd) }}
128+
if: ${{ fromJson(steps.load-config.outputs.config).platformId == 'android' && fromJson(steps.load-config.outputs.config).config.device.type == 'emulator' && fromJson(steps.load-config.outputs.config).action.avdCachingEnabled }}
142129
with:
143130
path: |
144131
~/.android/avd
145132
~/.android/adb*
146133
key: ${{ steps.avd-key.outputs.key }}
147-
- name: Create AVD and generate snapshot for caching
148-
if: ${{ fromJson(steps.load-config.outputs.config).platformId == 'android' && fromJSON(inputs.cacheAvd) && steps.avd-cache.outputs.cache-hit != 'true' }}
149-
uses: reactivecircus/android-emulator-runner@v2
150-
with:
151-
api-level: ${{ fromJson(steps.load-config.outputs.config).config.device.avd.apiLevel }}
152-
arch: ${{ steps.arch.outputs.arch }}
153-
profile: ${{ fromJson(steps.load-config.outputs.config).config.device.avd.profile }}
154-
disk-size: ${{ fromJson(steps.load-config.outputs.config).config.device.avd.diskSize }}
155-
heap-size: ${{ fromJson(steps.load-config.outputs.config).config.device.avd.heapSize }}
156-
force-avd-creation: false
157-
avd-name: ${{ fromJson(steps.load-config.outputs.config).config.device.name }}
158-
disable-animations: true
159-
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
160-
script: echo "Generated AVD snapshot for caching."
161-
- name: Save AVD cache
162-
if: ${{ fromJson(steps.load-config.outputs.config).platformId == 'android' && fromJSON(inputs.cacheAvd) && steps.avd-cache.outputs.cache-hit != 'true' }}
163-
uses: actions/cache/save@v4
164-
with:
165-
path: |
166-
~/.android/avd
167-
~/.android/adb*
168-
key: ${{ steps.avd-key.outputs.key }}
169-
170134
# ── Web ──────────────────────────────────────────────────────────────────
171135
- name: Install Playwright Browsers
172136
if: fromJson(steps.load-config.outputs.config).platformId == 'web'
@@ -225,116 +189,27 @@ runs:
225189
fi
226190
- name: Run E2E tests
227191
id: run-tests
228-
if: fromJson(steps.load-config.outputs.config).platformId != 'android'
229192
shell: bash
230193
working-directory: ${{ steps.load-config.outputs.projectRoot }}
231194
env:
232195
PRE_RUN_HOOK: ${{ inputs.preRunHook }}
233196
AFTER_RUN_HOOK: ${{ inputs.afterRunHook }}
234197
HARNESS_RUNNER: ${{ inputs.runner }}
198+
HARNESS_APP_PATH: ${{ inputs.app }}
199+
HARNESS_AVD_CACHING: ${{ inputs.cacheAvd }}
235200
run: |
236201
export HARNESS_PROJECT_ROOT="$PWD"
237202
238-
if [ -n "$PRE_RUN_HOOK" ]; then
239-
pre_hook_file="$(mktemp "${RUNNER_TEMP:-/tmp}/harness-pre-run.XXXXXX.sh")"
240-
trap 'rm -f "$pre_hook_file"' EXIT
241-
printf '%s\n' "$PRE_RUN_HOOK" > "$pre_hook_file"
242-
chmod +x "$pre_hook_file"
243-
bash "$pre_hook_file"
244-
rm -f "$pre_hook_file"
245-
trap - EXIT
246-
fi
247-
248203
set +e
249204
${{ steps.detect-pm.outputs.runner }}react-native-harness --harnessRunner ${{ inputs.runner }} ${{ inputs.harnessArgs }}
250205
harness_exit_code=$?
251206
set -e
252207
253-
export HARNESS_EXIT_CODE="$harness_exit_code"
254-
after_run_exit_code=0
255-
if [ -n "$AFTER_RUN_HOOK" ]; then
256-
after_hook_file="$(mktemp "${RUNNER_TEMP:-/tmp}/harness-after-run.XXXXXX.sh")"
257-
trap 'rm -f "$after_hook_file"' EXIT
258-
printf '%s\n' "$AFTER_RUN_HOOK" > "$after_hook_file"
259-
chmod +x "$after_hook_file"
260-
set +e
261-
bash "$after_hook_file"
262-
after_run_exit_code=$?
263-
set -e
264-
rm -f "$after_hook_file"
265-
trap - EXIT
266-
fi
267-
268208
echo "harness_exit_code=$harness_exit_code" >> "$GITHUB_OUTPUT"
269209
270210
if [ "$harness_exit_code" -ne 0 ]; then
271211
exit "$harness_exit_code"
272212
fi
273-
274-
if [ "$after_run_exit_code" -ne 0 ]; then
275-
exit "$after_run_exit_code"
276-
fi
277-
- name: Run E2E tests
278-
id: run-tests-android
279-
if: fromJson(steps.load-config.outputs.config).platformId == 'android'
280-
uses: reactivecircus/android-emulator-runner@v2
281-
env:
282-
PRE_RUN_HOOK: ${{ inputs.preRunHook }}
283-
AFTER_RUN_HOOK: ${{ inputs.afterRunHook }}
284-
HARNESS_RUNNER: ${{ inputs.runner }}
285-
# android-emulator-runner executes each script line via `sh -c`, so multi-line
286-
# shell control flow must live in a separate bash script instead of `with.script`.
287-
HARNESS_ANDROID_SESSION_SCRIPT: |-
288-
export HARNESS_PROJECT_ROOT="$PWD"
289-
290-
adb install -r "${{ inputs.app }}"
291-
292-
if [ -n "$PRE_RUN_HOOK" ]; then
293-
pre_hook_file="$(mktemp "${RUNNER_TEMP:-/tmp}/harness-pre-run.XXXXXX.sh")"
294-
printf "%s\n" "$PRE_RUN_HOOK" > "$pre_hook_file"
295-
chmod +x "$pre_hook_file"
296-
bash "$pre_hook_file"
297-
rm -f "$pre_hook_file"
298-
fi
299-
300-
set +e
301-
${{ steps.detect-pm.outputs.runner }}react-native-harness --harnessRunner "${{ inputs.runner }}" ${{ inputs.harnessArgs }}
302-
harness_exit_code=$?
303-
echo "harness_exit_code=$harness_exit_code" >> "$GITHUB_OUTPUT"
304-
set -e
305-
306-
export HARNESS_EXIT_CODE="$harness_exit_code"
307-
after_run_exit_code=0
308-
if [ -n "$AFTER_RUN_HOOK" ]; then
309-
after_hook_file="$(mktemp "${RUNNER_TEMP:-/tmp}/harness-after-run.XXXXXX.sh")"
310-
printf "%s\n" "$AFTER_RUN_HOOK" > "$after_hook_file"
311-
chmod +x "$after_hook_file"
312-
set +e
313-
bash "$after_hook_file"
314-
after_run_exit_code=$?
315-
set -e
316-
rm -f "$after_hook_file"
317-
fi
318-
319-
if [ "$harness_exit_code" -ne 0 ]; then
320-
exit "$harness_exit_code"
321-
fi
322-
323-
if [ "$after_run_exit_code" -ne 0 ]; then
324-
exit "$after_run_exit_code"
325-
fi
326-
with:
327-
working-directory: ${{ steps.load-config.outputs.projectRoot }}
328-
api-level: ${{ fromJson(steps.load-config.outputs.config).config.device.avd.apiLevel }}
329-
arch: ${{ steps.arch.outputs.arch }}
330-
force-avd-creation: false
331-
avd-name: ${{ fromJson(steps.load-config.outputs.config).config.device.name }}
332-
disable-animations: true
333-
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
334-
# Keep `script` to a single line so the emulator action does not split our bash
335-
# session apart before the hooks and Harness command run.
336-
script: >-
337-
harness_script_file="$(mktemp "${RUNNER_TEMP:-/tmp}/harness-android-run.XXXXXX.sh")"; printf '%s\n' "$HARNESS_ANDROID_SESSION_SCRIPT" > "$harness_script_file"; chmod +x "$harness_script_file"; bash "$harness_script_file"; status=$?; rm -f "$harness_script_file"; exit "$status"
338213
- name: Upload visual test artifacts
339214
if: always() && inputs.uploadVisualTestArtifacts == 'true'
340215
uses: actions/upload-artifact@v4
@@ -344,6 +219,14 @@ runs:
344219
${{ steps.load-config.outputs.projectRoot }}/**/__image_snapshots__/**/*-diff.png
345220
${{ steps.load-config.outputs.projectRoot }}/**/__image_snapshots__/**/*-actual.png
346221
if-no-files-found: ignore
222+
- name: Save AVD cache
223+
if: ${{ always() && fromJson(steps.load-config.outputs.config).platformId == 'android' && fromJson(steps.load-config.outputs.config).config.device.type == 'emulator' && fromJson(steps.load-config.outputs.config).action.avdCachingEnabled && steps.avd-cache.outputs.cache-hit != 'true' }}
224+
uses: actions/cache/save@v4
225+
with:
226+
path: |
227+
~/.android/avd
228+
~/.android/adb*
229+
key: ${{ steps.avd-key.outputs.key }}
347230
- name: Upload crash report artifacts
348231
if: always()
349232
uses: actions/upload-artifact@v4

0 commit comments

Comments
 (0)