Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58672
Fantom CI retries used Jest's `--onlyFailures` cache after a failed full-suite run. Process-level failures such as `SIGSEGV` are not recorded as failed test results, so Jest selected no tests and both retries exited immediately.
Run the full Fantom suite on each retry so transient runner crashes get real retry attempts.
Changelog: [Internal]
___
Differential Revision: D121570534
fbshipit-source-id: 7d325eb8786848cbb018d9db6fea7e51650bb9e1
Summary:
Artifact uploads can fail on transient network errors such as the `ETIMEDOUT` in https://github.com/react/react-native/actions/runs/35598907154/job/106330670539.
This change:
- adds a local composite action backed by `actions/upload-artifact` v7.0.1
- retries failed uploads twice, waiting 10 seconds before attempt 2 and 20 seconds before attempt 3
- propagates the third failure to the caller
- preserves all v7 inputs and outputs
- migrates all 35 artifact upload call sites to the wrapper
## Changelog:
[INTERNAL] [FIXED] - Retry artifact uploads to reduce transient CI failures.
Pull Request resolved: https://github.com/react/react-native/pull/58620
Test Plan:
- `node_modules/.bin/prettier --check $(git diff --name-only HEAD^ -- '*.yml' '*.yaml')` — passed
- `npx --yes action-validator/cli@0.6.0 .github/actions/upload-artifact/action.yml` — passed
- `git diff HEAD^ --check` — passed
- Verified no `actions/upload-artifact@v6` references remain under `.github`
Reviewed By: andrewdacenko
Differential Revision: D121002745
Pulled By: cortinico
fbshipit-source-id: e63e30f3e86b0a2cb6c94aa549cdfe5e6dfbdc2b
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58457
Pin the RNTester iOS Debug, Release, and Maestro Cloud lanes to the same iPhone 17 Pro / iOS 26.2 profile. This keeps the existing 960x489 screenshot baseline valid across all three lanes while preserving automatic simulator selection for other action callers.
Document that shared screenshot baselines require an explicit matching device profile.
Changelog: [Internal]
Reviewed By: christophpurrer
Differential Revision: D119440006
fbshipit-source-id: e667400b55f08f539019ab7279db1ae61f6f98d8
Summary:
Stabilizes the Android RNTester E2E jobs after switching their APKs to ARM64 while continuing to run the emulator on an x86_64 host.
- Updates the Android wide-gamut screenshot baseline using the stable ARM64 result from the API 35 emulator. The emulator does not support wide color, so the Display-P3 fixture is converted to solid sRGB red.
- Marks the FlatList `maintainVisibleContentPosition` flows as Android release-only. These flows remain fully covered by the release APK, where they consistently pass, while avoiding debug-only timing failures caused by running the ARM64 debug runtime through native translation.
- Adds generic tag filtering to the Android Maestro runner and unit coverage for it.
Across seven post-migration `main` runs, the release APK passed every FlatList flow, while the debug APK consistently dropped or delayed Maestro interactions and skipped up to 172 frames during startup.
## Changelog:
[INTERNAL] [FIXED] - Stabilize Android RNTester E2E tests when running ARM64 APKs on x86_64 emulators.
Pull Request resolved: https://github.com/react/react-native/pull/58140
Test Plan:
- `./node_modules/.bin/jest .github/workflow-scripts/__tests__/maestro-android-test.js --runInBand --config='{"testEnvironment":"node","transform":{},"roots":["<rootDir>/.github/workflow-scripts"]}'` — passed (3 tests)
- `maestro 2.6.1 check-syntax` for all 24 tagged FlatList flows — passed
- Prettier check for all changed text files — passed
- `git diff --check` — passed
- Verified the filtered RNTester suite contains 16 debug flows and excludes 24 release-only FlatList MVCP flows
- Compared the new baseline against ARM64 CI screenshots: exact match for release; debug RMSE 0.0024
- Manually exercised the ARM64 release APK on an API 35 ARM64 emulator at 320×640: FlatList offsets progressed as expected (`500 → 544 → 2744 → 4944 → 7144`), and five rapid prepends reached `11500`
Related failing run: https://github.com/react/react-native/actions/runs/32821468795
Reviewed By: Abbondanzo
Differential Revision: D117361459
Pulled By: cortinico
fbshipit-source-id: 4514f8c42f7599c875672efe3c56aae7c9f0395c
Summary:
Follow-up to https://github.com/react/react-native/issues/58092.
Android API 35 x86_64 emulator images expose both `x86_64` and `arm64-v8a` through `libndk_translation.so`. SoLoader 0.12.1 only searches the first ABI when loading uncompressed native libraries directly from the APK, causing ARM64-only RNTester and template apps to crash while loading `libreactnative.so`.
Enable legacy JNI packaging through a CI-only Gradle init script so Android extracts the ARM64 libraries and the existing SoLoader `ApplicationSoSource` can load them. This applies only to dry-run RNTester builds and Android template E2E builds. Nightly and release packaging is unchanged.
Failure evidence: https://github.com/react/react-native/actions/runs/32741094253
## Changelog:
[INTERNAL] [FIXED] - Extract native libraries for ARM64 Android E2E APKs running through NDK translation.
Pull Request resolved: https://github.com/react/react-native/pull/58103
Test Plan:
- `./node_modules/.bin/prettier --check .github/actions/build-android/action.yml .github/workflows/e2e-android-templateapp.yml` — passed.
- Parsed both modified YAML files with the `yaml` Node package — passed.
- Parsed the embedded workflow shell scripts with `bash -n` — passed.
- Compiled `.github/workflow-scripts/legacy-jni-packaging.gradle` with the Groovy compiler bundled with Gradle 9.4.1 — passed.
- Full Android E2E validation is delegated to this draft PR because the local Gradle daemon could not establish its localhost connection.
Reviewed By: christophpurrer
Differential Revision: D117222109
Pulled By: cortinico
fbshipit-source-id: 65e09a38eed84474a2f50f7f5847e1676da4411b
Summary:
Build only the `arm64-v8a` Android ABI for dry-run CI artifacts and run the ARM64 RNTester and template-app APKs on an API 35 `google_apis` x86_64 emulator using the system images built-in NDK translation support.
This also makes the Maestro emulator API level and target configurable, logs the device ABI/native-bridge configuration, and updates local RNTester artifact selection to use the ARM64 split.
Release and nightly publication builds continue to build all supported Android ABIs.
## Changelog:
[INTERNAL] [CHANGED] - Run Android E2E tests with ARM64 APKs through NDK translation.
Pull Request resolved: https://github.com/react/react-native/pull/58092
Test Plan:
- `node --check .github/workflow-scripts/maestro-android.js` — passed.
- `node --check scripts/release-testing/test-release-local.js` — passed.
- Parsed all modified YAML files with the `yaml` Node package — passed.
- `./node_modules/.bin/prettier --check <modified files>` — passed.
- `git diff --check HEAD~3..HEAD` — passed.
- `actionlint` reported only existing repository metadata warnings for the custom `4-core-ubuntu` label and the missing description in the local `yarn-install` action.
- `yarn test .github/workflow-scripts/__tests__/maestro-android-test.js --runInBand` could not start because the local dependency tree is missing `flow-parser`; restoring dependencies was blocked by HTTP 503 responses from the npm registry.
- The draft CI run should validate ARM64 APK installation, Hermes startup, and the complete Maestro suites through `libndk_translation.so`.
Reviewed By: Abbondanzo
Differential Revision: D117195078
Pulled By: cortinico
fbshipit-source-id: a78f2127f04e80c3b5ca4c95d2024dffb92ff122
Summary:
Android Maestro E2E jobs currently stop after the first flow that exhausts its in-process retries. The workflow-level retry then starts the whole suite again, including flows that already passed.
This changes the retry model so that:
- each CI attempt runs every selected flow once and continues after individual failures;
- per-flow `passed`, `failed`, and `pending` state is saved atomically after every flow;
- cumulative results and attempt counts are shown in the GitHub job summary and uploaded as an artifact;
- retry workflows download that state and skip flows that already passed, running only failed or unfinished flows;
- a flavor whose downloaded state is already fully passed skips emulator startup and APK installation entirely;
- a missing state artifact falls back to running the full suite, so infrastructure failures remain retryable.
The Android E2E timeout is increased from 60 to 90 minutes to give the initial all-flows attempt enough time to finish. The existing three workflow attempts now provide up to three executions per failing flow instead of multiplying workflow retries by in-process retries.
### CI follow-ups
- RNTester Debug completed all 40 flows with 38 passes and 2 failures. Retry 1 downloaded its state, skipped exactly those 38 passing flows, and executed only the two failures, validating the selective retry behavior.
- RNTester Release became unhealthy after an early flow failure and timed out while later flows were still pending. The state file was being written incrementally, but its artifact upload was inside the timed composite action and was killed by the same timeout. Moved state upload into the outer reusable workflow so `if: always()` preserves passed, failed, and pending results after an E2E timeout.
- The next Release retry downloaded the preserved state, skipped its 7 prior passes, reran the remaining flows, and recovered to 40/40. A later matrix retry could still start that completed flavor and fail during an unnecessary APK installation, so retry jobs now skip the entire E2E action when downloaded state is fully passed.
- Both `test_js` variants failed because the repository Jest preset throws whenever `console.error` is called, and the new failure-path unit test intentionally exercised a production error log. The test now mocks that expected log while continuing to assert the aggregate flow failure.
- RNTester Debug consistently failed `image-wide-gamut.yml` with exactly 83.974% screenshot similarity and `legacy-native-module.yml` before the APIs search became visible, while Release passed both immediately. Reproducing Debug with an offline Android emulator showed the actual cause: importing `ImageExample.js` eagerly starts a Facebook image prefetch, and its promise could reject before the Image Loading Events example attached its rejection callback. That produced an `Uncaught (in promise): UnknownHostException` LogBox notification, which covered the screenshot and intercepted the APIs tab. The prefetch now attaches a rejection handler immediately while preserving the existing example-level success/failure reporting. No LogBox dismissal or E2E-specific workaround remains.
- The remaining `image-wide-gamut.yml` failure was separate from LogBox: the flow explicitly accepted `P3: error` but then compared against a golden screenshot containing the successfully loaded Display-P3 fixture. The same ICC-profiled WebKit sample is now embedded as a compact data URI, removing the external network dependency, and the flow requires `P3: loaded` before screenshot comparison.
## Changelog:
[INTERNAL] [CHANGED] - Retry only failed or unfinished Android Maestro E2E flows.
Pull Request resolved: https://github.com/react/react-native/pull/57998
Test Plan:
- `git diff --check` (passed)
- `node --check .github/workflow-scripts/maestro-android.js` (passed)
- `yarn jest .github/workflow-scripts/__tests__/maestro-android-test.js --runInBand --config '{"testEnvironment":"node","transform":{}}'` (passed)
- `ruby -ryaml -e "ARGV.each { |file| YAML.parse_file(file) }" .github/actions/maestro-android/action.yml .github/workflows/e2e-android-rntester.yml .github/workflows/e2e-android-templateapp.yml .github/workflows/test-all.yml` (passed)
- `yarn prettier --check .github/workflow-scripts/maestro-android.js .github/workflow-scripts/__tests__/maestro-android-test.js .github/actions/maestro-android/action.yml .github/workflows/e2e-android-rntester.yml .github/workflows/e2e-android-templateapp.yml .github/workflows/test-all.yml` (passed)
- Verified the retry-state `jq` predicate returns false only when every recorded flow has passed.
- `./node_modules/.bin/prettier --check packages/rn-tester/js/examples/Image/ImageExample.js` (passed)
- Reproduced on a local Android Debug emulator with external DNS unavailable. Before the fix, `logcat` reported `Uncaught (in promise): UnknownHostException` and LogBox covered the bottom navigation. After the fix, no unhandled rejection or LogBox appeared, the APIs tab displayed `explorer_search`, and the wide-gamut example was unobstructed.
- Verified on a local Android Debug emulator with external DNS unavailable that the embedded Display-P3 fixture reaches `P3: loaded` and renders without a network request.
- The next Debug run passed the stricter `P3: loaded` gate but still reproduced the exact 83.974% screenshot mismatch, followed by the legacy APIs-search failure. This confirms the embedded Display-P3 fixture is loading and that a second Debug-only UI state remains. The previous action skipped its Maestro-log upload because the emulator wrapper masked the inner script failure, and it pulled `screen.mp4` before stopping the recorder, leaving an unplayable artifact. The runner now captures a PNG, UI hierarchy, logcat, and Metro output when each flow fails, stops `screenrecord` before pulling the MP4, and always uploads the diagnostic bundle. The next run will expose the actual obstructing UI so it can be fixed at its source.
- The first diagnostic run exposed a flaw in the new evidence collection itself: Debug remained inside the E2E action far beyond its normal duration because the `uiautomator`/ADB capture commands were unbounded. Every diagnostic subprocess now has a 15-second timeout, so a problem collecting evidence is logged but can never stall later flows or prevent state persistence.
- The captured screenshots and hierarchy identified the root cause shared by all remaining Debug failures (including one additional FlatList flow): `StaticViewConfigValidator` reported that `AndroidTextInput.validAttributes.fontVariationSettings` had the wrong value. The object-syntax change in https://github.com/react/react-native/issues/57929 added a JS processor to the static TextInput config, but runtime native view-config reflection still derived plain `true` from the native `String` prop. Debug validation therefore emitted a LogBox; its notifications covered the wide-gamut screenshot and FlatList controls, and its expanded console blocked the legacy APIs tab. Native view-config construction now recognizes `fontVariationSettings` and installs the same processor as the static config. This both makes validation agree and preserves object-to-string normalization when reflected native configs are active. A regression test verifies the reflected attribute matches the static processor and serializes object settings deterministically.
- Targeted regression test: `yarn test packages/react-native/Libraries/ReactNative/__tests__/getNativeComponentAttributes-test.js --runInBand` (passed).
- Both `test_js` variants then failed at ESLint before running tests because the new regression test lacked the required Flow file annotation and its CommonJS imports were not in repository order. Added `flow strict-local` and reordered the requires; the targeted Jest test and Prettier check remain green.
- Final Android validation on `bd55f0aa4226`: the initial RNTester emulators lost ADB after three passing flows, so the outer state artifacts preserved those passes and marked the remaining work for retry. Retry 1 started fresh emulators, skipped the three prior passes, ran the remaining 37 flows, and finished with 40/40 passed in both Debug and Release; retry 2 was skipped. `image-wide-gamut.yml`, `legacy-native-module.yml`, and `flatlist-inverted-recycle-maintainvisible.yml` each passed on their first execution after the view-config fix. All Android checks are green, including Android builds, HelloWorld, TemplateApp E2E, and RNTester E2E.
Reviewed By: Abbondanzo
Differential Revision: D116463690
Pulled By: cipolleschi
fbshipit-source-id: 20f6d04ac8e21cdbb1fd04618cd879df6d413276
Summary:
Step 2 of the prebuilt-deps roadmap: ship the deps headers as a **SwiftPM-ready, self-contained artifact** and make every header namespace have exactly **one physical home**.
1. **New artifact: `ReactNativeDependenciesHeaders.xcframework`** — the binary `ReactNativeDependencies.xcframework` is framework-type, so its root `Headers/` is invisible to SwiftPM binaryTargets (`HeadersPath` is rejected on framework entries; verified empirically). The deps prebuild now emits a headers-only library-type sidecar (stub archives + per-slice `Headers/` + `HeadersPath` — the exact `ReactNativeHeaders` recipe, factored into a shared `headers-xcframework.js` emitter) carrying all seven deps namespaces incl. SocketRocket, with slice parity derived from the binary artifact's Info.plist. Ships inside the deps tarball *and* standalone.
2. **`ReactNativeHeaders` goes pure-RN** — the R2 relocation of deps namespaces (and the `DEPS_NAMESPACES_NOT_RELOCATED` SocketRocket exclusion list) is deleted. Relocated copies are what enabled the SocketRocket dual-copy regression (duplicate `interface` / poisoned module graph under `use_frameworks!`); that bug class is now structurally impossible. Headers gate flipped: deps namespaces must be **absent** from RNH; the sidecar emitter enforces set-equality with `DEPS_NAMESPACES` fail-closed in both directions. On the CocoaPods side, a new `ReactNativeDependenciesUtils.configure_aggregate_xcconfig` injects the deps pod's `Headers/` globally (aggregate + every pod target), mirroring the rncore injection — this replaces the folly/glog resolution pods previously got via the flattened `React-Core-prebuilt/Headers`.
3. **CI: prebuilt + dynamic-frameworks lane** — the regression's exact config had no coverage (the `test-ios-rntester` action hard-coupled `use-frameworks:true` to source builds). New `use-prebuilds` input; `test_ios_rntester`'s dynamic cells now consume the workflow-built prebuilt artifacts.
4. **Maven publishing** — `ReactNativeHeaders` and `ReactNativeDependenciesHeaders` publish standalone on `react-native-artifacts` (classifiers `reactnative-headers-*`, `reactnative-dependencies-headers-*`); `verifyArtifactsAreOnMaven` now HEAD-checks every classifier tarball instead of only the POM.
Stacked on https://github.com/react/react-native/issues/57440. The SwiftPM preview (https://github.com/react/react-native/issues/57332) rebases on top and wires the sidecar as its 5th binaryTarget.
## Changelog:
[IOS] [CHANGED] - Prebuilt artifacts: ReactNativeHeaders is pure-RN; third-party deps headers ship in the new ReactNativeDependenciesHeaders.xcframework sidecar (and the ReactNativeDependencies pod), published standalone to Maven
Pull Request resolved: https://github.com/react/react-native/pull/57442
Test Plan:
- Headers gate: include-health, structural (deps absent from RNH, byte-matched module maps), and compile smokes (React module + 14 namespace modules + Expo-shape ObjC++/Swift fixtures vs the deps include path) — ALL PASSED
- jest: 33/33 (`scripts/ios-prebuild/__tests__`, incl. new sidecar set-equality tests)
- ESLint (`--max-warnings 0`), Prettier, Flow (`yarn flow-check`): clean
- E2E (locally built artifacts): rn-tester prebuilt static ✅, prebuilt `USE_FRAMEWORKS=dynamic` ✅ (the regression config — verified `React-Core-prebuilt/Headers` contains no deps namespaces and the deps pod serves all seven), helloworld static ✅, source-core + prebuilt-deps ✅ (React compiled from source resolves folly via the deps pod), source-mode control with unchanged dependency graph ✅
- Sidecar inspected: per-slice `HeadersPath`, 7 namespaces, slice parity with the binary
- Publication validated end-to-end with `publishReleasePublicationToMavenLocal`: all 12 files + POM land with the expected classifier names
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Reviewed By: fabriziocucci
Differential Revision: D111449462
Pulled By: cipolleschi
fbshipit-source-id: e1217d14c0588d00a207622d346c9e6f4705a95d
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57307
Bumps `MAESTRO_VERSION` from `1.40.0` to `2.6.1` so we can use the new the visual-regression `assertScreenshot` command.
The two Maestro 2.0.0 breaking changes are already satisfied: JDK 17 is set up in both actions (`actions/setup-java@v5`), and the flows use only plain `${...}` variable interpolation rather than the JS scripting affected by the Rhino -> GraalJS engine swap.
Changelog: [Internal]
Reviewed By: christophpurrer
Differential Revision: D109359976
fbshipit-source-id: 78377a8dadaaee5d316513adc47d56a2b9b4dc40
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57286
We currently have a mix of quote styles in `.yml` files (AI summary below). This applies prettier and reformats everything to single quotes to align with defaults.
Also fixes a couple of cases of over-indentation.
```
Single-quotes only (0 double-quoted scalars):
analyze-pr.yml
— 12 single, 0 double
api-changes.yml
— 3 single, 0 double
check-for-reproducer.yml
— 4 single, 0 double
retry-workflow.yml
— 1 single, 0 double
Single-quote predominant > double:
autorebase.yml 2 vs 1
create-draft-release.yml 8 vs 2
generate-changelog.yml 3 vs 2
on-issue-labeled.yml 7 vs 2
prebuild-ios-core.yml 59 vs 17
prebuild-ios-dependencies.yml 39 vs 1
stale-bot.yml 18 vs 15
test-all.yml 70 vs 27
Double-quote predominant > single:
bump-podfile-lock.yml 1 vs 10
create-release.yml 3 vs 12
e2e-android-rntester.yml 2 vs 6
e2e-android-templateapp.yml 6 vs 13
e2e-ios-rntester.yml 2 vs 7
e2e-ios-templateapp.yml 2 vs 18
fantom-tests.yml 2 vs 7
monitor-new-issues.yml 3 vs 12
publish-npm.yml 42 vs 50
validate-cxx-api-snapshots.yml 2 vs 23
validate-dotslash-artifacts.yml 2 vs 5
Tie / 1-1:
cache-reaper.yml 1 vs 1
close-pr.yml 1 vs 1
needs-attention.yml 2 vs 2
All files contain single quotes somewhere, but only those 4 are single-quote-exclusive. Most CI-heavy workflows — bump, create-release, e2e-, fantom, monitor, publish-npm, validate- — lean double-quoted, while the pr/issue automation, prebuild ios, test-all, and stale-bot lean single-quoted.
```
Changelog: [Internal]
___
Differential Revision: D109151683
fbshipit-source-id: 24391e906c0dd92fe402224089dce8bb2068b4d9
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57269
Trusted publish support requires `npm` CLI version >=11.5.1 ([docs](https://docs.npmjs.com/trusted-publishers)), which is bundled with Node 24.
This bumps the Node version for just those jobs that call `npm publish`.
Changelog: [Internal]
Reviewed By: fabriziocucci
Differential Revision: D109009971
fbshipit-source-id: 6e7f412c6da0e5e5749a29e789f8c2e67610d7b0
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/57099
Replaces the long-lived `GHA_NPM_TOKEN` automation token with npm
Trusted Publishing (OIDC) for every `npm publish` invoked from this
repo's GitHub Actions.
Why a reusable workflow:
npmjs.com Trusted Publishing accepts only ONE (org, repo,
workflow_filename, environment) tuple per package. Today, packages
are published from multiple workflow files:
- `react-native` from publish-release.yml + nightly.yml
- every `react-native/*` from nightly.yml + publish-bumped-packages.yml
A naive per-workflow OIDC migration would require two Trusted
Publisher entries per package, which npm doesn't support. Instead,
this diff funnels every `npm publish` through one new file —
`.github/workflows/publish-npm.yml` — invoked via `workflow_call`
from the existing top-level workflows. The OIDC `job_workflow_ref`
claim therefore always resolves to `publish-npm.yml`, so each
package needs exactly one Trusted Publisher entry pointing here.
What changes:
* New `.github/workflows/publish-npm.yml`: reusable workflow with a
`mode` input. `mode: react-native` runs the full Android + iOS
prebuilt + JS build path (used by release & nightly, publishes
`react-native` and — in nightly mode — every `react-native/*`
package via `scripts/releases-ci/publish-npm.js`). `mode:
monorepo-packages` runs only the JS build and publishes the
delta-bumped packages via
`scripts/releases-ci/publish-updated-packages.js` (used by
publish-bumped-packages.yml). Both jobs grant `id-token: write` so
the npm CLI can mint the OIDC token for Trusted Publishing.
* `.github/workflows/publish-release.yml`: replace the
`build_npm_package` job's inline build/publish steps with a
`uses: ./.github/workflows/publish-npm.yml` call. The
template-publish, rn-diff-purge, npm-verify, and Maven-verify
steps move into a new `post_publish` follow-up job that
`needs: [build_npm_package]`. Drops `GHA_NPM_TOKEN` from the env.
* `.github/workflows/nightly.yml`: same — `build_npm_package` now
delegates to the reusable workflow. Drops `GHA_NPM_TOKEN` and the
obsolete `Verify NPM token` precheck (Trusted Publishing has no
pre-mintable token to validate; failures surface at `npm publish`
time).
* `.github/workflows/publish-bumped-packages.yml`: shrinks to a thin
trigger wrapper that calls the reusable workflow with
`mode: monorepo-packages`.
* `.github/workflows/create-release.yml`: drop the obsolete `Verify
NPM token` step.
* `.github/actions/build-npm-package`: drop the `gha-npm-token`
input and the `Set npm credentials` step that wrote `_authToken`.
Pass `registry-url: https://registry.npmjs.org` to setup-node so
`actions/setup-node@v6` writes a `.npmrc` configured to consume
the OIDC token at publish time.
* `.github/actions/setup-node`: thread a new `registry-url` input
through to `actions/setup-node@v6`.
The publish scripts themselves (`scripts/releases-ci/publish-npm.js`,
`scripts/releases-ci/publish-updated-packages.js`,
`scripts/releases/utils/npm-utils.js`) are unchanged: they shell out
to plain `npm publish`, which performs the OIDC exchange transparently
when it sees a GitHub Actions OIDC environment and a Trusted Publisher
configured for the package on npmjs.com.
Note: this diff only changes the workflow definitions. Each package
on npmjs.com must additionally be configured with a Trusted Publisher
pointing at:
- org: facebook
- repo: react-native
- workflow filename: publish-npm.yml
- environment: npm-publish
The npm CLI's OIDC exchange returns 404 until that registry-side
config is in place. Trusted Publisher entries are additive on
npmjs.com (don't enable "Require Trusted Publishing" yet) so the
existing token-based flow keeps working through the cutover. See the
stack landing notes for the full package list and UI steps.
Backport: this also needs picking back to `*-stable` branches before
"Require Trusted Publishing" is enabled on any package, since
GitHub Actions runs the workflow file from the ref that triggers it.
Changelog:
[Internal]
Reviewed By: cortinico, cipolleschi
Differential Revision: D107805971
fbshipit-source-id: 7a360dff9666c4b0952504331d26c0af74148789
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56871
`diff-js-api-changes` was posting false positive "JavaScript API change detected" warnings on PRs that never modified `ReactNativeApi.d.ts`.
This happened because the action ran `git merge-base` against limited local history (`git fetch --depth=500`), which couldn't find the common ancestor for branches that were far behind main — including (often) pick requests to release branches. The fallback wrote an empty "before" snapshot, causing the entire API surface to appear newly added.
{F1989977284}
#### Changes
- Query the GitHub API first — if the PR doesn't touch `ReactNativeApi.d.ts`, skip the diff entirely.
- When the snapshot is touched, use the GitHub compare API to resolve the merge base instead of relying on local git history.
- Limit the check to PRs targeting `main` or `*-stable` branches.
Changelog: [Internal]
Reviewed By: christophpurrer
Differential Revision: D105572432
fbshipit-source-id: 20e5db01c9e6b51acb55548746c8fd512a363274
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55915
Addresses a design gap with conditional Android/iOS test runs ([#55449](https://github.com/facebook/react-native/pull/55449)). `build_npm_package` depended on both Android and iOS prebuilds, causing platform-specific E2E tests to be skipped unnecessarily.
Fixed by allowing `build_npm_package` to optionally skip bundling Apple prebuits, and updating the dependencies of the E2E test jobs.
Changelog: [Internal]
Reviewed By: cortinico
Differential Revision: D95218910
fbshipit-source-id: 29dd91b773a567ccf83c1888250493773232140d
Summary:
- Adds retry jobs (up to 2 retries) for all 4 E2E test jobs on PRs to handle flakiness
- Original E2E jobs use `continue-on-error` on PRs so failures don't block the workflow; on `main`, behavior is unchanged and the existing `rerun-failed-jobs` mechanism continues to work
- Each retry runs on a fresh runner (addressing environment-level flakes) and is triggered via step-level outcome captured as a job output
- Added `overwrite: true` to artifact uploads in maestro composite actions so retry jobs don't conflict on artifact names
### How it works
- **On PRs:** E2E job fails → `retry_1` triggers → if that fails → `retry_2` triggers. All have `continue-on-error` so the workflow stays green.
- **On `main`:** `continue-on-error` is `false`, retry jobs are skipped (PR-only), and `rerun-failed-jobs` handles retries as before.
### Known limitation
Since these are matrix jobs (Debug/Release), the job output uses the last-to-complete matrix combination's value. If only one flavor fails and the passing one finishes last, the retry may not trigger. In the common flakiness pattern (environment-level issues), both flavors tend to be affected, so this works well in practice.
## Changelog:
[Internal] - Add E2E test retry jobs for PRs
Pull Request resolved: https://github.com/facebook/react-native/pull/56581
Test Plan:
- CI will validate the workflow syntax
- On a PR where E2E tests pass: retry jobs should be skipped
- On a PR where E2E tests fail due to flakiness: retry jobs should trigger and (ideally) pass on a fresh runner
- On pushes to `main`: existing `rerun-failed-jobs` behavior is preserved (retry jobs are skipped)
Reviewed By: cortinico
Differential Revision: D102327900
Pulled By: cipolleschi
fbshipit-source-id: e257e012357fdba442c302085ceed0667355272e
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/56425
Changelog: [Internal]
The Fantom CI retry loop previously re-ran the entire test suite on each attempt. This wastes time and can introduce new flaky failures that weren't in the original run (e.g., a FlatList race condition appearing on attempt 2 but not attempt 1).
This changes the retry logic to use Jest's `--onlyFailures` flag on attempts 2 and 3, so only the test suites that actually failed get re-run. For example, if 1 out of 99 suites fails with a SIGSEGV, the retry runs just that 1 suite instead of all 99 — reducing retry time from ~80s to seconds.
Reviewed By: rubennorte
Differential Revision: D100618771
fbshipit-source-id: 3b311ddb6e88b8948120e9510b50212dfe79ae81
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/54729
Changelog: [Internal]
- Created new build-fantom-runner action to compile the Fantom runner binary
- Modified run-fantom-tests action to download and use pre-built binary
- Updated test-all.yml workflow to run build and test as separate jobs
- Removed build dependencies and ccache configuration from test job
Reviewed By: cortinico
Differential Revision: D88012198
fbshipit-source-id: cd1c91b18cccc3c62b9edbcbeb131e80551369f1
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55867
Changelog: [Internal]
The build_android workflow was incorrectly using for dry-run
builds on stable branches (e.g., 0.85-stable), causing it to append suffix
to the Hermes version. This resulted in trying to fetch non-existent SNAPSHOT artifacts
like in https://github.com/facebook/react-native/actions/runs/22592250332/job/65471130298.
This fix adds a check to detect stable branches (via github.ref_name or github.base_ref)
and uses instead, which fetches the stable Hermes release from
Maven Central without the -SNAPSHOT suffix.
We check both github.ref_name and github.base_ref to cover two scenarios:
* ref_name: Direct pushes to stable branches (e.g. pushing to 0.85-stable)
* base_ref: Pull requests targeting stable branches (e.g. cherry-pick PRs where the source branch isn't named -stable but the target is)
Reviewed By: cipolleschi
Differential Revision: D95022571
fbshipit-source-id: d5888a00b29c9b5a22328fa794070c317671db2b
Summary:
When a PR targets a `-stable` branch, `github.ref_name` is the PR branch (not ending in `-stable`), so the version script was incorrectly running. Added a check for `github.base_ref` to also skip the script when the PR target branch is a stable branch.
## Changelog:
[Internal] - Skip set-rn-artifacts-version for PRs targeting stable branches
Pull Request resolved: https://github.com/facebook/react-native/pull/55809
Test Plan: CI should pass without running the artifacts version script on PRs targeting stable branches.
Reviewed By: cortinico
Differential Revision: D94678295
Pulled By: cipolleschi
fbshipit-source-id: 5809ec710c191075f1bc1528ecff95f8bd745257
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55341
Changelog:
[INTERNAL] [CHANGED] - Add api-changes.yml workflow to replace danger-pr for detecting changes in the js api
The workflow:
- Triggers on `pull_request_target` for opened, edited, reopened, and synchronize events
- Checks out the main branch (for security, using trusted code)
- Runs the `diff-js-api-changes` action to detect API changes
- Posts a PR comment using the generic `post-pr-comment` action
The PR comment script creates, updates, or deletes a bot comment based on whether
there are any sections to report, using a marker to identify existing bot comments.
Reviewed By: huntie
Differential Revision: D90991845
fbshipit-source-id: 753475a7c24df8bc581b2ab47bfad1f5551c823c
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55427
Following previous diffs, this now promotes the `lint` action to direct job steps.
**Motivation**
This has the advantage of making sub-steps in the GitHub UI visible, rather than running the 7 lint steps under a single banner.
I feel this is justified in the case of `lint`, although increasing the size of `.github/workflowsl/test-all.yml` slightly, because:
- Each step in this job is a distinct tool run with differing output, rather than one logical "action" — and this grouped output is therefore useful to the user.
- Lint failures are reasonably frequent for users, emphasising the above.
Changelog: [Internal]
Reviewed By: cortinico
Differential Revision: D92417807
fbshipit-source-id: ed24cfa2e581a528e80faec4128d280926f56613
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55425
See blame — this script lints for a `"PATENTS"` string inside any Git changes, which should not occur any more.
> D7119356 (8 years ago)
>
> [react-native][PR] Check PATENTS does not creep into files
>
> Summary:
> Some files have crept into the repo with the old license header. These are usually from PRs that were opened prior to the re-licensing of the project.
Changelog: [Internal]
Reviewed By: cortinico
Differential Revision: D92417808
fbshipit-source-id: 36e3507f835fe5df99644eb1a47cdc60fa68f88c
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55421
Deletes the largely unused `analyze_code`/`code-analysis-bot` script, which was part of our earlier CircleCI infra.
**Motivation**
- **Security**: Removes another use of a `GITHUB_TOKEN` env var being loaded into a script in our CI (similar to S603729).
- **Cleanup**: This script attempted to read various lint job results (including google-java-format, which is no longer present), and post a GitHub PR comment for >5 issues. In a GitHub Actions world, we don't really need this functionality.
**Other changes**
- The `yarn shellcheck` run from this script was load bearing, and is moved directly into the `lint` action.
Changelog: [Internal]
Reviewed By: cipolleschi
Differential Revision: D92407627
fbshipit-source-id: ef5664a273ad4aac721dbb53de73f2b96b47d75b
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55420
After https://github.com/facebook/react-native/pull/54857 (use of the "publishConfig" field), this check is no longer necessary, since `yarn build` will no longer make changes to any checked in files.
In the (expectedly) rare case that `yarn build --prepack` changes are committed (only intended for CI), Flow will also fail independently.
Changelog: [Internal]
Reviewed By: cipolleschi
Differential Revision: D92397786
fbshipit-source-id: 872cc91b62295cdb6d8c2799cffb8a4cadc4106e
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/55245
Changelog: [INTERNAL] [FIXED] - Fix diff-js-api-changes workflow to correctly compare PR head vs merge base
The `diff-js-api-changes` action was comparing main to main instead of comparing the PR head to the point of main it branched from.
The workflow now:
1. Checks out main in `danger-pr.yml` to get the trusted scripts
2. Fetches the PR head commit and computes the merge base (the point it branched from main)
3. Extracts the API snapshots from both refs using `git show` to read-only temp files
4. Runs main's diff script to compare the two snapshots
**Security notes:**
- `git fetch` only downloads git objects, it does not modify the working directory
- `git show <sha>:path` extracts a file as read-only data, not executable code
- All executed scripts come from main (trusted), PR content is only used as data
- The PR's `.d.ts` file is written to a temp directory and passed as input to main's diff script
Reviewed By: huntie
Differential Revision: D90978905
fbshipit-source-id: fc9b420a27c84f1812b436f41d3169fad4f91291
Summary:
Fixes a typo on the step name of `maestro-ios` gh action:
From `Set up JDK 11` -? `Set up JDK 17`
to match the actual version and be in sync with the rest of the other actions (e.g. maestro-android)
## Changelog:
<!-- Help reviewers and the release process by writing your own changelog entry.
Pick one each for the category and type tags:
[GENERAL] [FIXED] - typo on maestro ios gh action for jdk step
For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
Pull Request resolved: https://github.com/facebook/react-native/pull/55167
Test Plan: No testing required
Reviewed By: cipolleschi
Differential Revision: D90688156
Pulled By: cortinico
fbshipit-source-id: d2f4ff27bd6cee18c5931ff81df5f965ddf6d01b
Summary:
When setting up Xcode, we also download the SDKs that is needed.
There might be cases where we can save money and time and skip the download
## Changelog:
[Internal] -
Pull Request resolved: https://github.com/facebook/react-native/pull/55147
Test Plan: GHA
Reviewed By: javache
Differential Revision: D90594740
Pulled By: cipolleschi
fbshipit-source-id: 2923d891d626dfbb8446641d37b4b3f896c1daf2
Summary:
This is a pick of 4cac35f7d0 inside `main`.
The commit is already on the `0.84-stable` branch.
The reasoning here is that `cat` + `jq` failed to run with:
```
Run echo "rn-version=$(cat packages/react-native/package.json | jq -r 'version')" >> $GITHUB_OUTPUT
echo "rn-version=$(cat packages/react-native/package.json | jq -r 'version')" >> $GITHUB_OUTPUT
shell: bash --noprofile --norc -e -o pipefail {0}
jq: error: version/0 is not defined at <top-level>, line 1:
version
jq: 1 compile error
```
I'm moving to a single `jq` invocation as it's more resilient.
## Changelog:
[INTERNAL] -
Pull Request resolved: https://github.com/facebook/react-native/pull/55057
Test Plan: N/A
Reviewed By: fabriziocucci, alanleedev
Differential Revision: D90189240
Pulled By: cortinico
fbshipit-source-id: 9b1cd6ad6d37913f8a468892cedce5f808c8c33e
Summary:
This is a cherry-pick of dc90b0b7f3 on main from 0.83 and 0.84
## Changelog:
[INTERNAL] -
Pull Request resolved: https://github.com/facebook/react-native/pull/55054
Test Plan: CI
Reviewed By: cipolleschi
Differential Revision: D90174387
Pulled By: cortinico
fbshipit-source-id: 74b0ec3b853f2654ce140b9af27f13fe22c81f4a
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/54865
Removes introduced in D88654826, replaced with a `git fetch` with `--depth`.
This should fix CI runs on `main` (where we believe the extra checkout is clobbering the `yarn-install` step), and improve execution time.
Also shorten action name.
Changelog: [Internal]
Reviewed By: cipolleschi
Differential Revision: D89044330
fbshipit-source-id: 690eb5c7db9490e5f160e933d64eae6ac21464c8
Summary:
Updates the `diff-js-api-breaking-changes` action to compare the PR's changes against the merge base (where the branch diverged from main) instead of the current tip of main.
### Problem
The previous implementation compared the current state of `main` to the PR head. This could produce false positive results when main had new commits to reactNativeApi.d.ts reporting breaking changes from main as if they were introduced by the PR.
### Solution
- Calculate the merge base between the PR head and `origin/main`
- Compare the API snapshot at the merge base to the snapshot at the PR head
## Changelog:
[GENERAL] [FIXED] - Updates the `diff-js-api-breaking-changes` action to compare the PR's changes against the merge base (where the branch diverged from main) instead of the current tip of main.
Pull Request resolved: https://github.com/facebook/react-native/pull/54819
Test Plan:
(outputs shown for https://github.com/facebook/react-native/pull/54815)
Tested locally on branch that previously got false positive:
Mirror old approach:
```
mkdir -p /tmp/api-diff-old
git show origin/main:packages/react-native/ReactNativeApi.d.ts > /tmp/api-diff-old/before.d.ts
git show HEAD:packages/react-native/ReactNativeApi.d.ts > /tmp/api-diff-old/after.d.ts
node ./scripts/js-api/diff-api-snapshot /tmp/api-diff-old/before.d.ts /tmp/api-diff-old/after.d.ts
```
output:
```
{
"result": "BREAKING",
"changedApis": [
"ActivityIndicatorProps",
"Animated",
"DrawerLayoutAndroidProps",
"FlatList",
"FlatListProps",
"ImageBackground",
"ImageBackgroundProps",
"ImageProps",
"ImagePropsBase",
"KeyDownEvent",
"KeyEvent",
"KeyUpEvent",
"KeyboardAvoidingView",
"KeyboardAvoidingViewProps",
"ModalProps",
"PressableProps",
"ProgressBarAndroidProps",
"RefreshControl",
"RefreshControlProps",
"ScrollViewProps",
"SectionList",
"SectionListProps",
"SwitchProps",
"TextInputProps",
"ViewProps",
"VirtualizedListProps",
"VirtualizedSectionListProps"
]
}
```
Mirror new approach:
```
git fetch origin main
MERGE_BASE=$(git merge-base HEAD origin/main)
echo "Merge base: $MERGE_BASE"
mkdir -p /tmp/api-diff
git show $MERGE_BASE:packages/react-native/ReactNativeApi.d.ts > /tmp/api-diff/before.d.ts
git show HEAD:packages/react-native/ReactNativeApi.d.ts > /tmp/api-diff/after.d.ts
node ./scripts/js-api/diff-api-snapshot /tmp/api-diff/before.d.ts /tmp/api-diff/after.d.ts
```
output:
```
{
"result": "NON_BREAKING",
"changedApis": []
}
```
Reviewed By: huntie
Differential Revision: D88654826
Pulled By: emily8rown
fbshipit-source-id: 5dc2e295d7d527899b5cb6a643c4878aeebf7f0b
Summary:
Adds a new action that will run every day after the nightly build is published. This action will set up a blank app from the template, enable Hermes V1, and run a simple E2E test on Android and iOS in both Debug and Release configurations.
## Changelog:
[INTERNAL] [ADDED] - Added basic E2E tests for Hermes V1
Pull Request resolved: https://github.com/facebook/react-native/pull/54576
Test Plan: I haven't tested the changes since they require larger action runners, but the changes are additive and don't impact existing infra (besides adding an optional parameter).
Reviewed By: cortinico
Differential Revision: D87331639
Pulled By: j-piasecki
fbshipit-source-id: 8d26cb7df66f2588b49f86f01ff0b623501e7f2b
Summary:
After moving to SwiftPM, we stopped testing the build from source using Cocoapods and dynamic frameworks. Given that the migration will take some more time, this change reintroduces a job to keep the build from source using dynamic frameworks in check
## Changelog:
[Internal] -
Pull Request resolved: https://github.com/facebook/react-native/pull/54482
Test Plan: GHA
Reviewed By: javache
Differential Revision: D86760336
Pulled By: cipolleschi
fbshipit-source-id: c131af44209de40f2ee7f7d08fa61d88aa48d3ee
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53837
Changelog: [Internal]
Replaces usage of Hermes built inside the React Native repository with the release published from the Hermes repo.
Reviewed By: cipolleschi
Differential Revision: D82721725
fbshipit-source-id: 357d5e2b914675ec6e60f810c382a945aa461732
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53817
What is currently happening, is that the various commits on the release branches like `0.82-stable` are resetting the version of native artifacts to `1000.0.0-<SHA>`.
The reason is that during the `test-all` workflow, we pass the `dry-run` as release type.
That's to prevent the various tools from calling `npm publish` and so on.
The problem is that on the releases branches, the version was already set at branch cut time.
Therefore, we see the version 1000.0.0 reappearing during Android E2E test in the emulator. Similary this is also affecting iOS prebuilds so I'm attempting to fix it here.
Changelog:
[Internal] [Changed] -
Reviewed By: huntie
Differential Revision: D82553599
fbshipit-source-id: 31a52e7df036e700663b3d3dd677973a7a210a30