mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09115012c8 |
+7
-1
@@ -30,11 +30,17 @@ module.exports = {
|
||||
// These rules are not required with hermes-eslint
|
||||
'ft-flow/define-flow-type': 0,
|
||||
'ft-flow/use-flow-type': 0,
|
||||
'lint/sort-imports': 1,
|
||||
// flow handles this check for us, so it's not required
|
||||
'no-undef': 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.js', '*.js.flow'],
|
||||
excludedFiles: ['packages/react-native/template/**/*'],
|
||||
rules: {
|
||||
'lint/sort-imports': 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['package.json'],
|
||||
parser: 'jsonc-eslint-parser',
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
[ignore]
|
||||
; Ignore build cache folder
|
||||
; Ignore templates for 'react-native init'
|
||||
<PROJECT_ROOT>/packages/react-native/template/.*
|
||||
<PROJECT_ROOT>/packages/react-native/sdks/.*
|
||||
|
||||
; Ignore the codegen e2e tests
|
||||
@@ -90,4 +91,4 @@ untyped-import
|
||||
untyped-type-import
|
||||
|
||||
[version]
|
||||
^0.251.1
|
||||
^0.242.0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: 🐛 React Native - Bug Report
|
||||
name: 🐛 Bug Report
|
||||
description: Report a reproducible bug or regression in React Native.
|
||||
labels: ["Needs: Triage :mag:"]
|
||||
body:
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
name: 🔍 Debugger - Bug Report
|
||||
description: Report a bug with React Native DevTools and the New Debugger
|
||||
labels: ["Needs: Triage :mag:", "Debugger"]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "## Reporting a bug for React Native DevTools"
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for taking the time to report an issue for React Native DevTools, our new Debugger for React Native.
|
||||
|
||||
Before you continue:
|
||||
* If you're using **Expo** and you're noticing a bug, [report it here](https://github.com/expo/expo/issues).
|
||||
* If you've found a problem with our **documentation**, [report it here](https://github.com/facebook/react-native-website/issues/).
|
||||
* If you're having an issue with **Metro** (the bundler), [report it here](https://github.com/facebook/metro/issues/).
|
||||
* If you're using an external library, report the issue to the **library first**.
|
||||
* Please [search for similar issues](https://github.com/facebook/react-native/issues) in our issue tracker.
|
||||
|
||||
Make sure that your issue is tested against the [**latest stable**](https://github.com/facebook/react-native/releases/) of React Native.
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: A clear and concise description of what the bug is.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: The list of steps that reproduces the issue.
|
||||
placeholder: |
|
||||
1. Install the application with `yarn android`
|
||||
2. Press `j` to open the debugger
|
||||
3. Do something...
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: React Native Version
|
||||
description: The version of react-native that this issue reproduces on. Bear in mind that only issues on [supported versions](https://github.com/reactwg/react-native-releases#which-versions-are-currently-supported) will be looked into.
|
||||
placeholder: "0.76.0"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: react-native-info
|
||||
attributes:
|
||||
label: Output of `npx react-native info`
|
||||
description: Run `npx react-native info` in your terminal, copy and paste the results here.
|
||||
placeholder: |
|
||||
Paste the output of `npx react-native info` here. The output looks like:
|
||||
...
|
||||
System:
|
||||
OS: macOS 14.1.1
|
||||
CPU: (10) arm64 Apple M1 Max
|
||||
Memory: 417.81 MB / 64.00 GB
|
||||
Shell:
|
||||
version: "5.9"
|
||||
path: /bin/zsh
|
||||
Binaries:
|
||||
Node: ...
|
||||
version: 18.14.0
|
||||
...
|
||||
render: text
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: extra
|
||||
attributes:
|
||||
label: Screenshots and Videos
|
||||
description: |
|
||||
Please provide screenshot or a video of your bug if relevant.
|
||||
Issues with videos and screenshots are more likely to **get prioritized**.
|
||||
@@ -10,9 +10,6 @@ inputs:
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Setup git safe folders
|
||||
shell: bash
|
||||
run: git config --global --add safe.directory '*'
|
||||
- name: Setup node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
- name: Install node dependencies
|
||||
@@ -65,13 +62,13 @@ runs:
|
||||
shell: bash
|
||||
run: ccache -s -v
|
||||
- name: Upload Maven Artifacts
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: maven-local
|
||||
path: /tmp/maven-local
|
||||
- name: Upload test results
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-android-results
|
||||
compression-level: 1
|
||||
@@ -81,28 +78,28 @@ runs:
|
||||
packages/react-native/ReactAndroid/build/reports
|
||||
- name: Upload RNTester APK - hermes-debug
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: rntester-hermes-debug
|
||||
path: packages/rn-tester/android/app/build/outputs/apk/hermes/debug/
|
||||
compression-level: 0
|
||||
- name: Upload RNTester APK - hermes-release
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: rntester-hermes-release
|
||||
path: packages/rn-tester/android/app/build/outputs/apk/hermes/release/
|
||||
compression-level: 0
|
||||
- name: Upload RNTester APK - jsc-debug
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: rntester-jsc-debug
|
||||
path: packages/rn-tester/android/app/build/outputs/apk/jsc/debug/
|
||||
compression-level: 0
|
||||
- name: Upload RNTester APK - jsc-release
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: rntester-jsc-release
|
||||
path: packages/rn-tester/android/app/build/outputs/apk/jsc/release/
|
||||
|
||||
@@ -9,7 +9,7 @@ inputs:
|
||||
description: The version of Hermes
|
||||
slice:
|
||||
required: true
|
||||
description: The slice of hermes you want to build. It could be iphone, iphonesimulator, macos, catalyst, appletvos, appletvsimulator, xros, or xrossimulator
|
||||
description: The slice of hermes you want to build. It could be iphone, iphonesimulator, macos, catalyst, xros, or xrossimulator
|
||||
flavor:
|
||||
required: true
|
||||
description: The flavor we want to build. It can be Debug or Release
|
||||
@@ -30,7 +30,7 @@ runs:
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: ./packages/react-native/sdks/hermes/build_${{ inputs.slice }}_${{ inputs.flavor }}
|
||||
key: v6-hermes-apple-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}-${{ hashfiles('packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh') }}-${{ inputs.slice }}-${{ inputs.flavor }}
|
||||
key: v4-hermes-apple-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}-${{ hashfiles('packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh') }}-${{ inputs.slice }}-${{ inputs.flavor }}
|
||||
- name: Build the Hermes ${{ inputs.slice }} frameworks
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -85,19 +85,14 @@ runs:
|
||||
echo "Please try again"
|
||||
exit 1
|
||||
fi
|
||||
- name: Compress slices to preserve Symlinks
|
||||
shell: bash
|
||||
run: |
|
||||
cd ./packages/react-native/sdks/hermes
|
||||
tar -czv -f build_${{ matrix.slice }}_${{ matrix.flavor }}.tar.gz build_${{ matrix.slice }}_${{ matrix.flavor }}
|
||||
- name: Upload Artifact for Slice (${{ inputs.slice }}, ${{ inputs.flavor }}}
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: slice-${{ inputs.slice }}-${{ inputs.flavor }}
|
||||
path: ./packages/react-native/sdks/hermes/build_${{ inputs.slice }}_${{ inputs.flavor }}.tar.gz
|
||||
path: ./packages/react-native/sdks/hermes/build_${{ inputs.slice }}_${{ inputs.flavor }}
|
||||
- name: Save slice cache
|
||||
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, '-stable') }} # To avoid that the cache explode.
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: ./packages/react-native/sdks/hermes/build_${{ inputs.slice }}_${{ inputs.flavor }}
|
||||
key: v6-hermes-apple-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}-${{ hashfiles('packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh') }}-${{ inputs.SLICE }}-${{ inputs.FLAVOR }}
|
||||
key: v4-hermes-apple-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}-${{ hashfiles('packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh') }}-${{ inputs.SLICE }}-${{ inputs.FLAVOR }}
|
||||
|
||||
@@ -22,7 +22,7 @@ runs:
|
||||
- name: Restore Cached Artifacts
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
key: v4-hermes-artifacts-${{ inputs.flavor }}-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}-${{ hashFiles('./packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh') }}
|
||||
key: v3-hermes-artifacts-${{ inputs.flavor }}-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}
|
||||
path: |
|
||||
/tmp/hermes/osx-bin/${{ inputs.flavor }}
|
||||
/tmp/hermes/dSYM/${{ inputs.flavor }}
|
||||
@@ -52,64 +52,38 @@ runs:
|
||||
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./packages/react-native/sdks/hermes/
|
||||
path: ./packages/react-native/sdks/hermes/build_macosx_${{ inputs.flavor }}
|
||||
name: slice-macosx-${{ inputs.flavor }}
|
||||
- name: Slice cache iphoneos
|
||||
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./packages/react-native/sdks/hermes/
|
||||
path: ./packages/react-native/sdks/hermes/build_iphoneos_${{ inputs.flavor }}
|
||||
name: slice-iphoneos-${{ inputs.flavor }}
|
||||
- name: Slice cache iphonesimulator
|
||||
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./packages/react-native/sdks/hermes/
|
||||
path: ./packages/react-native/sdks/hermes/build_iphonesimulator_${{ inputs.flavor }}
|
||||
name: slice-iphonesimulator-${{ inputs.flavor }}
|
||||
- name: Slice cache appletvos
|
||||
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./packages/react-native/sdks/hermes/
|
||||
name: slice-appletvos-${{ inputs.flavor }}
|
||||
- name: Slice cache appletvsimulator
|
||||
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./packages/react-native/sdks/hermes/
|
||||
name: slice-appletvsimulator-${{ inputs.flavor }}
|
||||
- name: Slice cache catalyst
|
||||
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./packages/react-native/sdks/hermes/
|
||||
path: ./packages/react-native/sdks/hermes/build_catalyst_${{ inputs.flavor }}
|
||||
name: slice-catalyst-${{ inputs.flavor }}
|
||||
- name: Slice cache xros
|
||||
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./packages/react-native/sdks/hermes/
|
||||
path: ./packages/react-native/sdks/hermes/build_xros_${{ inputs.flavor }}
|
||||
name: slice-xros-${{ inputs.flavor }}
|
||||
- name: Slice cache xrsimulator
|
||||
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./packages/react-native/sdks/hermes/
|
||||
path: ./packages/react-native/sdks/hermes/build_xrsimulator_${{ inputs.flavor }}
|
||||
name: slice-xrsimulator-${{ inputs.flavor }}
|
||||
- name: Unzip slices
|
||||
shell: bash
|
||||
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
|
||||
run: |
|
||||
cd ./packages/react-native/sdks/hermes
|
||||
ls -l .
|
||||
tar -xzv -f build_catalyst_${{ matrix.flavor }}.tar.gz
|
||||
tar -xzv -f build_iphoneos_${{ matrix.flavor }}.tar.gz
|
||||
tar -xzv -f build_iphonesimulator_${{ matrix.flavor }}.tar.gz
|
||||
tar -xzv -f build_appletvos_${{ matrix.flavor }}.tar.gz
|
||||
tar -xzv -f build_appletvsimulator_${{ matrix.flavor }}.tar.gz
|
||||
tar -xzv -f build_macosx_${{ matrix.flavor }}.tar.gz
|
||||
tar -xzv -f build_xros_${{ matrix.flavor }}.tar.gz
|
||||
tar -xzv -f build_xrsimulator_${{ matrix.flavor }}.tar.gz
|
||||
- name: Move back build folders
|
||||
if: ${{ steps.check_if_apple_artifacts_are_there.outputs.ARTIFACTS_EXIST != 'true' }}
|
||||
shell: bash
|
||||
@@ -119,8 +93,6 @@ runs:
|
||||
mv build_macosx_${{ inputs.flavor }} build_macosx
|
||||
mv build_iphoneos_${{ inputs.flavor }} build_iphoneos
|
||||
mv build_iphonesimulator_${{ inputs.flavor }} build_iphonesimulator
|
||||
mv build_appletvos_${{ inputs.flavor }} build_appletvos
|
||||
mv build_appletvsimulator_${{ inputs.flavor }} build_appletvsimulator
|
||||
mv build_catalyst_${{ inputs.flavor }} build_catalyst
|
||||
mv build_xros_${{ inputs.flavor }} build_xros
|
||||
mv build_xrsimulator_${{ inputs.flavor }} build_xrsimulator
|
||||
@@ -179,8 +151,6 @@ runs:
|
||||
mkdir -p "$WORKING_DIR/catalyst"
|
||||
mkdir -p "$WORKING_DIR/iphoneos"
|
||||
mkdir -p "$WORKING_DIR/iphonesimulator"
|
||||
mkdir -p "$WORKING_DIR/appletvos"
|
||||
mkdir -p "$WORKING_DIR/appletvsimulator"
|
||||
mkdir -p "$WORKING_DIR/xros"
|
||||
mkdir -p "$WORKING_DIR/xrsimulator"
|
||||
|
||||
@@ -191,8 +161,6 @@ runs:
|
||||
cp -r build_catalyst/$DSYM_FILE_PATH "$WORKING_DIR/catalyst/"
|
||||
cp -r build_iphoneos/$DSYM_FILE_PATH "$WORKING_DIR/iphoneos/"
|
||||
cp -r build_iphonesimulator/$DSYM_FILE_PATH "$WORKING_DIR/iphonesimulator/"
|
||||
cp -r build_appletvos/$DSYM_FILE_PATH "$WORKING_DIR/appletvos/"
|
||||
cp -r build_appletvsimulator/$DSYM_FILE_PATH "$WORKING_DIR/appletvsimulator/"
|
||||
cp -r build_xros/$DSYM_FILE_PATH "$WORKING_DIR/xros/"
|
||||
cp -r build_xrsimulator/$DSYM_FILE_PATH "$WORKING_DIR/xrsimulator/"
|
||||
|
||||
@@ -202,17 +170,17 @@ runs:
|
||||
mkdir -p "$DEST_DIR"
|
||||
mv "hermes.framework.dSYM" "$DEST_DIR"
|
||||
- name: Upload hermes dSYM artifacts
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hermes-dSYM-${{ inputs.flavor }}
|
||||
path: /tmp/hermes/dSYM/${{ inputs.flavor }}
|
||||
- name: Upload hermes Runtime artifacts
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hermes-darwin-bin-${{ inputs.flavor }}
|
||||
path: /tmp/hermes/hermes-runtime-darwin/hermes-ios-${{ inputs.flavor }}.tar.gz
|
||||
- name: Upload hermes osx artifacts
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hermes-osx-bin-${{ inputs.flavor }}
|
||||
path: /tmp/hermes/osx-bin/${{ inputs.flavor }}
|
||||
@@ -220,7 +188,7 @@ runs:
|
||||
uses: actions/cache/save@v4
|
||||
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, '-stable') }} # To avoid that the cache explode.
|
||||
with:
|
||||
key: v4-hermes-artifacts-${{ inputs.flavor }}-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}-${{ hashFiles('./packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh') }}
|
||||
key: v3-hermes-artifacts-${{ inputs.flavor }}-${{ inputs.hermes-version }}-${{ inputs.react-native-version }}
|
||||
path: |
|
||||
/tmp/hermes/osx-bin/${{ inputs.flavor }}
|
||||
/tmp/hermes/dSYM/${{ inputs.flavor }}
|
||||
|
||||
@@ -24,7 +24,7 @@ runs:
|
||||
. ./utils/build-apple-framework.sh
|
||||
build_host_hermesc_if_needed
|
||||
- name: Upload HermesC Artifact
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hermesc-apple
|
||||
path: ./packages/react-native/sdks/hermes/build_host_hermesc
|
||||
|
||||
@@ -43,7 +43,7 @@ runs:
|
||||
cp /tmp/hermes/build/bin/hermesc /tmp/hermes/linux64-bin/.
|
||||
fi
|
||||
- name: Upload linux artifacts
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hermes-linux-bin
|
||||
path: /tmp/hermes/linux64-bin
|
||||
|
||||
@@ -80,7 +80,7 @@ runs:
|
||||
Write-Host "Skipping; Clean c:\tmp\hermes\win64-bin to rebuild."
|
||||
}
|
||||
- name: Upload windows artifacts
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hermes-win64-bin
|
||||
path: D:\tmp\hermes\win64-bin\
|
||||
|
||||
@@ -14,9 +14,6 @@ inputs:
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Setup git safe folders
|
||||
shell: bash
|
||||
run: git config --global --add safe.directory '*'
|
||||
- name: Create /tmp/hermes/osx-bin directory
|
||||
shell: bash
|
||||
run: mkdir -p /tmp/hermes/osx-bin
|
||||
@@ -126,7 +123,7 @@ runs:
|
||||
fi
|
||||
node ./scripts/releases-ci/publish-npm.js -t ${{ inputs.release-type }}
|
||||
- name: Upload npm logs
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: npm-logs
|
||||
path: ~/.npm/_logs
|
||||
@@ -141,7 +138,7 @@ runs:
|
||||
|
||||
echo "$FILENAME" > build/react-native-package-version
|
||||
- name: Upload release package
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ inputs.release-type == 'dry-run' }}
|
||||
with:
|
||||
name: react-native-package
|
||||
|
||||
@@ -31,7 +31,7 @@ runs:
|
||||
GIT_PAGER=cat git show HEAD
|
||||
- name: Update "latest" tag if needed
|
||||
shell: bash
|
||||
if: ${{ inputs.is-latest-on-npm == 'true' }}
|
||||
if: ${{ inputs.tag == 'latest' }}
|
||||
run: |
|
||||
git tag -d "latest"
|
||||
git push origin :latest
|
||||
|
||||
@@ -23,7 +23,6 @@ runs:
|
||||
run: yarn lint-ci
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ inputs.github-token }}
|
||||
GITHUB_PR_NUMBER: ${{ github.event.number }}
|
||||
- name: Lint code
|
||||
shell: bash
|
||||
run: ./scripts/circleci/exec_swallow_error.sh yarn lint --format junit -o ./reports/junit/eslint/results.xml
|
||||
|
||||
@@ -17,15 +17,6 @@ inputs:
|
||||
required: false
|
||||
default: 'true'
|
||||
description: whether this action has to install java 17 or not
|
||||
flavor:
|
||||
required: true
|
||||
description: the flavor we want to run - either debug or release
|
||||
default: release
|
||||
working-directory:
|
||||
required: false
|
||||
default: "."
|
||||
description: The directory from which metro should be started
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
@@ -34,7 +25,7 @@ runs:
|
||||
run: export MAESTRO_VERSION=1.36.0; curl -Ls "https://get.maestro.mobile.dev" | bash
|
||||
- name: Set up JDK 17
|
||||
if: ${{ inputs.install-java == 'true' }}
|
||||
uses: actions/setup-java@v4
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
@@ -47,38 +38,33 @@ runs:
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
- name: Build Codegen
|
||||
shell: bash
|
||||
if: ${{ inputs.flavor == 'debug' }}
|
||||
run: ./packages/react-native-codegen/scripts/oss/build.sh
|
||||
- name: Run e2e tests
|
||||
uses: reactivecircus/android-emulator-runner@v2
|
||||
with:
|
||||
api-level: 24
|
||||
arch: x86
|
||||
ram-size: '4096M'
|
||||
disk-size: '10G'
|
||||
disable-animations: false
|
||||
avd-name: e2e_emulator
|
||||
script: node .github/workflow-scripts/maestro-android.js ${{ inputs.app-path }} ${{ inputs.app-id }} ${{ inputs.maestro-flow }} ${{ inputs.flavor }} ${{ inputs.working-directory }}
|
||||
- name: Normalize APP_ID
|
||||
id: normalize-app-id
|
||||
shell: bash
|
||||
if: always()
|
||||
run: |
|
||||
NORM_APP_ID=$(echo "${{ inputs.app-id }}" | tr '.' '-')
|
||||
echo "app-id=$NORM_APP_ID" >> $GITHUB_OUTPUT
|
||||
script: |
|
||||
echo "Install APK from ${{ inputs.app-path }}"
|
||||
adb install "${{ inputs.app-path }}"
|
||||
|
||||
echo "Start recording to /sdcard/screen.mp4"
|
||||
adb shell screenrecord /sdcard/screen.mp4
|
||||
|
||||
echo "Start testing ${{ inputs.maestro-flow }}"
|
||||
$HOME/.maestro/bin/maestro test ${{ inputs.maestro-flow }} --format junit -e APP_ID=${{ inputs.app-id }} --debug-output /tmp/MaestroLogs
|
||||
|
||||
echo "Stop recording. Saving to screen.mp4"
|
||||
adb pull /sdcard/screen.mp4
|
||||
- name: Store tests result
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: e2e_android_${{ steps.normalize-app-id.outputs.app-id }}_report_${{ inputs.jsengine }}_${{ inputs.flavor }}
|
||||
name: e2e_android_${{ inputs.app-id }}_report_${{ inputs.jsengine }}
|
||||
path: |
|
||||
report.xml
|
||||
screen.mp4
|
||||
- name: Store Logs
|
||||
if: failure() && steps.run-tests.outcome == 'failure'
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: maestro-logs-android-${{ steps.normalize-app-id.outputs.app-id }}-${{ inputs.jsengine }}-${{ inputs.flavor }}
|
||||
name: maestro-logs-android-${{ inputs.app-id }}-${{ inputs.jsengine }}
|
||||
path: /tmp/MaestroLogs
|
||||
|
||||
@@ -13,15 +13,6 @@ inputs:
|
||||
maestro-flow:
|
||||
required: true
|
||||
description: the folder that contains the maestro tests
|
||||
flavor:
|
||||
required: true
|
||||
description: Whether we are building for Debug or Release
|
||||
default: Release
|
||||
working-directory:
|
||||
required: false
|
||||
default: "."
|
||||
description: The directory from which metro should be started
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
@@ -38,13 +29,6 @@ runs:
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
- name: Start Metro in Debug
|
||||
shell: bash
|
||||
if: ${{ inputs.flavor == 'Debug' }}
|
||||
run: |
|
||||
cd ${{ inputs.working-directory }}
|
||||
yarn start &
|
||||
sleep 5 # to give metro time to load
|
||||
- name: Run tests
|
||||
id: run-tests
|
||||
shell: bash
|
||||
@@ -69,16 +53,11 @@ runs:
|
||||
echo "Launch the app"
|
||||
xcrun simctl launch $UDID ${{ inputs.app-id }}
|
||||
|
||||
if [[ ${{ inputs.flavor }} == 'Debug' ]]; then
|
||||
# To give the app time to warm the metro's cache
|
||||
sleep 20
|
||||
fi
|
||||
|
||||
echo "Running tests with Maestro"
|
||||
export MAESTRO_DRIVER_STARTUP_TIMEOUT=1500000 # 25 min. CI is extremely slow
|
||||
|
||||
# Add retries for flakyness
|
||||
MAX_ATTEMPTS=5
|
||||
MAX_ATTEMPTS=3
|
||||
CURR_ATTEMPT=0
|
||||
RESULT=1
|
||||
|
||||
@@ -86,8 +65,6 @@ runs:
|
||||
CURR_ATTEMPT=$((CURR_ATTEMPT+1))
|
||||
echo "Attempt number $CURR_ATTEMPT"
|
||||
|
||||
|
||||
|
||||
echo "Start video record using pid: video_record_${{ inputs.jsengine }}_$CURR_ATTEMPT.pid"
|
||||
xcrun simctl io booted recordVideo video_record_$CURR_ATTEMPT.mov & echo $! > video_record_${{ inputs.jsengine }}_$CURR_ATTEMPT.pid
|
||||
|
||||
@@ -103,19 +80,17 @@ runs:
|
||||
exit $RESULT
|
||||
- name: Store video record
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: e2e_ios_${{ inputs.app-id }}_report_${{ inputs.jsengine }}_${{ inputs.flavor }}
|
||||
name: e2e_ios_${{ inputs.app-id }}_report_${{ inputs.jsengine }}
|
||||
path: |
|
||||
video_record_1.mov
|
||||
video_record_2.mov
|
||||
video_record_3.mov
|
||||
video_record_4.mov
|
||||
video_record_5.mov
|
||||
report.xml
|
||||
- name: Store Logs
|
||||
if: failure() && steps.run-tests.outcome == 'failure'
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: maestro-logs-${{ inputs.app-id }}-${{ inputs.jsengine }}-${{ inputs.flavor }}
|
||||
name: maestro-logs-${{ inputs.app-id }}-${{ inputs.jsengine }}
|
||||
path: /tmp/MaestroLogs
|
||||
|
||||
@@ -82,7 +82,7 @@ runs:
|
||||
echo ${{ steps.hermes-version.outputs.version }}
|
||||
|
||||
- name: Upload Hermes artifact
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hermes-workspace
|
||||
path: |
|
||||
|
||||
@@ -8,7 +8,7 @@ runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Setup gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
with:
|
||||
gradle-version: wrapper
|
||||
# We want the Gradle cache to be written only on main/-stable branches run, and only for jobs with `cache-read-only` == false (i.e. `build_android`).
|
||||
|
||||
@@ -20,9 +20,9 @@ runs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: packages/rn-tester/Podfile.lock
|
||||
key: v11-podfilelock-${{ github.job }}-${{ hashfiles('packages/rn-tester/Podfile') }}-${{ hashfiles('/tmp/week_year') }}-${{ inputs.hermes-version }}
|
||||
key: v10-podfilelock-${{ github.job }}-${{ hashfiles('packages/rn-tester/Podfile') }}-${{ hashfiles('/tmp/week_year') }}-${{ inputs.hermes-version}}
|
||||
- name: Cache cocoapods
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: packages/rn-tester/Pods
|
||||
key: v13-cocoapods-${{ github.job }}-${{ hashfiles('packages/rn-tester/Podfile.lock') }}-${{ hashfiles('packages/rn-tester/Podfile') }}-${{ inputs.hermes-version}}
|
||||
key: v12-cocoapods-${{ github.job }}-${{ hashfiles('packages/rn-tester/Podfile.lock') }}-${{ hashfiles('packages/rn-tester/Podfile') }}-${{ inputs.hermes-version}}
|
||||
|
||||
@@ -121,21 +121,21 @@ runs:
|
||||
if: ${{ inputs.run-unit-tests != 'true' && inputs.run-e2e-tests == 'false' }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -o pipefail && xcodebuild build \
|
||||
xcodebuild build \
|
||||
-workspace packages/rn-tester/RNTesterPods.xcworkspace \
|
||||
-scheme RNTester \
|
||||
-sdk iphonesimulator | xcbeautify
|
||||
-sdk iphonesimulator
|
||||
- name: Build RNTester (E2E Tests)
|
||||
shell: bash
|
||||
if: ${{ inputs.run-e2e-tests == 'true' }}
|
||||
run: |
|
||||
set -o pipefail && xcodebuild \
|
||||
xcrun xcodebuild \
|
||||
-scheme "RNTester" \
|
||||
-workspace packages/rn-tester/RNTesterPods.xcworkspace \
|
||||
-configuration "${{ inputs.flavor }}" \
|
||||
-configuration "Release" \
|
||||
-sdk "iphonesimulator" \
|
||||
-destination "generic/platform=iOS Simulator" \
|
||||
-derivedDataPath "/tmp/RNTesterBuild" | xcbeautify
|
||||
-derivedDataPath "/tmp/RNTesterBuild"
|
||||
|
||||
echo "Print path to *.app file"
|
||||
find "/tmp/RNTesterBuild" -type d -name "*.app"
|
||||
@@ -153,14 +153,14 @@ runs:
|
||||
XCRESULT_PATH=$(find . -name '*.xcresult')
|
||||
tar -zcvf xcresults.tar.gz $XCRESULT_PATH
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ inputs.run-unit-tests == 'true' }}
|
||||
with:
|
||||
name: xcresults
|
||||
path: /Users/distiller/Library/Developer/Xcode/xcresults.tar.gz
|
||||
- name: Store test results
|
||||
if: ${{ inputs.run-unit-tests == 'true' }}
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-results
|
||||
path: ./reports/junit
|
||||
|
||||
@@ -19,7 +19,7 @@ runs:
|
||||
run: node ./scripts/run-ci-javascript-tests.js --maxWorkers 2
|
||||
- name: Upload test results
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-js-results
|
||||
compression-level: 1
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
name: test-library-on-nightly
|
||||
description: Tests a library on a nightly
|
||||
inputs:
|
||||
library-npm-package:
|
||||
description: The library npm package to add
|
||||
required: true
|
||||
platform:
|
||||
description: whether we want to build for iOS or Android
|
||||
required: true
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Create new app
|
||||
shell: bash
|
||||
run: |
|
||||
cd /tmp
|
||||
npx @react-native-community/cli init RNApp --skip-install --version nightly
|
||||
- name: Add library
|
||||
shell: bash
|
||||
run: |
|
||||
cd /tmp/RNApp
|
||||
yarn add ${{ inputs.library-npm-package }}
|
||||
|
||||
- name: Build iOS
|
||||
shell: bash
|
||||
if: ${{ inputs.platform == 'ios' }}
|
||||
run: |
|
||||
cd /tmp/RNApp/ios
|
||||
bundle install
|
||||
bundle exec pod install
|
||||
cd ..
|
||||
yarn ios
|
||||
- name: Setup Java for Android
|
||||
if: ${{ inputs.platform == 'android' }}
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
- name: Build Android
|
||||
shell: bash
|
||||
if: ${{ inputs.platform == 'android' }}
|
||||
run: |
|
||||
cd /tmp/RNApp/android
|
||||
./gradlew assembleDebug
|
||||
@@ -1,158 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
const {
|
||||
publishTemplate,
|
||||
verifyPublishedTemplate,
|
||||
} = require('../publishTemplate');
|
||||
|
||||
const mockRun = jest.fn();
|
||||
const mockSleep = jest.fn();
|
||||
const mockGetNpmPackageInfo = jest.fn();
|
||||
const silence = () => {};
|
||||
|
||||
jest.mock('../utils.js', () => ({
|
||||
log: silence,
|
||||
run: mockRun,
|
||||
sleep: mockSleep,
|
||||
getNpmPackageInfo: mockGetNpmPackageInfo,
|
||||
}));
|
||||
|
||||
const getMockGithub = () => ({
|
||||
rest: {
|
||||
actions: {
|
||||
createWorkflowDispatch: jest.fn(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
describe('#publishTemplate', () => {
|
||||
beforeEach(jest.clearAllMocks);
|
||||
|
||||
it('checks commits for magic #publish-package-to-npm&latest string and sets latest', async () => {
|
||||
mockRun.mockReturnValueOnce(`
|
||||
The commit message
|
||||
|
||||
#publish-packages-to-npm&latest`);
|
||||
|
||||
const github = getMockGithub();
|
||||
await publishTemplate(github, '0.76.0', true);
|
||||
expect(github.rest.actions.createWorkflowDispatch).toHaveBeenCalledWith({
|
||||
owner: 'react-native-community',
|
||||
repo: 'template',
|
||||
workflow_id: 'release.yaml',
|
||||
ref: '0.76-stable',
|
||||
inputs: {
|
||||
dry_run: true,
|
||||
is_latest_on_npm: true,
|
||||
version: '0.76.0',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('pubished as is_latest_on_npm = false if missing magic string', async () => {
|
||||
mockRun.mockReturnValueOnce(`
|
||||
The commit message without magic
|
||||
`);
|
||||
|
||||
const github = getMockGithub();
|
||||
await publishTemplate(github, '0.76.0', false);
|
||||
expect(github.rest.actions.createWorkflowDispatch).toHaveBeenCalledWith({
|
||||
owner: 'react-native-community',
|
||||
repo: 'template',
|
||||
workflow_id: 'release.yaml',
|
||||
ref: '0.76-stable',
|
||||
inputs: {
|
||||
dry_run: false,
|
||||
is_latest_on_npm: false,
|
||||
version: '0.76.0',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#verifyPublishedTemplate', () => {
|
||||
beforeEach(jest.clearAllMocks);
|
||||
|
||||
it("waits on npm updating for version and not 'latest'", async () => {
|
||||
const NOT_LATEST = false;
|
||||
mockGetNpmPackageInfo
|
||||
// template@<version>
|
||||
.mockReturnValueOnce(Promise.reject('mock http/404'))
|
||||
.mockReturnValueOnce(Promise.resolve());
|
||||
mockSleep.mockReturnValueOnce(Promise.resolve()).mockImplementation(() => {
|
||||
throw new Error('Should not be called again!');
|
||||
});
|
||||
|
||||
const version = '0.77.0';
|
||||
await verifyPublishedTemplate(version, NOT_LATEST);
|
||||
|
||||
expect(mockGetNpmPackageInfo).toHaveBeenLastCalledWith(
|
||||
'@react-native-community/template',
|
||||
version,
|
||||
);
|
||||
});
|
||||
|
||||
it('waits on npm updating version and latest tag', async () => {
|
||||
const IS_LATEST = true;
|
||||
const version = '0.77.0';
|
||||
mockGetNpmPackageInfo
|
||||
// template@latest → unknown tag
|
||||
.mockReturnValueOnce(Promise.reject('mock http/404'))
|
||||
// template@latest != version → old tag
|
||||
.mockReturnValueOnce(Promise.resolve({version: '0.76.5'}))
|
||||
// template@latest == version → correct tag
|
||||
.mockReturnValueOnce(Promise.resolve({version}));
|
||||
mockSleep
|
||||
.mockReturnValueOnce(Promise.resolve())
|
||||
.mockReturnValueOnce(Promise.resolve())
|
||||
.mockImplementation(() => {
|
||||
throw new Error('Should not be called again!');
|
||||
});
|
||||
|
||||
await verifyPublishedTemplate(version, IS_LATEST);
|
||||
|
||||
expect(mockGetNpmPackageInfo).toHaveBeenCalledWith(
|
||||
'@react-native-community/template',
|
||||
'latest',
|
||||
);
|
||||
});
|
||||
|
||||
describe('timeouts', () => {
|
||||
let mockProcess;
|
||||
beforeEach(() => {
|
||||
mockProcess = jest.spyOn(process, 'exit').mockImplementation(code => {
|
||||
throw new Error(`process.exit(${code}) called!`);
|
||||
});
|
||||
});
|
||||
afterEach(() => mockProcess.mockRestore());
|
||||
it('will timeout if npm does not update package version after a set number of retries', async () => {
|
||||
const RETRIES = 2;
|
||||
mockGetNpmPackageInfo.mockReturnValue(Promise.reject('mock http/404'));
|
||||
mockSleep.mockReturnValue(Promise.resolve());
|
||||
await expect(() =>
|
||||
verifyPublishedTemplate('0.77.0', true, RETRIES),
|
||||
).rejects.toThrowError('process.exit(1) called!');
|
||||
expect(mockGetNpmPackageInfo).toHaveBeenCalledTimes(RETRIES);
|
||||
});
|
||||
|
||||
it('will timeout if npm does not update latest tag after a set number of retries', async () => {
|
||||
const RETRIES = 7;
|
||||
const IS_LATEST = true;
|
||||
mockGetNpmPackageInfo.mockReturnValue(
|
||||
Promise.resolve({version: '0.76.5'}),
|
||||
);
|
||||
mockSleep.mockReturnValue(Promise.resolve());
|
||||
await expect(async () => {
|
||||
await verifyPublishedTemplate('0.77.0', IS_LATEST, RETRIES);
|
||||
}).rejects.toThrowError('process.exit(1) called!');
|
||||
expect(mockGetNpmPackageInfo).toHaveBeenCalledTimes(RETRIES);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -48,84 +48,96 @@ module.exports = async (github, context, labelWithContext) => {
|
||||
switch (labelWithContext.label) {
|
||||
case 'Type: Invalid':
|
||||
await addComment(
|
||||
`> [!CAUTION]` +
|
||||
`> **Invalid issue**: This issue is not valid, either is not a bug in React Native, it doesn't match any of the issue template, or we can't help further with this.`,
|
||||
`| :warning: | Issue is Invalid |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | This issue doesn't match any of the expected types for this repository - closing. |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Type: Question':
|
||||
await addComment(
|
||||
`> [!NOTE]` +
|
||||
`> **Not a bug report**: This issue looks like a question. We are using GitHub issues exclusively to track bugs in React Native. GitHub may not be the ideal place to ask a question, but you can try asking over on [Stack Overflow](http://stackoverflow.com/questions/tagged/react-native), or on [Reactiflux](https://www.reactiflux.com/).`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Resolution: For Stack Overflow':
|
||||
await addComment(
|
||||
`> [!NOTE]` +
|
||||
`> **Not a bug report**: This issue looks like a question. We are using GitHub issues exclusively to track bugs in React Native. GitHub may not be the ideal place to ask a question, but you can try asking over on [Stack Overflow](http://stackoverflow.com/questions/tagged/react-native), or on [Reactiflux](https://www.reactiflux.com/).`,
|
||||
`| :warning: | Issue is a Question |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | We are using GitHub issues exclusively to track bugs in React Native. GitHub may not be the ideal place to ask a question, but you can try asking over on [Stack Overflow](http://stackoverflow.com/questions/tagged/react-native), or on [Reactiflux](https://www.reactiflux.com/). |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Type: Docs':
|
||||
await addComment(
|
||||
`> [!NOTE]` +
|
||||
`> **Docs issue**: This issue looks like an issue related to our docs. Please report documentation issues in the [react-native-website](https://github.com/facebook/react-native-website/issues) repository.`,
|
||||
`| :warning: | Documentation Issue |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | Please report documentation issues in the [react-native-website](https://github.com/facebook/react-native-website/issues) repository. |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Resolution: For Stack Overflow':
|
||||
await addComment(
|
||||
`| :warning: | Issue is a Question |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | We are using GitHub issues exclusively to track bugs in the core React Native library. Please try asking over on [Stack Overflow](http://stackoverflow.com/questions/tagged/react-native) as it is better suited for this type of question. |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Type: Expo':
|
||||
await addComment(
|
||||
`> [!NOTE]` +
|
||||
`> **Expo related**: It looks like your issue is related to Expo and not React Native core. Please open your issue in [Expo's repository](https://github.com/expo/expo/issues/new). If you are able to create a repro that showcases that this issue is also happening in React Native vanilla, we will be happy to re-open.`,
|
||||
`| :warning: | Issue is Related to Expo |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | It looks like your issue is related to Expo and not React Native core. Please open your issue in [Expo's repository](https://github.com/expo/expo/issues/new). If you are able to create a repro that showcases that this issue is also happening in React Native vanilla, we will be happy to re-open. |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
case 'Needs: Issue Template':
|
||||
await addComment(
|
||||
`> [!WARNING]` +
|
||||
`> **Missing issue template**: It looks like your issue may be missing some necessary information. GitHub provides an example template whenever a [new issue is created](https://github.com/facebook/react-native/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A&projects=&template=bug_report.yml). Could you go back and make sure to fill out the template? You may edit this issue, or close it and open a new one.`,
|
||||
`| :warning: | Missing Required Fields |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | It looks like your issue may be missing some necessary information. GitHub provides an example template whenever a [new issue is created](https://github.com/facebook/react-native/issues/new?template=bug_report.md). Could you go back and make sure to fill out the template? You may edit this issue, or close it and open a new one. |`,
|
||||
);
|
||||
await requestAuthorFeedback();
|
||||
return;
|
||||
case 'Needs: Environment Info':
|
||||
await addComment(
|
||||
`> [!WARNING]` +
|
||||
`> **Missing info**: It looks like your issue may be missing information about your development environment. You can obtain the missing information by running <code>react-native info</code> in a console.`,
|
||||
`| :warning: | Missing Environment Information |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | Your issue may be missing information about your development environment. You can obtain the missing information by running <code>react-native info</code> in a console. |`,
|
||||
);
|
||||
await requestAuthorFeedback();
|
||||
return;
|
||||
case 'Newer Patch Available':
|
||||
await addComment(
|
||||
`> [!TIP]` +
|
||||
`> **Newer version available**: You are on a supported minor version, but it looks like there's a newer patch available - ${labelWithContext.newestPatch}. Please [upgrade](https://reactnative.dev/docs/upgrading) to the highest patch for your minor or latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If it does not repro, please let us know so we can close out this issue. This helps us ensure we are looking at issues that still exist in the most recent releases.`,
|
||||
`| :warning: | Newer Version of React Native is Available! |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | You are on a supported minor version, but it looks like there's a newer patch available - ${labelWithContext.newestPatch}. Please [upgrade](https://reactnative.dev/docs/upgrading) to the highest patch for your minor or latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If it does not repro, please let us know so we can close out this issue. This helps us ensure we are looking at issues that still exist in the most recent releases. |`,
|
||||
);
|
||||
return;
|
||||
case 'Needs: Version Info':
|
||||
await addComment(
|
||||
`> [!WARNING]` +
|
||||
`> **Could not parse version**: We could not find or parse the version number of React Native in your issue report. Please use the template, and report your version including major, minor, and patch numbers - e.g. 0.76.2.`,
|
||||
`| :warning: | Add or Reformat Version Info |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | We could not find or parse the version number of React Native in your issue report. Please use the template, and report your version including major, minor, and patch numbers - e.g. 0.70.2 |`,
|
||||
);
|
||||
await requestAuthorFeedback();
|
||||
return;
|
||||
case 'Needs: Repro':
|
||||
await addComment(
|
||||
`> [!WARNING]` +
|
||||
`> **Missing reproducer**: We could not detect a reproducible example in your issue report. Please provide either: <br/><ul><li>If your bug is UI related: a [Snack](https://snack.expo.dev)</li><li> If your bug is build/upgrade related: a project using our [Reproducer Template](https://github.com/react-native-community/reproducer-react-native/generate)</li><li>Otherwise send us a Pull Request with the [RNTesterPlayground.js](https://github.com/facebook/react-native/blob/main/packages/rn-tester/js/examples/Playground/RNTesterPlayground.js) edited to reproduce your bug.</li></ul>`,
|
||||
`| :warning: | Missing Reproducible Example |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | We could not detect a reproducible example in your issue report. Please provide either: <br /><ul><li>If your bug is UI related: a [Snack](https://snack.expo.dev)</li><li> If your bug is build/update related: use our [Reproducer Template](https://github.com/react-native-community/reproducer-react-native/generate)</li></ul> |`,
|
||||
);
|
||||
await requestAuthorFeedback();
|
||||
return;
|
||||
case 'Type: Unsupported Version':
|
||||
await addComment(
|
||||
`> [!WARNING]` +
|
||||
`> **Unsupported version**: It looks like your issue or the example you provided uses an [unsupported version of React Native](https://github.com/reactwg/react-native-releases/blob/main/docs/support.md).<br/><br/>Due to the number of issues we receive, we're currently only accepting new issues against one of the supported versions. Please [upgrade](https://reactnative.dev/docs/upgrading) to latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If you cannot upgrade, please open your issue on [StackOverflow](https://stackoverflow.com/questions/tagged/react-native) to get further community support.`,
|
||||
`| :warning: | Unsupported Version of React Native |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | It looks like your issue or the example you provided uses an [unsupported version of React Native](https://github.com/reactwg/react-native-releases/blob/main/README.md#releases-support-policy).<br/><br/>Due to the number of issues we receive, we're currently only accepting new issues against one of the supported versions. Please [upgrade](https://reactnative.dev/docs/upgrading) to latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If you cannot upgrade, please open your issue on [StackOverflow](https://stackoverflow.com/questions/tagged/react-native) to get further community support. |`,
|
||||
);
|
||||
await requestAuthorFeedback();
|
||||
return;
|
||||
case 'Type: Too Old Version':
|
||||
await addComment(
|
||||
`> [!CAUTION]` +
|
||||
`> **Too old version**: It looks like your issue or the example you provided uses a [**Too Old Version of React Native**](https://github.com/reactwg/react-native-releases/blob/main/docs/support.md).<br/><br/>Due to the number of issues we receive, we're currently only accepting new issues against one of the supported versions. Please [upgrade](https://reactnative.dev/docs/upgrading) to latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If you cannot upgrade, please open your issue on [StackOverflow](https://stackoverflow.com/questions/tagged/react-native) to get further community support.`,
|
||||
`| :warning: | Too Old Version of React Native |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | It looks like your issue or the example you provided uses a [**Too Old Version of React Native**](https://github.com/reactwg/react-native-releases/blob/main/README.md#releases-support-policy).<br/><br/>Due to the number of issues we receive, we're currently only accepting new issues against one of the supported versions. Please [upgrade](https://reactnative.dev/docs/upgrading) to latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If you cannot upgrade, please open your issue on [StackOverflow](https://stackoverflow.com/questions/tagged/react-native) to get further community support. |`,
|
||||
);
|
||||
await closeIssue();
|
||||
return;
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
|
||||
const NEEDS_REPRO_LABEL = 'Needs: Repro';
|
||||
const NEEDS_AUTHOR_FEEDBACK_LABEL = 'Needs: Author Feedback';
|
||||
const NEEDS_REPRO_HEADER = 'Missing Reproducible Example';
|
||||
const NEEDS_REPRO_MESSAGE =
|
||||
`| :warning: | Missing Reproducible Example |\n` +
|
||||
`| --- | --- |\n` +
|
||||
`| :information_source: | We could not detect a reproducible example in your issue report. Please provide either: <br /><ul><li>If your bug is UI related: a [Snack](https://snack.expo.dev)</li><li> If your bug is build/update related: use our [Reproducer Template](https://github.com/react-native-community/reproducer-react-native/generate). A reproducer needs to be in a GitHub repository under your username.</li></ul> |`;
|
||||
const SKIP_ISSUES_OLDER_THAN = '2023-07-01T00:00:00Z';
|
||||
|
||||
module.exports = async (github, context) => {
|
||||
@@ -20,6 +25,7 @@ module.exports = async (github, context) => {
|
||||
|
||||
const issue = await github.rest.issues.get(issueData);
|
||||
const comments = await github.rest.issues.listComments(issueData);
|
||||
|
||||
const author = issue.data.user.login;
|
||||
|
||||
const issueDate = issue.data.created_at;
|
||||
@@ -37,6 +43,10 @@ module.exports = async (github, context) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const botComment = comments.data.find(comment =>
|
||||
comment.body.includes(NEEDS_REPRO_HEADER),
|
||||
);
|
||||
|
||||
const entities = [issue.data, ...comments.data];
|
||||
|
||||
// Look for Snack or a GH repo associated with the user that added an issue or comment
|
||||
@@ -64,11 +74,25 @@ module.exports = async (github, context) => {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!botComment) return;
|
||||
|
||||
await github.rest.issues.deleteComment({
|
||||
...issueData,
|
||||
comment_id: botComment.id,
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.addLabels({
|
||||
...issueData,
|
||||
labels: [NEEDS_REPRO_LABEL, NEEDS_AUTHOR_FEEDBACK_LABEL],
|
||||
});
|
||||
|
||||
if (botComment) return;
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
...issueData,
|
||||
body: NEEDS_REPRO_MESSAGE,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -77,7 +101,7 @@ function containsPattern(body, pattern) {
|
||||
return body.search(regexp) !== -1;
|
||||
}
|
||||
|
||||
// Prevents the bot from responding when maintainer has changed the 'Needs: Repro' label
|
||||
// Prevents the bot from responding when maintainer has changed Needs: Repro the label
|
||||
async function hasMaintainerChangedLabel(github, issueData, author) {
|
||||
const timeline = await github.rest.issues.listEventsForTimeline(issueData);
|
||||
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
const childProcess = require('child_process');
|
||||
|
||||
const usage = `
|
||||
=== Usage ===
|
||||
node maestro-android.js <path to app> <app_id> <maestro_flow> <flavor> <working_directory>
|
||||
|
||||
@param {string} appPath - Path to the app APK
|
||||
@param {string} appId - App ID that needs to be launched
|
||||
@param {string} maestroFlow - Path to the maestro flow to be executed
|
||||
@param {string} flavor - Flavor of the app to be launched. Can be 'release' or 'debug'
|
||||
@param {string} workingDirectory - Working directory from where to run Metro
|
||||
==============
|
||||
`;
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
if (args.length !== 5) {
|
||||
throw new Error(`Invalid number of arguments.\n${usage}`);
|
||||
}
|
||||
|
||||
const APP_PATH = args[0];
|
||||
const APP_ID = args[1];
|
||||
const MAESTRO_FLOW = args[2];
|
||||
const IS_DEBUG = args[3] === 'debug';
|
||||
const WORKING_DIRECTORY = args[4];
|
||||
|
||||
async function main() {
|
||||
console.info('\n==============================');
|
||||
console.info('Running tests for Android with the following parameters:');
|
||||
console.info(`APP_PATH: ${APP_PATH}`);
|
||||
console.info(`APP_ID: ${APP_ID}`);
|
||||
console.info(`MAESTRO_FLOW: ${MAESTRO_FLOW}`);
|
||||
console.info(`IS_DEBUG: ${IS_DEBUG}`);
|
||||
console.info(`WORKING_DIRECTORY: ${WORKING_DIRECTORY}`);
|
||||
console.info('==============================\n');
|
||||
|
||||
console.info('Install app');
|
||||
childProcess.execSync(`adb install ${APP_PATH}`, {stdio: 'ignore'});
|
||||
|
||||
let metroProcess = null;
|
||||
if (IS_DEBUG) {
|
||||
console.info('Start Metro');
|
||||
childProcess.execSync(`cd ${WORKING_DIRECTORY}`, {stdio: 'ignore'});
|
||||
metroProcess = childProcess.spawn('yarn', ['start', '&'], {
|
||||
cwd: WORKING_DIRECTORY,
|
||||
stdio: 'ignore',
|
||||
detached: true,
|
||||
});
|
||||
console.info(`- Metro PID: ${metroProcess.pid}`);
|
||||
}
|
||||
|
||||
console.info('Wait For Metro to Start');
|
||||
await sleep(5000);
|
||||
|
||||
console.info('Start the app');
|
||||
childProcess.execSync(`adb shell monkey -p ${APP_ID} 1`, {stdio: 'ignore'});
|
||||
|
||||
console.info('Start recording to /sdcard/screen.mp4');
|
||||
childProcess
|
||||
.exec('adb shell screenrecord /sdcard/screen.mp4', {
|
||||
stdio: 'ignore',
|
||||
detached: true,
|
||||
})
|
||||
.unref();
|
||||
|
||||
console.info(`Start testing ${MAESTRO_FLOW}`);
|
||||
let error = null;
|
||||
try {
|
||||
childProcess.execSync(
|
||||
`MAESTRO_DRIVER_STARTUP_TIMEOUT=120000 $HOME/.maestro/bin/maestro test ${MAESTRO_FLOW} --format junit -e APP_ID=${APP_ID} --debug-output /tmp/MaestroLogs`,
|
||||
{stdio: 'inherit'},
|
||||
);
|
||||
} catch (err) {
|
||||
error = err;
|
||||
} finally {
|
||||
console.info('Stop recording');
|
||||
childProcess.execSync('adb pull /sdcard/screen.mp4', {stdio: 'ignore'});
|
||||
|
||||
if (IS_DEBUG && metroProcess != null) {
|
||||
const pid = metroProcess.pid;
|
||||
console.info(`Kill Metro. PID: ${pid}`);
|
||||
process.kill(-pid);
|
||||
console.info(`Metro Killed`);
|
||||
process.exit();
|
||||
}
|
||||
}
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,103 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
const {run, sleep, getNpmPackageInfo, log} = require('./utils.js');
|
||||
|
||||
const TAG_AS_LATEST_REGEX = /#publish-packages-to-npm&latest/;
|
||||
|
||||
/**
|
||||
* Should this commit be `latest` on npm?
|
||||
*/
|
||||
function isLatest() {
|
||||
const commitMessage = run('git log -n1 --pretty=%B');
|
||||
return TAG_AS_LATEST_REGEX.test(commitMessage);
|
||||
}
|
||||
module.exports.isLatest = isLatest;
|
||||
|
||||
/**
|
||||
* Create a Github Action to publish the community template matching the released version
|
||||
* of React Native.
|
||||
*/
|
||||
module.exports.publishTemplate = async (github, version, dryRun = true) => {
|
||||
log(`📤 Get the ${TEMPLATE_NPM_PKG} repo to publish ${version}`);
|
||||
|
||||
const is_latest_on_npm = isLatest();
|
||||
|
||||
const majorMinor = /^v?(\d+\.\d+)/.exec(version);
|
||||
|
||||
if (!majorMinor) {
|
||||
log(`🔥 can't capture MAJOR.MINOR from '${version}', giving up.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// MAJOR.MINOR-stable
|
||||
const ref = `${majorMinor[1]}-stable`;
|
||||
|
||||
await github.rest.actions.createWorkflowDispatch({
|
||||
owner: 'react-native-community',
|
||||
repo: 'template',
|
||||
workflow_id: 'release.yaml',
|
||||
ref,
|
||||
inputs: {
|
||||
dry_run: dryRun,
|
||||
is_latest_on_npm,
|
||||
// 0.75.0-rc.0, note no 'v' prefix
|
||||
version: version.replace(/^v/, ''),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const SLEEP_S = 10;
|
||||
const MAX_RETRIES = 3 * 6; // 3 minutes
|
||||
const TEMPLATE_NPM_PKG = '@react-native-community/template';
|
||||
|
||||
/**
|
||||
* Will verify that @latest and the @<version> have been published.
|
||||
*
|
||||
* NOTE: This will infinitely query each step until successful, make sure the
|
||||
* calling job has a timeout.
|
||||
*/
|
||||
module.exports.verifyPublishedTemplate = async (
|
||||
version,
|
||||
latest = false,
|
||||
retries = MAX_RETRIES,
|
||||
) => {
|
||||
log(`🔍 Is ${TEMPLATE_NPM_PKG}@${version} on npm?`);
|
||||
|
||||
let count = retries;
|
||||
while (count-- > 0) {
|
||||
try {
|
||||
const json = await getNpmPackageInfo(
|
||||
TEMPLATE_NPM_PKG,
|
||||
latest ? 'latest' : version,
|
||||
);
|
||||
log(`🎉 Found ${TEMPLATE_NPM_PKG}@${version} on npm`);
|
||||
if (!latest) {
|
||||
return;
|
||||
}
|
||||
if (json.version === version) {
|
||||
log(`🎉 ${TEMPLATE_NPM_PKG}@latest → ${version} on npm`);
|
||||
return;
|
||||
}
|
||||
log(
|
||||
`🐌 ${TEMPLATE_NPM_PKG}@latest → ${pkg.version} on npm and not ${version} as expected, retrying...`,
|
||||
);
|
||||
} catch (e) {
|
||||
log(`Nope, fetch failed: ${e.message}`);
|
||||
}
|
||||
await sleep(SLEEP_S);
|
||||
}
|
||||
|
||||
let msg = `🚨 Timed out when trying to verify ${TEMPLATE_NPM_PKG}@${version} on npm`;
|
||||
if (latest) {
|
||||
msg += ' and latest tag points to this version.';
|
||||
}
|
||||
log(msg);
|
||||
process.exit(1);
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
const {execSync} = require('child_process');
|
||||
|
||||
function run(cmd) {
|
||||
return execSync(cmd, 'utf8').toString().trim();
|
||||
}
|
||||
module.exports.run = run;
|
||||
|
||||
async function sleep(seconds) {
|
||||
return new Promise(resolve => setTimeout(resolve, seconds * 1000));
|
||||
}
|
||||
module.exports.sleep = sleep;
|
||||
|
||||
async function getNpmPackageInfo(pkg, versionOrTag) {
|
||||
return fetch(`https://registry.npmjs.org/${pkg}/${versionOrTag}`).then(resp =>
|
||||
resp.json(),
|
||||
);
|
||||
}
|
||||
module.exports.getNpmPackageInfo = getNpmPackageInfo;
|
||||
|
||||
module.exports.log = (...args) => console.log(...args);
|
||||
@@ -10,6 +10,11 @@
|
||||
module.exports = async (github, context) => {
|
||||
const issue = context.payload.issue;
|
||||
|
||||
// Ignore issues using upgrade template (they use a special label)
|
||||
if (issue.labels.find(label => label.name === 'Type: Upgrade Issue')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const issueVersionUnparsed =
|
||||
getReactNativeVersionFromIssueBodyIfExists(issue);
|
||||
const issueVersion = parseVersionFromString(issueVersionUnparsed);
|
||||
|
||||
@@ -8,7 +8,6 @@ on:
|
||||
|
||||
jobs:
|
||||
cache-cleaner:
|
||||
if: github.repository == 'facebook/react-native'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -24,5 +24,3 @@ jobs:
|
||||
else
|
||||
echo 'Nightly Worked, All Good!'
|
||||
fi
|
||||
- name: Test Libraries
|
||||
uses: ./.github/workflows/test-libraries-on-nightlies.yml
|
||||
|
||||
@@ -15,7 +15,7 @@ on:
|
||||
dry-run:
|
||||
description: "Whether the job should be executed in dry-run mode or not"
|
||||
type: boolean
|
||||
default: true
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
create_release:
|
||||
@@ -25,8 +25,6 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
|
||||
fetch-depth: 0
|
||||
fetch-tags: 'true'
|
||||
- name: Check if on stable branch
|
||||
id: check_stable_branch
|
||||
run: |
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
name: "Validate Gradle Wrapper"
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
validation:
|
||||
name: "Validation"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: gradle/actions/wrapper-validation@v3
|
||||
@@ -60,14 +60,14 @@ jobs:
|
||||
HERMES_WS_DIR: /tmp/hermes
|
||||
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
|
||||
HERMES_OSXBIN_ARTIFACTS_DIR: /tmp/hermes/osx-bin
|
||||
IOS_DEPLOYMENT_TARGET: "15.1"
|
||||
IOS_DEPLOYMENT_TARGET: "13.4"
|
||||
XROS_DEPLOYMENT_TARGET: "1.0"
|
||||
MAC_DEPLOYMENT_TARGET: "10.15"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
flavor: [Debug, Release]
|
||||
slice: [macosx, iphoneos, iphonesimulator, appletvos, appletvsimulator, catalyst, xros, xrsimulator]
|
||||
slice: [macosx, iphoneos, iphonesimulator, catalyst, xros, xrsimulator]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
@@ -57,14 +57,14 @@ jobs:
|
||||
HERMES_WS_DIR: /tmp/hermes
|
||||
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
|
||||
HERMES_OSXBIN_ARTIFACTS_DIR: /tmp/hermes/osx-bin
|
||||
IOS_DEPLOYMENT_TARGET: "15.1"
|
||||
IOS_DEPLOYMENT_TARGET: "13.4"
|
||||
XROS_DEPLOYMENT_TARGET: "1.0"
|
||||
MAC_DEPLOYMENT_TARGET: "10.15"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
flavor: [Debug, Release]
|
||||
slice: [macosx, iphoneos, iphonesimulator, appletvos, appletvsimulator, catalyst, xros, xrsimulator]
|
||||
slice: [macosx, iphoneos, iphonesimulator, catalyst, xros, xrsimulator]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -180,9 +180,6 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
- name: Build and Publish NPM PAckage
|
||||
uses: ./.github/actions/build-npm-package
|
||||
with:
|
||||
@@ -191,23 +188,46 @@ jobs:
|
||||
gha-npm-token: ${{ env.GHA_NPM_TOKEN }}
|
||||
- name: Publish @react-native-community/template
|
||||
id: publish-template-to-npm
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
|
||||
script: |
|
||||
const {publishTemplate} = require('./.github/workflow-scripts/publishTemplate.js')
|
||||
const version = "${{ github.ref_name }}"
|
||||
const isDryRun = false
|
||||
await publishTemplate(github, version, isDryRun);
|
||||
shell: bash
|
||||
run: |
|
||||
COMMIT_MSG=$(git log -n1 --pretty=%B);
|
||||
if grep -q '#publish-packages-to-npm&latest' <<< "$COMMIT_MSG"; then
|
||||
echo "TAG=latest" >> $GITHUB_OUTPUT
|
||||
IS_LATEST=true
|
||||
else
|
||||
IS_LATEST=false
|
||||
fi
|
||||
# Go from v0.75.0-rc.4 -> 0.75-stable, which is the template's branching scheme
|
||||
VERSION=$(grep -oE '\d+\.\d+' <<< "${{ github.ref_name }}" | { read version; echo "$version-stable"; })
|
||||
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
curl -L -X POST https://api.github.com/repos/react-native-community/template/release.yaml/dispatches \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: Bearer $REACT_NATIVE_BOT_GITHUB_TOKEN" \
|
||||
-d "{\"ref\":\"$VERSION\",\"inputs\":{\"version\":\"${{ github.ref_name }}\",\"is_latest_on_npm\":\"$IS_LATEST\"}}\n"
|
||||
- name: Wait for template to be published
|
||||
timeout-minutes: 3
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
|
||||
script: |
|
||||
const {verifyPublishedTemplate, isLatest} = require('./.github/workflow-scripts/publishTemplate.js')
|
||||
const version = "${{ github.ref_name }}"
|
||||
await verifyPublishedTemplate(version, isLatest());
|
||||
env:
|
||||
VERSION: ${{ steps.publish-template-to-npm.outputs.VERSION }}
|
||||
TAG: ${{ steps.publish-template-to-npm.outputs.TAG }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Waiting until @react-native-community/template is published to npm"
|
||||
while true; do
|
||||
if curl -o /dev/null -s -f "https://registry.npmjs.org/@react-native-community/template/$VERSION"; then
|
||||
echo "Confirm that @react-native-community/template@$VERSION is published on npm"
|
||||
break
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
while [ "$TAG" == "latest" ]; do
|
||||
CURRENT=$(curl -s "https://registry.npmjs.org/react-native/latest" | jq -r '.version');
|
||||
if [ "$CURRENT" == "$VERSION" ]; then
|
||||
echo "Confirm that @react-native-community/template@latest == $VERSION on npm"
|
||||
break
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
- name: Update rn-diff-purge to generate upgrade-support diff
|
||||
run: |
|
||||
curl -X POST https://api.github.com/repos/react-native-community/rn-diff-purge/dispatches \
|
||||
|
||||
@@ -2,17 +2,16 @@ name: Test All
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
run-e2e-tests:
|
||||
description: Whether to run E2E tests or not
|
||||
type: boolean
|
||||
default: false
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "*-stable"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true # cancel previous runs
|
||||
|
||||
jobs:
|
||||
set_release_type:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -35,8 +34,6 @@ jobs:
|
||||
echo "RELEASE_TYPE=dry-run" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
echo "Should I run E2E tests? ${{ inputs.run-e2e-tests }}"
|
||||
|
||||
prepare_hermes_workspace:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
@@ -76,14 +73,14 @@ jobs:
|
||||
HERMES_WS_DIR: /tmp/hermes
|
||||
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
|
||||
HERMES_OSXBIN_ARTIFACTS_DIR: /tmp/hermes/osx-bin
|
||||
IOS_DEPLOYMENT_TARGET: "15.1"
|
||||
IOS_DEPLOYMENT_TARGET: "13.4"
|
||||
XROS_DEPLOYMENT_TARGET: "1.0"
|
||||
MAC_DEPLOYMENT_TARGET: "10.15"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
flavor: [Debug, Release]
|
||||
slice: [macosx, iphoneos, iphonesimulator, appletvos, appletvsimulator, catalyst, xros, xrsimulator]
|
||||
slice: [macosx, iphoneos, iphonesimulator, catalyst, xros, xrsimulator]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -183,8 +180,8 @@ jobs:
|
||||
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
|
||||
|
||||
test_e2e_ios_rntester:
|
||||
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') || inputs.run-e2e-tests }}
|
||||
runs-on: macos-13-large
|
||||
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') }}
|
||||
runs-on: macos-13
|
||||
needs:
|
||||
[build_apple_slices_hermes, prepare_hermes_workspace, build_hermes_macos]
|
||||
env:
|
||||
@@ -196,7 +193,6 @@ jobs:
|
||||
matrix:
|
||||
jsengine: [Hermes, JSC]
|
||||
architecture: [NewArch]
|
||||
flavor: [Debug, Release]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -210,19 +206,19 @@ jobs:
|
||||
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
|
||||
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
|
||||
run-e2e-tests: "true"
|
||||
flavor: ${{ matrix.flavor }}
|
||||
- name: Run E2E Tests
|
||||
uses: ./.github/actions/maestro-ios
|
||||
with:
|
||||
app-path: "/tmp/RNTesterBuild/Build/Products/${{ matrix.flavor }}-iphonesimulator/RNTester.app"
|
||||
app-path: "/tmp/RNTesterBuild/Build/Products/Release-iphonesimulator/RNTester.app"
|
||||
app-id: com.meta.RNTester.localDevelopment
|
||||
jsengine: ${{ matrix.jsengine }}
|
||||
maestro-flow: ./packages/rn-tester/.maestro/
|
||||
flavor: ${{ matrix.flavor }}
|
||||
|
||||
test_e2e_ios_templateapp:
|
||||
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') || inputs.run-e2e-tests }}
|
||||
runs-on: macos-13-large
|
||||
# Template is not compatible with main anymore. We need to find a better strategy to test the template e2e
|
||||
# if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') }}
|
||||
if: ${{ contains(github.ref, 'stable') }}
|
||||
runs-on: macos-13
|
||||
needs: build_npm_package
|
||||
env:
|
||||
HERMES_WS_DIR: /tmp/hermes
|
||||
@@ -232,7 +228,6 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
jsengine: [Hermes, JSC]
|
||||
flavor: [Debug, Release]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -249,7 +244,7 @@ jobs:
|
||||
- name: Download Hermes
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: hermes-darwin-bin-${{matrix.flavor}}
|
||||
name: hermes-darwin-bin-Release
|
||||
path: /tmp/react-native-tmp
|
||||
- name: Download React Native Package
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -266,46 +261,39 @@ jobs:
|
||||
HERMES_PATH=$(find /tmp/react-native-tmp -type f -name "*.tar.gz")
|
||||
echo "Hermes path is $HERMES_PATH"
|
||||
|
||||
# For stable branches, we want to use the stable branch of the template
|
||||
# In all the other cases, we want to use "main"
|
||||
BRANCH=${{ github.ref_name }}
|
||||
if ! [[ $BRANCH == *-stable* ]]; then
|
||||
BRANCH=main
|
||||
fi
|
||||
|
||||
node ./scripts/e2e/init-project-e2e.js --projectName RNTestProject --currentBranch $BRANCH --directory /tmp/RNTestProject --pathToLocalReactNative $REACT_NATIVE_PKG
|
||||
# TODO: from next/latest/main convert to branch
|
||||
node ./scripts/e2e/init-project-e2e.js --projectName RNTestProject --currentBranch 0.75-stable --directory /tmp/RNTestProject --pathToLocalReactNative $REACT_NATIVE_PKG
|
||||
|
||||
cd /tmp/RNTestProject/ios
|
||||
bundle install
|
||||
HERMES_ENGINE_TARBALL_PATH=$HERMES_PATH bundle exec pod install
|
||||
|
||||
xcodebuild \
|
||||
xcrun xcodebuild \
|
||||
-scheme "RNTestProject" \
|
||||
-workspace RNTestProject.xcworkspace \
|
||||
-configuration "${{ matrix.flavor }}" \
|
||||
-configuration "Release" \
|
||||
-sdk "iphonesimulator" \
|
||||
-destination "generic/platform=iOS Simulator" \
|
||||
-derivedDataPath "/tmp/RNTestProject"
|
||||
- name: Run E2E Tests
|
||||
uses: ./.github/actions/maestro-ios
|
||||
with:
|
||||
app-path: "/tmp/RNTestProject/Build/Products/${{ matrix.flavor }}-iphonesimulator/RNTestProject.app"
|
||||
app-path: "/tmp/RNTestProject/Build/Products/Release-iphonesimulator/RNTestProject.app"
|
||||
app-id: org.reactjs.native.example.RNTestProject
|
||||
jsengine: ${{ matrix.jsengine }}
|
||||
maestro-flow: ./scripts/e2e/.maestro/
|
||||
flavor: ${{ matrix.flavor }}
|
||||
working-directory: /tmp/RNTestProject
|
||||
|
||||
test_e2e_android_templateapp:
|
||||
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') || inputs.run-e2e-tests }}
|
||||
runs-on: 4-core-ubuntu
|
||||
# Template is not compatible with main anymore. We need to find a better strategy to test the template e2e
|
||||
# if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') }}
|
||||
if: ${{ contains(github.ref, 'stable') }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: build_npm_package
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
jsengine: [Hermes, JSC]
|
||||
flavor: [debug, release]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -331,7 +319,6 @@ jobs:
|
||||
- name: Print /tmp folder
|
||||
run: ls -lR /tmp/react-native-tmp
|
||||
- name: Prepare artifacts
|
||||
id: prepare-artifacts
|
||||
run: |
|
||||
REACT_NATIVE_PKG=$(find /tmp/react-native-tmp -type f -name "*.tgz")
|
||||
echo "React Native tgs is $REACT_NATIVE_PKG"
|
||||
@@ -339,13 +326,8 @@ jobs:
|
||||
MAVEN_LOCAL=/tmp/react-native-tmp/maven-local
|
||||
echo "Maven local path is $MAVEN_LOCAL"
|
||||
|
||||
# For stable branches, we want to use the stable branch of the template
|
||||
# In all the other cases, we want to use "main"
|
||||
BRANCH=${{ github.ref_name }}
|
||||
if ! [[ $BRANCH == *-stable* ]]; then
|
||||
BRANCH=main
|
||||
fi
|
||||
node ./scripts/e2e/init-project-e2e.js --projectName RNTestProject --currentBranch $BRANCH --directory /tmp/RNTestProject --pathToLocalReactNative $REACT_NATIVE_PKG
|
||||
# TODO: from next/latest/main convert to branch
|
||||
node ./scripts/e2e/init-project-e2e.js --projectName RNTestProject --currentBranch 0.75-stable --directory /tmp/RNTestProject --pathToLocalReactNative $REACT_NATIVE_PKG
|
||||
|
||||
echo "Feed maven local to gradle.properties"
|
||||
cd /tmp/RNTestProject
|
||||
@@ -353,19 +335,15 @@ jobs:
|
||||
|
||||
# Build
|
||||
cd android
|
||||
CAPITALIZED_FLAVOR=$(echo "${{ matrix.flavor }}" | awk '{print toupper(substr($0, 1, 1)) substr($0, 2)}')
|
||||
./gradlew assemble$CAPITALIZED_FLAVOR --no-daemon -PreactNativeArchitectures=x86
|
||||
|
||||
./gradlew assembleRelease --no-daemon -PreactNativeArchitectures=x86
|
||||
- name: Run E2E Tests
|
||||
uses: ./.github/actions/maestro-android
|
||||
with:
|
||||
app-path: /tmp/RNTestProject/android/app/build/outputs/apk/${{ matrix.flavor }}/app-${{ matrix.flavor }}.apk
|
||||
app-path: /tmp/RNTestProject/android/app/build/outputs/apk/release/app-release.apk
|
||||
app-id: com.rntestproject
|
||||
jsengine: ${{ matrix.jsengine }}
|
||||
maestro-flow: ./scripts/e2e/.maestro/
|
||||
install-java: 'false'
|
||||
flavor: ${{ matrix.flavor }}
|
||||
working-directory: /tmp/RNTestProject
|
||||
|
||||
build_hermesc_linux:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -418,17 +396,16 @@ jobs:
|
||||
uses: ./.github/actions/build-android
|
||||
with:
|
||||
release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
|
||||
run-e2e-tests: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') || inputs.run-e2e-tests }}
|
||||
run-e2e-tests: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') }}
|
||||
|
||||
test_e2e_android_rntester:
|
||||
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') || inputs.run-e2e-tests }}
|
||||
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build_android]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
jsengine: [hermes, jsc]
|
||||
flavor: [debug, release]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -439,18 +416,17 @@ jobs:
|
||||
- name: Download APK
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: rntester-${{ matrix.jsengine }}-${{ matrix.flavor }}
|
||||
path: ./packages/rn-tester/android/app/build/outputs/apk/${{ matrix.jsengine }}/${{ matrix.flavor }}/
|
||||
name: rntester-${{ matrix.jsengine }}-release
|
||||
path: ./packages/rn-tester/android/app/build/outputs/apk/${{ matrix.jsengine }}/release/
|
||||
- name: Print folder structure
|
||||
run: ls -lR ./packages/rn-tester/android/app/build/outputs/apk/${{ matrix.jsengine }}/${{ matrix.flavor }}/
|
||||
run: ls -lR ./packages/rn-tester/android/app/build/outputs/apk/${{ matrix.jsengine }}/release/
|
||||
- name: Run E2E Tests
|
||||
uses: ./.github/actions/maestro-android
|
||||
with:
|
||||
app-path: ./packages/rn-tester/android/app/build/outputs/apk/${{ matrix.jsengine }}/${{ matrix.flavor }}/app-${{ matrix.jsengine }}-x86-${{ matrix.flavor }}.apk
|
||||
app-path: ./packages/rn-tester/android/app/build/outputs/apk/${{ matrix.jsengine }}/release/app-${{ matrix.jsengine }}-x86-release.apk
|
||||
app-id: com.facebook.react.uiapp
|
||||
jsengine: ${{ matrix.jsengine }}
|
||||
maestro-flow: ./packages/rn-tester/.maestro
|
||||
flavor: ${{ matrix.flavor }}
|
||||
maestro-flow: ./packages/rn-tester/.maestro/
|
||||
|
||||
build_npm_package:
|
||||
runs-on: 8-core-ubuntu
|
||||
@@ -502,8 +478,6 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup git safe folders
|
||||
run: git config --global --add safe.directory '*'
|
||||
- name: Download npm package artifact
|
||||
uses: actions/download-artifact@v4.1.3
|
||||
with:
|
||||
@@ -537,7 +511,7 @@ jobs:
|
||||
fi
|
||||
yarn build android "${args[@]}" -P reactNativeArchitectures="$TARGET_ARCHITECTURE" -P react.internal.mavenLocalRepo="/tmp/maven-local"
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4.3.4
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: helloworld-apk-${{ matrix.flavor }}-${{ matrix.architecture }}-${{ matrix.jsengine }}
|
||||
path: ./packages/helloworld/android/app/build/outputs/apk/
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
name: Test Libraries on Nightlies
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
test-library-on-nightly-android:
|
||||
name: "[Android] ${{ matrix.library }}"
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
library: [
|
||||
"react-native-async-storage",
|
||||
"react-native-blob-util",
|
||||
"@react-native-clipboard/clipboard",
|
||||
"@react-native-community/datetimepicker",
|
||||
"react-native-gesture-handler",
|
||||
"react-native-image-picker",
|
||||
"react-native-linear-gradient",
|
||||
"@react-native-masked-view/masked-view",
|
||||
"react-native-maps",
|
||||
"@react-native-community/netinfo",
|
||||
"react-native-reanimated",
|
||||
"react-native-svg",
|
||||
"react-native-video",
|
||||
"react-native-webview",
|
||||
"react-native-mmkv",
|
||||
"react-native-screens",
|
||||
"react-native-pager-view",
|
||||
"@react-native-community/slider"
|
||||
]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Test ${{ inputs.library-name }}
|
||||
uses: ./.github/actions/test-library-on-nightly
|
||||
with:
|
||||
library-npm-package: ${{ matrix.library }}
|
||||
platform: android
|
||||
|
||||
test-library-on-nightly-ios:
|
||||
name: "[iOS] ${{ matrix.library }}"
|
||||
runs-on: macos-13-large
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
library: [
|
||||
"react-native-async-storage",
|
||||
"react-native-blob-util",
|
||||
"@react-native-clipboard/clipboard",
|
||||
"@react-native-community/datetimepicker",
|
||||
"react-native-gesture-handler",
|
||||
"react-native-image-picker",
|
||||
"react-native-linear-gradient",
|
||||
"@react-native-masked-view/masked-view",
|
||||
"react-native-maps",
|
||||
"@react-native-community/netinfo",
|
||||
"react-native-reanimated",
|
||||
"react-native-svg",
|
||||
"react-native-video",
|
||||
"react-native-webview",
|
||||
"react-native-mmkv",
|
||||
"react-native-screens",
|
||||
"react-native-pager-view",
|
||||
"@react-native-community/slider"
|
||||
]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Test ${{ inputs.library-name }}
|
||||
uses: ./.github/actions/test-library-on-nightly
|
||||
with:
|
||||
library-npm-package: ${{ matrix.library }}
|
||||
platform: ios
|
||||
@@ -1,45 +0,0 @@
|
||||
name: Trigger E2E Tests on Comment
|
||||
# This workflow is used to automatically trigger E2E tests when a comment is made
|
||||
# containing the text "/run-e2e-tests".
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
trigger-e2e-tests:
|
||||
name: Trigger E2E Tests
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/test-e2e')
|
||||
steps:
|
||||
# This is needed because of https://github.com/actions/runner-images/issues/6283
|
||||
# TL;DR: brew is not in the PATH anymore.
|
||||
- name: Setup Homebrew
|
||||
uses: Homebrew/actions/setup-homebrew@master
|
||||
- name: Install jq
|
||||
run: brew install jq
|
||||
- name: Run E2E Tests
|
||||
run: |
|
||||
# Github does not provide the branch of a PR when a comment on a PR is made
|
||||
# So, given the issue number, which is the PR number, we can retrieve the branch with
|
||||
# a quick API call
|
||||
echo "Retrieving branch"
|
||||
BRANCH=$(curl -L \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/facebook/react-native/pulls/$PR_NUMBER | jq -r '.head.ref')
|
||||
|
||||
echo "Trigger Test All workflow for branch $BRANCH"
|
||||
curl -L \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/facebook/react-native/actions/workflows/test-all.yml/dispatches \
|
||||
-d "{\"ref\": \"$BRANCH\", \"inputs\": {\"run-e2e-tests\": \"true\"}}"
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
|
||||
PR_NUMBER: ${{ github.event.issue.number }}
|
||||
@@ -39,6 +39,8 @@ project.xcworkspace
|
||||
/packages/react-native/ReactAndroid/external-artifacts/artifacts/
|
||||
/packages/react-native/ReactAndroid/hermes-engine/build/
|
||||
/packages/react-native/ReactAndroid/hermes-engine/.cxx/
|
||||
/packages/react-native/template/android/app/build/
|
||||
/packages/react-native/template/android/build/
|
||||
/packages/helloworld/android/app/build/
|
||||
/packages/helloworld/android/build/
|
||||
/packages/react-native-popup-menu-android/android/build/
|
||||
@@ -106,12 +108,16 @@ package-lock.json
|
||||
|
||||
# Ruby Gems (Bundler)
|
||||
/packages/react-native/vendor
|
||||
/packages/react-native/template/vendor
|
||||
/packages/helloworld/vendor
|
||||
.ruby-version
|
||||
/**/.ruby-version
|
||||
vendor/
|
||||
|
||||
# iOS / CocoaPods
|
||||
/packages/react-native/template/ios/build/
|
||||
/packages/react-native/template/ios/Pods/
|
||||
/packages/react-native/template/ios/Podfile.lock
|
||||
/packages/helloworld/ios/build/
|
||||
/packages/helloworld/ios/Pods/
|
||||
/packages/helloworld/ios/Podfile.lock
|
||||
|
||||
+432
-736
File diff suppressed because it is too large
Load Diff
@@ -5,4 +5,3 @@ ruby ">= 2.6.10"
|
||||
|
||||
gem 'cocoapods', '~> 1.13', '!= 1.15.0', '!= 1.15.1'
|
||||
gem 'activesupport', '>= 6.1.7.5', '< 7.1.0'
|
||||
gem 'xcodeproj', '< 1.26.0'
|
||||
|
||||
-9
@@ -900,9 +900,7 @@ declare module '@babel/traverse' {
|
||||
isImportAttribute(opts?: Opts): boolean;
|
||||
isImportDeclaration(opts?: Opts): boolean;
|
||||
isImportDefaultSpecifier(opts?: Opts): boolean;
|
||||
isImportExpression(opts?: Opts): boolean;
|
||||
isImportNamespaceSpecifier(opts?: Opts): boolean;
|
||||
isImportOrExportDeclaration(opts?: Opts): boolean;
|
||||
isImportSpecifier(opts?: Opts): boolean;
|
||||
isIndexedAccessType(opts?: Opts): boolean;
|
||||
isInferredPredicate(opts?: Opts): boolean;
|
||||
@@ -1217,9 +1215,7 @@ declare module '@babel/traverse' {
|
||||
assertImportAttribute(opts?: Opts): void;
|
||||
assertImportDeclaration(opts?: Opts): void;
|
||||
assertImportDefaultSpecifier(opts?: Opts): void;
|
||||
assertImportExpression(opts?: Opts): void;
|
||||
assertImportNamespaceSpecifier(opts?: Opts): void;
|
||||
assertImportOrExportDeclaration(opts?: Opts): void;
|
||||
assertImportSpecifier(opts?: Opts): void;
|
||||
assertIndexedAccessType(opts?: Opts): void;
|
||||
assertInferredPredicate(opts?: Opts): void;
|
||||
@@ -1575,15 +1571,10 @@ declare module '@babel/traverse' {
|
||||
ImportAttribute?: VisitNode<BabelNodeImportAttribute, TState>,
|
||||
ImportDeclaration?: VisitNode<BabelNodeImportDeclaration, TState>,
|
||||
ImportDefaultSpecifier?: VisitNode<BabelNodeImportDefaultSpecifier, TState>,
|
||||
ImportExpression?: VisitNode<BabelNodeImportExpression, TState>,
|
||||
ImportNamespaceSpecifier?: VisitNode<
|
||||
BabelNodeImportNamespaceSpecifier,
|
||||
TState,
|
||||
>,
|
||||
ImportOrExportDeclaration?: VisitNode<
|
||||
BabelNodeImportOrExportDeclaration,
|
||||
TState,
|
||||
>,
|
||||
ImportSpecifier?: VisitNode<BabelNodeImportSpecifier, TState>,
|
||||
IndexedAccessType?: VisitNode<BabelNodeIndexedAccessType, TState>,
|
||||
InferredPredicate?: VisitNode<BabelNodeInferredPredicate, TState>,
|
||||
|
||||
Vendored
+37
-58
File diff suppressed because one or more lines are too long
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
// flow-typed signature: b1b274e8ae71623bf11c20224c446842
|
||||
// flow-typed version: c6154227d1/mkdirp_v0.5.x/flow_>=v0.104.x
|
||||
|
||||
declare module 'mkdirp' {
|
||||
declare type Options = number | {
|
||||
mode?: number,
|
||||
fs?: mixed,
|
||||
...
|
||||
};
|
||||
|
||||
declare type Callback = (err: ?Error, path: ?string) => void;
|
||||
|
||||
declare module.exports: {
|
||||
(path: string, options?: Options | Callback, callback?: Callback): void,
|
||||
sync(path: string, options?: Options): void,
|
||||
...
|
||||
};
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
type PrettyFormatPlugin =
|
||||
| {
|
||||
test: (value: mixed) => boolean,
|
||||
print: (value: mixed) => string,
|
||||
}
|
||||
| {
|
||||
test: (value: mixed) => boolean,
|
||||
serialize: (value: mixed) => string,
|
||||
};
|
||||
|
||||
declare module 'pretty-format' {
|
||||
declare module.exports: {
|
||||
(
|
||||
value: mixed,
|
||||
options?: ?{
|
||||
callToJSON?: ?boolean,
|
||||
escapeRegex?: ?boolean,
|
||||
escapeString?: ?boolean,
|
||||
highlight?: ?boolean,
|
||||
indent?: ?number,
|
||||
maxDepth?: ?number,
|
||||
min?: ?boolean,
|
||||
plugins?: ?Array<PrettyFormatPlugin>,
|
||||
printFunctionName?: ?boolean,
|
||||
theme?: ?{
|
||||
comment?: ?string,
|
||||
prop?: ?string,
|
||||
tag?: ?string,
|
||||
value: ?string,
|
||||
},
|
||||
},
|
||||
): string,
|
||||
|
||||
plugins: {
|
||||
AsymmetricMatcher: PrettyFormatPlugin,
|
||||
ConvertAnsi: PrettyFormatPlugin,
|
||||
DOMCollection: PrettyFormatPlugin,
|
||||
DOMElement: PrettyFormatPlugin,
|
||||
Immutable: PrettyFormatPlugin,
|
||||
ReactElement: PrettyFormatPlugin,
|
||||
ReactTestComponent: PrettyFormatPlugin,
|
||||
},
|
||||
};
|
||||
}
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
/**
|
||||
* (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
|
||||
*
|
||||
* @flow strict
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
declare type Print = (value: mixed) => string;
|
||||
declare type Indent = (value: string) => string;
|
||||
declare type PluginOptions = {
|
||||
edgeSpacing: string,
|
||||
min: boolean,
|
||||
spacing: string,
|
||||
};
|
||||
declare type Colors = {
|
||||
comment: {close: string, open: string},
|
||||
content: {close: string, open: string},
|
||||
prop: {close: string, open: string},
|
||||
tag: {close: string, open: string},
|
||||
value: {close: string, open: string},
|
||||
};
|
||||
declare type CompareKeys = ((a: string, b: string) => number) | null | void;
|
||||
|
||||
declare type PrettyFormatPlugin =
|
||||
| {
|
||||
print: (
|
||||
value: mixed,
|
||||
print?: ?Print,
|
||||
indent?: ?Indent,
|
||||
options?: ?PluginOptions,
|
||||
colors?: ?Colors,
|
||||
) => string,
|
||||
test: (value: mixed) => boolean,
|
||||
}
|
||||
| {
|
||||
serialize: (value: mixed) => string,
|
||||
test: (value: mixed) => boolean,
|
||||
};
|
||||
|
||||
declare module 'pretty-format' {
|
||||
declare export function format(
|
||||
value: mixed,
|
||||
options?: ?{
|
||||
callToJSON?: ?boolean,
|
||||
compareKeys?: CompareKeys,
|
||||
escapeRegex?: ?boolean,
|
||||
escapeString?: ?boolean,
|
||||
highlight?: ?boolean,
|
||||
indent?: ?number,
|
||||
maxDepth?: ?number,
|
||||
maxWidth?: ?number,
|
||||
min?: ?boolean,
|
||||
plugins?: ?Array<PrettyFormatPlugin>,
|
||||
printBasicPrototype?: ?boolean,
|
||||
printFunctionName?: ?boolean,
|
||||
theme?: ?{
|
||||
comment?: ?string,
|
||||
content?: ?string,
|
||||
prop?: ?string,
|
||||
tag?: ?string,
|
||||
value: ?string,
|
||||
},
|
||||
},
|
||||
): string;
|
||||
declare export const plugins: {
|
||||
AsymmetricMatcher: PrettyFormatPlugin,
|
||||
DOMCollection: PrettyFormatPlugin,
|
||||
DOMElement: PrettyFormatPlugin,
|
||||
Immutable: PrettyFormatPlugin,
|
||||
ReactElement: PrettyFormatPlugin,
|
||||
ReactTestComponent: PrettyFormatPlugin,
|
||||
};
|
||||
}
|
||||
Vendored
-1
@@ -323,7 +323,6 @@ declare module "yargs" {
|
||||
updateStrings(obj: { [key: string]: string, ... }): this;
|
||||
|
||||
usage(message: string, opts?: { [key: string]: Options, ... }): this;
|
||||
usage(message: string, desc?: string, builder: CommonModuleObject["builder"], handler: CommonModuleObject["handler"]): this;
|
||||
|
||||
version(): this;
|
||||
version(version: string | false): this;
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
Vendored
+94
-99
@@ -1,99 +1,94 @@
|
||||
@REM Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
@REM
|
||||
@REM This source code is licensed under the MIT license found in the
|
||||
@REM LICENSE file in the root directory of this source tree.
|
||||
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
|
||||
+2
-12
@@ -11,11 +11,6 @@
|
||||
|
||||
const {defaults} = require('jest-config');
|
||||
|
||||
const PODS_LOCATIONS = [
|
||||
'packages/rn-tester/Pods',
|
||||
'packages/helloworld/ios/Pods',
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
transform: {
|
||||
'^.+\\.(bmp|gif|jpg|jpeg|mp4|png|psd|svg|webp)$':
|
||||
@@ -35,11 +30,10 @@ module.exports = {
|
||||
testRegex: '/__tests__/.*-test(\\.fb)?\\.js$',
|
||||
testPathIgnorePatterns: [
|
||||
'/node_modules/',
|
||||
'<rootDir>/packages/react-native/template',
|
||||
'<rootDir>/packages/react-native/sdks',
|
||||
'<rootDir>/packages/react-native/Libraries/Renderer',
|
||||
'<rootDir>/packages/react-native-test-renderer/src',
|
||||
'<rootDir>/packages/react-native/sdks/hermes/',
|
||||
...PODS_LOCATIONS,
|
||||
],
|
||||
transformIgnorePatterns: ['node_modules/(?!@react-native/)'],
|
||||
haste: {
|
||||
@@ -47,11 +41,7 @@ module.exports = {
|
||||
platforms: ['ios', 'android'],
|
||||
},
|
||||
moduleFileExtensions: ['fb.js'].concat(defaults.moduleFileExtensions),
|
||||
modulePathIgnorePatterns: [
|
||||
'scripts/.*/__fixtures__/',
|
||||
'<rootDir>/packages/react-native/sdks/hermes/',
|
||||
...PODS_LOCATIONS,
|
||||
],
|
||||
modulePathIgnorePatterns: ['scripts/.*/__fixtures__/'],
|
||||
unmockedModulePathPatterns: [
|
||||
'node_modules/react/',
|
||||
'packages/react-native/Libraries/Renderer',
|
||||
|
||||
+15
-23
@@ -12,31 +12,18 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
// eslint-disable-next-line lint/sort-imports
|
||||
const {
|
||||
transformFromAstSync: babelTransformFromAstSync,
|
||||
transformSync: babelTransformSync,
|
||||
} = require('@babel/core');
|
||||
const generate = require('@babel/generator').default;
|
||||
const createCacheKeyFunction =
|
||||
require('@jest/create-cache-key-function').default;
|
||||
/* eslint-disable lint/sort-imports */
|
||||
|
||||
const metroBabelRegister = require('metro-babel-register');
|
||||
const nullthrows = require('nullthrows');
|
||||
const createCacheKeyFunction =
|
||||
require('@jest/create-cache-key-function').default;
|
||||
|
||||
if (process.env.FBSOURCE_ENV === '1') {
|
||||
// If we're running in the Meta-internal monorepo, use the central Babel
|
||||
// registration, which registers all of the relevant source directories
|
||||
// including Metro's root.
|
||||
//
|
||||
// $FlowExpectedError[cannot-resolve-module] - Won't resolve in OSS
|
||||
require('@fb-tools/babel-register');
|
||||
} else {
|
||||
// Register Babel to allow local packages to be loaded from source
|
||||
require('../scripts/build/babel-register').registerForMonorepo();
|
||||
}
|
||||
|
||||
const transformer = require('@react-native/metro-babel-transformer');
|
||||
const metroTransformPlugins = require('metro-transform-plugins');
|
||||
const {
|
||||
transformSync: babelTransformSync,
|
||||
transformFromAstSync: babelTransformFromAstSync,
|
||||
} = require('@babel/core');
|
||||
const generate = require('@babel/generator').default;
|
||||
|
||||
// Files matching this pattern will be transformed with the Node JS Babel
|
||||
// transformer, rather than with the React Native Babel transformer. Scripts
|
||||
@@ -47,6 +34,10 @@ const nodeFiles = /[\\/]metro(?:-[^/]*)[\\/]/;
|
||||
// hook. This is used below to configure babelTransformSync under Jest.
|
||||
const {only: _, ...nodeBabelOptions} = metroBabelRegister.config([]);
|
||||
|
||||
// Register Babel to allow the transformer itself to be loaded from source.
|
||||
require('../scripts/build/babel-register').registerForMonorepo();
|
||||
const transformer = require('@react-native/metro-babel-transformer');
|
||||
|
||||
// Set BUILD_EXCLUDE_BABEL_REGISTER (see ../scripts/build/babel-register.js) to
|
||||
// prevent inline Babel registration in code under test, normally required when
|
||||
// running from source, but not in combination with the Jest transformer.
|
||||
@@ -99,7 +90,8 @@ module.exports = {
|
||||
ast: true,
|
||||
retainLines: true,
|
||||
plugins: [
|
||||
metroTransformPlugins.inlineRequiresPlugin,
|
||||
// TODO(moti): Replace with require('metro-transform-plugins').inlineRequiresPlugin when available in OSS
|
||||
require('babel-preset-fbjs/plugins/inline-requires'),
|
||||
babelPluginPreventBabelRegister,
|
||||
],
|
||||
sourceType: 'module',
|
||||
|
||||
+21
-20
@@ -3,7 +3,6 @@
|
||||
"private": true,
|
||||
"version": "1000.0.0",
|
||||
"license": "MIT",
|
||||
"packageManager": "yarn@1.22.22",
|
||||
"scripts": {
|
||||
"android": "cd packages/rn-tester && npm run android",
|
||||
"build-android": "./gradlew :packages:react-native:ReactAndroid:build",
|
||||
@@ -14,7 +13,8 @@
|
||||
"flow": "flow",
|
||||
"format-check": "prettier --list-different \"./**/*.{js,md,yml,ts,tsx}\"",
|
||||
"format": "npm run prettier && npm run clang-format",
|
||||
"featureflags": "cd packages/react-native && yarn featureflags",
|
||||
"featureflags-check": "cd packages/react-native && yarn featureflags-check",
|
||||
"featureflags-update": "cd packages/react-native && yarn featureflags-update",
|
||||
"lint-ci": "./scripts/circleci/analyze_code.sh && yarn shellcheck",
|
||||
"lint-java": "node ./scripts/lint-java.js",
|
||||
"lint": "eslint .",
|
||||
@@ -40,25 +40,26 @@
|
||||
"!packages/helloworld"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
"@babel/eslint-parser": "^7.25.1",
|
||||
"@babel/generator": "^7.25.0",
|
||||
"@babel/plugin-transform-regenerator": "^7.24.7",
|
||||
"@babel/preset-env": "^7.25.3",
|
||||
"@babel/preset-flow": "^7.24.7",
|
||||
"@babel/core": "^7.20.0",
|
||||
"@babel/eslint-parser": "^7.20.0",
|
||||
"@babel/generator": "^7.20.0",
|
||||
"@babel/plugin-transform-regenerator": "^7.20.0",
|
||||
"@babel/preset-env": "^7.20.0",
|
||||
"@babel/preset-flow": "^7.20.0",
|
||||
"@definitelytyped/dtslint": "^0.0.127",
|
||||
"@jest/create-cache-key-function": "^29.6.3",
|
||||
"@pkgjs/parseargs": "^0.11.0",
|
||||
"@react-native/metro-babel-transformer": "0.77.0-main",
|
||||
"@react-native/metro-config": "0.77.0-main",
|
||||
"@react-native/metro-babel-transformer": "0.76.0-main",
|
||||
"@react-native/metro-config": "0.76.0-main",
|
||||
"@tsconfig/node18": "1.0.1",
|
||||
"@types/react": "^18.2.6",
|
||||
"@typescript-eslint/parser": "^7.1.1",
|
||||
"ansi-styles": "^4.2.1",
|
||||
"babel-plugin-minify-dead-code-elimination": "^0.5.2",
|
||||
"babel-plugin-syntax-hermes-parser": "0.24.0",
|
||||
"babel-plugin-transform-define": "^2.1.4",
|
||||
"babel-plugin-syntax-hermes-parser": "0.23.0",
|
||||
"babel-plugin-transform-define": "^2.1.2",
|
||||
"babel-plugin-transform-flow-enums": "^0.0.2",
|
||||
"babel-preset-fbjs": "^3.4.0",
|
||||
"chalk": "^4.0.0",
|
||||
"clang-format": "^1.8.0",
|
||||
"connect": "^3.6.5",
|
||||
@@ -76,23 +77,23 @@
|
||||
"eslint-plugin-react-native": "^4.0.0",
|
||||
"eslint-plugin-redundant-undefined": "^0.4.0",
|
||||
"eslint-plugin-relay": "^1.8.3",
|
||||
"flow-api-translator": "0.24.0",
|
||||
"flow-bin": "^0.251.1",
|
||||
"flow-api-translator": "0.23.0",
|
||||
"flow-bin": "^0.242.0",
|
||||
"glob": "^7.1.1",
|
||||
"hermes-eslint": "0.24.0",
|
||||
"hermes-transform": "0.24.0",
|
||||
"hermes-eslint": "0.23.0",
|
||||
"hermes-transform": "0.23.0",
|
||||
"inquirer": "^7.1.0",
|
||||
"jest": "^29.6.3",
|
||||
"jest-junit": "^10.0.0",
|
||||
"jscodeshift": "^0.14.0",
|
||||
"metro-babel-register": "^0.81.0",
|
||||
"metro-memory-fs": "^0.81.0",
|
||||
"metro-transform-plugins": "^0.81.0",
|
||||
"metro-babel-register": "^0.80.0",
|
||||
"metro-memory-fs": "^0.80.0",
|
||||
"micromatch": "^4.0.4",
|
||||
"mkdirp": "^0.5.1",
|
||||
"node-fetch": "^2.2.0",
|
||||
"nullthrows": "^1.1.1",
|
||||
"prettier": "2.8.8",
|
||||
"prettier-plugin-hermes-parser": "0.24.0",
|
||||
"prettier-plugin-hermes-parser": "0.23.0",
|
||||
"react": "19.0.0-rc-fb9a90fa48-20240614",
|
||||
"react-test-renderer": "19.0.0-rc-fb9a90fa48-20240614",
|
||||
"rimraf": "^3.0.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@react-native/assets-registry",
|
||||
"version": "0.77.0-main",
|
||||
"version": "0.76.0-main",
|
||||
"description": "Asset support code for React Native.",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
||||
@@ -55,7 +55,7 @@ const drawableFileTypes = new Set([
|
||||
function getAndroidResourceFolderName(
|
||||
asset: PackagerAsset,
|
||||
scale: number,
|
||||
): string {
|
||||
): string | $TEMPORARY$string<'raw'> {
|
||||
if (!drawableFileTypes.has(asset.type)) {
|
||||
return 'raw';
|
||||
}
|
||||
@@ -78,7 +78,7 @@ function getAndroidResourceIdentifier(asset: PackagerAsset): string {
|
||||
.toLowerCase()
|
||||
.replace(/\//g, '_') // Encode folder structure in file name
|
||||
.replace(/([^a-z0-9_])/g, '') // Remove illegal chars
|
||||
.replace(/^(?:assets|assetsunstable_path)_/, ''); // Remove "assets_" or "assetsunstable_path_" prefix
|
||||
.replace(/^assets_/, ''); // Remove "assets_" prefix
|
||||
}
|
||||
|
||||
function getBasePath(asset: PackagerAsset): string {
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
export type AssetDestPathResolver = 'android' | 'generic';
|
||||
|
||||
export type PackagerAsset = {
|
||||
+__packager_asset: boolean,
|
||||
+fileSystemLocation: string,
|
||||
@@ -22,7 +20,6 @@ export type PackagerAsset = {
|
||||
+hash: string,
|
||||
+name: string,
|
||||
+type: string,
|
||||
+resolver?: AssetDestPathResolver,
|
||||
...
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
let FlowParser, TypeScriptParser, RNCodegen;
|
||||
|
||||
const {cheap: traverseCheap} = require('@babel/traverse').default;
|
||||
const {basename} = require('path');
|
||||
|
||||
try {
|
||||
@@ -169,32 +168,16 @@ module.exports = function ({parse, types: t}) {
|
||||
exit(path) {
|
||||
if (this.defaultExport) {
|
||||
const viewConfig = generateViewConfig(this.filename, this.code);
|
||||
|
||||
const ast = parse(viewConfig, {
|
||||
babelrc: false,
|
||||
browserslistConfigFile: false,
|
||||
configFile: false,
|
||||
});
|
||||
|
||||
// Almost the whole file is replaced with the viewConfig generated code that doesn't
|
||||
// have a clear equivalent code on the source file when the user debugs, so we point
|
||||
// it to the location of the default export that in that file, which is the closest
|
||||
// to representing the code that is being generated.
|
||||
// This is mostly useful when that generated code throws an error.
|
||||
traverseCheap(ast, node => {
|
||||
if (node?.loc) {
|
||||
node.loc = this.defaultExport.node.loc;
|
||||
node.start = this.defaultExport.node.start;
|
||||
node.end = this.defaultExport.node.end;
|
||||
}
|
||||
});
|
||||
|
||||
this.defaultExport.replaceWithMultiple(ast.program.body);
|
||||
|
||||
this.defaultExport.replaceWithMultiple(
|
||||
parse(viewConfig, {
|
||||
babelrc: false,
|
||||
browserslistConfigFile: false,
|
||||
configFile: false,
|
||||
}).program.body,
|
||||
);
|
||||
if (this.commandsExport != null) {
|
||||
this.commandsExport.remove();
|
||||
}
|
||||
|
||||
this.codeInserted = true;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@react-native/babel-plugin-codegen",
|
||||
"version": "0.77.0-main",
|
||||
"version": "0.76.0-main",
|
||||
"description": "Babel plugin to generate native module and view manager code for React Native.",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
@@ -25,10 +25,9 @@
|
||||
"index.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"@babel/traverse": "^7.25.3",
|
||||
"@react-native/codegen": "0.77.0-main"
|
||||
"@react-native/codegen": "0.76.0-main"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2"
|
||||
"@babel/core": "^7.20.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@react-native/community-cli-plugin",
|
||||
"version": "0.77.0-main",
|
||||
"version": "0.76.0-main",
|
||||
"description": "Core CLI commands for React Native",
|
||||
"keywords": [
|
||||
"react-native",
|
||||
@@ -22,20 +22,18 @@
|
||||
"dist"
|
||||
],
|
||||
"dependencies": {
|
||||
"@react-native/dev-middleware": "0.77.0-main",
|
||||
"@react-native/metro-babel-transformer": "0.77.0-main",
|
||||
"@react-native/dev-middleware": "0.76.0-main",
|
||||
"@react-native/metro-babel-transformer": "0.76.0-main",
|
||||
"chalk": "^4.0.0",
|
||||
"debug": "^2.2.0",
|
||||
"invariant": "^2.2.4",
|
||||
"metro": "^0.81.0",
|
||||
"metro-config": "^0.81.0",
|
||||
"metro-core": "^0.81.0",
|
||||
"execa": "^5.1.1",
|
||||
"metro": "^0.80.3",
|
||||
"metro-config": "^0.80.3",
|
||||
"metro-core": "^0.80.3",
|
||||
"node-fetch": "^2.2.0",
|
||||
"readline": "^1.3.0",
|
||||
"semver": "^7.1.3"
|
||||
"readline": "^1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"metro-resolver": "^0.81.0"
|
||||
"metro-resolver": "^0.80.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-native-community/cli-server-api": "*"
|
||||
|
||||
@@ -14,10 +14,10 @@ import type {ConfigT} from 'metro-config';
|
||||
import type {RequestOptions} from 'metro/src/shared/types.flow';
|
||||
|
||||
import loadMetroConfig from '../../utils/loadMetroConfig';
|
||||
import {logger} from '../../utils/logger';
|
||||
import parseKeyValueParamArray from '../../utils/parseKeyValueParamArray';
|
||||
import saveAssets from './saveAssets';
|
||||
import chalk from 'chalk';
|
||||
import {promises as fs} from 'fs';
|
||||
import Server from 'metro/src/Server';
|
||||
import metroBundle from 'metro/src/shared/output/bundle';
|
||||
import metroRamBundle from 'metro/src/shared/output/RamBundle';
|
||||
@@ -71,13 +71,13 @@ async function buildBundleWithConfig(
|
||||
);
|
||||
|
||||
if (config.resolver.platforms.indexOf(args.platform) === -1) {
|
||||
console.error(
|
||||
`${chalk.red('error')}: Invalid platform ${
|
||||
logger.error(
|
||||
`Invalid platform ${
|
||||
args.platform ? `"${chalk.bold(args.platform)}" ` : ''
|
||||
}selected.`,
|
||||
);
|
||||
|
||||
console.info(
|
||||
logger.info(
|
||||
`Available platforms are: ${config.resolver.platforms
|
||||
.map(x => `"${chalk.bold(x)}"`)
|
||||
.join(
|
||||
@@ -112,17 +112,11 @@ async function buildBundleWithConfig(
|
||||
try {
|
||||
const bundle = await bundleImpl.build(server, requestOpts);
|
||||
|
||||
// Ensure destination directory exists before saving the bundle
|
||||
await fs.mkdir(path.dirname(args.bundleOutput), {
|
||||
recursive: true,
|
||||
mode: 0o755,
|
||||
});
|
||||
|
||||
// $FlowIgnore[class-object-subtyping]
|
||||
// $FlowIgnore[incompatible-call]
|
||||
// $FlowIgnore[prop-missing]
|
||||
// $FlowIgnore[incompatible-exact]
|
||||
await bundleImpl.save(bundle, args, console.info);
|
||||
await bundleImpl.save(bundle, args, logger.info);
|
||||
|
||||
// Save the assets of the bundle
|
||||
const outputAssets = await server.getAssets({
|
||||
@@ -139,7 +133,7 @@ async function buildBundleWithConfig(
|
||||
args.assetCatalogDest,
|
||||
);
|
||||
} finally {
|
||||
await server.end();
|
||||
server.end();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
import type {AssetData} from 'metro/src/Assets';
|
||||
|
||||
import {logger} from '../../utils/logger';
|
||||
import {
|
||||
cleanAssetCatalog,
|
||||
getImageSet,
|
||||
@@ -20,7 +21,6 @@ import {
|
||||
import filterPlatformAssetScales from './filterPlatformAssetScales';
|
||||
import getAssetDestPathAndroid from './getAssetDestPathAndroid';
|
||||
import getAssetDestPathIOS from './getAssetDestPathIOS';
|
||||
import chalk from 'chalk';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
@@ -35,7 +35,7 @@ async function saveAssets(
|
||||
assetCatalogDest?: string,
|
||||
): Promise<void> {
|
||||
if (assetsDest == null) {
|
||||
console.warn('Warning: Assets destination folder is not set, skipping...');
|
||||
logger.warn('Assets destination folder is not set, skipping...');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -64,13 +64,13 @@ async function saveAssets(
|
||||
// remove unused scales from the optimized bundle.
|
||||
const catalogDir = path.join(assetCatalogDest, 'RNAssets.xcassets');
|
||||
if (!fs.existsSync(catalogDir)) {
|
||||
console.error(
|
||||
`${chalk.red('error')}: Could not find asset catalog 'RNAssets.xcassets' in ${assetCatalogDest}. Make sure to create it if it does not exist.`,
|
||||
logger.error(
|
||||
`Could not find asset catalog 'RNAssets.xcassets' in ${assetCatalogDest}. Make sure to create it if it does not exist.`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
console.info('Adding images to asset catalog', catalogDir);
|
||||
logger.info('Adding images to asset catalog', catalogDir);
|
||||
cleanAssetCatalog(catalogDir);
|
||||
for (const asset of assets) {
|
||||
if (isCatalogAsset(asset)) {
|
||||
@@ -84,7 +84,7 @@ async function saveAssets(
|
||||
addAssetToCopy(asset);
|
||||
}
|
||||
}
|
||||
console.info('Done adding images to asset catalog');
|
||||
logger.info('Done adding images to asset catalog');
|
||||
} else {
|
||||
assets.forEach(addAssetToCopy);
|
||||
}
|
||||
@@ -98,7 +98,7 @@ function copyAll(filesToCopy: CopiedFiles) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
console.info(`Copying ${queue.length} asset files`);
|
||||
logger.info(`Copying ${queue.length} asset files`);
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const copyNext = (error?: Error) => {
|
||||
if (error) {
|
||||
@@ -106,7 +106,7 @@ function copyAll(filesToCopy: CopiedFiles) {
|
||||
return;
|
||||
}
|
||||
if (queue.length === 0) {
|
||||
console.info('Done copying assets');
|
||||
logger.info('Done copying assets');
|
||||
resolve();
|
||||
} else {
|
||||
// queue.length === 0 is checked in previous branch, so this is string
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import type TerminalReporter from 'metro/src/lib/TerminalReporter';
|
||||
|
||||
import chalk from 'chalk';
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
type PageDescription = $ReadOnly<{
|
||||
id: string,
|
||||
title: string,
|
||||
description: string,
|
||||
...
|
||||
}>;
|
||||
|
||||
export default class OpenDebuggerKeyboardHandler {
|
||||
#devServerUrl: string;
|
||||
#reporter: TerminalReporter;
|
||||
#targetsShownForSelection: ?$ReadOnlyArray<PageDescription> = null;
|
||||
|
||||
constructor({
|
||||
devServerUrl,
|
||||
reporter,
|
||||
}: {
|
||||
devServerUrl: string,
|
||||
reporter: TerminalReporter,
|
||||
}) {
|
||||
this.#devServerUrl = devServerUrl;
|
||||
this.#reporter = reporter;
|
||||
}
|
||||
|
||||
async #tryOpenDebuggerForTarget(target: PageDescription): Promise<void> {
|
||||
this.#targetsShownForSelection = null;
|
||||
this.#clearTerminalMenu();
|
||||
|
||||
try {
|
||||
await fetch(
|
||||
new URL(
|
||||
'/open-debugger?target=' + encodeURIComponent(target.id),
|
||||
this.#devServerUrl,
|
||||
).href,
|
||||
{method: 'POST'},
|
||||
);
|
||||
} catch (e) {
|
||||
this.#log(
|
||||
'error',
|
||||
'Failed to open debugger for %s (%s): %s',
|
||||
target.title,
|
||||
target.description,
|
||||
e.message,
|
||||
);
|
||||
this.#clearTerminalMenu();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in response to 'j' to debug - fetch the available debug targets and:
|
||||
* - If no targets, warn
|
||||
* - If one target, open it
|
||||
* - If more, show a list. The keyboard listener should run subsequent key
|
||||
* presses through maybeHandleTargetSelection, which will launch the
|
||||
* debugger if a match is made.
|
||||
*/
|
||||
async handleOpenDebugger(): Promise<void> {
|
||||
this.#setTerminalMenu('Fetching available debugging targets...');
|
||||
this.#targetsShownForSelection = null;
|
||||
|
||||
try {
|
||||
const res = await fetch(this.#devServerUrl + '/json/list', {
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
if (res.status !== 200) {
|
||||
throw new Error(`Unexpected status code: ${res.status}`);
|
||||
}
|
||||
const targets = (await res.json()) as $ReadOnlyArray<PageDescription>;
|
||||
if (!Array.isArray(targets)) {
|
||||
throw new Error('Expected array.');
|
||||
}
|
||||
|
||||
if (targets.length === 0) {
|
||||
this.#log('warn', 'No connected targets');
|
||||
this.#clearTerminalMenu();
|
||||
} else if (targets.length === 1) {
|
||||
const target = targets[0];
|
||||
// eslint-disable-next-line no-void
|
||||
void this.#tryOpenDebuggerForTarget(target);
|
||||
} else {
|
||||
this.#targetsShownForSelection = targets;
|
||||
|
||||
if (targets.length > 9) {
|
||||
this.#log(
|
||||
'warn',
|
||||
'10 or more debug targets available, showing the first 9.',
|
||||
);
|
||||
}
|
||||
|
||||
this.#setTerminalMenu(
|
||||
`Multiple debug targets available, please select:\n ${targets
|
||||
.slice(0, 9)
|
||||
.map(
|
||||
({title}, i) =>
|
||||
`${chalk.white.inverse(` ${i + 1} `)} - "${title}"`,
|
||||
)
|
||||
.join('\n ')}`,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
this.#log('error', `Failed to fetch debug targets: ${e.message}`);
|
||||
this.#clearTerminalMenu();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle key presses that correspond to a valid selection from a visible
|
||||
* selection list.
|
||||
*
|
||||
* @return true if we've handled the key as a target selection, false if the
|
||||
* caller should handle the key.
|
||||
*/
|
||||
maybeHandleTargetSelection(keyName: string): boolean {
|
||||
if (keyName >= '1' && keyName <= '9') {
|
||||
const targetIndex = Number(keyName) - 1;
|
||||
if (
|
||||
this.#targetsShownForSelection != null &&
|
||||
targetIndex < this.#targetsShownForSelection.length
|
||||
) {
|
||||
const target = this.#targetsShownForSelection[targetIndex];
|
||||
// eslint-disable-next-line no-void
|
||||
void this.#tryOpenDebuggerForTarget(target);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss any target selection UI, if shown.
|
||||
*/
|
||||
dismiss() {
|
||||
this.#clearTerminalMenu();
|
||||
this.#targetsShownForSelection = null;
|
||||
}
|
||||
|
||||
#log(level: 'info' | 'warn' | 'error', ...data: Array<mixed>): void {
|
||||
this.#reporter.update({
|
||||
type: 'unstable_server_log',
|
||||
level,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
#setTerminalMenu(message: string) {
|
||||
this.#reporter.update({
|
||||
type: 'unstable_server_menu_updated',
|
||||
message,
|
||||
});
|
||||
}
|
||||
|
||||
#clearTerminalMenu() {
|
||||
this.#reporter.update({
|
||||
type: 'unstable_server_menu_cleared',
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -9,127 +9,104 @@
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import type TerminalReporter from 'metro/src/lib/TerminalReporter';
|
||||
import type {Config} from '@react-native-community/cli-types';
|
||||
|
||||
import OpenDebuggerKeyboardHandler from './OpenDebuggerKeyboardHandler';
|
||||
import {KeyPressHandler} from '../../utils/KeyPressHandler';
|
||||
import {logger} from '../../utils/logger';
|
||||
import chalk from 'chalk';
|
||||
import invariant from 'invariant';
|
||||
import readline from 'readline';
|
||||
import {ReadStream} from 'tty';
|
||||
import execa from 'execa';
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
const CTRL_C = '\u0003';
|
||||
const CTRL_D = '\u0004';
|
||||
const RELOAD_TIMEOUT = 500;
|
||||
|
||||
const throttle = (callback: () => void, timeout: number) => {
|
||||
let previousCallTimestamp = 0;
|
||||
return () => {
|
||||
const currentCallTimestamp = new Date().getTime();
|
||||
if (currentCallTimestamp - previousCallTimestamp > timeout) {
|
||||
previousCallTimestamp = currentCallTimestamp;
|
||||
callback();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
type KeyEvent = {
|
||||
sequence: string,
|
||||
name: string,
|
||||
ctrl: boolean,
|
||||
meta: boolean,
|
||||
shift: boolean,
|
||||
};
|
||||
|
||||
export default function attachKeyHandlers({
|
||||
cliConfig,
|
||||
devServerUrl,
|
||||
messageSocket,
|
||||
reporter,
|
||||
experimentalDebuggerFrontend,
|
||||
}: {
|
||||
cliConfig: Config,
|
||||
devServerUrl: string,
|
||||
messageSocket: $ReadOnly<{
|
||||
broadcast: (type: string, params?: Record<string, mixed> | null) => void,
|
||||
...
|
||||
}>,
|
||||
reporter: TerminalReporter,
|
||||
experimentalDebuggerFrontend: boolean,
|
||||
}) {
|
||||
if (process.stdin.isTTY !== true) {
|
||||
reporter.update({
|
||||
type: 'unstable_server_log',
|
||||
level: 'info',
|
||||
data: 'Interactive mode is not supported in this environment',
|
||||
});
|
||||
logger.debug('Interactive mode is not supported in this environment');
|
||||
return;
|
||||
}
|
||||
|
||||
readline.emitKeypressEvents(process.stdin);
|
||||
setRawMode(true);
|
||||
const execaOptions = {
|
||||
env: {FORCE_COLOR: chalk.supportsColor ? 'true' : 'false'},
|
||||
};
|
||||
|
||||
const reload = throttle(() => {
|
||||
reporter.update({
|
||||
type: 'unstable_server_log',
|
||||
level: 'info',
|
||||
data: 'Reloading connected app(s)...',
|
||||
});
|
||||
messageSocket.broadcast('reload', null);
|
||||
}, RELOAD_TIMEOUT);
|
||||
|
||||
const openDebuggerKeyboardHandler = new OpenDebuggerKeyboardHandler({
|
||||
reporter,
|
||||
devServerUrl,
|
||||
});
|
||||
|
||||
process.stdin.on('keypress', (str: string, key: KeyEvent) => {
|
||||
if (openDebuggerKeyboardHandler.maybeHandleTargetSelection(key.name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (key.sequence) {
|
||||
const onPress = async (key: string) => {
|
||||
switch (key.toLowerCase()) {
|
||||
case 'r':
|
||||
reload();
|
||||
logger.info('Reloading connected app(s)...');
|
||||
messageSocket.broadcast('reload', null);
|
||||
break;
|
||||
case 'd':
|
||||
reporter.update({
|
||||
type: 'unstable_server_log',
|
||||
level: 'info',
|
||||
data: 'Opening Dev Menu...',
|
||||
});
|
||||
logger.info('Opening Dev Menu...');
|
||||
messageSocket.broadcast('devMenu', null);
|
||||
break;
|
||||
case 'i':
|
||||
logger.info('Opening app on iOS...');
|
||||
execa(
|
||||
'npx',
|
||||
[
|
||||
'react-native',
|
||||
'run-ios',
|
||||
...(cliConfig.project.ios?.watchModeCommandParams ?? []),
|
||||
],
|
||||
execaOptions,
|
||||
).stdout?.pipe(process.stdout);
|
||||
break;
|
||||
case 'a':
|
||||
logger.info('Opening app on Android...');
|
||||
execa(
|
||||
'npx',
|
||||
[
|
||||
'react-native',
|
||||
'run-android',
|
||||
...(cliConfig.project.android?.watchModeCommandParams ?? []),
|
||||
],
|
||||
execaOptions,
|
||||
).stdout?.pipe(process.stdout);
|
||||
break;
|
||||
case 'j':
|
||||
// eslint-disable-next-line no-void
|
||||
void openDebuggerKeyboardHandler.handleOpenDebugger();
|
||||
if (!experimentalDebuggerFrontend) {
|
||||
return;
|
||||
}
|
||||
await fetch(devServerUrl + '/open-debugger', {method: 'POST'});
|
||||
break;
|
||||
case CTRL_C:
|
||||
case CTRL_D:
|
||||
openDebuggerKeyboardHandler.dismiss();
|
||||
reporter.update({
|
||||
type: 'unstable_server_log',
|
||||
level: 'info',
|
||||
data: 'Stopping server',
|
||||
});
|
||||
setRawMode(false);
|
||||
process.stdin.pause();
|
||||
logger.info('Stopping server');
|
||||
keyPressHandler.stopInterceptingKeyStrokes();
|
||||
process.emit('SIGINT');
|
||||
process.exit();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
reporter.update({
|
||||
type: 'unstable_server_log',
|
||||
level: 'info',
|
||||
data: `Key commands available:
|
||||
const keyPressHandler = new KeyPressHandler(onPress);
|
||||
keyPressHandler.createInteractionListener();
|
||||
keyPressHandler.startInterceptingKeyStrokes();
|
||||
|
||||
${chalk.bold.inverse(' r ')} - reload app(s)
|
||||
${chalk.bold.inverse(' d ')} - open Dev Menu
|
||||
${chalk.bold.inverse(' j ')} - open DevTools
|
||||
`,
|
||||
});
|
||||
}
|
||||
|
||||
function setRawMode(enable: boolean) {
|
||||
invariant(
|
||||
process.stdin instanceof ReadStream,
|
||||
'process.stdin must be a readable stream to modify raw mode',
|
||||
logger.log(
|
||||
[
|
||||
'',
|
||||
`${chalk.bold('i')} - run on iOS`,
|
||||
`${chalk.bold('a')} - run on Android`,
|
||||
`${chalk.bold('d')} - open Dev Menu`,
|
||||
...(experimentalDebuggerFrontend
|
||||
? [`${chalk.bold('j')} - open debugger (experimental, Hermes only)`]
|
||||
: []),
|
||||
`${chalk.bold('r')} - reload app`,
|
||||
'',
|
||||
].join('\n'),
|
||||
);
|
||||
process.stdin.setRawMode(enable);
|
||||
}
|
||||
|
||||
@@ -95,6 +95,13 @@ const startCommand: Command = {
|
||||
name: '--no-interactive',
|
||||
description: 'Disables interactive mode',
|
||||
},
|
||||
{
|
||||
name: '--experimental-debugger',
|
||||
description:
|
||||
"[Experimental] Enable the new debugger experience and 'j' to " +
|
||||
'debug. This enables the new frontend experience only: connection ' +
|
||||
'reliability and some basic features are unstable in this release.',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import type {NextHandleFunction, Server} from 'connect';
|
||||
import type {TerminalReportableEvent} from 'metro/src/lib/TerminalReporter';
|
||||
|
||||
const debug = require('debug')('ReactNative:CommunityCliPlugin');
|
||||
import {logger} from '../../utils/logger';
|
||||
|
||||
type MiddlewareReturn = {
|
||||
middleware: Server,
|
||||
@@ -71,7 +71,7 @@ try {
|
||||
communityMiddlewareFallback.createDevServerMiddleware =
|
||||
community.createDevServerMiddleware;
|
||||
} catch {
|
||||
debug(`⚠️ Unable to find @react-native-community/cli-server-api
|
||||
logger.debug(`⚠️ Unable to find @react-native-community/cli-server-api
|
||||
Starting the server without the community middleware.`);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,15 +14,15 @@ import type {Reporter} from 'metro/src/lib/reporting';
|
||||
import type {TerminalReportableEvent} from 'metro/src/lib/TerminalReporter';
|
||||
import typeof TerminalReporter from 'metro/src/lib/TerminalReporter';
|
||||
|
||||
import createDevMiddlewareLogger from '../../utils/createDevMiddlewareLogger';
|
||||
import isDevServerRunning from '../../utils/isDevServerRunning';
|
||||
import loadMetroConfig from '../../utils/loadMetroConfig';
|
||||
import {logger} from '../../utils/logger';
|
||||
import * as version from '../../utils/version';
|
||||
import attachKeyHandlers from './attachKeyHandlers';
|
||||
import {
|
||||
createDevServerMiddleware,
|
||||
indexPageMiddleware,
|
||||
} from './middleware';
|
||||
} from '@react-native-community/cli-server-api';
|
||||
import {createDevMiddleware} from '@react-native/dev-middleware';
|
||||
import chalk from 'chalk';
|
||||
import Metro from 'metro';
|
||||
@@ -34,6 +34,7 @@ export type StartCommandArgs = {
|
||||
assetPlugins?: string[],
|
||||
cert?: string,
|
||||
customLogReporterPath?: string,
|
||||
experimentalDebugger: boolean,
|
||||
host?: string,
|
||||
https?: boolean,
|
||||
maxWorkers?: number,
|
||||
@@ -51,10 +52,10 @@ export type StartCommandArgs = {
|
||||
|
||||
async function runServer(
|
||||
_argv: Array<string>,
|
||||
cliConfig: Config,
|
||||
ctx: Config,
|
||||
args: StartCommandArgs,
|
||||
) {
|
||||
const metroConfig = await loadMetroConfig(cliConfig, {
|
||||
const metroConfig = await loadMetroConfig(ctx, {
|
||||
config: args.config,
|
||||
maxWorkers: args.maxWorkers,
|
||||
port: args.port,
|
||||
@@ -72,26 +73,24 @@ async function runServer(
|
||||
const protocol = args.https === true ? 'https' : 'http';
|
||||
const devServerUrl = url.format({protocol, hostname, port});
|
||||
|
||||
console.info(
|
||||
chalk.blue(`\nWelcome to React Native v${cliConfig.reactNativeVersion}`),
|
||||
);
|
||||
logger.info(`Welcome to React Native v${ctx.reactNativeVersion}`);
|
||||
|
||||
const serverStatus = await isDevServerRunning(devServerUrl, projectRoot);
|
||||
|
||||
if (serverStatus === 'matched_server_running') {
|
||||
console.info(
|
||||
logger.info(
|
||||
`A dev server is already running for this project on port ${port}. Exiting.`,
|
||||
);
|
||||
return;
|
||||
} else if (serverStatus === 'port_taken') {
|
||||
console.error(
|
||||
`${chalk.red('error')}: Another process is running on port ${port}. Please terminate this ` +
|
||||
logger.error(
|
||||
`Another process is running on port ${port}. Please terminate this ` +
|
||||
'process and try again, or use another port with "--port".',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
console.info(`Starting dev server on ${devServerUrl}\n`);
|
||||
logger.info(`Starting dev server on port ${chalk.bold(String(port))}...`);
|
||||
|
||||
if (args.assetPlugins) {
|
||||
// $FlowIgnore[cannot-write] Assigning to readonly property
|
||||
@@ -100,11 +99,6 @@ async function runServer(
|
||||
);
|
||||
}
|
||||
|
||||
let reportEvent: (event: TerminalReportableEvent) => void;
|
||||
const terminal = new Terminal(process.stdout);
|
||||
const ReporterImpl = getReporterImpl(args.customLogReporterPath);
|
||||
const terminalReporter = new ReporterImpl(terminal);
|
||||
|
||||
const {
|
||||
middleware: communityMiddleware,
|
||||
websocketEndpoints: communityWebsocketEndpoints,
|
||||
@@ -118,9 +112,17 @@ async function runServer(
|
||||
const {middleware, websocketEndpoints} = createDevMiddleware({
|
||||
projectRoot,
|
||||
serverBaseUrl: devServerUrl,
|
||||
logger: createDevMiddlewareLogger(terminalReporter),
|
||||
logger,
|
||||
unstable_experiments: {
|
||||
// NOTE: Only affects the /open-debugger endpoint
|
||||
enableNewDebugger: args.experimentalDebugger,
|
||||
},
|
||||
});
|
||||
|
||||
let reportEvent: (event: TerminalReportableEvent) => void;
|
||||
const terminal = new Terminal(process.stdout);
|
||||
const ReporterImpl = getReporterImpl(args.customLogReporterPath);
|
||||
const terminalReporter = new ReporterImpl(terminal);
|
||||
const reporter: Reporter = {
|
||||
update(event: TerminalReportableEvent) {
|
||||
terminalReporter.update(event);
|
||||
@@ -128,15 +130,12 @@ async function runServer(
|
||||
reportEvent(event);
|
||||
}
|
||||
if (args.interactive && event.type === 'initialize_done') {
|
||||
terminalReporter.update({
|
||||
type: 'unstable_server_log',
|
||||
level: 'info',
|
||||
data: `Dev server ready. ${chalk.dim('Press Ctrl+C to exit.')}`,
|
||||
});
|
||||
logger.info('Dev server ready');
|
||||
attachKeyHandlers({
|
||||
cliConfig: ctx,
|
||||
devServerUrl,
|
||||
messageSocket: messageSocketEndpoint,
|
||||
reporter: terminalReporter,
|
||||
experimentalDebuggerFrontend: args.experimentalDebugger,
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -174,7 +173,7 @@ async function runServer(
|
||||
//
|
||||
serverInstance.keepAliveTimeout = 30000;
|
||||
|
||||
await version.logIfUpdateAvailable(cliConfig, terminalReporter);
|
||||
await version.logIfUpdateAvailable(ctx.root);
|
||||
}
|
||||
|
||||
function getReporterImpl(customLogReporterPath?: string): TerminalReporter {
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import {CLIError} from './errors';
|
||||
import {logger} from './logger';
|
||||
|
||||
const CTRL_C = '\u0003';
|
||||
|
||||
/** An abstract key stroke interceptor. */
|
||||
export class KeyPressHandler {
|
||||
_isInterceptingKeyStrokes = false;
|
||||
_isHandlingKeyPress = false;
|
||||
_onPress: (key: string) => Promise<void>;
|
||||
|
||||
constructor(onPress: (key: string) => Promise<void>) {
|
||||
this._onPress = onPress;
|
||||
}
|
||||
|
||||
/** Start observing interaction pause listeners. */
|
||||
createInteractionListener(): ({pause: boolean, ...}) => void {
|
||||
// Support observing prompts.
|
||||
let wasIntercepting = false;
|
||||
|
||||
const listener = ({pause}: {pause: boolean, ...}) => {
|
||||
if (pause) {
|
||||
// Track if we were already intercepting key strokes before pausing, so we can
|
||||
// resume after pausing.
|
||||
wasIntercepting = this._isInterceptingKeyStrokes;
|
||||
this.stopInterceptingKeyStrokes();
|
||||
} else if (wasIntercepting) {
|
||||
// Only start if we were previously intercepting.
|
||||
this.startInterceptingKeyStrokes();
|
||||
}
|
||||
};
|
||||
|
||||
return listener;
|
||||
}
|
||||
|
||||
_handleKeypress = async (key: string): Promise<CLIError | void> => {
|
||||
// Prevent sending another event until the previous event has finished.
|
||||
if (this._isHandlingKeyPress && key !== CTRL_C) {
|
||||
return;
|
||||
}
|
||||
this._isHandlingKeyPress = true;
|
||||
try {
|
||||
logger.debug(`Key pressed: ${key}`);
|
||||
await this._onPress(key);
|
||||
} catch (error) {
|
||||
return new CLIError('There was an error with the key press handler.');
|
||||
} finally {
|
||||
this._isHandlingKeyPress = false;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
/** Start intercepting all key strokes and passing them to the input `onPress` method. */
|
||||
startInterceptingKeyStrokes() {
|
||||
if (this._isInterceptingKeyStrokes) {
|
||||
return;
|
||||
}
|
||||
this._isInterceptingKeyStrokes = true;
|
||||
const {stdin} = process;
|
||||
// $FlowFixMe[prop-missing]
|
||||
stdin.setRawMode(true);
|
||||
stdin.resume();
|
||||
stdin.setEncoding('utf8');
|
||||
stdin.on('data', this._handleKeypress);
|
||||
}
|
||||
|
||||
/** Stop intercepting all key strokes. */
|
||||
stopInterceptingKeyStrokes() {
|
||||
if (!this._isInterceptingKeyStrokes) {
|
||||
return;
|
||||
}
|
||||
this._isInterceptingKeyStrokes = false;
|
||||
const {stdin} = process;
|
||||
stdin.removeListener('data', this._handleKeypress);
|
||||
// $FlowFixMe[prop-missing]
|
||||
stdin.setRawMode(false);
|
||||
stdin.resume();
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import type TerminalReporter from 'metro/src/lib/TerminalReporter';
|
||||
|
||||
type LoggerFn = (...message: $ReadOnlyArray<string>) => void;
|
||||
|
||||
/**
|
||||
* Create a dev-middleware logger object that will emit logs via Metro's
|
||||
* terminal reporter.
|
||||
*/
|
||||
export default function createDevMiddlewareLogger(
|
||||
reporter: TerminalReporter,
|
||||
): $ReadOnly<{
|
||||
info: LoggerFn,
|
||||
error: LoggerFn,
|
||||
warn: LoggerFn,
|
||||
}> {
|
||||
return {
|
||||
info: makeLogger(reporter, 'info'),
|
||||
warn: makeLogger(reporter, 'warn'),
|
||||
error: makeLogger(reporter, 'error'),
|
||||
};
|
||||
}
|
||||
|
||||
function makeLogger(
|
||||
reporter: TerminalReporter,
|
||||
level: 'info' | 'warn' | 'error',
|
||||
): LoggerFn {
|
||||
return (...data: Array<mixed>) =>
|
||||
reporter.update({
|
||||
type: 'unstable_server_log',
|
||||
level,
|
||||
data,
|
||||
});
|
||||
}
|
||||
@@ -13,12 +13,11 @@ import type {Config} from '@react-native-community/cli-types';
|
||||
import type {ConfigT, InputConfigT, YargArguments} from 'metro-config';
|
||||
|
||||
import {CLIError} from './errors';
|
||||
import {logger} from './logger';
|
||||
import {reactNativePlatformResolver} from './metroPlatformResolver';
|
||||
import {loadConfig, mergeConfig, resolveConfig} from 'metro-config';
|
||||
import path from 'path';
|
||||
|
||||
const debug = require('debug')('ReactNative:CommunityCliPlugin');
|
||||
|
||||
export type {Config};
|
||||
|
||||
export type ConfigLoadingContext = $ReadOnly<{
|
||||
@@ -93,20 +92,20 @@ export default async function loadMetroConfig(
|
||||
throw new CLIError(`No Metro config found in ${cwd}`);
|
||||
}
|
||||
|
||||
debug(`Reading Metro config from ${projectConfig.filepath}`);
|
||||
logger.debug(`Reading Metro config from ${projectConfig.filepath}`);
|
||||
|
||||
if (!global.__REACT_NATIVE_METRO_CONFIG_LOADED) {
|
||||
const warning = `
|
||||
=================================================================================================
|
||||
From React Native 0.73, your project's Metro config should extend '@react-native/metro-config'
|
||||
or it will fail to build. Please copy the template at:
|
||||
https://github.com/react-native-community/template/blob/main/template/metro.config.js
|
||||
https://github.com/facebook/react-native/blob/main/packages/react-native/template/metro.config.js
|
||||
This warning will be removed in future (https://github.com/facebook/metro/issues/1018).
|
||||
=================================================================================================
|
||||
`;
|
||||
|
||||
for (const line of warning.trim().split('\n')) {
|
||||
console.warn(line);
|
||||
logger.warn(line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import chalk from 'chalk';
|
||||
|
||||
const SEPARATOR = ', ';
|
||||
|
||||
let verbose: boolean = process.argv.includes('--verbose');
|
||||
let disabled: boolean = false;
|
||||
let hidden: boolean = false;
|
||||
|
||||
const formatMessages = (messages: Array<string>) =>
|
||||
chalk.reset(messages.join(SEPARATOR));
|
||||
|
||||
const success = (...messages: Array<string>) => {
|
||||
if (!disabled) {
|
||||
console.log(`${chalk.green.bold('success')} ${formatMessages(messages)}`);
|
||||
}
|
||||
};
|
||||
|
||||
const info = (...messages: Array<string>) => {
|
||||
if (!disabled) {
|
||||
console.log(`${chalk.cyan.bold('info')} ${formatMessages(messages)}`);
|
||||
}
|
||||
};
|
||||
|
||||
const warn = (...messages: Array<string>) => {
|
||||
if (!disabled) {
|
||||
console.warn(`${chalk.yellow.bold('warn')} ${formatMessages(messages)}`);
|
||||
}
|
||||
};
|
||||
|
||||
const error = (...messages: Array<string>) => {
|
||||
if (!disabled) {
|
||||
console.error(`${chalk.red.bold('error')} ${formatMessages(messages)}`);
|
||||
}
|
||||
};
|
||||
|
||||
const debug = (...messages: Array<string>) => {
|
||||
if (verbose && !disabled) {
|
||||
console.log(`${chalk.gray.bold('debug')} ${formatMessages(messages)}`);
|
||||
} else {
|
||||
hidden = true;
|
||||
}
|
||||
};
|
||||
|
||||
const log = (...messages: Array<string>) => {
|
||||
if (!disabled) {
|
||||
console.log(`${formatMessages(messages)}`);
|
||||
}
|
||||
};
|
||||
|
||||
const setVerbose = (level: boolean) => {
|
||||
verbose = level;
|
||||
};
|
||||
|
||||
const isVerbose = (): boolean => verbose;
|
||||
|
||||
const disable = () => {
|
||||
disabled = true;
|
||||
};
|
||||
|
||||
const enable = () => {
|
||||
disabled = false;
|
||||
};
|
||||
|
||||
const hasDebugMessages = (): boolean => hidden;
|
||||
|
||||
let communityLogger;
|
||||
try {
|
||||
const {logger} = require('@react-native-community/cli-tools');
|
||||
logger.debug("Using @react-naive-community/cli-tools' logger");
|
||||
communityLogger = logger;
|
||||
} catch {
|
||||
// This is no longer a required dependency in react-native projects, but use it instead of
|
||||
// our forked version if it's available. Fail silently otherwise.
|
||||
}
|
||||
|
||||
type Logger = $ReadOnly<{
|
||||
debug: (...message: Array<string>) => void,
|
||||
error: (...message: Array<string>) => void,
|
||||
log: (...message: Array<string>) => void,
|
||||
info: (...message: Array<string>) => void,
|
||||
warn: (...message: Array<string>) => void,
|
||||
...
|
||||
}>;
|
||||
|
||||
export const logger: Logger = communityLogger ?? {
|
||||
success,
|
||||
info,
|
||||
warn,
|
||||
error,
|
||||
debug,
|
||||
log,
|
||||
setVerbose,
|
||||
isVerbose,
|
||||
hasDebugMessages,
|
||||
disable,
|
||||
enable,
|
||||
};
|
||||
|
||||
if (communityLogger == null) {
|
||||
logger.debug("Using @react-native/communityu-cli-plugin's logger");
|
||||
}
|
||||
@@ -9,14 +9,12 @@
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import type {Config} from '@react-native-community/cli-types';
|
||||
import type TerminalReporter from 'metro/src/lib/TerminalReporter';
|
||||
|
||||
import {logger} from './logger';
|
||||
import chalk from 'chalk';
|
||||
import {readFileSync} from 'fs';
|
||||
import path from 'path';
|
||||
import semver from 'semver';
|
||||
|
||||
const debug = require('debug')('ReactNative:CommunityCliPlugin');
|
||||
|
||||
type Release = {
|
||||
// The current stable release
|
||||
stable: string,
|
||||
@@ -37,6 +35,15 @@ interface DiffPurge {
|
||||
node_id: string;
|
||||
}
|
||||
|
||||
type Update = {
|
||||
// Only populated if an upgrade is available
|
||||
upgrade?: Release,
|
||||
// The project's package's current version
|
||||
current: string,
|
||||
// The project's package's name
|
||||
name: string,
|
||||
};
|
||||
|
||||
type LatestVersions = {
|
||||
candidate?: string,
|
||||
stable: string,
|
||||
@@ -47,45 +54,68 @@ type Headers = {
|
||||
[header: string]: string,
|
||||
};
|
||||
|
||||
function getReactNativeVersion(projectRoot: string): string | void {
|
||||
try {
|
||||
const resolvedPath: string = require.resolve('react-native/package.json', {
|
||||
paths: [projectRoot],
|
||||
});
|
||||
logger.debug(
|
||||
`Found 'react-native' from '${projectRoot}' -> '${resolvedPath}'`,
|
||||
);
|
||||
return JSON.parse(readFileSync(resolvedPath, 'utf8')).version;
|
||||
} catch {
|
||||
logger.debug("Couldn't read the version of 'react-native'");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs out a message if the user's version is behind a stable version of React Native
|
||||
*/
|
||||
export async function logIfUpdateAvailable(
|
||||
cliConfig: Config,
|
||||
reporter: TerminalReporter,
|
||||
): Promise<void> {
|
||||
const {reactNativeVersion: currentVersion} = cliConfig;
|
||||
let newVersion = null;
|
||||
export async function logIfUpdateAvailable(projectRoot: string): Promise<void> {
|
||||
const versions = await latest(projectRoot);
|
||||
if (!versions?.upgrade) {
|
||||
return;
|
||||
}
|
||||
if (semver.gt(versions.upgrade.stable, versions.current)) {
|
||||
logger.info(
|
||||
`React Native v${versions.upgrade.stable} is now available (your project is running on v${versions.name}).
|
||||
Changelog: ${chalk.dim.underline(versions.upgrade?.changelogUrl ?? 'none')}
|
||||
Diff: ${chalk.dim.underline(versions.upgrade?.diffUrl ?? 'none')}
|
||||
`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the latest stables version of React Native > current version
|
||||
*/
|
||||
async function latest(projectRoot: string): Promise<Update | void> {
|
||||
try {
|
||||
const upgrade = await getLatestRelease(currentVersion);
|
||||
const currentVersion = getReactNativeVersion(projectRoot);
|
||||
if (currentVersion == null) {
|
||||
return;
|
||||
}
|
||||
const {name} = JSON.parse(
|
||||
readFileSync(path.join(projectRoot, 'package.json'), 'utf8'),
|
||||
);
|
||||
const upgrade = await getLatestRelease(name, currentVersion);
|
||||
|
||||
if (upgrade) {
|
||||
newVersion = upgrade;
|
||||
return {
|
||||
name,
|
||||
current: currentVersion,
|
||||
upgrade,
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
// We let the flow continue as this component is not vital for the rest of
|
||||
// the CLI.
|
||||
debug(
|
||||
logger.debug(
|
||||
'Cannot detect current version of React Native, ' +
|
||||
'skipping check for a newer release',
|
||||
);
|
||||
debug(e);
|
||||
}
|
||||
|
||||
if (newVersion == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (semver.gt(newVersion.stable, currentVersion)) {
|
||||
reporter.update({
|
||||
type: 'unstable_server_log',
|
||||
level: 'info',
|
||||
data: `React Native v${newVersion.stable} is now available (your project is running on v${currentVersion}).
|
||||
Changelog: ${chalk.dim.underline(newVersion?.changelogUrl ?? 'none')}
|
||||
Diff: ${chalk.dim.underline(newVersion?.diffUrl ?? 'none')}
|
||||
`,
|
||||
});
|
||||
logger.debug(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,11 +136,12 @@ function isDiffPurgeEntry(data: Partial<DiffPurge>): data is DiffPurge {
|
||||
* will return undefined.
|
||||
*/
|
||||
export default async function getLatestRelease(
|
||||
name: string,
|
||||
currentVersion: string,
|
||||
): Promise<Release | void> {
|
||||
debug('Checking for a newer version of React Native');
|
||||
logger.debug('Checking for a newer version of React Native');
|
||||
try {
|
||||
debug(`Current version: ${currentVersion}`);
|
||||
logger.debug(`Current version: ${currentVersion}`);
|
||||
|
||||
// if the version is a nightly/canary build, we want to bail
|
||||
// since they are nightlies or unreleased versions
|
||||
@@ -118,14 +149,14 @@ export default async function getLatestRelease(
|
||||
return;
|
||||
}
|
||||
|
||||
debug('Checking for newer releases on GitHub');
|
||||
const latestVersion = await getLatestRnDiffPurgeVersion();
|
||||
logger.debug('Checking for newer releases on GitHub');
|
||||
const latestVersion = await getLatestRnDiffPurgeVersion(name);
|
||||
if (latestVersion == null) {
|
||||
debug('Failed to get latest release');
|
||||
logger.debug('Failed to get latest release');
|
||||
return;
|
||||
}
|
||||
const {stable, candidate} = latestVersion;
|
||||
debug(`Latest release: ${stable} (${candidate ?? ''})`);
|
||||
logger.debug(`Latest release: ${stable} (${candidate ?? ''})`);
|
||||
|
||||
if (semver.compare(stable, currentVersion) >= 0) {
|
||||
return {
|
||||
@@ -136,8 +167,10 @@ export default async function getLatestRelease(
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
debug('Something went wrong with remote version checking, moving on');
|
||||
debug(e);
|
||||
logger.debug(
|
||||
'Something went wrong with remote version checking, moving on',
|
||||
);
|
||||
logger.debug(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +185,9 @@ function buildDiffUrl(oldVersion: string, newVersion: string) {
|
||||
/**
|
||||
* Returns the most recent React Native version available to upgrade to.
|
||||
*/
|
||||
async function getLatestRnDiffPurgeVersion(): Promise<LatestVersions | void> {
|
||||
async function getLatestRnDiffPurgeVersion(
|
||||
name: string,
|
||||
): Promise<LatestVersions | void> {
|
||||
const options = {
|
||||
// https://developer.github.com/v3/#user-agent-required
|
||||
headers: {'User-Agent': '@react-native/community-cli-plugin'} as Headers,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@react-native/core-cli-utils",
|
||||
"version": "0.77.0-main",
|
||||
"version": "0.76.0-main",
|
||||
"description": "React Native CLI library for Frameworks to build on",
|
||||
"license": "MIT",
|
||||
"main": "./src/index.flow.js",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@generated SignedSource<<b5e82d2eb99e1ed4c012065a530ca78b>>
|
||||
Git revision: ff343d805527223750fafb8573ee48f8e2fb0d1e
|
||||
@generated SignedSource<<e8d57aefb12604f69c383af770cbf1ed>>
|
||||
Git revision: 7b143e5d05a102c8c9cc7e282bab7b0751f75d61
|
||||
Built with --nohooks: false
|
||||
Is local checkout: false
|
||||
Remote URL: https://github.com/facebookexperimental/rn-chrome-devtools-frontend
|
||||
|
||||
@@ -18,9 +18,6 @@ style.setProperty('--image-file-navigationControls_2x', 'url(\"' + new URL('./na
|
||||
style.setProperty('--image-file-navigationControls', 'url(\"' + new URL('./navigationControls.png', import.meta.url).toString() + '\")');
|
||||
style.setProperty('--image-file-nodeIcon', 'url(\"' + new URL('./nodeIcon.avif', import.meta.url).toString() + '\")');
|
||||
style.setProperty('--image-file-popoverArrows', 'url(\"' + new URL('./popoverArrows.png', import.meta.url).toString() + '\")');
|
||||
style.setProperty('--image-file-react_native/learn-debugging-basics', 'url(\"' + new URL('./react_native/learn-debugging-basics.jpg', import.meta.url).toString() + '\")');
|
||||
style.setProperty('--image-file-react_native/learn-native-debugging', 'url(\"' + new URL('./react_native/learn-native-debugging.jpg', import.meta.url).toString() + '\")');
|
||||
style.setProperty('--image-file-react_native/learn-react-native-devtools', 'url(\"' + new URL('./react_native/learn-react-native-devtools.jpg', import.meta.url).toString() + '\")');
|
||||
style.setProperty('--image-file-react_native/welcomeIcon', 'url(\"' + new URL('./react_native/welcomeIcon.png', import.meta.url).toString() + '\")');
|
||||
style.setProperty('--image-file-toolbarResizerVertical', 'url(\"' + new URL('./toolbarResizerVertical.png', import.meta.url).toString() + '\")');
|
||||
style.setProperty('--image-file-touchCursor_2x', 'url(\"' + new URL('./touchCursor_2x.png', import.meta.url).toString() + '\")');
|
||||
|
||||
packages/debugger-frontend/dist/third-party/front_end/Images/react_native/learn-debugging-basics.jpg
Vendored
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 53 KiB |
packages/debugger-frontend/dist/third-party/front_end/Images/react_native/learn-native-debugging.jpg
Vendored
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 66 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 97 KiB |
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -1 +1 @@
|
||||
import*as e from"../root/root.js";const t=e.Runtime.RNExperimentName,i={didInitializeExperiments:!1,isReactNativeEntryPoint:!1};class n{name;title;unstable;docLink;feedbackLink;enabledByDefault;constructor(e){this.name=e.name,this.title=e.title,this.unstable=e.unstable,this.docLink=e.docLink,this.feedbackLink=e.feedbackLink,this.enabledByDefault=function(e,t){if(null==e)return()=>t;if("boolean"==typeof e)return()=>e;return e}(e.enabledByDefault,!1)}}const r=new class{#e=new Map;#t=new Set;register(e){if(i.didInitializeExperiments)throw new Error("Experiments must be registered before constructing MainImpl");const{name:t}=e;if(this.#e.has(t))throw new Error(`React Native Experiment ${t} is already registered`);this.#e.set(t,new n(e))}enableExperimentsByDefault(e){if(i.didInitializeExperiments)throw new Error("Experiments must be configured before constructing MainImpl");for(const i of e)if(Object.prototype.hasOwnProperty.call(t,i)){const e=this.#e.get(i);if(!e)throw new Error(`React Native Experiment ${i} is not registered`);e.enabledByDefault=()=>!0}else this.#t.add(i)}copyInto(e,t=""){for(const[n,r]of this.#e)e.register(n,t+r.title,r.unstable,r.docLink,r.feedbackLink),r.enabledByDefault({isReactNativeEntryPoint:i.isReactNativeEntryPoint})&&e.enableExperimentsByDefault([n]);for(const t of this.#t)e.enableExperimentsByDefault([t]);i.didInitializeExperiments=!0}};r.register({name:t.JS_HEAP_PROFILER_ENABLE,title:"Enable Heap Profiler (Memory Panel)",unstable:!1,enabledByDefault:({isReactNativeEntryPoint:e})=>!e}),r.register({name:t.REACT_NATIVE_SPECIFIC_UI,title:"Show React Native-specific UI",unstable:!1,enabledByDefault:({isReactNativeEntryPoint:e})=>e}),r.register({name:t.ENABLE_PERFORMANCE_PANEL,title:"Enable Performance panel",unstable:!0,enabledByDefault:({isReactNativeEntryPoint:e})=>!e});var a=Object.freeze({__proto__:null,RNExperimentName:t,setIsReactNativeEntryPoint:function(e){if(i.didInitializeExperiments)throw new Error("setIsReactNativeEntryPoint must be called before constructing MainImpl");i.isReactNativeEntryPoint=e},Instance:r});export{a as RNExperimentsImpl};
|
||||
import*as e from"../root/root.js";const t=e.Runtime.RNExperimentName,i={didInitializeExperiments:!1,isReactNativeEntryPoint:!1};class n{name;title;unstable;docLink;feedbackLink;enabledByDefault;constructor(e){this.name=e.name,this.title=e.title,this.unstable=e.unstable,this.docLink=e.docLink,this.feedbackLink=e.feedbackLink,this.enabledByDefault=function(e,t){if(null==e)return()=>t;if("boolean"==typeof e)return()=>e;return e}(e.enabledByDefault,!1)}}const r=new class{#e=new Map;#t=new Set;register(e){if(i.didInitializeExperiments)throw new Error("Experiments must be registered before constructing MainImpl");const{name:t}=e;if(this.#e.has(t))throw new Error(`React Native Experiment ${t} is already registered`);this.#e.set(t,new n(e))}enableExperimentsByDefault(e){if(i.didInitializeExperiments)throw new Error("Experiments must be configured before constructing MainImpl");for(const i of e)if(Object.prototype.hasOwnProperty.call(t,i)){const e=this.#e.get(i);if(!e)throw new Error(`React Native Experiment ${i} is not registered`);e.enabledByDefault=()=>!0}else this.#t.add(i)}copyInto(e,t=""){for(const[n,r]of this.#e)e.register(n,t+r.title,r.unstable,r.docLink,r.feedbackLink),r.enabledByDefault({isReactNativeEntryPoint:i.isReactNativeEntryPoint})&&e.enableExperimentsByDefault([n]);for(const t of this.#t)e.enableExperimentsByDefault([t]);i.didInitializeExperiments=!0}};r.register({name:t.JS_HEAP_PROFILER_ENABLE,title:"Enable Heap Profiler",unstable:!1,enabledByDefault:({isReactNativeEntryPoint:e})=>!e}),r.register({name:t.REACT_NATIVE_SPECIFIC_UI,title:"Show React Native-specific UI",unstable:!1,enabledByDefault:({isReactNativeEntryPoint:e})=>e}),r.register({name:t.ENABLE_PERFORMANCE_PANEL,title:"Enable Performance panel",unstable:!0,enabledByDefault:({isReactNativeEntryPoint:e})=>!e});var a=Object.freeze({__proto__:null,RNExperimentName:t,setIsReactNativeEntryPoint:function(e){if(i.didInitializeExperiments)throw new Error("setIsReactNativeEntryPoint must be called before constructing MainImpl");i.isReactNativeEntryPoint=e},Instance:r});export{a as RNExperimentsImpl};
|
||||
|
||||
@@ -1 +1 @@
|
||||
import*as e from"../platform/platform.js";const t=new URLSearchParams(location.search);let n,s="";class r{constructor(){}static instance(e={forceNew:null}){const{forceNew:t}=e;return n&&!t||(n=new r),n}static removeInstance(){n=void 0}static queryParam(e){return t.get(e)}static setQueryParamForTesting(e,n){t.set(e,n)}static experimentsSetting(){try{return e.StringUtilities.toKebabCaseKeys(JSON.parse(self.localStorage&&self.localStorage.experiments?self.localStorage.experiments:"{}"))}catch(e){return console.error("Failed to parse localStorage['experiments']"),{}}}static setPlatform(e){s=e}static platform(){return s}static isDescriptorEnabled(e){const{experiment:t}=e;if("*"===t)return!0;if(t&&t.startsWith("!")&&o.isEnabled(t.substring(1)))return!1;if(t&&!t.startsWith("!")&&!o.isEnabled(t))return!1;const{condition:n}=e;return!n||n()}loadLegacyModule(e){return import(`../../${e}`)}}class i{#e;#t;#n;#s;#r;constructor(){this.#e=[],this.#t=new Set,this.#n=new Set,this.#s=new Set,this.#r=new Set}allConfigurableExperiments(){const e=[];for(const t of this.#e)this.#n.has(t.name)||e.push(t);return e}setExperimentsSetting(e){self.localStorage&&(self.localStorage.experiments=JSON.stringify(e))}register(t,n,s,r,i){if(this.#t.has(t))throw new Error(`Duplicate registraction of experiment '${t}'`);this.#t.add(t),this.#e.push(new a(this,t,n,Boolean(s),r??e.DevToolsPath.EmptyUrlString,i??e.DevToolsPath.EmptyUrlString))}isEnabled(e){return this.checkExperiment(e),!1!==r.experimentsSetting()[e]&&(!(!this.#n.has(e)&&!this.#s.has(e))||(!!this.#r.has(e)||Boolean(r.experimentsSetting()[e])))}setEnabled(e,t){this.checkExperiment(e);const n=r.experimentsSetting();n[e]=t,this.setExperimentsSetting(n)}enableExperimentsTransiently(e){for(const t of e)this.checkExperiment(t),this.#n.add(t)}enableExperimentsByDefault(e){for(const t of e)this.checkExperiment(t),this.#s.add(t)}setServerEnabledExperiments(e){for(const t of e)this.checkExperiment(t),this.#r.add(t)}enableForTest(e){this.checkExperiment(e),this.#n.add(e)}disableForTest(e){this.checkExperiment(e),this.#n.delete(e)}clearForTest(){this.#e=[],this.#t.clear(),this.#n.clear(),this.#s.clear(),this.#r.clear()}cleanUpStaleExperiments(){const e=r.experimentsSetting(),t={};for(const{name:n}of this.#e)if(e.hasOwnProperty(n)){const s=e[n];(s||this.#s.has(n))&&(t[n]=s)}this.setExperimentsSetting(t)}checkExperiment(e){if(!this.#t.has(e))throw new Error(`Unknown experiment '${e}'`)}}class a{name;title;unstable;docLink;feedbackLink;#e;constructor(e,t,n,s,r,i){this.name=t,this.title=n,this.unstable=s,this.docLink=r,this.feedbackLink=i,this.#e=e}isEnabled(){return this.#e.isEnabled(this.name)}setEnabled(e){this.#e.setEnabled(this.name,e)}}const o=new i;var l,c;!function(e){e.REACT_NATIVE_SPECIFIC_UI="react-native-specific-ui",e.JS_HEAP_PROFILER_ENABLE="js-heap-profiler-enable",e.ENABLE_PERFORMANCE_PANEL="enable-performance-panel"}(l||(l={})),function(e){e.CAN_DOCK="can_dock",e.NOT_SOURCES_HIDE_ADD_FOLDER="!sources.hide_add_folder",e.REACT_NATIVE_UNSTABLE_NETWORK_PANEL="unstable_enableNetworkPanel"}(c||(c={}));const m={canDock:()=>Boolean(r.queryParam("can_dock")),notSourcesHideAddFolder:()=>Boolean(r.queryParam(c.NOT_SOURCES_HIDE_ADD_FOLDER)),reactNativeUnstableNetworkPanel:()=>Boolean(r.queryParam(c.REACT_NATIVE_UNSTABLE_NETWORK_PANEL))};var h=Object.freeze({__proto__:null,getRemoteBase:function(e=self.location.toString()){const t=new URL(e).searchParams.get("remoteBase");if(!t)return null;const n=/\/serve_file\/(@[0-9a-zA-Z]+)\/?$/.exec(t);return n?{base:`devtools://devtools/remote/serve_file/${n[1]}/`,version:n[1]}:null},Runtime:r,ExperimentsSupport:i,Experiment:a,experiments:o,get RNExperimentName(){return l},get ConditionName(){return c},conditions:m});export{h as Runtime};
|
||||
import*as e from"../platform/platform.js";const t=new URLSearchParams(location.search);let n,s="";class r{constructor(){}static instance(e={forceNew:null}){const{forceNew:t}=e;return n&&!t||(n=new r),n}static removeInstance(){n=void 0}static queryParam(e){return t.get(e)}static setQueryParamForTesting(e,n){t.set(e,n)}static experimentsSetting(){try{return e.StringUtilities.toKebabCaseKeys(JSON.parse(self.localStorage&&self.localStorage.experiments?self.localStorage.experiments:"{}"))}catch(e){return console.error("Failed to parse localStorage['experiments']"),{}}}static setPlatform(e){s=e}static platform(){return s}static isDescriptorEnabled(e){const{experiment:t}=e;if("*"===t)return!0;if(t&&t.startsWith("!")&&l.isEnabled(t.substring(1)))return!1;if(t&&!t.startsWith("!")&&!l.isEnabled(t))return!1;const{condition:n}=e;return!n||n()}loadLegacyModule(e){return import(`../../${e}`)}}class i{#e;#t;#n;#s;#r;constructor(){this.#e=[],this.#t=new Set,this.#n=new Set,this.#s=new Set,this.#r=new Set}allConfigurableExperiments(){const e=[];for(const t of this.#e)this.#n.has(t.name)||e.push(t);return e}setExperimentsSetting(e){self.localStorage&&(self.localStorage.experiments=JSON.stringify(e))}register(t,n,s,r,i){if(this.#t.has(t))throw new Error(`Duplicate registraction of experiment '${t}'`);this.#t.add(t),this.#e.push(new a(this,t,n,Boolean(s),r??e.DevToolsPath.EmptyUrlString,i??e.DevToolsPath.EmptyUrlString))}isEnabled(e){return this.checkExperiment(e),!1!==r.experimentsSetting()[e]&&(!(!this.#n.has(e)&&!this.#s.has(e))||(!!this.#r.has(e)||Boolean(r.experimentsSetting()[e])))}setEnabled(e,t){this.checkExperiment(e);const n=r.experimentsSetting();n[e]=t,this.setExperimentsSetting(n)}enableExperimentsTransiently(e){for(const t of e)this.checkExperiment(t),this.#n.add(t)}enableExperimentsByDefault(e){for(const t of e)this.checkExperiment(t),this.#s.add(t)}setServerEnabledExperiments(e){for(const t of e)this.checkExperiment(t),this.#r.add(t)}enableForTest(e){this.checkExperiment(e),this.#n.add(e)}disableForTest(e){this.checkExperiment(e),this.#n.delete(e)}clearForTest(){this.#e=[],this.#t.clear(),this.#n.clear(),this.#s.clear(),this.#r.clear()}cleanUpStaleExperiments(){const e=r.experimentsSetting(),t={};for(const{name:n}of this.#e)if(e.hasOwnProperty(n)){const s=e[n];(s||this.#s.has(n))&&(t[n]=s)}this.setExperimentsSetting(t)}checkExperiment(e){if(!this.#t.has(e))throw new Error(`Unknown experiment '${e}'`)}}class a{name;title;unstable;docLink;feedbackLink;#e;constructor(e,t,n,s,r,i){this.name=t,this.title=n,this.unstable=s,this.docLink=r,this.feedbackLink=i,this.#e=e}isEnabled(){return this.#e.isEnabled(this.name)}setEnabled(e){this.#e.setEnabled(this.name,e)}}const l=new i;var o,c;!function(e){e.REACT_NATIVE_SPECIFIC_UI="react-native-specific-ui",e.JS_HEAP_PROFILER_ENABLE="js-heap-profiler-enable",e.ENABLE_PERFORMANCE_PANEL="enable-performance-panel"}(o||(o={})),function(e){e.CAN_DOCK="can_dock",e.NOT_SOURCES_HIDE_ADD_FOLDER="!sources.hide_add_folder",e.REACT_NATIVE_UNSTABLE_NETWORK_PANEL="unstable_enableNetworkPanel",e.REACT_NATIVE_USE_INTERNAL_BRANDING="unstable_useInternalBranding"}(c||(c={}));const m={canDock:()=>Boolean(r.queryParam("can_dock")),notSourcesHideAddFolder:()=>Boolean(r.queryParam(c.NOT_SOURCES_HIDE_ADD_FOLDER)),reactNativeUnstableNetworkPanel:()=>Boolean(r.queryParam(c.REACT_NATIVE_UNSTABLE_NETWORK_PANEL))};var h=Object.freeze({__proto__:null,getRemoteBase:function(e=self.location.toString()){const t=new URL(e).searchParams.get("remoteBase");if(!t)return null;const n=/\/serve_file\/(@[0-9a-zA-Z]+)\/?$/.exec(t);return n?{base:`devtools://devtools/remote/serve_file/${n[1]}/`,version:n[1]}:null},Runtime:r,ExperimentsSupport:i,Experiment:a,experiments:l,get RNExperimentName(){return o},get ConditionName(){return c},conditions:m});export{h as Runtime};
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+2
-2
File diff suppressed because one or more lines are too long
Vendored
+1
@@ -0,0 +1 @@
|
||||
import*as e from"../../core/i18n/i18n.js";import*as t from"../../ui/legacy/legacy.js";const o={title:"⚛️ React DevTools",command:"Show React DevTools panel"},a=e.i18n.registerUIStrings("panels/react_devtools/react_devtools-meta.ts",o),i=e.i18n.getLazilyComputedLocalizedString.bind(void 0,a);let n;t.ViewManager.registerViewExtension({location:"panel",id:"react-devtools",title:i(o.title),commandPrompt:i(o.command),persistence:"permanent",order:1e3,loadView:async()=>new((await async function(){return n||(n=await import("./react_devtools.js")),n}()).ReactDevToolsView.ReactDevToolsViewImpl)});
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
-1
@@ -1 +0,0 @@
|
||||
import*as e from"../../core/i18n/i18n.js";import*as o from"../../ui/legacy/legacy.js";const t={title:"Components ⚛",command:"Show React DevTools Components panel"},n=e.i18n.registerUIStrings("panels/react_devtools/react_devtools_components-meta.ts",t),a=e.i18n.getLazilyComputedLocalizedString.bind(void 0,n);let i;o.ViewManager.registerViewExtension({location:"panel",id:"react-devtools-components",title:a(t.title),commandPrompt:a(t.command),persistence:"permanent",order:1e3,loadView:async()=>new((await async function(){return i||(i=await import("./react_devtools.js")),i}()).ReactDevToolsComponentsView.ReactDevToolsComponentsViewImpl)});
|
||||
-1
@@ -1 +0,0 @@
|
||||
import*as e from"../../core/i18n/i18n.js";import*as o from"../../ui/legacy/legacy.js";const t={title:"Profiler ⚛",command:"Show React DevTools Profiler panel"},i=e.i18n.registerUIStrings("panels/react_devtools/react_devtools_profiler-meta.ts",t),r=e.i18n.getLazilyComputedLocalizedString.bind(void 0,i);let a;o.ViewManager.registerViewExtension({location:"panel",id:"react-devtools-profiler",title:r(t.title),commandPrompt:r(t.command),persistence:"permanent",order:1e3,loadView:async()=>new((await async function(){return a||(a=await import("./react_devtools.js")),a}()).ReactDevToolsProfilerView.ReactDevToolsProfilerViewImpl)});
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import*as e from"../../core/i18n/i18n.js";import"../../core/root/root.js";import*as o from"../../ui/legacy/legacy.js";const n={rnWelcome:"Welcome",showRnWelcome:"Show React Native Welcome panel",debuggerBrandName:"React Native DevTools"},r=e.i18n.registerUIStrings("panels/rn_welcome/rn_welcome-meta.ts",n),a=e.i18n.getLazilyComputedLocalizedString.bind(void 0,r);let i;o.ViewManager.registerViewExtension({location:"panel",id:"rn-welcome",title:a(n.rnWelcome),commandPrompt:a(n.showRnWelcome),order:-10,persistence:"permanent",loadView:async()=>(await async function(){return i||(i=await import("./rn_welcome.js")),i}()).RNWelcome.RNWelcomeImpl.instance({debuggerBrandName:a(n.debuggerBrandName),showBetaLabel:!1,showDocs:!0}),experiment:"react-native-specific-ui"});
|
||||
import*as e from"../../core/i18n/i18n.js";import*as o from"../../core/root/root.js";import*as n from"../../ui/legacy/legacy.js";const a={rnWelcome:"Welcome",showRnWelcome:"Show React Native Welcome panel",debuggerBrandName:"React Native DevTools",debuggerBrandNameInternal:"React Native DevTools (Fusebox ⚡)"},r=e.i18n.registerUIStrings("panels/rn_welcome/rn_welcome-meta.ts",a),t=e.i18n.getLazilyComputedLocalizedString.bind(void 0,r);let i;n.ViewManager.registerViewExtension({location:"panel",id:"rn-welcome",title:t(a.rnWelcome),commandPrompt:t(a.showRnWelcome),order:-10,persistence:"permanent",loadView:async()=>(await async function(){return i||(i=await import("./rn_welcome.js")),i}()).RNWelcome.RNWelcomeImpl.instance({debuggerBrandName:t(Boolean(o.Runtime.Runtime.queryParam(o.Runtime.ConditionName.REACT_NATIVE_USE_INTERNAL_BRANDING))?a.debuggerBrandNameInternal:a.debuggerBrandName),showBetaLabel:!0,showDocs:!0}),experiment:"react-native-specific-ui"});
|
||||
|
||||
+19
-25
@@ -1,59 +1,53 @@
|
||||
import*as e from"../../ui/legacy/legacy.js";import*as t from"../../core/host/host.js";import*as o from"../../core/i18n/i18n.js";import*as i from"../../core/sdk/sdk.js";import*as n from"../../ui/lit-html/lit-html.js";const r=new CSSStyleSheet;r.replaceSync('.rn-welcome-panel{display:flex;flex-direction:column;flex-shrink:0;align-items:stretch;justify-content:center;padding:36px;background-color:var(--color-background-elevation-0);min-height:100%}@media (min-width: 1000px){.rn-welcome-panel{flex-direction:row;align-items:center;justify-content:stretch;height:100%;padding:0}}.rn-welcome-hero{display:flex;flex-direction:column;flex-grow:1;flex-shrink:0;align-items:center;justify-content:center;padding:16px;text-align:center}@media (min-width: 1000px){.rn-welcome-hero{margin-left:24px}}.rn-welcome-heading{display:flex;align-items:center;margin-bottom:16px}.rn-welcome-icon{width:30px;height:30px;border-radius:4px;margin-right:12px}.rn-welcome-title{font-size:20px;font-weight:normal;color:var(--color-text-primary)}.rn-welcome-title-accessory{margin-left:12px;padding:4px 8px;border-radius:4px;background-color:var(--color-green);font-size:12px;color:var(--color-on-primary)}.rn-welcome-title-accessory-purple{background-color:var(--color-purple-bright)}.rn-welcome-tagline{margin-bottom:24px;font-size:1rem;line-height:1.3;color:var(--color-text-secondary)}.rn-welcome-links{display:flex;align-items:center}.rn-welcome-links > .devtools-link{position:relative;margin:0 16px;font-size:14px}.rn-welcome-links > .devtools-link:not(:last-child)::after{content:"";position:absolute;right:-16px;height:16px;border-right:1px solid var(--color-details-hairline)}.rn-welcome-version{position:fixed;top:8px;right:8px;margin-top:24px;padding:4px 12px;border-radius:6px;background-color:var(--color-background-hover-overlay);color:var(--color-text-secondary);font-size:11px}.rn-welcome-docsfeed{display:flex;flex-direction:column;flex-shrink:0;align-items:stretch;max-width:700px;margin:0 auto;padding:24px}@media (min-width: 1000px){.rn-welcome-docsfeed{flex-shrink:1;width:45%;max-height:100%;margin:0;padding:20px 24px;padding-right:80px;overflow:auto}}.rn-welcome-h2{flex-shrink:0;font-size:16px;font-weight:normal;color:var(--color-text-primary)}.rn-welcome-docsfeed-item{display:flex;flex-shrink:0;align-items:center;margin-bottom:8px;padding:8px;padding-right:16px;border:1px solid var(--color-details-hairline);border-radius:4px;background-color:var(--color-background);text-align:left;font-size:14px;cursor:pointer}.rn-welcome-docsfeed-item:hover{background-color:var(--color-background-elevation-0)}.rn-welcome-docsfeed-item:focus{outline:solid var(--color-button-outline-focus)}.rn-welcome-docsfeed-item p{margin:0;margin-bottom:4px;text-decoration:none}.rn-welcome-docsfeed-item :not(.devtools-link){color:var(--color-text-secondary)}.rn-welcome-image{flex-shrink:0;aspect-ratio:calc(16 / 9);height:64px;margin-right:16px;border-radius:2px;background-color:var(--color-gray-100);background-position:center;background-size:cover}\n/*# sourceURL=rnWelcome.css */\n');const a={betaLabel:"Beta",techPreviewLabel:"Tech Preview",welcomeMessage:"Welcome to debugging in React Native",docsLabel:"Debugging docs",whatsNewLabel:"What's new",docsDebuggingBasics:"Debugging Basics",docsDebuggingBasicsDetail:"Overview of debugging tools in React Native",docsReactNativeDevTools:"React Native DevTools",docsReactDevToolsDetail:"Explore features available in React Native DevTools",docsNativeDebugging:"Native Debugging",docsNativeDebuggingDetail:"Find out more about native debugging tools"},{render:s,html:l}=n,c=o.i18n.registerUIStrings("panels/rn_welcome/RNWelcome.ts",a),d=o.i18n.getLocalizedString.bind(void 0,c);let g;class p extends e.Widget.VBox{options;#e;static instance(e){return g||(g=new p(e)),g}constructor(e){super(!0,!0),this.options=e,i.TargetManager.TargetManager.instance().observeModels(i.ReactNativeApplicationModel.ReactNativeApplicationModel,this)}wasShown(){super.wasShown(),this.registerCSSFiles([r]),this.render(),e.InspectorView.InspectorView.instance().showDrawer({focus:!0,hasTargetDrawer:!1})}modelAdded(e){e.ensureEnabled(),e.addEventListener("MetadataUpdated",this.#t,this),this.#e=e.metadataCached?.reactNativeVersion}modelRemoved(e){e.removeEventListener("MetadataUpdated",this.#t,this)}#t(e){this.#e=e.data.reactNativeVersion,this.isShowing()&&this.render()}#o(e){t.InspectorFrontendHost.InspectorFrontendHostInstance.openInNewTab(e)}render(){const{debuggerBrandName:e,showBetaLabel:t=!1,showTechPreviewLabel:o=!1,showDocs:i=!1}=this.options,n=new URL("../../Images/react_native/welcomeIcon.png",import.meta.url).toString(),r=new URL("../../Images/react_native/learn-debugging-basics.jpg",import.meta.url).toString(),c=new URL("../../Images/react_native/learn-react-native-devtools.jpg",import.meta.url).toString(),g=new URL("../../Images/react_native/learn-native-debugging.jpg",import.meta.url).toString();s(l`
|
||||
import*as e from"../../ui/legacy/legacy.js";import*as o from"../../core/host/host.js";import*as t from"../../core/i18n/i18n.js";import*as i from"../../core/sdk/sdk.js";import*as a from"../../ui/lit-html/lit-html.js";const r=new CSSStyleSheet;r.replaceSync('.rn-welcome-panel{display:flex;flex-direction:column;flex-shrink:0;align-items:stretch;justify-content:center;padding:36px;background-color:var(--color-background-elevation-0);min-height:100%}@media (min-width: 1000px){.rn-welcome-panel{flex-direction:row;align-items:center;justify-content:stretch;height:100%;padding:24px 60px}}.rn-welcome-hero{display:flex;flex-direction:column;flex-grow:1;flex-shrink:0;align-items:center;padding:16px;text-align:center}.rn-welcome-heading{display:flex;align-items:center;margin-bottom:16px}.rn-welcome-icon{width:30px;height:30px;border-radius:4px;margin-right:12px}.rn-welcome-title{font-size:20px;font-weight:normal;color:var(--color-text-primary)}.rn-welcome-title-accessory{margin-left:12px;padding:4px 8px;border-radius:4px;background-color:var(--color-green);font-size:12px;color:var(--color-on-primary)}.rn-welcome-title-accessory-purple{background-color:var(--color-purple-bright)}.rn-welcome-tagline{margin-bottom:24px;font-size:1rem;line-height:1.3;color:var(--color-text-secondary)}.rn-welcome-links{display:flex;align-items:center}.rn-welcome-links > .devtools-link{position:relative;margin:0 16px;font-size:14px}.rn-welcome-links > .devtools-link:not(:last-child)::after{content:"";position:absolute;right:-16px;height:16px;border-right:1px solid var(--color-details-hairline)}.rn-welcome-version{position:fixed;bottom:0;right:8px;margin-top:24px;padding:4px 12px;border-radius:6px;background-color:var(--color-background-hover-overlay);color:var(--color-text-secondary);font-size:11px}.rn-welcome-docsfeed{display:flex;flex-direction:column;flex-shrink:0;align-items:stretch;max-width:700px;margin:0 auto;padding:24px}@media (min-width: 1000px){.rn-welcome-docsfeed{flex-shrink:1;width:45%;margin:0}}.rn-welcome-h2{font-size:16px;font-weight:normal;color:var(--color-text-primary)}.rn-welcome-docsfeed-item{display:flex;align-items:center;margin-bottom:8px;padding:8px;padding-right:16px;border:1px solid var(--color-details-hairline);border-radius:4px;background-color:var(--color-background);text-align:left;font-size:14px;cursor:pointer}.rn-welcome-docsfeed-item:hover{background-color:var(--color-background-elevation-0)}.rn-welcome-docsfeed-item p{margin:0;margin-bottom:4px;text-decoration:none}.rn-welcome-docsfeed-item :not(.devtools-link){color:var(--color-text-secondary)}.rn-welcome-image{aspect-ratio:calc(16 / 9);height:64px;margin-right:16px;border-radius:2px;background-color:var(--color-gray-100);background-position:center;background-size:cover}\n/*# sourceURL=rnWelcome.css */\n');const n={betaLabel:"Beta",techPreviewLabel:"Tech Preview",welcomeMessage:"Welcome to debugging in React Native",docsLabel:"Debugging docs",whatsNewLabel:"What's new",docsDebuggingBasics:"Debugging Basics",docsDebuggingBasicsDetail:"Overview of debugging tools in React Native",docsReactDevTools:"React DevTools",docsReactDevToolsDetail:"Debug React components with React DevTools",docsRNDevTools:"React Native DevTools",docsRNDevToolsDetail:"Explore features available in React Native DevTools"},{render:s,html:l}=a,c=t.i18n.registerUIStrings("panels/rn_welcome/RNWelcome.ts",n),d=t.i18n.getLocalizedString.bind(void 0,c);let g;class p extends e.Widget.VBox{options;#e;static instance(e){return g||(g=new p(e)),g}constructor(e){super(!0,!0),this.options=e,i.TargetManager.TargetManager.instance().observeModels(i.ReactNativeApplicationModel.ReactNativeApplicationModel,this)}wasShown(){super.wasShown(),this.registerCSSFiles([r]),this.render(),e.InspectorView.InspectorView.instance().showDrawer({focus:!0,hasTargetDrawer:!1})}modelAdded(e){e.ensureEnabled(),e.addEventListener("MetadataUpdated",this.#o,this),this.#e=e.metadataCached?.reactNativeVersion}modelRemoved(e){e.removeEventListener("MetadataUpdated",this.#o,this)}#o(e){this.#e=e.data.reactNativeVersion,this.isShowing()&&this.render()}_handleLinkPress(e){o.InspectorFrontendHost.InspectorFrontendHostInstance.openInNewTab(e)}render(){const{debuggerBrandName:e,showBetaLabel:o=!1,showTechPreviewLabel:t=!1,showDocs:i=!1}=this.options,a=new URL("../../Images/react_native/welcomeIcon.png",import.meta.url).toString();s(l`
|
||||
<div class="rn-welcome-panel">
|
||||
<header class="rn-welcome-hero">
|
||||
<div class="rn-welcome-heading">
|
||||
<img class="rn-welcome-icon" src=${n} role="presentation" />
|
||||
<img class="rn-welcome-icon" src="${a}" role="presentation" />
|
||||
<h1 class="rn-welcome-title">
|
||||
${e()}
|
||||
</h1>
|
||||
${t?l`
|
||||
${o?l`
|
||||
<div class="rn-welcome-title-accessory">
|
||||
${d(a.betaLabel)}
|
||||
${d(n.betaLabel)}
|
||||
</div>
|
||||
`:null}
|
||||
${o?l`
|
||||
${t?l`
|
||||
<div class="rn-welcome-title-accessory rn-welcome-title-accessory-purple">
|
||||
${d(a.techPreviewLabel)}
|
||||
${d(n.techPreviewLabel)}
|
||||
</div>
|
||||
`:null}
|
||||
</div>
|
||||
<div class="rn-welcome-tagline">
|
||||
${d(a.welcomeMessage)}
|
||||
${d(n.welcomeMessage)}
|
||||
</div>
|
||||
<div class="rn-welcome-links">
|
||||
<x-link class="devtools-link" href="https://reactnative.dev/docs/debugging">
|
||||
${d(a.docsLabel)}
|
||||
${d(n.docsLabel)}
|
||||
</x-link>
|
||||
<x-link class="devtools-link" href="https://reactnative.dev/blog">
|
||||
${d(a.whatsNewLabel)}
|
||||
${d(n.whatsNewLabel)}
|
||||
</x-link>
|
||||
</div>
|
||||
${null!==this.#e&&void 0!==this.#e?l`
|
||||
${null!=this.#e?l`
|
||||
<p class="rn-welcome-version">React Native: <code>${this.#e}</code></p>
|
||||
`:null}
|
||||
</header>
|
||||
${i?l`
|
||||
<section class="rn-welcome-docsfeed">
|
||||
<h2 class="rn-welcome-h2">Learn</h2>
|
||||
<button class="rn-welcome-docsfeed-item" type="button" role="link" @click=${this.#o.bind(this,"https://reactnative.dev/docs/debugging")} title=${d(a.docsDebuggingBasics)}>
|
||||
<div class="rn-welcome-image" style="background-image: url('${r}')"></div>
|
||||
<button class="rn-welcome-docsfeed-item" type="button" role="link" @click=${this._handleLinkPress.bind(this,"https://reactnative.dev/docs/debugging")} title="${d(n.docsDebuggingBasics)}">
|
||||
<div class="rn-welcome-image" style="background-image: url('https://reactnative.dev/assets/images/debugging-dev-menu-2453a57e031a9da86b2ed42f16ffe82a.jpg')"></div>
|
||||
<div>
|
||||
<p class="devtools-link">${d(a.docsDebuggingBasics)}</p>
|
||||
<p>${d(a.docsDebuggingBasicsDetail)}</p>
|
||||
<p class="devtools-link">${d(n.docsDebuggingBasics)}</p>
|
||||
<p>${d(n.docsDebuggingBasicsDetail)}</p>
|
||||
</div>
|
||||
</button>
|
||||
<button class="rn-welcome-docsfeed-item" type="button" role="link" @click=${this.#o.bind(this,"https://reactnative.dev/docs/react-devtools")} title=${d(a.docsReactNativeDevTools)}>
|
||||
<div class="rn-welcome-image" style="background-image: url('${c}')"></div>
|
||||
<!-- TODO(huntie): Replace this item when React Native DevTools docs are complete -->
|
||||
<button class="rn-welcome-docsfeed-item" type="button" role="link" @click=${this._handleLinkPress.bind(this,"https://reactnative.dev/docs/debugging/react-devtools")} title="${d(n.docsReactDevTools)}">
|
||||
<div class="rn-welcome-image" style="background-image: url('https://reactnative.dev/assets/images/debugging-react-devtools-detail-914f08a97163dd51ebe732fd8ae4ea3c.jpg')"></div>
|
||||
<div>
|
||||
<p class="devtools-link">${d(a.docsReactNativeDevTools)}</p>
|
||||
<p>${d(a.docsReactDevToolsDetail)}</p>
|
||||
</div>
|
||||
</button>
|
||||
<button class="rn-welcome-docsfeed-item" type="button" role="link" @click=${this.#o.bind(this,"https://reactnative.dev/docs/debugging-native-code")} title=${d(a.docsNativeDebugging)}>
|
||||
<div class="rn-welcome-image" style="background-image: url('${g}')"></div>
|
||||
<div>
|
||||
<p class="devtools-link">${d(a.docsNativeDebugging)}</p>
|
||||
<p>${d(a.docsNativeDebuggingDetail)}</p>
|
||||
<p class="devtools-link">${d(n.docsReactDevTools)}</p>
|
||||
<p>${d(n.docsReactDevToolsDetail)}</p>
|
||||
</div>
|
||||
</button>
|
||||
</section>
|
||||
|
||||
Vendored
+5
-5
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,4 +1,4 @@
|
||||
import*as e from"../../lit-html/lit-html.js";import*as t from"../../visual_logging/visual_logging.js";import*as i from"../icon_button/icon_button.js";import*as n from"../input/input.js";import*as s from"../../../core/common/common.js";const a=new CSSStyleSheet;a.replaceSync(":host{display:block;padding:0;margin:0}input{height:12px;width:12px;min-height:12px;min-width:12px}label{display:inline-flex;align-items:center;overflow:hidden;text-overflow:ellipsis}p{margin:12px 0}.disabled-reason{box-sizing:border-box;margin-left:3px;width:16px;height:16px}\n/*# sourceURL=settingCheckbox.css */\n");const o=new CSSStyleSheet;o.replaceSync(".clickable{cursor:pointer}devtools-icon{vertical-align:text-bottom;padding-left:2px}\n/*# sourceURL=settingDeprecationWarning.css */\n");class c extends HTMLElement{static litTagName=e.literal`devtools-setting-deprecation-warning`;#e=this.attachShadow({mode:"open"});connectedCallback(){this.#e.adoptedStyleSheets=[o]}set data(e){this.#t(e)}#t({disabled:t,warning:n,experiment:a}){const o={clickable:!1};let c;t&&a&&(o.clickable=!0,c=()=>{s.Revealer.reveal(a)}),e.render(e.html`<${i.Icon.Icon.litTagName} class=${e.Directives.classMap(o)} .data=${{iconName:"info",color:"var(--icon-default)",width:"16px"}} title=${n} @click=${c}></${i.Icon.Icon.litTagName}>`,this.#e,{host:this})}}customElements.define("devtools-setting-deprecation-warning",c);var l=Object.freeze({__proto__:null,SettingDeprecationWarning:c});class r extends HTMLElement{static litTagName=e.literal`setting-checkbox`;#e=this.attachShadow({mode:"open"});#i;#n;connectedCallback(){this.#e.adoptedStyleSheets=[n.checkboxStyles,a]}set data(e){this.#n&&this.#i&&this.#i.removeChangeListener(this.#n.listener),this.#i=e.setting,this.#n=this.#i.addChangeListener((()=>{this.#t()})),this.#t()}#s(){if(this.#i?.deprecation)return e.html`<${c.litTagName} .data=${this.#i.deprecation}></${c.litTagName}>`}#t(){if(!this.#i)throw new Error('No "Setting" object provided for rendering');const n=this.#s(),s=this.#i.disabledReason()?e.html`
|
||||
import*as e from"../../lit-html/lit-html.js";import*as t from"../../visual_logging/visual_logging.js";import*as i from"../icon_button/icon_button.js";import*as n from"../input/input.js";import*as s from"../../../core/common/common.js";const a=new CSSStyleSheet;a.replaceSync(":host{padding:0;margin:0}input{height:12px;width:12px;min-height:12px;min-width:12px}label{display:inline-flex;align-items:center;overflow:hidden;text-overflow:ellipsis}p{margin:12px 0}.disabled-reason{box-sizing:border-box;margin-left:3px;width:16px;height:16px}\n/*# sourceURL=settingCheckbox.css */\n");const o=new CSSStyleSheet;o.replaceSync(".clickable{cursor:pointer}devtools-icon{vertical-align:text-bottom;padding-left:2px}\n/*# sourceURL=settingDeprecationWarning.css */\n");class c extends HTMLElement{static litTagName=e.literal`devtools-setting-deprecation-warning`;#e=this.attachShadow({mode:"open"});connectedCallback(){this.#e.adoptedStyleSheets=[o]}set data(e){this.#t(e)}#t({disabled:t,warning:n,experiment:a}){const o={clickable:!1};let c;t&&a&&(o.clickable=!0,c=()=>{s.Revealer.reveal(a)}),e.render(e.html`<${i.Icon.Icon.litTagName} class=${e.Directives.classMap(o)} .data=${{iconName:"info",color:"var(--icon-default)",width:"16px"}} title=${n} @click=${c}></${i.Icon.Icon.litTagName}>`,this.#e,{host:this})}}customElements.define("devtools-setting-deprecation-warning",c);var l=Object.freeze({__proto__:null,SettingDeprecationWarning:c});class r extends HTMLElement{static litTagName=e.literal`setting-checkbox`;#e=this.attachShadow({mode:"open"});#i;#n;connectedCallback(){this.#e.adoptedStyleSheets=[n.checkboxStyles,a]}set data(e){this.#n&&this.#i&&this.#i.removeChangeListener(this.#n.listener),this.#i=e.setting,this.#n=this.#i.addChangeListener((()=>{this.#t()})),this.#t()}#s(){if(this.#i?.deprecation)return e.html`<${c.litTagName} .data=${this.#i.deprecation}></${c.litTagName}>`}#t(){if(!this.#i)throw new Error('No "Setting" object provided for rendering');const n=this.#s(),s=this.#i.disabledReason()?e.html`
|
||||
<${i.Icon.Icon.litTagName} class="disabled-reason" name="info" title=${this.#i.disabledReason()} @click=${onclick}></${i.Icon.Icon.litTagName}>
|
||||
`:e.nothing;e.render(e.html`
|
||||
<p>
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@react-native/debugger-frontend",
|
||||
"version": "0.77.0-main",
|
||||
"version": "0.76.0-main",
|
||||
"description": "Debugger frontend for React Native based on Chrome DevTools",
|
||||
"keywords": [
|
||||
"react-native",
|
||||
|
||||
@@ -64,16 +64,12 @@ Subpaths of this endpoint are reserved to serve the JavaScript debugger frontend
|
||||
|
||||
#### POST `/open-debugger`
|
||||
|
||||
Open the JavaScript debugger for a given CDP target. Must be provided with one of the following query params:
|
||||
|
||||
- `device` — An ID unique to a combination of device and app, stable across installs. Implemented by `getInspectorDeviceId` on each native platform.
|
||||
- `target` — The target page ID as returned by `/json/list` for the current dev server session.
|
||||
- `appId` (deprecated, legacy only) — The application bundle identifier to match (non-unique across multiple connected devices). This param will only match legacy Hermes debugger targets.
|
||||
Open the JavaScript debugger for a given CDP target (direct Hermes debugging).
|
||||
|
||||
<details>
|
||||
<summary>Example</summary>
|
||||
|
||||
curl -X POST 'http://localhost:8081/open-debugger?target=<targetId>'
|
||||
curl -X POST 'http://localhost:8081/open-debugger?appId=com.meta.RNTester'
|
||||
</details>
|
||||
|
||||
### WebSocket endpoints
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@react-native/dev-middleware",
|
||||
"version": "0.77.0-main",
|
||||
"version": "0.76.0-main",
|
||||
"description": "Dev server middleware for React Native",
|
||||
"keywords": [
|
||||
"react-native",
|
||||
@@ -23,7 +23,7 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"@isaacs/ttlcache": "^1.4.1",
|
||||
"@react-native/debugger-frontend": "0.77.0-main",
|
||||
"@react-native/debugger-frontend": "0.76.0-main",
|
||||
"chrome-launcher": "^0.15.2",
|
||||
"chromium-edge-launcher": "^0.2.0",
|
||||
"connect": "^3.6.5",
|
||||
@@ -31,7 +31,7 @@
|
||||
"nullthrows": "^1.1.1",
|
||||
"open": "^7.0.3",
|
||||
"selfsigned": "^2.4.1",
|
||||
"serve-static": "^1.16.2",
|
||||
"serve-static": "^1.13.1",
|
||||
"ws": "^6.2.3"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -21,7 +21,7 @@ declare var globalThis: $FlowFixMe;
|
||||
*/
|
||||
export async function fetchLocal(
|
||||
url: string,
|
||||
options?: Partial<Parameters<typeof fetch>[1] & {dispatcher?: mixed}>,
|
||||
options?: Parameters<typeof fetch>[1] & {dispatcher?: mixed},
|
||||
): ReturnType<typeof fetch> {
|
||||
return await fetch(url, {
|
||||
...options,
|
||||
|
||||
@@ -14,7 +14,6 @@ import type {
|
||||
JsonVersionResponse,
|
||||
} from '../inspector-proxy/types';
|
||||
|
||||
import DefaultBrowserLauncher from '../utils/DefaultBrowserLauncher';
|
||||
import {fetchJson, fetchLocal} from './FetchUtils';
|
||||
import {createDeviceMock} from './InspectorDeviceUtils';
|
||||
import {withAbortSignalForEachTest} from './ResourceUtils';
|
||||
@@ -185,7 +184,6 @@ describe('inspector proxy HTTP API', () => {
|
||||
);
|
||||
expect(json).toEqual([
|
||||
{
|
||||
appId: 'bar-app',
|
||||
description: 'bar-app',
|
||||
deviceName: 'foo',
|
||||
devtoolsFrontendUrl: expect.any(String),
|
||||
@@ -200,7 +198,6 @@ describe('inspector proxy HTTP API', () => {
|
||||
webSocketDebuggerUrl: expect.any(String),
|
||||
},
|
||||
{
|
||||
appId: 'bar-app',
|
||||
description: 'bar-app',
|
||||
deviceName: 'foo',
|
||||
devtoolsFrontendUrl: expect.any(String),
|
||||
@@ -371,59 +368,4 @@ describe('inspector proxy HTTP API', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('/open-debugger endpoint', () => {
|
||||
test('opens requested device using device and target query params', async () => {
|
||||
// Connect a device to use when opening the debugger
|
||||
const device = await createDeviceMock(
|
||||
`${serverRef.serverBaseWsUrl}/inspector/device?device=device1&name=foo&app=bar`,
|
||||
autoCleanup.signal,
|
||||
);
|
||||
device.getPages.mockImplementation(() => [
|
||||
{
|
||||
app: 'bar-app',
|
||||
id: 'page1',
|
||||
title: 'bar-title',
|
||||
vm: 'bar-vm',
|
||||
capabilities: {
|
||||
// Ensure the device target can be found when launching the debugger
|
||||
nativePageReloads: true,
|
||||
},
|
||||
},
|
||||
]);
|
||||
jest.advanceTimersByTime(PAGES_POLLING_DELAY);
|
||||
|
||||
// Hook into `DefaultBrowserLauncher.launchDebuggerAppWindow` to ensure debugger was launched
|
||||
const launchDebuggerSpy = jest
|
||||
.spyOn(DefaultBrowserLauncher, 'launchDebuggerAppWindow')
|
||||
.mockResolvedValueOnce();
|
||||
|
||||
try {
|
||||
// Fetch the target information for the device
|
||||
const pageListResponse = await fetchJson<JsonPagesListResponse>(
|
||||
`${serverRef.serverBaseUrl}/json`,
|
||||
);
|
||||
// Select the first target from the page list response
|
||||
expect(pageListResponse.length).toBeGreaterThanOrEqual(1);
|
||||
const firstPage = pageListResponse[0];
|
||||
|
||||
// Build the URL for the debugger
|
||||
const openUrl = new URL('/open-debugger', serverRef.serverBaseUrl);
|
||||
openUrl.searchParams.set(
|
||||
'device',
|
||||
firstPage.reactNative.logicalDeviceId,
|
||||
);
|
||||
openUrl.searchParams.set('target', firstPage.id);
|
||||
// Request to open the debugger for the first device
|
||||
const response = await fetchLocal(openUrl.toString(), {method: 'POST'});
|
||||
|
||||
// Ensure the request was handled properly
|
||||
expect(response.status).toBe(200);
|
||||
// Ensure the debugger was launched
|
||||
expect(launchDebuggerSpy).toHaveBeenCalledWith(expect.any(String));
|
||||
} finally {
|
||||
device.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user