From f6eee5f560a1d6958f7842b079b80e908fc2623e Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Wed, 22 Apr 2026 13:48:14 -0700 Subject: [PATCH 1/7] ci: re-enable react-native-test-app integration test using local pack Replace Verdaccio with local `yarn pack` + tarball install to fix the hanging issue (#2344). Follows the same pattern already used by the react-native-macos-init integration test. Also moves and converts .ado/scripts/export-versions.mjs to .github/scripts/export-versions.mts with GitHub Actions output support. Co-Authored-By: Claude Opus 4.6 --- .ado/scripts/export-versions.mjs | 27 ------------- .github/scripts/export-versions.mts | 35 +++++++++++++++++ .github/workflows/microsoft-pr.yml | 14 +++---- ...soft-react-native-test-app-integration.yml | 38 +++++++------------ 4 files changed, 54 insertions(+), 60 deletions(-) delete mode 100644 .ado/scripts/export-versions.mjs create mode 100644 .github/scripts/export-versions.mts diff --git a/.ado/scripts/export-versions.mjs b/.ado/scripts/export-versions.mjs deleted file mode 100644 index 53fb6ae28323..000000000000 --- a/.ado/scripts/export-versions.mjs +++ /dev/null @@ -1,27 +0,0 @@ -// @ts-check -import * as fs from "node:fs"; -import { URL } from "node:url"; - -/** - * @param {string} version - * @returns {string} - */ -function coerce(version) { - const [major, minor = 0] = version.split("-")[0].split("."); - return `${major}.${minor}`; -} - -/** - * @param {string} name - * @param {unknown} value - */ -function exportValue(name, value) { - console.log(`##vso[task.setvariable variable=${name}]${value}`); -} - -const manifestPath = new URL("../../packages/react-native/package.json", import.meta.url); -const json = fs.readFileSync(manifestPath, { encoding: "utf-8" }); -const { dependencies, peerDependencies } = JSON.parse(json); - -exportValue("react_version", peerDependencies["react"]); -exportValue("react_native_version", coerce(dependencies["@react-native/codegen"])); diff --git a/.github/scripts/export-versions.mts b/.github/scripts/export-versions.mts new file mode 100644 index 000000000000..fe9734081b05 --- /dev/null +++ b/.github/scripts/export-versions.mts @@ -0,0 +1,35 @@ +#!/usr/bin/env node +/** + * Export react and react-native version information from packages/react-native/package.json. + * + * Outputs (written to $GITHUB_OUTPUT): + * react_version – the React peer dependency version (e.g. "19.0.0") + * react_native_version – the coerced major.minor React Native version (e.g. "0.79") + */ +import * as fs from "node:fs"; +import { URL } from "node:url"; + +function coerce(version: string): string { + const [major, minor = "0"] = version.split("-")[0].split("."); + return `${major}.${minor}`; +} + +function exportValue(name: string, value: string): void { + const githubOutput = process.env.GITHUB_OUTPUT; + if (githubOutput) { + fs.appendFileSync(githubOutput, `${name}=${value}\n`); + } else { + // Fallback: print to stdout for local debugging + console.log(`${name}=${value}`); + } +} + +const manifestPath = new URL( + "../../packages/react-native/package.json", + import.meta.url +); +const json = fs.readFileSync(manifestPath, { encoding: "utf-8" }); +const { dependencies, peerDependencies } = JSON.parse(json); + +exportValue("react_version", peerDependencies["react"]); +exportValue("react_native_version", coerce(dependencies["@react-native/codegen"])); diff --git a/.github/workflows/microsoft-pr.yml b/.github/workflows/microsoft-pr.yml index 157cd8b05fa2..2566b0ec5f44 100644 --- a/.github/workflows/microsoft-pr.yml +++ b/.github/workflows/microsoft-pr.yml @@ -143,13 +143,11 @@ jobs: if: ${{ endsWith(github.base_ref, '-stable') }} uses: ./.github/workflows/microsoft-test-react-native-macos-init.yml - # https://github.com/microsoft/react-native-macos/issues/2344 - # Disable these tests because verdaccio hangs - # react-native-test-app-integration: - # name: "Test react-native-test-app integration" - # permissions: {} - # if: ${{ endsWith(github.base_ref, '-stable') }} - # uses: ./.github/workflows/microsoft-react-native-test-app-integration.yml + react-native-test-app-integration: + name: "Test react-native-test-app integration" + permissions: {} + if: ${{ endsWith(github.base_ref, '-stable') }} + uses: ./.github/workflows/microsoft-react-native-test-app-integration.yml PR: name: "PR" @@ -164,7 +162,7 @@ jobs: - build-rntester - prebuild-macos-core - test-react-native-macos-init - # - react-native-test-app-integration + - react-native-test-app-integration steps: - name: Check for failures or cancellations if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }} diff --git a/.github/workflows/microsoft-react-native-test-app-integration.yml b/.github/workflows/microsoft-react-native-test-app-integration.yml index 8725a42a9cd0..27a864d8d229 100644 --- a/.github/workflows/microsoft-react-native-test-app-integration.yml +++ b/.github/workflows/microsoft-react-native-test-app-integration.yml @@ -25,43 +25,38 @@ jobs: run: yarn install - name: Build community CLI plugin - run: yarn build + run: | + yarn build + # yarn build rewrites package.json exports; restore them + git checkout -- packages/*/package.json - name: Build react-native-macos-init working-directory: packages/react-native-macos-init run: yarn build - - name: Start Verdaccio server - run: | - set -euo pipefail - nohup npx --yes verdaccio --config .ado/verdaccio/config.yaml >/dev/null 2>&1 & - echo $! > $RUNNER_TEMP/verdaccio.pid - - name: Wait for Verdaccio to be ready - run: node .ado/scripts/waitForVerdaccio.mjs http://localhost:4873 - - - name: Configure npm for Verdaccio - run: .ado/scripts/verdaccio.sh init + - name: Export versions + id: versions + run: node .github/scripts/export-versions.mts - - name: Publish to Verdaccio - run: .ado/scripts/verdaccio.sh publish --branch origin/${{ github.base_ref }} + - name: Pack local react-native-macos + working-directory: packages/react-native + run: | + set -eox pipefail + yarn pack -o ${{ runner.temp }}/react-native-macos.tgz - name: Clone react-native-test-app run: | git clone --filter=blob:none --progress https://github.com/microsoft/react-native-test-app.git - - name: Export versions - run: node .ado/scripts/export-versions.mjs - - name: Configure react-native-test-app dependencies working-directory: react-native-test-app run: | - npm run set-react-version $(cat ${{ github.workspace }}/.react_native_version) -- --overrides '{ "react-native-macos": "1000.0.0" }' + npm run set-react-version ${{ steps.versions.outputs.react_native_version }} -- --overrides '{ "react-native-macos": "file:${{ runner.temp }}/react-native-macos.tgz" }' - name: Install dependencies in test app working-directory: react-native-test-app run: | set -eo pipefail - ${{ github.workspace }}/.ado/scripts/verdaccio.sh configure yarn --no-immutable - name: Bundle JavaScript @@ -79,10 +74,3 @@ jobs: working-directory: react-native-test-app/example run: | ../scripts/build/xcodebuild.sh macos/Example.xcworkspace build - - - name: Stop Verdaccio - if: always() - run: | - if [ -f "$RUNNER_TEMP/verdaccio.pid" ]; then - kill "$(cat $RUNNER_TEMP/verdaccio.pid)" || true - fi From 0c9349ed216925c34ea14cc1c69cb6f67312e51a Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Wed, 22 Apr 2026 14:24:24 -0700 Subject: [PATCH 2/7] fix(ci): update react-native-test-app integration for current repo structure - Use `yarn workspace react-native-test-app set-react-version` instead of root-level `npm run set-react-version` (script moved to workspace) - Update paths from `example/` to `packages/example-macos/` - Update xcodebuild script path from `scripts/build/` to `scripts/` Co-Authored-By: Claude Opus 4.6 --- .../microsoft-react-native-test-app-integration.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/microsoft-react-native-test-app-integration.yml b/.github/workflows/microsoft-react-native-test-app-integration.yml index 27a864d8d229..86b2ba2db503 100644 --- a/.github/workflows/microsoft-react-native-test-app-integration.yml +++ b/.github/workflows/microsoft-react-native-test-app-integration.yml @@ -51,7 +51,7 @@ jobs: - name: Configure react-native-test-app dependencies working-directory: react-native-test-app run: | - npm run set-react-version ${{ steps.versions.outputs.react_native_version }} -- --overrides '{ "react-native-macos": "file:${{ runner.temp }}/react-native-macos.tgz" }' + yarn workspace react-native-test-app set-react-version ${{ steps.versions.outputs.react_native_version }} --overrides '{ "react-native-macos": "file:${{ runner.temp }}/react-native-macos.tgz" }' - name: Install dependencies in test app working-directory: react-native-test-app @@ -60,17 +60,17 @@ jobs: yarn --no-immutable - name: Bundle JavaScript - working-directory: react-native-test-app/example + working-directory: react-native-test-app/packages/example-macos run: | yarn build:macos || yarn build:macos - name: Install Pods - working-directory: react-native-test-app/example + working-directory: react-native-test-app/packages/example-macos run: | rm -f macos/Podfile.lock pod install --project-directory=macos - name: Build test app - working-directory: react-native-test-app/example + working-directory: react-native-test-app/packages/example-macos run: | - ../scripts/build/xcodebuild.sh macos/Example.xcworkspace build + ../../scripts/xcodebuild.sh macos/Example.xcworkspace build From 1d18e52b3abe3793caaec562cf35f333eb3f7986 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Wed, 22 Apr 2026 15:44:48 -0700 Subject: [PATCH 3/7] fix(ci): run set-react-version directly to avoid yarn workspace install requirement The yarn workspace command requires dependencies to be installed first. Run the script directly with node from packages/app instead. Co-Authored-By: Claude Opus 4.6 --- .../workflows/microsoft-react-native-test-app-integration.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/microsoft-react-native-test-app-integration.yml b/.github/workflows/microsoft-react-native-test-app-integration.yml index 86b2ba2db503..ce1def09f9cb 100644 --- a/.github/workflows/microsoft-react-native-test-app-integration.yml +++ b/.github/workflows/microsoft-react-native-test-app-integration.yml @@ -49,9 +49,9 @@ jobs: git clone --filter=blob:none --progress https://github.com/microsoft/react-native-test-app.git - name: Configure react-native-test-app dependencies - working-directory: react-native-test-app + working-directory: react-native-test-app/packages/app run: | - yarn workspace react-native-test-app set-react-version ${{ steps.versions.outputs.react_native_version }} --overrides '{ "react-native-macos": "file:${{ runner.temp }}/react-native-macos.tgz" }' + node scripts/internal/set-react-version.mts ${{ steps.versions.outputs.react_native_version }} --overrides '{ "react-native-macos": "file:${{ runner.temp }}/react-native-macos.tgz" }' - name: Install dependencies in test app working-directory: react-native-test-app From da383a59553a207436384c4d50d1e80e3a7a480f Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Wed, 22 Apr 2026 15:54:44 -0700 Subject: [PATCH 4/7] fix(ci): disable Yarn hardened mode for test-app dependency install Yarn auto-enables hardened mode on public PRs, which quarantines @react-native-macos/virtualized-lists. Disable it for this step since we're installing known packages from our own tarball. Co-Authored-By: Claude Opus 4.6 --- .../workflows/microsoft-react-native-test-app-integration.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/microsoft-react-native-test-app-integration.yml b/.github/workflows/microsoft-react-native-test-app-integration.yml index ce1def09f9cb..027006fa00e8 100644 --- a/.github/workflows/microsoft-react-native-test-app-integration.yml +++ b/.github/workflows/microsoft-react-native-test-app-integration.yml @@ -55,6 +55,8 @@ jobs: - name: Install dependencies in test app working-directory: react-native-test-app + env: + YARN_ENABLE_HARDENED_MODE: 0 run: | set -eo pipefail yarn --no-immutable From c01cdce5dc6309b3e3cad945e524646304f449b8 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 23 Apr 2026 07:22:21 -0700 Subject: [PATCH 5/7] fix(ci): disable Yarn npmMinimalAgeGate for test-app install The test-app's .yarnrc.yml sets npmMinimalAgeGate: 7d which quarantines recently published packages like @react-native-macos/virtualized-lists. Override with YARN_NPM_MINIMAL_AGE_GATE=0. Co-Authored-By: Claude Opus 4.6 --- .../workflows/microsoft-react-native-test-app-integration.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/microsoft-react-native-test-app-integration.yml b/.github/workflows/microsoft-react-native-test-app-integration.yml index 027006fa00e8..4550be55a1ff 100644 --- a/.github/workflows/microsoft-react-native-test-app-integration.yml +++ b/.github/workflows/microsoft-react-native-test-app-integration.yml @@ -57,6 +57,7 @@ jobs: working-directory: react-native-test-app env: YARN_ENABLE_HARDENED_MODE: 0 + YARN_NPM_MINIMAL_AGE_GATE: 0 run: | set -eo pipefail yarn --no-immutable From e67bc0d79efaa9a878cc7f3f9ef22e1be22ba283 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 23 Apr 2026 12:06:02 -0700 Subject: [PATCH 6/7] fix(ci): add yarn resolution to deduplicate react-native-macos The set-react-version script updates packages/app/package.json but not packages/example-macos/package.json, causing two copies of react-native-macos (0.81.5 from npm + tarball). Add a root-level yarn resolution to force all workspaces to use the local tarball. Co-Authored-By: Claude Opus 4.6 --- .../microsoft-react-native-test-app-integration.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/microsoft-react-native-test-app-integration.yml b/.github/workflows/microsoft-react-native-test-app-integration.yml index 4550be55a1ff..87cbc5227dc0 100644 --- a/.github/workflows/microsoft-react-native-test-app-integration.yml +++ b/.github/workflows/microsoft-react-native-test-app-integration.yml @@ -53,6 +53,17 @@ jobs: run: | node scripts/internal/set-react-version.mts ${{ steps.versions.outputs.react_native_version }} --overrides '{ "react-native-macos": "file:${{ runner.temp }}/react-native-macos.tgz" }' + - name: Force react-native-macos resolution to local tarball + working-directory: react-native-test-app + run: | + node -e " + const fs = require('fs'); + const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8')); + pkg.resolutions = pkg.resolutions || {}; + pkg.resolutions['react-native-macos'] = 'file:${{ runner.temp }}/react-native-macos.tgz'; + fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n'); + " + - name: Install dependencies in test app working-directory: react-native-test-app env: From 137486c28282ba3c11a4bdc72f3f458b89f26323 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 23 Apr 2026 13:18:38 -0700 Subject: [PATCH 7/7] fix(ci): override react-native-macos in all workspaces to fix duplicate The pnpm linker creates separate virtual stores per workspace. Override the dependency in both root resolutions and packages/example-macos to ensure a single copy of react-native-macos from the local tarball. Co-Authored-By: Claude Opus 4.6 --- ...soft-react-native-test-app-integration.yml | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/.github/workflows/microsoft-react-native-test-app-integration.yml b/.github/workflows/microsoft-react-native-test-app-integration.yml index 87cbc5227dc0..654dca3a4814 100644 --- a/.github/workflows/microsoft-react-native-test-app-integration.yml +++ b/.github/workflows/microsoft-react-native-test-app-integration.yml @@ -53,15 +53,26 @@ jobs: run: | node scripts/internal/set-react-version.mts ${{ steps.versions.outputs.react_native_version }} --overrides '{ "react-native-macos": "file:${{ runner.temp }}/react-native-macos.tgz" }' - - name: Force react-native-macos resolution to local tarball + - name: Force react-native-macos to local tarball in all workspaces working-directory: react-native-test-app run: | node -e " const fs = require('fs'); - const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8')); - pkg.resolutions = pkg.resolutions || {}; - pkg.resolutions['react-native-macos'] = 'file:${{ runner.temp }}/react-native-macos.tgz'; - fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n'); + const tarball = 'file:${{ runner.temp }}/react-native-macos.tgz'; + + // Add root-level resolution + const root = JSON.parse(fs.readFileSync('package.json', 'utf8')); + root.resolutions = root.resolutions || {}; + root.resolutions['react-native-macos'] = tarball; + fs.writeFileSync('package.json', JSON.stringify(root, null, 2) + '\n'); + + // Override direct dependency in example-macos + const exMacosPath = 'packages/example-macos/package.json'; + const exMacos = JSON.parse(fs.readFileSync(exMacosPath, 'utf8')); + if (exMacos.dependencies && exMacos.dependencies['react-native-macos']) { + exMacos.dependencies['react-native-macos'] = tarball; + fs.writeFileSync(exMacosPath, JSON.stringify(exMacos, null, 2) + '\n'); + } " - name: Install dependencies in test app