Compare commits

..
48 Commits
Author SHA1 Message Date
Lorenzo Sciandra 0190c9c97b [0.60.3] Bump version numbers 2019-07-11 11:33:44 -07:00
Mathieu ActhernoeneandChristoph Nakazawa 348b8f0082 Fix Hermes binary path (#25598) 2019-07-11 19:02:08 +01:00
cpojer b867cf8974 [0.60.2] Bump version numbers 2019-07-11 17:17:13 +01:00
cpojer 0738fe5738 Fix path to Hermes package. 2019-07-11 17:17:08 +01:00
cpojer 8dd8ec7cb0 [0.60.1] Bump version numbers 2019-07-11 16:51:34 +01:00
cpojer e857d7066b Add Hermes support to React Native 0.60 2019-07-11 16:51:00 +01:00
Lorenzo Sciandra 769e35ba5f [0.60.0] Bump version numbers 2019-07-03 13:54:51 +01:00
Lorenzo Sciandra 35aeb8c027 [LOCAL] bump CLI 2019-07-03 13:00:27 +01:00
Michał PierzchałaandLorenzo Sciandra 8fdecf3010 - Publish react-native.config.js (#25436)
Summary:
Looks we forgot to add this file to publish list. By adding it, we can remove some code in CLI that special-cases `react-native` package, since it now announces itself as a proper platform.

cc kelset, we'd like to have this cherry-picked for 0.60.

## Changelog

[Internal] [Fixed] - Publish `react-native.config.js`
Pull Request resolved: https://github.com/facebook/react-native/pull/25436

Test Plan: `npm pack` shows `react-native.config.js`

Differential Revision: D16071113

Pulled By: cpojer

fbshipit-source-id: df18affbb9a0ad7f2cfdd1a4cc93191aa5ffadeb
2019-07-03 11:56:25 +01:00
Jerry.LuoandLorenzo Sciandra ff9855cc3b Check if mCurrentActivity is set according to LifecycleState (#23336)
Summary:
Issues: Related to  #13439
react-native-website:Related to PR [#792](https://github.com/facebook/react-native-website/pull/792)
solution: https://github.com/facebook/react-native/issues/13439#issuecomment-400256114

When we integration with Existing  Android Apps.and set LifecycleState  is `LifecycleState.RESUMED`.
It's lead to `mCurrentActivity`  is null .

At this time , the behave of set `mCurrentActivity ` which  is unexpectedly.

## Changelog
[Android] [Fixed] - Check if mCurrentActivity is set according to LifecycleState
Pull Request resolved: https://github.com/facebook/react-native/pull/23336

Differential Revision: D14298654

Pulled By: cpojer

fbshipit-source-id: 5cc17539a51154faeb838349b068d92511946f79
2019-07-03 11:55:29 +01:00
Lorenzo Sciandra 8a43321271 [0.60.0-rc.3] Bump version numbers 2019-06-28 10:49:34 +01:00
Lorenzo Sciandra db1d60fa95 bump jsc dep 2019-06-28 08:39:52 +01:00
Lorenzo Sciandra 93c83181fb bump CLI rc 2019-06-28 08:39:43 +01:00
soh335andLorenzo Sciandra 9837d2480c Fix some languages wrapped texts are cut off on android (#25306)
Summary:
Fix wrapped some languages (like Japanese, Chinese) texts are cut off on android. This p-r is based on linjson [patch](https://github.com/facebook/react-native/issues/25275#issuecomment-502548807).

- related (maybe)
    - https://github.com/facebook/react-native/issues/25297
    - https://github.com/facebook/react-native/issues/25275
    - https://github.com/facebook/react-native/issues/24837
    - https://github.com/facebook/react-native/issues/25155

`setUseLineSpacingFromFallbacks` is recommended to set true on [document](https://developer.android.com/reference/android/text/StaticLayout.Builder#setUseLineSpacingFromFallbacks(boolean))

>For backward compatibility reasons, the default is false, but setting this to true is strongly recommended. It is required to be true if text could be in languages like Burmese or Tibetan where text is typically much taller or deeper than Latin text.

## Changelog

[Android] [Fixed] - Fix some languages wrapped texts are cut off.
Pull Request resolved: https://github.com/facebook/react-native/pull/25306

Test Plan:
Set the target SDK to 28 in ``fbsource/fbandroid/java/com/facebook/catalyst/shell/AndroidManifest.xml``:
```
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="28"/>
```

Insert the following code into Playground.js: P67720709

Start the Catalyst Android app and navigate to the playground:

`buck install -r catalyst`

|Before|After|
|{F163482789}|{F163481060}|

Reviewed By: cpojer

Differential Revision: D15985809

Pulled By: makovkastar

fbshipit-source-id: 0f98760b7a7fe4689fa3fe90ca747e9bf9fc4780
2019-06-28 08:38:26 +01:00
Janic DuplessisandLorenzo Sciandra b68966ec7b Use CALayers to draw text (#24387)
Summary:
The current technique we use to draw text uses linear memory, which means that when text is too long the UIView layer is unable to draw it. This causes the issue described [here](https://github.com/facebook/react-native/issues/19453). On an iOS simulator the bug happens at around 500 lines which is quite annoying. It can also happen on a real device but requires a lot more text.

To be more specific the amount of text doesn't actually matter, it is the size of the UIView that we use to draw the text. When we use `[drawRect:]` the view creates a bitmap to send to the gpu to render, if that bitmap is too big it cannot render.

To fix this we can use `CATiledLayer` which will split drawing into smaller parts, that gets executed when the content is about to be visible. This drawing is also async which means the text can seem to appear during scroll. See https://developer.apple.com/documentation/quartzcore/calayer?language=objc.

`CATiledLayer` also adds some overhead that we don't want when rendering small amount of text. To fix this we can use either a regular `CALayer` or a `CATiledLayer` depending on the size of the view containing the text. I picked 1024 as the threshold which is about 1 screen and a half, and is still smaller than the height needed for the bug to occur when using a regular `CALayer` on a iOS simulator.

Also found this which addresses the problem in a similar manner and took some inspiration from the code linked there https://github.com/GitHawkApp/StyledTextKit/issues/14#issuecomment-395234885

Fixes https://github.com/facebook/react-native/issues/19453

## Changelog

[iOS] [Fixed] - Use CALayers to draw text, fixes rendering for long text
Pull Request resolved: https://github.com/facebook/react-native/pull/24387

Test Plan:
- Added the example I was using to verify the fix to RNTester.
- Made sure all other examples are still rendering properly.
- Tested text selection

Reviewed By: shergin

Differential Revision: D15918277

Pulled By: sammy-SC

fbshipit-source-id: c45409a8413e6e3ad272be39ba527a4e8d349e28
2019-06-28 08:38:17 +01:00
Robert YingandLorenzo Sciandra 99bc31cfa6 Fix regression of improper assets copy (revert #24518 #24778) (#25363)
Summary:
Pull requests https://github.com/facebook/react-native/issues/24518 #24778 make Gradle copy all **generated** assets and resources into `android/app/src/res`, which is a bad behavior, because `src/res` goes into version control and should hold only those **original** resource files.

These changes in https://github.com/facebook/react-native/issues/24518 #24778 were merged into 0.60.0-rc release and cause regression.

This pull request will:

- Revert pull requests https://github.com/facebook/react-native/issues/24518 #24778
- Close https://github.com/facebook/react-native/issues/25325

## Changelog

[Android] [Fixed] - Fix regression of improper assets copy (revert https://github.com/facebook/react-native/issues/24518 #24778)
Pull Request resolved: https://github.com/facebook/react-native/pull/25363

Test Plan: It is a revert pull request and the reverted script should work the same as it has in 0.59.x.

Differential Revision: D15963329

Pulled By: cpojer

fbshipit-source-id: 5619a318dbdb40e816e37b6e37d4fe32caa46e9e
2019-06-28 08:38:10 +01:00
DulmandakhandLorenzo Sciandra c36c481016 bump fresco to 2.0.0, supports AndroidX (#25358)
Summary:
Bump Fresco to 2.0.0, which supports AndroidX. We should cherry-pick to 0.60 release, to support brown field apps but also native components.

## Changelog

[Android] [Changed] - Bump Fresco to 2.0.0, supports AndroidX
Pull Request resolved: https://github.com/facebook/react-native/pull/25358

Test Plan: CI is green, and RNTester builds and runs as expected.

Differential Revision: D15959443

Pulled By: mdvacca

fbshipit-source-id: 58ba2c3e4d1342014d6ea632cd865b4f413548d9
2019-06-28 08:38:01 +01:00
DulmandakhandLorenzo Sciandra 13f4fa0245 custom fontWeight numeric values for Text on Android (#25341)
Summary:
I found that on Android we only support 2 fontWeight options, either **normal** or **bold**, even developer can set any numeric value. But iOS supports all possible numeric values. This PR tries to add support for all possible numeric values on Android, even if it's supported only on Android P(28) and above.

This change might break texts where fontWeight use improperly, because this PR removes conversion of values above 500 to BOLD and below 500 to normal.

FYI, also moved **mCustomTypefaceCache** usage up because it was working after unnecessary mFontCache usage.

## Changelog

[Android] [Changed] - add custom font weight support to Text component on Android, only on P(API 28) and above versions.
Pull Request resolved: https://github.com/facebook/react-native/pull/25341

Test Plan: RNTester app's Text examples will show Rubik Regular, Rubik Light, Rubik Bold, Rubik Medium and Rubik Medium Italic texts in corresponding font family, style and weights.

Differential Revision: D15956350

Pulled By: mdvacca

fbshipit-source-id: 61079d953c65fb34ab4497d44c22317912a5a616
2019-06-28 08:37:51 +01:00
Lorenzo Sciandra 9792f2c9d7 [0.60.0-rc.2] Bump version numbers 2019-06-20 11:40:30 +01:00
Lorenzo Sciandra 53cec2dc1f [LOCAL] bump version in template to match repo 2019-06-20 10:07:32 +01:00
Rick HanlonandLorenzo Sciandra b4f3d4b92e Move scheduler to dependencies
Summary: Fixes https://github.com/react-native-community/releases/issues/116#issuecomment-503449687

Reviewed By: gaearon

Differential Revision: D15901557

fbshipit-source-id: 653119c181585cf9a4a561b350c66bd10cb674bd
2019-06-20 10:06:01 +01:00
SalakarandLorenzo Sciandra e741488659 Implement changes to enable native modules auto linking (#24506)
Summary:
Replaces #24099 (original PR became detached for some reason)

Implements the template changes required to enable native modules auto-linking for both Android & iOS.

Requires the following to be merged first and an updated CLI to be published:

- [x] https://github.com/react-native-community/react-native-cli/pull/254
- [x] https://github.com/react-native-community/react-native-cli/pull/256
- [x] https://github.com/react-native-community/react-native-cli/pull/258

cc grabbou thymikee orta for review

- [ ] https://github.com/facebook/react-native/pull/24517 update CLI version)

[TEMPLATE] [FEATURE] - Enable auto-initialization/linking of react native modules for new projects
Pull Request resolved: https://github.com/facebook/react-native/pull/24506

Differential Revision: D15062701

Pulled By: cpojer

fbshipit-source-id: 65296cbec2925405fe8033de71910325e0c719bc

# Conflicts:
#	template/ios/Podfile
2019-06-19 14:10:57 +01:00
Michał PierzchałaandLorenzo Sciandra bf4ee6f5c1 Bump CLI to 2.0.0-rc.2 (#25241)
Summary:
Fixing Metro validation issue. Hope that helps with fixing the CI �.

## Changelog

[General] [Changed] - Bump CLI to 2.0.0-rc.2
Pull Request resolved: https://github.com/facebook/react-native/pull/25241

Differential Revision: D15803610

Pulled By: cpojer

fbshipit-source-id: 22136db1583f8cf5a40afd5d8a561d98cb6de982
2019-06-19 12:54:50 +01:00
zhongwuzwandLorenzo Sciandra cecba01b71 Removed autoresizing mask for modal host container view (#25150)
Summary:
Fixes #18177 . Related #24497. Autoresizing mask would conflict with `AutoLayout`. For example , it would impact `SafeAreaView`. And actually we don't need to use autoresizing mask,  we observe the bounds change notification and [update the frame manually](https://github.com/facebook/react-native/blob/1151c096dab17e5d9a6ac05b61aacecd4305f3db/React/Views/RCTModalHostView.m#L59).

## Changelog

[iOS] [Fixed] - Removed autoresizing mask for modal host container view
Pull Request resolved: https://github.com/facebook/react-native/pull/25150

Differential Revision: D15645148

Pulled By: cpojer

fbshipit-source-id: 95d5f40feaa980b959a3de6e273dccac8158c57b
2019-06-19 12:54:39 +01:00
Lorenzo Sciandra 06fffc2042 [0.60.0-rc.1] Bump version numbers 2019-06-10 12:30:15 +01:00
Lorenzo Sciandra 5ecc87bf3e bump versions to match the requirements 2019-06-07 17:54:20 +01:00
Lorenzo Sciandra 7082c3e449 re-add the hasteImpl 2019-06-07 15:52:42 +01:00
Michał PierzchałaandLorenzo Sciandra 39ce412b25 Bump CLI to 2.0.0-rc.0 (#25175)
Summary:
Upgrading the CLI to the latest with a bunch of fixes and features included.

## Changelog

[General] [Changed] - Bump CLI to 2.0.0-rc.0
Pull Request resolved: https://github.com/facebook/react-native/pull/25175

Differential Revision: D15694764

Pulled By: cpojer

fbshipit-source-id: 25fbf1c275ed5379e1cdb372512b6bb6327dea92

# Conflicts:
#	jest/hasteImpl.js
#	package.json
#	yarn.lock
2019-06-07 15:14:32 +01:00
Пётр ПотаповandLorenzo Sciandra 00c7cf3d68 Fix: RefreshControl in FlatList makes borderWidth not working (#24411)
Summary:
Fixes #22752

On line 1021 you are passing base style to props:
`style: [baseStyle, this.props.style],`

Explicitly passing base style to ScrollView just overrides this line and doesn't let developers to customise style of any inheritors of ScrollView (not only FlatList) with custom RefreshControl.

So this line (1113) seems to be removed.

## Changelog

[GENERAL] [Fixed] - fix of Android's bug that doesn't let override ScrollView's Style with custom RefreshControl.
Pull Request resolved: https://github.com/facebook/react-native/pull/24411

Differential Revision: D15713061

Pulled By: cpojer

fbshipit-source-id: 461259800f867af15e53e0743a5057ea4528ae69
2019-06-07 15:13:00 +01:00
NateandLorenzo Sciandra a916dd6632 Android Fix for 9145: No longer hard code build port (#23616)
Summary:
### Problem

According to https://github.com/facebook/react-native/issues/9145, the `--port` setting is not respected when executing `react-native run-android`. The templates that report things like what port the dev server runs on are hard coded as well.

### Solution

This commit replaces the hardcoded instances of port 8081 on Android with a build configuration property. This allows setting of the port React Native Android connects to for the local build server.

For this change to work, there must also be an update to the react native CLI to pass along this setting:

https://github.com/react-native-community/react-native-cli/compare/master...nhunzaker:9145-android-no-port-hardcode-cli

To avoid some noise on their end, I figured I wouldn't submit a PR until it's this approach is deemed workable.

## Changelog

[Android][fixed] - `react-native run-android --port <x>` correctly connects to dev server and related error messages display the correct port
Pull Request resolved: https://github.com/facebook/react-native/pull/23616

Differential Revision: D15645200

Pulled By: cpojer

fbshipit-source-id: 3bdfd458b8ac3ec78290736c9ed0db2e5776ed46
2019-06-07 15:12:11 +01:00
Eric LewisandLorenzo Sciandra eb73dbe24e Fix Xcode 11 build (#25146)
Summary:
Fixes build in Xcode 11 beta, the signature for `__unused` was changed. This adds a new check for the new style.

## Changelog

[iOS] [Fixed] - Xcode 11 beta build
Pull Request resolved: https://github.com/facebook/react-native/pull/25146

Differential Revision: D15628404

Pulled By: cpojer

fbshipit-source-id: 781a188a0e1562a3316fbe62920b12b03a44e4a7
2019-06-07 15:12:03 +01:00
Sharon GongandLorenzo Sciandra bcc9fcf1c7 Fix accessibilityActions accessors (#25134)
Summary:
The accessibilityActions accessors  in UIView+React.m are not aligned with the property declaration in the header file.

## Changelog

[General] [Fixed] - Fix accessibilityActions accessors
Pull Request resolved: https://github.com/facebook/react-native/pull/25134

Differential Revision: D15621848

Pulled By: cpojer

fbshipit-source-id: f344689292ae7988e46d0d4263980306d364366b
2019-06-07 15:11:56 +01:00
DratwasandLorenzo Sciandra 3e937eac2b fix indexed RAM bundle (#24967)
Summary:
Co-Authored: zamotany
With React Native 0.59.8 the app keeps crashing with indexed RAM bundle on Android with the following error:

```
2019-05-09 11:58:06.684 2793-2856/? E/AndroidRuntime: FATAL EXCEPTION: mqt_js
    Process: com.ramtestapp, PID: 2793
    com.facebook.jni.CppException: getPropertyAsObject: property '__fbRequireBatchedBridge' is not an Object

    no stack
        at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:29)
        at android.os.Looper.loop(Looper.java:193)
        at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:232)
        at java.lang.Thread.run(Thread.java:764)
```

After investigation we found that when using any bundle, let it be non-ram, FIle RAM bundle or Index RAM bundle, the `CatalystInstanceImpl.java` is always using `loadScriptsFromAsset`, which is calling `CatalystInstanceImpl::jniLoadScriptFromAssets` in C++. This method when checking if bundle is a RAM bundle, uses `JniJSModulesUnbundle::isUnbundle` which only check for js-modules/UNBUNDLE - file generated when building File RAM bundle. There is no other logic to handle Indexed RAM bundle, so it figures that the bundle is not RAM, cause there is no js-modules/UNBUNDLE file and tries to load as regular bundle and fails.

In this PR we added check if it is indexed RAM bundle in `jniLoadScriptFromAssets` and handle it if it is.
## Changelog
[Android] [Fixed] fix indexed RAM bundle

Solves https://github.com/facebook/react-native/issues/21282
Pull Request resolved: https://github.com/facebook/react-native/pull/24967

Differential Revision: D15575924

Pulled By: cpojer

fbshipit-source-id: 5ea428e0b793edd8242243f39f933d1092b35260
2019-06-07 15:11:50 +01:00
Michael MasonandLorenzo Sciandra 0d05051f3c - Fix missing whitespace in debug instructions (#25122)
Summary:
Fixes minor whitespace issue with the new new-app template.

## Changelog

[Android] [Fixed] - Fix missing whitespace in debug instructions
Pull Request resolved: https://github.com/facebook/react-native/pull/25122

Differential Revision: D15602100

Pulled By: cpojer

fbshipit-source-id: 07c51c6359e37826941de659bcedea692ff3315a
2019-06-07 15:11:43 +01:00
Janic DuplessisandLorenzo Sciandra 54471963e0 Remove vendored fetch polyfill, update to whatwg-fetch@3.0 (#24418)
Summary:
The original reason for vendoring the fetch polyfill was to remove the default blob response type but this was reverted.

Here's a little history around the fetch polyfill and the blob issue:

- Original commit introducing the vendored polyfill: #19333, the goal was to fix a memory leak because our blob implementation doesn't release resources automatically. Not an ideal fix but since the issue was pretty severe and the infra for a proper fix was not in place.
- This introduced an issue when downloading images using `fetch` which was fixed by #22063 which re-added the default blob content type. However that re-introduced the original fetch memory leak.
- We have better infra now with jsi and I was able to get blob deallocation working, see #24405

Currently the vendored fetch polyfill is useless since it was changed back to the original version. We can just use the npm version again. I also updated to 3.0 which brings better spec compliance and support for cancellation via `AbortController`, https://github.com/github/fetch/releases/tag/v3.0.0.

## Changelog

[General] [Changed] - Remove vendored fetch polyfill, update to whatwg-fetch@3.0
Pull Request resolved: https://github.com/facebook/react-native/pull/24418

Differential Revision: D14932683

Pulled By: cpojer

fbshipit-source-id: 915e3d25978e8b9d7507ed807e7fba45aa88385a
2019-06-07 15:11:36 +01:00
Petter HesselbergandLorenzo Sciandra 1b8f7e7a36 Don't reference null android.ndkDirectory in build.gradle (#25088)
Summary:
If you (try to) build React Native for Android without having the NDK properly installed and referenced, you get the following error:

>A problem occurred evaluating project ':ReactAndroid'.
\> Cannot get property 'absolutePath' on null object

This is not an overly helpful diagnostic. This PR results in this message instead:

>ndk-build binary cannot be found, check if you've set $ANDROID_NDK environment variable correctly or if ndk.dir is setup in local.properties

Fixes #25087

## Changelog

[Android] [Fixed] - Show proper error message instead of throwing a NullReferenceException if Gradle cannot find the NDK
Pull Request resolved: https://github.com/facebook/react-native/pull/25088

Differential Revision: D15559271

Pulled By: cpojer

fbshipit-source-id: 35c9a9321af4e4a34bf519144ada48884b48352d
2019-06-07 15:11:29 +01:00
Andrea CimitanandLorenzo Sciandra 46500b3e36 Linking.getInitialURL() to work with NFC tags on Android (#25055)
Summary:
This PR solves bug https://github.com/facebook/react-native/issues/24393 for Android. Allows an app to be opened with an NFC tag and getting the url trough Linking.getInitialURL()

## Changelog
[Android] [Fixed] - This branch checks also for `ACTION_NDEF_DISCOVERED` intent matches to set the initialURL
Pull Request resolved: https://github.com/facebook/react-native/pull/25055

Differential Revision: D15516873

Pulled By: cpojer

fbshipit-source-id: e8803738d857a69e1063e926fc3858a416a0b25e
2019-06-07 15:11:22 +01:00
Oleksandr MelnykovandLorenzo Sciandra ed40f382e8 Fix backgroundColor top level prop of TextInput
Summary:
Changelog: [Android] [FIXED] - Fix backgroundColor top level prop of TextInput

This diff fixes two issues with the `backgroundColor` top level property of TextInput on Android:
 * Now it is possible to set a **string** value for the top-level `backgroundColor` property of TextInput (crashed the app previously):
```
<TextInput backgroundColor="#ffccbb">Hello, React Native</TextInput>
```
* Now it's possible to set an **integer** value for the top-level `backgroundColor` property of TextInput (had no effect previously):
```
<TextInput backgroundColor={0xffccbbff}>Hello, React Native</TextInput>
```

A `customType = "Color"` annotation parameter must be provided for `ReactBaseTextShadowNode.setBackgroundColor(...)` since the color value must be previously processed in JS before sending it over the bridge to the native code. The JS code will parse the color value and return the proper ARGB color integer to the native platforms (https://fburl.com/uqup52tn).

Without providing the custom type for the background color, if a string value is set for the top-level `backgroundColor` property in the JS code, the Android code will crash since it expects an integer value for the color in `ReactBaseTextShadowNode.setBackgroundColor(...)`, but a string will be passed from JS without any conversion and there will be a `ClassCastException` thrown. If an integer value without the alpha component (like `0xffccbb`) is set, the Android native view would get an integer color value with its alpha component set to `0x00`, which means a transparent color.

On a side note: the alpha component of a color must always be set when using an integer value for `backgroundColor` since the JS code, while processing the color type, shifts the rightmost 8 bytes (alpha component) to the leftmost position. If those 8 bytes are not the alpha component, you will get the wrong color in the end. It doesn't seem to be a problem for string values of `backgroundColor` though.

Reviewed By: mdvacca

Differential Revision: D15453980

fbshipit-source-id: f3f5d9c9877cdbce79a67f2ed93ad4589576d166
2019-06-07 15:11:14 +01:00
DulmandakhandLorenzo Sciandra 8d61a4e5f9 bump android gradle plugin to 3.4.1 (#24883)
Summary:
bump android gradle plugin to 3.4.1, includes many fixes and improvements.

## Changelog

[Android] [Changed] - bump android gradle plugin to 3.4.1
Pull Request resolved: https://github.com/facebook/react-native/pull/24883

Differential Revision: D15474556

Pulled By: hramos

fbshipit-source-id: 8d1eb91855b9f416ed3380c61f34672deded26c1
2019-06-07 15:11:05 +01:00
Héctor Ramos 55332afb29 [0.60.0-rc.0] Bump version numbers 2019-05-30 08:29:45 -07:00
Héctor Ramos d014fc7153 Use newer Docker container, with ssl support 2019-05-30 08:28:56 -07:00
Héctor Ramos 29496ede07 Revert "[0.60.0-rc.0] Bump version numbers"
This reverts commit f4508a6765.
2019-05-30 08:23:24 -07:00
Mike Grabowski f4508a6765 [0.60.0-rc.0] Bump version numbers 2019-05-30 13:34:40 +02:00
Héctor Ramos 53e32a47e4 Remove duplicate Android SDK steps already present in container 2019-05-28 18:15:43 -07:00
Héctor Ramos 41742b3fe3 Fix config for 0.60 release 2019-05-28 07:56:31 -07:00
Héctor Ramos 5be47faff7 Make publish job depend on checkout_code as git is not available in RNAndroid docker container 2019-05-28 07:55:22 -07:00
Héctor Ramos ea460d6d3e Revert "[0.60.0-rc.0] Bump version numbers"
This reverts commit edb749f283.
2019-05-28 07:39:11 -07:00
Mike Grabowski edb749f283 [0.60.0-rc.0] Bump version numbers 2019-05-22 22:29:43 +02:00
10491 changed files with 446437 additions and 1114444 deletions
+47
View File
@@ -0,0 +1,47 @@
environment:
ANDROID_HOME: "C:\\android-sdk-windows"
ANDROID_NDK: "C:\\android-sdk-windows\\android-ndk-r17c"
ANDROID_BUILD_VERSION: 28
ANDROID_TOOLS_VERSION: 28.0.3
GRADLE_OPTS: -Dorg.gradle.daemon=false
SDK_TOOLS_URL: https://dl.google.com/android/repository/sdk-tools-windows-3859397.zip
NDK_TOOLS_URL: https://dl.google.com/android/repository/android-ndk-r17c-windows-x86_64.zip
matrix:
- nodejs_version: 8
- nodejs_version: 10
install:
# Install Android SDK Tools
- mkdir "%ANDROID_HOME%"
- appveyor DownloadFile "%SDK_TOOLS_URL%" -FileName "%TMP%/sdk-tools.zip"
- 7z x "%TMP%/sdk-tools.zip" -o"%ANDROID_HOME%" > nul
- set PATH=%PATH%;"%ANDROID_HOME%\tools\bin"
- yes 2> nul | sdkmanager --licenses > nul
- yes 2> nul | sdkmanager "system-images;android-19;google_apis;armeabi-v7a"
- yes 2> nul | sdkmanager "platforms;android-%ANDROID_BUILD_VERSION%"
- yes 2> nul | sdkmanager "build-tools;%ANDROID_TOOLS_VERSION%"
- yes 2> nul | sdkmanager "add-ons;addon-google_apis-google-23"
- yes 2> nul | sdkmanager "extras;android;m2repository"
- appveyor DownloadFile "%NDK_TOOLS_URL%" -FileName "%TMP%/ndk.zip"
- 7z x "%TMP%/ndk.zip" -o"%ANDROID_HOME%" > nul
- ps: Install-Product node $env:nodejs_version x64
- npx envinfo@latest
- appveyor-retry yarn install
build_script:
- yarn run flow-check-android
- yarn run flow-check-ios
- yarn run test
- gradlew.bat RNTester:android:app:assembleRelease
cache:
- node_modules
- "%LOCALAPPDATA%/Yarn"
- "%USERPROFILE%/.gradle/caches"
- "%USERPROFILE%/.gradle/wrapper"
-8
View File
@@ -1,8 +0,0 @@
{
"presets": [
"module:@react-native/babel-preset"
],
"plugins": [
"babel-plugin-transform-flow-enums"
]
}
+13
View File
@@ -0,0 +1,13 @@
[android]
target = android-28
[download]
max_number_of_retries = 3
[maven_repositories]
central = https://repo1.maven.org/maven2
google = https://dl.google.com/dl/android/maven2/
[alias]
rntester = //RNTester/android/app:app
+1
View File
@@ -0,0 +1 @@
-Xmx512m -XX:+HeapDumpOnOutOfMemoryError
-2
View File
@@ -1,2 +0,0 @@
BUNDLE_PATH: "vendor/bundle"
BUNDLE_FORCE_RUBY_PLATFORM: 1
+81
View File
@@ -0,0 +1,81 @@
# Docker Test Environment
This is a high-level overview of the test configuration using Docker.
It explains how to run the tests locally.
## Docker Installation
It is required to have Docker running on your machine in order to build and run the tests in the Dockerfiles.
See <https://docs.docker.com/engine/installation/> for more information on how to install.
## Convenience Scripts
We have added a number of default run scripts to the `package.json` file to simplify building and running your tests.
### Configuring Docker Images
The following two scripts need to be run first before you can move on to testing:
- `yarn run docker-setup-android`: Pulls down the React Native Community Android image that serves as a base image when building the actual test image.
- `yarn run docker-build-android`: Builds a test image with the latest dependencies and React Native library code, including a compiled Android test app.
### Running Tests
Once the test image has been built, it can be used to run our Android tests.
- `yarn run test-android-run-unit` runs the unit tests, as defined in `scripts/run-android-docker-unit-tests.sh`.
- `yarn run test-android-run-e2e` runs the end to end tests, as defined in `scripts/run-ci-e2e-tests.sh`.
- `yarn run test-android-run-instrumentation` runs the instrumentation tests, as defined in `scripts/run-android-docker-instrumentation-tests.sh`.
#### Instrumentation Tests
The instrumentation test script accepts the following flags in order to customize the execution of the tests:
`--filter` - A regex that filters which instrumentation tests will be run. (Defaults to .*)
`--package` - Name of the java package containing the instrumentation tests (Defaults to com.facebook.react.tests)
`--path` - Path to the directory containing the instrumentation tests. (Defaults to ./ReactAndroid/src/androidTest/java/com/facebook/react/tests)
`--retries` - Number of times to retry a failed test before declaring a failure (Defaults to 2)
For example, if locally you only wanted to run the InitialPropsTestCase, you could do the following:
`yarn run test-android-run-instrumentation -- --filter="InitialPropsTestCase"`
## Detailed Android Setup
There are two Dockerfiles for use with the Android codebase.
The base image used to build `reactnativecommunity/react-native-android` is located in the https://github.com/react-native-community/docker-android GitHub repository.
It contains all the necessary prerequisites required to run the React Android tests.
It is separated out into a separate Dockerfile because these are dependencies that rarely change and also because it is quite a beastly image since it contains all the Android dependencies for running Android and the emulators (~9GB).
The good news is you should rarely have to build or pull down the base image!
All iterative code updates happen as part of the `Dockerfile.android` image build.
Lets break it down...
First, you'll need to pull the base image.
You can use `docker pull` to grab the latest version of the `reactnativecommunity/react-native-android` base image.
This is what you get when you run `yarn run docker-setup-android`.
This will take quite some time depending on your connection and you need to ensure you have ~10GB of free disk space.
Once you have downloaded the base image, the test image can be built using `docker build -t reactnativeci/android -f ./.circleci/Dockerfiles/Dockerfile.android .`. This is what `yarn run docker-build-android` does. Note that the `-t` flag is how you tell Docker what to name this image locally. You can then use `docker run -t reactnativeci/android` to run this image.
Now that you've built the test image, you can run unit tests using what you've learned so far:
```bash
docker run --cap-add=SYS_ADMIN -it reactnativeci/android bash .circleci/Dockerfiles/scripts/run-android-docker-unit-tests.sh
```
> Note: `--cap-add=SYS_ADMIN` flag is required for the `.circleci/Dockerfiles/scripts/run-android-docker-unit-tests.sh` and `.circleci/Dockerfiles/scripts/run-android-docker-instrumentation-tests.sh` in order to allow the remounting of `/dev/shm` as writeable so the `buck` build system may write temporary output to that location.
Every time you make any modifications to the codebase, including changes to the test scripts inside `.circleci/Dockerfiles/scripts`, you should re-run the `docker build ...` command in order for your updates to be included in your local docker test image.
For rapid iteration, it's useful to keep in mind that Docker can pass along arbitrary commands to an image.
For example, you can alternatively use Gradle in this manner:
```bash
docker run --cap-add=SYS_ADMIN -it reactnativeci/android ./gradlew RNTester:android:app:assembleRelease
```
+52
View File
@@ -0,0 +1,52 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
#
# This image builds upon the React Native Community Android image:
# https://github.com/react-native-community/docker-android
#
# The base image is expected to remain relatively stable, and only
# needs to be updated when major dependencies such as the Android
# SDK or NDK are updated.
#
# In this Android Test image, we download the latest dependencies
# and build a Android application that can be used to run the
# tests specified in the scripts/ directory.
#
FROM reactnativecommunity/react-native-android
LABEL Description="React Native Android Test Image"
LABEL maintainer="Héctor Ramos <hector@fb.com>"
# set default environment variables
ENV GRADLE_OPTS="-Dorg.gradle.daemon=false -Dorg.gradle.jvmargs=\"-Xmx512m -XX:+HeapDumpOnOutOfMemoryError\""
ENV JAVA_TOOL_OPTIONS="-Dfile.encoding=UTF8"
ADD .buckconfig /app/.buckconfig
ADD .buckjavaargs /app/.buckjavaargs
ADD tools /app/tools
ADD ReactAndroid /app/ReactAndroid
ADD ReactCommon /app/ReactCommon
ADD React /app/React
ADD keystores /app/keystores
WORKDIR /app
RUN buck fetch ReactAndroid/src/test/java/com/facebook/react/modules
RUN buck fetch ReactAndroid/src/main/java/com/facebook/react
RUN buck fetch ReactAndroid/src/main/java/com/facebook/react/shell
RUN buck fetch ReactAndroid/src/test/...
RUN buck fetch ReactAndroid/src/androidTest/...
RUN buck build ReactAndroid/src/main/java/com/facebook/react
RUN buck build ReactAndroid/src/main/java/com/facebook/react/shell
ADD . /app
RUN yarn
RUN ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog
RUN ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=1
@@ -0,0 +1,159 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
/**
* This script runs instrumentation tests one by one with retries
* Instrumentation tests tend to be flaky, so rerunning them individually increases
* chances for success and reduces total average execution time.
*
* We assume that all instrumentation tests are flat in one folder
* Available arguments:
* --path - path to all .java files with tests
* --package - com.facebook.react.tests
* --retries [num] - how many times to retry possible flaky commands: npm install and running tests, default 1
*/
const argv = require('yargs').argv;
const async = require('async');
const child_process = require('child_process');
const fs = require('fs');
const path = require('path');
const colors = {
GREEN: '\x1b[32m',
RED: '\x1b[31m',
RESET: '\x1b[0m',
};
const test_opts = {
FILTER: new RegExp(argv.filter || '.*', 'i'),
IGNORE: argv.ignore || null,
PACKAGE: argv.package || 'com.facebook.react.tests',
PATH: argv.path || './ReactAndroid/src/androidTest/java/com/facebook/react/tests',
RETRIES: parseInt(argv.retries || 2, 10),
TEST_TIMEOUT: parseInt(argv['test-timeout'] || 1000 * 60 * 10, 10),
OFFSET: argv.offset,
COUNT: argv.count,
};
let max_test_class_length = Number.NEGATIVE_INFINITY;
let testClasses = fs.readdirSync(path.resolve(process.cwd(), test_opts.PATH))
.filter((file) => {
return file.endsWith('.java');
}).map((clazz) => {
return path.basename(clazz, '.java');
});
if (test_opts.IGNORE) {
test_opts.IGNORE = new RegExp(test_opts.IGNORE, 'i');
testClasses = testClasses.filter(className => {
return !test_opts.IGNORE.test(className);
});
}
testClasses = testClasses.map((clazz) => {
return test_opts.PACKAGE + '.' + clazz;
}).filter((clazz) => {
return test_opts.FILTER.test(clazz);
});
// only process subset of the tests at corresponding offset and count if args provided
if (test_opts.COUNT != null && test_opts.OFFSET != null) {
const start = test_opts.COUNT * test_opts.OFFSET;
const end = start + test_opts.COUNT;
if (start >= testClasses.length) {
testClasses = [];
} else if (end >= testClasses.length) {
testClasses = testClasses.slice(start);
} else {
testClasses = testClasses.slice(start, end);
}
}
async.mapSeries(testClasses, (clazz, callback) => {
if (clazz.length > max_test_class_length) {
max_test_class_length = clazz.length;
}
return async.retry(test_opts.RETRIES, (retryCb) => {
const test_process = child_process.spawn('./.circleci/Dockerfiles/scripts/run-instrumentation-tests-via-adb-shell.sh', [test_opts.PACKAGE, clazz], {
stdio: 'inherit',
});
const timeout = setTimeout(() => {
test_process.kill();
}, test_opts.TEST_TIMEOUT);
test_process.on('error', (err) => {
clearTimeout(timeout);
retryCb(err);
});
test_process.on('exit', (code) => {
clearTimeout(timeout);
if (code !== 0) {
return retryCb(new Error(`Process exited with code: ${code}`));
}
return retryCb();
});
}, (err) => {
return callback(null, {
name: clazz,
status: err ? 'failure' : 'success',
});
});
}, (err, results) => {
print_test_suite_results(results);
const failures = results.filter((test) => {
return test.status === 'failure';
});
return failures.length === 0 ? process.exit(0) : process.exit(1);
});
function print_test_suite_results(results) {
console.log('\n\nTest Suite Results:\n');
let color;
let failing_suites = 0;
let passing_suites = 0;
function pad_output(num_chars) {
let i = 0;
while (i < num_chars) {
process.stdout.write(' ');
i++;
}
}
results.forEach((test) => {
if (test.status === 'success') {
color = colors.GREEN;
passing_suites++;
} else if (test.status === 'failure') {
color = colors.RED;
failing_suites++;
}
process.stdout.write(color);
process.stdout.write(test.name);
pad_output((max_test_class_length - test.name.length) + 8);
process.stdout.write(test.status);
process.stdout.write(`${colors.RESET}\n`);
});
console.log(`\n${passing_suites} passing, ${failing_suites} failing!`);
}
@@ -0,0 +1,42 @@
#!/bin/bash
#
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
#
# for buck gen
mount -o remount,exec /dev/shm
AVD_UUID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1)
# create virtual device
echo no | android create avd -n "$AVD_UUID" -f -t android-19 --abi default/armeabi-v7a
# emulator setup
emulator64-arm -avd $AVD_UUID -no-skin -no-audio -no-window -no-boot-anim &
bootanim=""
until [[ "$bootanim" =~ "stopped" ]]; do
sleep 5
bootanim=$(adb -e shell getprop init.svc.bootanim 2>&1)
echo "boot animation status=$bootanim"
done
set -x
# solve issue with max user watches limit
echo 65536 | tee -a /proc/sys/fs/inotify/max_user_watches
watchman shutdown-server
# integration tests
# build JS bundle for instrumentation tests
node cli.js bundle --platform android --dev true --entry-file ReactAndroid/src/androidTest/js/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js
# build test APK
# shellcheck disable=SC1091
source ./scripts/android-setup.sh && NO_BUCKD=1 retry3 buck install ReactAndroid/src/androidTest/buck-runner:instrumentation-tests --config build.threads=1
# run installed apk with tests
node ./.circleci/Dockerfiles/scripts/run-android-ci-instrumentation-tests.js "$*"
exit $?
@@ -0,0 +1,18 @@
#!/bin/bash
#
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
#
# set default environment variables
UNIT_TESTS_BUILD_THREADS="${UNIT_TESTS_BUILD_THREADS:-1}"
# for buck gen
mount -o remount,exec /dev/shm
set -x
# run unit tests
buck test ReactAndroid/src/test/... --config build.threads="$UNIT_TESTS_BUILD_THREADS"
+258
View File
@@ -0,0 +1,258 @@
#!/bin/bash
#
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
#
set -ex
# set default environment variables
ROOT=$(pwd)
SCRIPTS=$(pwd)/scripts
RUN_ANDROID=0
RUN_CLI_INSTALL=1
RUN_IOS=0
RUN_JS=0
RETRY_COUNT=${RETRY_COUNT:-2}
AVD_UUID=$(< /dev/urandom tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1)
ANDROID_NPM_DEPS="appium@1.5.1 mocha@2.4.5 wd@0.3.11 colors@1.0.3 pretty-data2@0.40.1"
CLI_PACKAGE="$ROOT/react-native-cli/react-native-cli-*.tgz"
PACKAGE="$ROOT/react-native-*.tgz"
# solve issue with max user watches limit
echo 65536 | tee -a /proc/sys/fs/inotify/max_user_watches
watchman shutdown-server
# retries command on failure
# $1 -- max attempts
# $2 -- command to run
function retry() {
local -r -i max_attempts="$1"; shift
local -r cmd="$*"
local -i attempt_num=1
until $cmd; do
if (( attempt_num == max_attempts )); then
echo "Execution of '$cmd' failed; no more attempts left"
return 1
else
(( attempt_num++ ))
echo "Execution of '$cmd' failed; retrying for attempt number $attempt_num..."
fi
done
}
# parse command line args & flags
while :; do
case "$1" in
--android)
RUN_ANDROID=1
shift
;;
--ios)
RUN_IOS=1
shift
;;
--js)
RUN_JS=1
shift
;;
--skip-cli-install)
RUN_CLI_INSTALL=0
shift
;;
--tvos)
RUN_IOS=1
shift
;;
*)
break
esac
done
function e2e_suite() {
cd "$ROOT"
if [ $RUN_ANDROID -eq 0 ] && [ $RUN_IOS -eq 0 ] && [ $RUN_JS -eq 0 ]; then
echo "No e2e tests specified!"
return 0
fi
# create temp dir
TEMP_DIR=$(mktemp -d /tmp/react-native-XXXXXXXX)
# To make sure we actually installed the local version
# of react-native, we will create a temp file inside the template
# and check that it exists after `react-native init
IOS_MARKER="$(mktemp "$ROOT"/template/ios/HelloWorld/XXXXXXXX)"
ANDROID_MARKER="$(mktemp "$ROOT"/template/android/XXXXXXXX)"
# install CLI
cd react-native-cli
npm pack
cd ..
# can skip cli install for non sudo mode
if [ $RUN_CLI_INSTALL -ne 0 ]; then
if ! npm install -g "$CLI_PACKAGE"
then
echo "Could not install react-native-cli globally, please run in su mode"
echo "Or with --skip-cli-install to skip this step"
return 1
fi
fi
if [ $RUN_ANDROID -ne 0 ]; then
set +ex
# create virtual device
if ! android list avd | grep "$AVD_UUID" > /dev/null; then
echo no | android create avd -n "$AVD_UUID" -f -t android-19 --abi default/armeabi-v7a
fi
# newline at end of adb devices call and first line is headers
DEVICE_COUNT=$(adb devices | wc -l)
((DEVICE_COUNT -= 2))
# will always kill an existing emulator if one exists for fresh setup
if [[ $DEVICE_COUNT -ge 1 ]]; then
adb emu kill
fi
# emulator setup
emulator64-arm -avd "$AVD_UUID" -no-skin -no-audio -no-window -no-boot-anim &
bootanim=""
# shellcheck disable=SC2076
until [[ "$bootanim" =~ "stopped" ]]; do
sleep 5
bootanim=$(adb -e shell getprop init.svc.bootanim 2>&1)
echo "boot animation status=$bootanim"
done
set -ex
if ! ./gradlew :ReactAndroid:installArchives -Pjobs=1 -Dorg.gradle.jvmargs="-Xmx512m -XX:+HeapDumpOnOutOfMemoryError"
then
echo "Failed to compile Android binaries"
return 1
fi
fi
if ! npm pack
then
echo "Failed to pack react-native"
return 1
fi
cd "$TEMP_DIR"
if ! retry "$RETRY_COUNT" react-native init EndToEndTest --version "$PACKAGE" --npm
then
echo "Failed to execute react-native init"
echo "Most common reason is npm registry connectivity, try again"
return 1
fi
cd EndToEndTest
# android tests
if [ $RUN_ANDROID -ne 0 ]; then
echo "Running an Android e2e test"
echo "Installing e2e framework"
if ! retry "$RETRY_COUNT" npm install --save-dev "$ANDROID_NPM_DEPS" --silent >> /dev/null
then
echo "Failed to install appium"
echo "Most common reason is npm registry connectivity, try again"
return 1
fi
cp "$SCRIPTS/android-e2e-test.js" android-e2e-test.js
(
cd android || exit
echo "Downloading Maven deps"
./gradlew :app:copyDownloadableDepsToLibs
)
keytool -genkey -v -keystore android/keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"
node ./node_modules/.bin/appium >> /dev/null &
APPIUM_PID=$!
echo "Starting appium server $APPIUM_PID"
echo "Building app"
buck build android/app
# hack to get node unhung (kill buckd)
if ! kill -9 "$(pgrep java)"
then
echo "could not execute Buck build, is it installed and in PATH?"
return 1
fi
echo "Starting packager server"
npm start >> /dev/null &
SERVER_PID=$!
sleep 15
echo "Executing android e2e test"
if ! retry "$RETRY_COUNT" node node_modules/.bin/_mocha android-e2e-test.js
then
echo "Failed to run Android e2e tests"
echo "Most likely the code is broken"
return 1
fi
# kill packager process
if kill -0 "$SERVER_PID"; then
echo "Killing packager $SERVER_PID"
kill -9 "$SERVER_PID"
fi
# kill appium process
if kill -0 "$APPIUM_PID"; then
echo "Killing appium $APPIUM_PID"
kill -9 "$APPIUM_PID"
fi
fi
# ios tests
if [ $RUN_IOS -ne 0 ]; then
echo "Running ios e2e tests not yet implemented for docker!"
fi
# js tests
if [ $RUN_JS -ne 0 ]; then
# Check the packager produces a bundle (doesn't throw an error)
if ! react-native bundle --max-workers 1 --platform android --dev true --entry-file index.js --bundle-output android-bundle.js
then
echo "Could not build android bundle"
return 1
fi
if ! react-native bundle --max-workers 1 --platform ios --dev true --entry-file index.js --bundle-output ios-bundle.js
then
echo "Could not build iOS bundle"
return 1
fi
# directory cleanup
rm "$IOS_MARKER"
rm "$ANDROID_MARKER"
return 0
}
retry "$RETRY_COUNT" e2e_suite
@@ -0,0 +1,72 @@
#!/bin/bash
#
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
#
# shellcheck disable=SC1117
# Python script to run instrumentation tests, copied from https://github.com/circleci/circle-dummy-android
# Example: ./scripts/run-android-instrumentation-tests.sh com.facebook.react.tests com.facebook.react.tests.ReactPickerTestCase
#
export PATH="$ANDROID_HOME/platform-tools:$ANDROID_HOME/tools:$PATH"
# clear the logs
adb logcat -c
# run tests and check output
python - "$1" "$2" << END
import re
import subprocess as sp
import sys
import threading
import time
done = False
test_app = sys.argv[1]
test_class = None
if len(sys.argv) > 2:
test_class = sys.argv[2]
def update():
# prevent CircleCI from killing the process for inactivity
while not done:
time.sleep(5)
print "Running in background. Waiting for 'adb' command response..."
t = threading.Thread(target=update)
t.dameon = True
t.start()
def run():
sp.Popen(['adb', 'wait-for-device']).communicate()
if (test_class != None):
p = sp.Popen('adb shell am instrument -w -e class %s %s/android.support.test.runner.AndroidJUnitRunner'
% (test_class, test_app), shell=True, stdout=sp.PIPE, stderr=sp.PIPE, stdin=sp.PIPE)
else :
p = sp.Popen('adb shell am instrument -w %s/android.support.test.runner.AndroidJUnitRunner'
% (test_app), shell=True, stdout=sp.PIPE, stderr=sp.PIPE, stdin=sp.PIPE)
return p.communicate()
success = re.compile(r'OK \(\d+ test(s)?\)')
stdout, stderr = run()
done = True
print stderr
print stdout
if success.search(stderr + stdout):
sys.exit(0)
else:
# dump the logs
sp.Popen(['adb', 'logcat', '-d']).communicate()
sys.exit(1) # make sure we fail if the test failed
END
RETVAL=$?
exit $RETVAL
+5
View File
@@ -0,0 +1,5 @@
# Circle CI
This directory is home to the Circle CI configuration file. Circle is our continuous integration service provider. You can see the overall status of React Native's builds at https://circleci.com/gh/facebook/react-native
You may also see an individual PR's build status by scrolling down to the Checks section in the PR.
+741
View File
@@ -0,0 +1,741 @@
# -------------------------
# ALIASES
# -------------------------
aliases:
# -------------------------
# ALIASES: Caches
# -------------------------
- &restore-yarn-cache
keys:
- v1-yarn-cache-{{ arch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }}
- v1-yarn-cache-{{ arch }}
- &save-yarn-cache
paths:
- ~/.cache/yarn
key: v1-yarn-cache-{{ arch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }}
- &restore-brew-cache
keys:
- v1-brew
- &save-brew-cache
paths:
- /usr/local/Homebrew
- ~/Library/Caches/Homebrew
key: v1-brew
# Android
- &restore-buck-downloads-cache
keys:
- v3-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}}
- v3-buck-v2019.01.10.01-
- &save-buck-downloads-cache
paths:
- ~/buck
- ~/okbuck
key: v3-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}
- &restore-gradle-downloads-cache
keys:
- v1-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }}
- v1-gradle-
- &save-gradle-downloads-cache
paths:
- ~/.gradle
- ReactAndroid/build/downloads
- ReactAndroid/build/third-party-ndk
key: v1-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }}
# -------------------------
# ALIASES: Shared Commands
# -------------------------
- &yarn
name: Run Yarn
command: |
# Skip yarn install on metro bump commits as the package is not yet
# available on npm
if [[ $(echo "$GIT_COMMIT_DESC" | grep -c "Bump metro@") -eq 0 ]]; then
yarn install --non-interactive --cache-folder ~/.cache/yarn
fi
- &setup-artifacts
name: Initial Setup
command: |
mkdir -p ~/react-native/reports/buck/
mkdir -p ~/react-native/reports/build/
mkdir -p ~/react-native/reports/junit/
mkdir -p ~/react-native/reports/outputs/
# Android
- &download-dependencies-buck
name: Download Dependencies Using Buck
command: ./scripts/circleci/buck_fetch.sh
- &download-dependencies-gradle
name: Download Dependencies Using Gradle
command: ./scripts/circleci/gradle_download_deps.sh
# JavaScript
- &run-js-tests
name: JavaScript Test Suite
command: yarn test-ci
# -------------------------
# ALIASES: Disabled Tests
# -------------------------
- &run-podspec-tests
name: Test CocoaPods
command: ./scripts/process-podspecs.sh
- &run-e2e-tests
name: End-to-End Test Suite
command: ./scripts/run-ci-e2e-tests.js --android --ios --js --retries 3;
- &run-android-e2e-tests
name: Android End-to-End Test Suite
command: node ./scripts/run-ci-e2e-tests.js --android --retries 3;
# -------------------------
# ALIASES: Branch Filters
# -------------------------
- &filter-only-master
branches:
only: master
- &filter-only-master-stable
branches:
only:
- /.*-stable/
- master
- &filter-only-stable
branches:
only:
- /.*-stable/
- &filter-ignore-gh-pages
branches:
ignore: gh-pages
- &filter-only-version-tags
# Both of the following conditions must be included!
# Ignore any commit on any branch by default.
branches:
ignore: /.*/
# Only act on version tags.
tags:
only: /v[0-9]+(\.[0-9]+)*(\-rc(\.[0-9]+)?)?/
- &filter-only-forked-pull-requests
branches:
only: /^pull\/.*$/
# -------------------------
# ALIASES: Workflows
# -------------------------
- &run-after-checkout
filters: *filter-ignore-gh-pages
requires:
- checkout_code
# -------------------------
# DEFAULTS
# -------------------------
defaults: &defaults
working_directory: ~/react-native
environment:
- GIT_COMMIT_DESC: git log --format=oneline -n 1 $CIRCLE_SHA1
# JavaScript
js_defaults: &js_defaults
<<: *defaults
docker:
- image: node:8
# Android
android_defaults: &android_defaults
<<: *defaults
docker:
- image: reactnativecommunity/react-native-android:2019-5-29
resource_class: "large"
environment:
- TERM: "dumb"
- ADB_INSTALL_TIMEOUT: 10
- _JAVA_OPTIONS: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap"
- GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-XX:+HeapDumpOnOutOfMemoryError"'
- BUILD_THREADS: 2
# iOS
macos_defaults: &macos_defaults
<<: *defaults
macos:
xcode: "10.2.0"
# -------------------------
# JOBS
# -------------------------
version: 2
jobs:
# Set up a Node environment for downstream jobs
checkout_code:
<<: *js_defaults
steps:
- checkout
- run: *setup-artifacts
- restore-cache: *restore-yarn-cache
- run: *yarn
- save-cache: *save-yarn-cache
- persist_to_workspace:
root: .
paths: .
# -------------------------
# JOBS: Analyze PR
# -------------------------
# Analyze pull request and raise any lint/flow issues.
# Issues will be posted to the PR itself via GitHub bots.
# This workflow should only fail if the bots fail to run.
analyze_pr:
<<: *defaults
docker:
- image: node:lts
# The public github tokens are publicly visible by design
environment:
- PUBLIC_PULLBOT_GITHUB_TOKEN_A: "a6edf8e8d40ce4e8b11a"
- PUBLIC_PULLBOT_GITHUB_TOKEN_B: "150e1341f4dd9c944d2a"
- PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A: "78a72af35445ca3f8180"
- PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B: "b1a98e0bbd56ff1ccba1"
steps:
- checkout
- run: *setup-artifacts
- restore-cache: *restore-yarn-cache
- run: *yarn
- run:
name: Analyze Shell Scripts
command: |
echo -e "\\x1B[36mInstalling additional dependencies\\x1B[0m"
apt update && apt install -y shellcheck jq
yarn add @octokit/rest@15.18.0
echo -e "\\x1B[36mAnalyzing shell scripts\\x1B[0m"; \
GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" \
GITHUB_OWNER="$CIRCLE_PROJECT_USERNAME" \
GITHUB_REPO="$CIRCLE_PROJECT_REPONAME" \
GITHUB_PR_NUMBER="$CIRCLE_PR_NUMBER" \
./scripts/circleci/analyze_scripts.sh
when: always
- run:
name: Analyze Code
command: |
echo -e "\\x1B[36mInstalling additional dependencies\\x1B[0m"; yarn add @octokit/rest@15.18.0
echo -e "\\x1B[36mAnalyzing code\\x1B[0m"; \
GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" \
GITHUB_OWNER="$CIRCLE_PROJECT_USERNAME" \
GITHUB_REPO="$CIRCLE_PROJECT_REPONAME" \
GITHUB_PR_NUMBER="$CIRCLE_PR_NUMBER" \
./scripts/circleci/analyze_code.sh
when: always
- run:
name: Analyze Pull Request
command: |
echo -e "\\x1B[36mInstalling additional dependencies\\x1B[0m"
cd bots
yarn install --non-interactive --cache-folder ~/.cache/yarn
echo -e "\\x1B[36mAnalyzing pull request\\x1B[0m"; \
DANGER_GITHUB_API_TOKEN="$PUBLIC_PULLBOT_GITHUB_TOKEN_A""$PUBLIC_PULLBOT_GITHUB_TOKEN_B" \
yarn danger ci --use-github-checks
when: always
- save-cache: *save-yarn-cache
# -------------------------
# JOBS: Analyze Code
# -------------------------
analyze:
<<: *js_defaults
steps:
- attach_workspace:
at: ~/react-native
- run:
name: Lint code
command: scripts/circleci/exec_swallow_error.sh yarn lint --format junit -o ~/react-native/reports/junit/eslint/results.xml
when: always
- run:
name: Check for errors in code using Flow (iOS)
command: yarn flow-check-ios
when: always
- run:
name: Check for errors in code using Flow (Android)
command: yarn flow-check-android
when: always
- run:
name: Sanity checks
command: |
./scripts/circleci/check_license.sh
./scripts/circleci/validate_yarn_lockfile.sh
when: always
- run:
name: Check formatting
command: yarn run format-check
when: always
- store_test_results:
path: ~/react-native/reports/junit
- store_artifacts:
path: ~/react-native/yarn.lock
# -------------------------
# JOBS: Test JavaScript
# -------------------------
# Runs JavaScript tests on Node 8
test_javascript:
<<: *js_defaults
steps:
- attach_workspace:
at: ~/react-native
- run:
name: JavaScript Test Suite
command: node ./scripts/run-ci-javascript-tests.js --maxWorkers 2
- store_test_results:
path: ~/react-native/reports/junit
# Run JavaScript tests on Node LTS
test_node_lts:
<<: *defaults
docker:
- image: node:lts
steps:
- checkout
- run: *setup-artifacts
- run: *yarn
- run:
name: JavaScript Test Suite
command: node ./scripts/run-ci-javascript-tests.js --maxWorkers 2
- store_test_results:
path: ~/react-native/reports/junit
# -------------------------
# JOBS: Test iOS
# -------------------------
# Runs unit tests on iOS devices
test_ios:
<<: *macos_defaults
environment:
- REPORTS_DIR: "./reports"
steps:
- attach_workspace:
at: ~/react-native
- run:
name: Print Xcode environment
command: xcodebuild -version
- run:
name: List available devices
command: instruments -s devices
- run:
name: Boot iOS Simulator
command: source scripts/.tests.env && xcrun simctl boot "$IOS_DEVICE" || true
- restore-cache: *restore-brew-cache
- run:
name: Install Watchman
command: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install watchman >/dev/null
touch .watchmanconfig
- save-cache: *save-brew-cache
- run:
name: Start Metro packager
command: yarn start --max-workers=1 || echo "Can't start packager automatically"
background: true
- run:
name: Start WebSocket test server
command: open "./IntegrationTests/launchWebSocketServer.command" || echo "Can't start web socket server automatically"
background: true
- run:
name: Verify RNTester can be built
command: |
source ./scripts/.tests.env
xcodebuild \
-project RNTester/RNTester.xcodeproj \
-scheme RNTester \
-sdk iphonesimulator \
-destination "platform=iOS Simulator,name=$IOS_DEVICE,OS=$IOS_TARGET_OS" \
-UseModernBuildSystem=NO \
build | \
xcpretty --report junit --output "$REPORTS_DIR/junit/ios_buiild/results.xml" && \
exit "${PIPESTATUS[0]}"
- run:
name: Wait for Metro packager
command: |
max_attempts=60
attempt_num=1
until curl -s http://localhost:8081/status | grep "packager-status:running" -q; do
if (( attempt_num == max_attempts )); then
echo "Packager did not respond in time. No more attempts left."
exit 1
else
(( attempt_num++ ))
echo "Packager did not respond. Retrying for attempt number $attempt_num..."
sleep 1
fi
done
echo "Packager is ready!"
- run:
name: Preload the RNTesterApp bundles
command: |
curl --silent 'http://localhost:8081/RNTester/js/RNTesterApp.ios.bundle?platform=ios&dev=true' --output /dev/null
curl --silent 'http://localhost:8081/RNTester/js/RNTesterApp.ios.bundle?platform=ios&dev=true&minify=false' --output /dev/null
curl --silent 'http://localhost:8081/IntegrationTests/IntegrationTestsApp.bundle?platform=ios&dev=true' --output /dev/null
curl --silent 'http://localhost:8081/IntegrationTests/RCTRootViewIntegrationTestApp.bundle?platform=ios&dev=true' --output /dev/null
- run:
name: Run RNTester Unit Tests
command: |
source ./scripts/.tests.env
xcodebuild \
-project RNTester/RNTester.xcodeproj \
-scheme RNTester \
-sdk iphonesimulator \
-destination "platform=iOS Simulator,name=$IOS_DEVICE,OS=$IOS_TARGET_OS" \
-UseModernBuildSystem=NO \
-only-testing:RNTesterUnitTests \
build test | \
xcpretty --report junit --output "$REPORTS_DIR/junit/ios_unit_tests/results.xml" && \
exit "${PIPESTATUS[0]}"
- run:
name: Run RNTester Integration Tests
command: |
source ./scripts/.tests.env
xcodebuild \
-project RNTester/RNTester.xcodeproj \
-scheme RNTester \
-sdk iphonesimulator \
-destination "platform=iOS Simulator,name=$IOS_DEVICE,OS=$IOS_TARGET_OS" \
-UseModernBuildSystem=NO \
-only-testing:RNTesterIntegrationTests \
build test | \
xcpretty --report junit --output "$REPORTS_DIR/junit/ios_integration_tests/results.xml" && \
exit "${PIPESTATUS[0]}"
- run:
name: Stop Metro packager and WebSocket test server
command: |
# kill whatever is occupying port 8081 (packager)
lsof -i tcp:8081 | awk 'NR!=1 {print $2}' | xargs kill
# kill whatever is occupying port 5555 (web socket server)
lsof -i tcp:5555 | awk 'NR!=1 {print $2}' | xargs kill
- store_test_results:
path: ~/react-native/reports/junit
# Runs end-to-end tests
test_end_to_end:
<<: *macos_defaults
steps:
- attach_workspace:
at: ~/react-native
- run:
name: Boot iPhone Simulator
command: source scripts/.tests.env && xcrun simctl boot "$IOS_DEVICE" || true
- run:
name: Configure Environment Variables
command: |
echo 'export PATH=/usr/local/opt/node@8/bin:$PATH' >> $BASH_ENV
source $BASH_ENV
# Brew
- restore-cache: *restore-brew-cache
- run:
name: Configure Detox Environment
command: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install node@8 >/dev/null
HOMEBREW_NO_AUTO_UPDATE=1 brew tap wix/brew >/dev/null
HOMEBREW_NO_AUTO_UPDATE=1 brew install applesimutils >/dev/null
touch .watchmanconfig
node -v
- save-cache: *save-brew-cache
# Yarn install
- restore-cache: *restore-yarn-cache
- run: *yarn
- save-cache: *save-yarn-cache
# Xcode build
- run:
name: Build app for Detox iOS End-to-End Tests
command: yarn run build-ios-e2e
# Test
- run:
name: Run Detox iOS End-to-End Tests
command: yarn run test-ios-e2e
when: always
- run:
name: Run JavaScript End-to-End Tests
command: |
# free up port 8081 for the packager before running tests
set +eo pipefail
lsof -i tcp:8081 | awk 'NR!=1 {print $2}' | xargs kill
set -eo pipefail
node ./scripts/run-ci-e2e-tests.js --js --retries 3
when: always
- run:
name: Run iOS End-to-End Tests
command: |
# free up port 8081 for the packager before running tests
set +eo pipefail
lsof -i tcp:8081 | awk 'NR!=1 {print $2}' | xargs kill
set -eo pipefail
node ./scripts/run-ci-e2e-tests.js --ios --retries 3;
when: always
# -------------------------
# JOBS: Test Android
# -------------------------
# Run Android tests
test_android:
<<: *android_defaults
steps:
- attach_workspace:
at: ~/react-native
# Validate Android SDK installation and packages
- run:
name: Validate Android SDK Install
command: ./scripts/validate-android-sdk.sh
# Starting emulator in advance as it takes some time to boot.
- run:
name: Create Android Virtual Device
command: source scripts/android-setup.sh && createAVD
- run:
name: Launch Android Virtual Device in Background
command: source scripts/android-setup.sh && launchAVD
background: true
# Keep configuring Android dependencies while AVD boots up
- restore-cache: *restore-buck-downloads-cache
- run:
name: Install Buck
command: |
buck --version
# Install related tooling
if [[ ! -e ~/okbuck ]]; then
git clone https://github.com/uber/okbuck.git ~/okbuck --depth=1
fi
mkdir -p ~/react-native/tooling/junit
cp -R ~/okbuck/tooling/junit/* ~/react-native/tooling/junit/.
- save-cache: *save-buck-downloads-cache
# Validate Android test environment (including Buck)
- run:
name: Validate Android Test Environment
command: ./scripts/validate-android-test-env.sh
# Download dependencies using Buck
- run: *download-dependencies-buck
# Download dependencies using Gradle
- restore-cache: *restore-gradle-downloads-cache
- run: *download-dependencies-gradle
- save-cache: *save-gradle-downloads-cache
# Build and compile
- run:
name: Build Android App
command: |
buck build ReactAndroid/src/main/java/com/facebook/react
buck build ReactAndroid/src/main/java/com/facebook/react/shell
- run:
name: Compile Native Libs for Unit and Integration Tests
command: ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=$BUILD_THREADS
no_output_timeout: 6m
# Build JavaScript Bundle for instrumentation tests
- run:
name: Build JavaScript Bundle
command: node cli.js bundle --max-workers 2 --platform android --dev true --entry-file ReactAndroid/src/androidTest/js/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js
# Wait for AVD to finish booting before running tests
- run:
name: Wait for Android Virtual Device
command: source scripts/android-setup.sh && waitForAVD
# Test Suite
- run:
name: Run Unit Tests
command: buck test ReactAndroid/src/test/... --config build.threads=$BUILD_THREADS --xml ~/react-native/reports/buck/all-results-raw.xml
- run:
name: Run Instrumentation Tests
command: |
if [[ ! -e ReactAndroid/src/androidTest/assets/AndroidTestBundle.js ]]; then
echo "JavaScript bundle missing, cannot run instrumentation tests. Verify Build JavaScript Bundle step completed successfully."; exit 1;
fi
source scripts/android-setup.sh && NO_BUCKD=1 retry3 timeout 300 buck install ReactAndroid/src/androidTest/buck-runner:instrumentation-tests --config build.threads=$BUILD_THREADS
- run:
name: Build Android RNTester App
command: ./gradlew RNTester:android:app:assembleRelease
# Collect Results
- run:
name: Collect Test Results
command: |
find . -type f -regex ".*/build/test-results/debug/.*xml" -exec cp {} ~/react-native/reports/build/ \;
find . -type f -regex ".*/outputs/androidTest-results/connected/.*xml" -exec cp {} ~/react-native/reports/outputs/ \;
find . -type f -regex ".*/buck-out/gen/ReactAndroid/src/test/.*/.*xml" -exec cp {} ~/react-native/reports/buck/ \;
./tooling/junit/buck_to_junit.sh ~/react-native/reports/buck/all-results-raw.xml ~/react-native/reports/junit/all-results-junit.xml
when: always
- store_test_results:
path: ~/react-native/reports/junit
# -------------------------
# JOBS: Test Docker Build
# -------------------------
test_docker_build:
machine: true
steps:
- checkout
- run:
name: Build Docker container for Android RNTester App
command: |
source ~/.bashrc
nvm i node
npm i -g yarn
npx envinfo@latest
yarn run docker-setup-android
yarn run docker-build-android
# -------------------------
# JOBS: Coverage
# -------------------------
# Collect JavaScript test coverage
js_coverage:
<<: *js_defaults
environment:
- CI_BRANCH: $CIRCLE_BRANCH
- CI_PULL_REQUEST: $CIRCLE_PULL_REQUEST
- CI_BUILD_NUMBER: $CIRCLE_BUILD_NUM
- CI_BUILD_URL: $CIRCLE_BUILD_URL
steps:
- checkout
- restore-cache: *restore-yarn-cache
- run: *yarn
- run:
name: Test coverage
command: |
yarn test --coverage --maxWorkers=2
cat ./coverage/lcov.info | ./node_modules/.bin/coveralls
when: always
- store_artifacts:
path: ~/react-native/coverage/
# -------------------------
# JOBS: Releases
# -------------------------
# Publishes new version onto npm
# Only works on stable branches when a properly tagged commit is pushed
publish_npm_package:
<<: *android_defaults
steps:
- checkout
- restore-cache: *restore-yarn-cache
- run: *yarn
# Fetch dependencies using Buck
- restore-cache: *restore-buck-downloads-cache
- run: *download-dependencies-buck
# Fetch dependencies using Gradle
- restore-cache: *restore-gradle-downloads-cache
- run: *download-dependencies-gradle
- run:
name: Authenticate with npm
command: echo "//registry.npmjs.org/:_authToken=${CIRCLE_NPM_TOKEN}" > ~/.npmrc
- run:
name: Authenticate git user
command: |
git config --global user.email "react-native-bot@users.noreply.github.com"
git config --global user.name "npm Deployment Script"
echo "machine github.com login react-native-bot password $GITHUB_TOKEN" > ~/.netrc
# Build and publish release. Requires an Android environment.
- run:
name: Publish React Native Package
command: node ./scripts/publish-npm.js
# -------------------------
# WORK FLOWS
# -------------------------
workflows:
version: 2
tests:
jobs:
- test_node_lts:
filters: *filter-ignore-gh-pages
- checkout_code:
filters: *filter-ignore-gh-pages
- analyze: *run-after-checkout
- test_javascript: *run-after-checkout
- test_android: *run-after-checkout
- test_ios: *run-after-checkout
- test_end_to_end: *run-after-checkout
- test_docker_build:
filters: *filter-ignore-gh-pages
releases:
jobs:
- checkout_code:
filters: *filter-only-version-tags
- publish_npm_package:
filters: *filter-only-version-tags
requires:
- checkout_code
analysis:
jobs:
# Run code checks on PRs from forks
- analyze_pr:
filters: *filter-only-forked-pull-requests
# Gather coverage on master
- js_coverage:
filters: *filter-only-master
+1 -3
View File
@@ -68,7 +68,7 @@ PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
@@ -84,10 +84,8 @@ SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
QualifierAlignment: Left
---
Language: ObjC
ColumnLimit: 120
BreakBeforeBraces: WebKit
PointerAlignment: Right
...
+7 -1
View File
@@ -1,4 +1,4 @@
# EditorConfig is awesome: https://EditorConfig.org
# EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
@@ -9,3 +9,9 @@ end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
[*.gradle]
indent_size = 4
[BUCK]
indent_size = 4
+9 -16
View File
@@ -1,18 +1,11 @@
**/main.js
# node_modules ignored by default
**/staticBundle.js
docs/generatedComponentApiDocs.js
packages/react-native/flow/
packages/react-native/sdks/
packages/react-native/ReactAndroid/build
packages/react-native/ReactAndroid/hermes-engine/build/
packages/react-native/Libraries/Renderer/*
packages/react-native/Libraries/vendor/**/*
node_modules/
**/main.js
Libraries/vendor/**/*
Libraries/Renderer/*
packages/*/node_modules
packages/*/dist
packages/*/types_generated
packages/debugger-frontend/dist/**/*
packages/react-native-codegen/lib
**/Pods/*
**/*.macos.js
**/*.windows.js
pr-inactivity-bookmarklet.js
question-bookmarklet.js
flow/
bots/node_modules
+37
View File
@@ -0,0 +1,37 @@
{
"root": true,
"extends": [
"./packages/eslint-config-react-native-community/index.js"
],
"overrides": [
{
"files": [
"**/__fixtures__/**/*.js",
"**/__mocks__/**/*.js",
"**/__tests__/**/*.js",
"jest/**/*.js",
"RNTester/**/*.js",
],
"globals": {
// Expose some Jest globals for test helpers
"afterAll": true,
"afterEach": true,
"beforeAll": true,
"beforeEach": true,
"expect": true,
"jest": true,
},
},
{
"files": [
"**/__tests__/**/*-test.js",
],
"env": {
"jasmine": true,
"jest": true,
},
},
],
}
-151
View File
@@ -1,151 +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.
*
* @noflow
* @format
*/
'use strict';
module.exports = {
root: true,
extends: ['@react-native'],
plugins: ['@react-native/monorepo', '@react-native/specs'],
overrides: [
// overriding the JS config from @react-native/eslint-config to ensure
// that we use hermes-eslint for all js files
{
files: ['*.js', '*.js.flow', '*.jsx'],
parser: 'hermes-eslint',
rules: {
'@react-native/monorepo/sort-imports': 'warn',
'eslint-comments/no-unlimited-disable': 'off',
'ft-flow/require-valid-file-annotation': ['error', 'always'],
'no-extra-boolean-cast': 'off',
'no-void': 'off',
// These rules are not required with hermes-eslint
'ft-flow/define-flow-type': 'off',
'ft-flow/use-flow-type': 'off',
// Flow handles these checks for us, so they aren't required
'no-undef': 'off',
'no-unreachable': 'off',
// Throwing from function or rejecting promises with non-error values could result in unclear error stack traces and lead to harder debugging
'prefer-promise-reject-errors': 'error',
'no-throw-literal': 'error',
},
},
{
files: ['*.js', '*.jsx', '*.ts', '*.tsx'],
rules: {
'@react-native/no-deep-imports': 'off',
},
},
{
files: [
'./packages/react-native/Libraries/**/*.{js,flow}',
'./packages/react-native/src/**/*.{js,flow}',
'./packages/assets/registry.js',
],
parser: 'hermes-eslint',
rules: {
'@react-native/monorepo/no-commonjs-exports': 'warn',
},
},
{
files: ['package.json'],
parser: 'jsonc-eslint-parser',
},
{
files: ['package.json'],
rules: {
'@react-native/monorepo/react-native-manifest': 'error',
},
},
{
files: ['flow-typed/**/*.js', 'packages/react-native/flow/**/*'],
rules: {
'@react-native/monorepo/valid-flow-typed-signature': 'error',
'ft-flow/require-valid-file-annotation': 'off',
'no-shadow': 'off',
'no-unused-vars': 'off',
quotes: 'off',
},
},
{
files: [
'packages/react-native/Libraries/**/*.js',
'packages/react-native/src/**/*.js',
],
rules: {
'@react-native/monorepo/no-haste-imports': 'error',
'@react-native/monorepo/no-react-default-imports': 'error',
'@react-native/monorepo/no-react-named-type-imports': 'error',
'@react-native/monorepo/no-react-native-imports': 'error',
'@react-native/monorepo/no-react-node-imports': 'error',
'@react-native/monorepo/require-extends-error': 'error',
'@react-native/platform-colors': 'error',
'@react-native/specs/react-native-modules': 'error',
},
},
{
files: [
'**/__fixtures__/**/*.js',
'**/__mocks__/**/*.js',
'**/__tests__/**/*.js',
'packages/react-native/jest/**/*.js',
'packages/rn-tester/**/*.js',
],
globals: {
// Expose some Jest globals for test helpers
afterAll: true,
afterEach: true,
beforeAll: true,
beforeEach: true,
expect: true,
jest: true,
},
},
{
files: ['**/__tests__/**/*-test.js'],
env: {
jasmine: true,
jest: true,
},
},
{
files: ['**/*.{ts,tsx}'],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint/eslint-plugin'],
rules: {
'@typescript-eslint/no-unused-vars': 'off',
'react-native/no-inline-styles': 'off',
'@typescript-eslint/no-shadow': 'off',
'no-self-compare': 'off',
'react/self-closing-comp': 'off',
},
},
{
files: ['**/*.d.ts'],
plugins: ['redundant-undefined'],
rules: {
'no-dupe-class-members': 'off',
'redundant-undefined/redundant-undefined': [
'error',
{followExactOptionalPropertyTypes: true},
],
},
},
{
files: ['**/__tests__/**'],
rules: {
'@react-native/monorepo/no-react-native-imports': 'off',
},
},
],
};
+54 -49
View File
@@ -1,81 +1,84 @@
[ignore]
; Ignore build cache folder
<PROJECT_ROOT>/packages/react-native/sdks/.*
; We fork some components by platform
.*/*[.]android.js
; Ignore fb_internal modules
<PROJECT_ROOT>/packages/react-native/src/fb_internal/.*
; Ignore the codegen e2e tests
<PROJECT_ROOT>/packages/react-native-codegen/e2e/__test_fixtures__/modules/NativeEnumTurboModule.js
; Ignore templates for 'react-native init'
<PROJECT_ROOT>/template/.*
; Ignore the Dangerfile
<PROJECT_ROOT>/private/react-native-bots/dangerfile.js
<PROJECT_ROOT>/bots/dangerfile.js
; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/
; Ignore other platform suffixes
.*\.macos\.js$
.*\.windows\.js$
; Ignore unexpected extra "@providesModule"
.*/node_modules/.*/node_modules/fbjs/.*
.*/node_modules/resolve/test/resolver/malformed_package_json/package\.json$
; Ignore duplicate module providers
; For RN Apps installed via npm, "Libraries" folder is inside
; "node_modules/react-native" but in the source repo it is in the root
.*/Libraries/react-native/React.js
; Checked-in build output
<PROJECT_ROOT>/packages/debugger-frontend/dist/
; Ignore polyfills
.*/Libraries/polyfills/.*
; Generated build output
<PROJECT_ROOT>/packages/.*/dist
; These should not be required directly
; require from fbjs/lib instead: require('fbjs/lib/warning')
.*/node_modules/warning/.*
; helloworld
<PROJECT_ROOT>/private/helloworld/ios/Pods/
; Ignore rn-tester Pods
<PROJECT_ROOT>/packages/rn-tester/Pods/
; Flow doesn't support platforms
.*/Libraries/Utilities/HMRLoadingView.js
[untyped]
.*/node_modules/@react-native-community/cli/.*/.*
[include]
[declarations]
.*/node_modules/.*
[libs]
flow-typed/
packages/react-native/interface.js
packages/react-native/flow/
Libraries/react-native/react-native-interface.js
flow/
[options]
enums=true
experimental.pattern_matching=true
casting_syntax=both
component_syntax=true
emoji=true
exact_by_default=true
format.bracket_spacing=false
esproposal.optional_chaining=enable
esproposal.nullish_coalescing=enable
module.file_ext=.js
module.file_ext=.json
module.file_ext=.ios.js
experimental.multi_platform=true
experimental.multi_platform.extensions=.ios
experimental.multi_platform.extensions=.android
module.system=haste
module.system.haste.use_name_reducers=true
# keep the following in sync with server/haste/hasteImpl.js
# get basename
module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1'
# strip .js or .js.flow suffix
module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1'
# strip .ios suffix
module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1'
module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
module.system.haste.paths.blacklist=.*/__tests__/.*
module.system.haste.paths.blacklist=.*/__mocks__/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/Libraries/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/RNTester/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/IntegrationTests/.*
module.system.haste.paths.blacklist=<PROJECT_ROOT>/Libraries/react-native/react-native-implementation.js
module.system.haste.paths.blacklist=<PROJECT_ROOT>/Libraries/Animated/src/polyfills/.*
munge_underscores=true
module.name_mapper='^react-native$' -> '<PROJECT_ROOT>/packages/react-native/index.js'
module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/packages/react-native/\1'
module.name_mapper='^@react-native/dev-middleware$' -> '<PROJECT_ROOT>/packages/dev-middleware'
module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\|xml\|ktx\)$' -> '<PROJECT_ROOT>/packages/react-native/Libraries/Image/RelativeImageStub'
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
module.system.haste.module_ref_prefix=m#
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
react.runtime=automatic
ban_spread_key_props=true
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
[lints]
sketchy-null-number=warn
@@ -83,10 +86,12 @@ sketchy-null-mixed=warn
sketchy-number=warn
untyped-type-import=warn
nonstrict-import=warn
deprecated-type=error
deprecated-type=warn
unsafe-getters-setters=warn
inexact-spread=warn
unnecessary-invariant=warn
unused-promise=error
signature-verification-failure=warn
deprecated-utility=error
[strict]
deprecated-type
@@ -98,4 +103,4 @@ untyped-import
untyped-type-import
[version]
^0.289.0
^0.98.0
+106
View File
@@ -0,0 +1,106 @@
[ignore]
; We fork some components by platform
.*/*[.]ios.js
; Ignore templates for 'react-native init'
<PROJECT_ROOT>/template/.*
; Ignore the Dangerfile
<PROJECT_ROOT>/bots/dangerfile.js
; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/
; Ignore unexpected extra "@providesModule"
.*/node_modules/.*/node_modules/fbjs/.*
; Ignore duplicate module providers
; For RN Apps installed via npm, "Libraries" folder is inside
; "node_modules/react-native" but in the source repo it is in the root
.*/Libraries/react-native/React.js
; Ignore polyfills
.*/Libraries/polyfills/.*
; These should not be required directly
; require from fbjs/lib instead: require('fbjs/lib/warning')
.*/node_modules/warning/.*
; Flow doesn't support platforms
.*/Libraries/Utilities/HMRLoadingView.js
[untyped]
.*/node_modules/@react-native-community/cli/.*/.*
[include]
[libs]
Libraries/react-native/react-native-interface.js
flow/
[options]
emoji=true
esproposal.optional_chaining=enable
esproposal.nullish_coalescing=enable
module.file_ext=.js
module.file_ext=.json
module.file_ext=.android.js
module.system=haste
module.system.haste.use_name_reducers=true
# keep the following in sync with server/haste/hasteImpl.js
# get basename
module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1'
# strip .js or .js.flow suffix
module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1'
# strip .android suffix
module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1'
module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
module.system.haste.paths.blacklist=.*/__tests__/.*
module.system.haste.paths.blacklist=.*/__mocks__/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/Libraries/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/RNTester/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/IntegrationTests/.*
module.system.haste.paths.blacklist=<PROJECT_ROOT>/Libraries/react-native/react-native-implementation.js
module.system.haste.paths.blacklist=<PROJECT_ROOT>/Libraries/Animated/src/polyfills/.*
munge_underscores=true
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_android\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_android\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
[lints]
sketchy-null-number=warn
sketchy-null-mixed=warn
sketchy-number=warn
untyped-type-import=warn
nonstrict-import=warn
deprecated-type=warn
unsafe-getters-setters=warn
inexact-spread=warn
unnecessary-invariant=warn
signature-verification-failure=warn
deprecated-utility=error
[strict]
deprecated-type
nonstrict-import
sketchy-null
unclear-type
unsafe-getters-setters
untyped-import
untyped-type-import
[version]
^0.98.0
+6 -1
View File
@@ -1 +1,6 @@
*.js.flow linguist-language=JavaScript
# Force LF line endings for Bash scripts. On Windows the rest of the source
# files will typically have CR+LF endings (Git default on Windows), but Bash
# scripts need to have LF endings to work (under Cygwin), thus override to force
# that.
gradlew text eol=lf
*.sh text eol=lf
+37
View File
@@ -0,0 +1,37 @@
# See https://help.github.com/en/articles/about-code-owners
# to learn more about code owners.
# Order is important; the last matching pattern takes the most
# precedence. You may specify either a GitHub username, or an
# email address if you prefer, as the code owner.
# Any Markdown file anywhere in the repository
**/*.md @hramos @cpojer
# GitHub Settings, Bots
/.github/ @hramos
/bots @hramos
# Continuous Integration
/.circleci/ @hramos
/.circleci/Dockerfiles @gengjiawen
/.appveyor/ @gengjiawen
# Internals
React/Base/* @shergin
React/Views/* @shergin
React/Modules/* @shergin
React/CxxBridge/* @mhorowitz
# Components and APIs
ReactAndroid/src/main/java/com/facebook/react/animated/* @janicduplessis
Libraries/Animated/* @janicduplessis
Libraries/NativeAnimation/* @janicduplessis
Libraries/Image/* @shergin
Libraries/Text/* @shergin
# Modifications to package.json typically require
# additional effort from a Facebook employee to land
/package.json @hramos @cpojer
# These should not be modified through a GitHub PR
LICENSE* @hramos @cpojer @yungsters
+3 -3
View File
@@ -1,4 +1,4 @@
✋ To keep the backlog clean and actionable, issues will be
🚫 closed if they do not follow one of the issue templates:
👉 https://github.com/facebook/react-native/issues/new/choose
👉 Please follow one of these issue templates:
- https://github.com/facebook/react-native/issues/new/choose
Note: to keep the backlog clean and actionable, issues may be immediately closed if they do not follow one of the above issue templates.
+40
View File
@@ -0,0 +1,40 @@
---
name: "🐛 Bug Report"
about: Report a reproducible bug or regression in React Native.
title: ''
labels: 'Bug'
---
<!--
Please provide a clear and concise description of what the bug is.
Include screenshots if needed.
Please test using the latest React Native release to make sure your issue has not already been fixed: http://facebook.github.io/react-native/docs/upgrading.html
-->
React Native version:
<!--
Run `react-native info` in your terminal and copy the results here.
-->
## Steps To Reproduce
1.
2.
<!--
Issues without reproduction steps or code are likely to stall.
-->
Describe what you expected to happen:
Snack, code example, or link to a repository:
<!--
Please provide a Snack (https://snack.expo.io/), a link to a repository on GitHub, or
provide a minimal code example that reproduces the problem.
Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve.
-->
-123
View File
@@ -1,123 +0,0 @@
name: 🐛 React Native - Bug Report
description: Report a reproducible bug or regression in React Native.
labels: ["Needs: Triage :mag:"]
body:
- type: markdown
attributes:
value: "## Reporting a bug to React Native"
- type: markdown
attributes:
value: |
Thank you for taking the time to report an issue for React Native, your contribution will help
make the framework better for everyone.
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're 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:
* Have a **valid reproducer** (See [How to report a bug](https://reactnative.dev/contributing/how-to-report-a-bug)).
* Is tested against the [**latest stable**](https://github.com/facebook/react-native/releases/) of React Native.
🚨 IMPORTANT: Due to the extreme number of bugs we receive, issues **without a reproducer** or for an [**unsupported versions**](https://github.com/reactwg/react-native-releases#which-versions-are-currently-supported) of React Native **will be closed**.
- 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 reproduce the issue.
placeholder: |
1. Install the application with `yarn android`
2. Click on the button on the Home
3. Notice the crash
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.73.0"
validations:
required: true
- type: dropdown
id: platforms
attributes:
label: Affected Platforms
description: Please select which platform you're developing to, and which OS you're using for building.
multiple: true
options:
- Runtime - Android
- Runtime - iOS
- Runtime - Web
- Runtime - Desktop
- Build - MacOS
- Build - Windows
- Build - Linux
- Other (please specify)
validations:
required: true
- type: textarea
id: react-native-info
attributes:
label: Output of `npx @react-native-community/cli info`
description: Run `npx @react-native-community/cli info` in your terminal, copy and paste the results here.
placeholder: |
Paste the output of `npx @react-native-community/cli 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: 22.14.0
...
render: text
validations:
required: true
- type: textarea
id: stacktrace
attributes:
label: Stacktrace or Logs
description: Please provide a stacktrace or a log of your crash or failure
render: text
placeholder: |
Paste your stacktraces and logs here. They might look like:
java.lang.UnsatisfiedLinkError: couldn't find DSO to load: libfabricjni.so caused by: com.facebook.react.fabric.StateWrapperImpl result: 0
at com.facebook.soloader.SoLoader.g(Unknown Source:341)
at com.facebook.soloader.SoLoader.t(Unknown Source:124)
at com.facebook.soloader.SoLoader.s(Unknown Source:2)
at com.facebook.soloader.SoLoader.q(Unknown Source:42)
at com.facebook.soloader.SoLoader.p(Unknown Source:1)
...
validations:
required: true
- type: input
id: reproducer
attributes:
label: MANDATORY Reproducer
description: A link to either a failing RNTesterPlayground.js file, an Expo Snack or a public repository from [this template](https://github.com/react-native-community/reproducer-react-native) that reproduces this bug. Reproducers are **mandatory**, issues without a reproducer will be closed.
placeholder: "https://github.com/<myuser>/<myreproducer>"
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**.
-26
View File
@@ -1,26 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: ⬆️ Upgrade - Build Regression
url: https://github.com/reactwg/react-native-releases/issues/new/choose
about: |
If you are upgrading to a new React Native version (stable or pre-release) and encounter a build regression.
- name: 🚀 Expo Issue
url: https://github.com/expo/expo/issues/new
about: |
If you're using Expo in your project, please report the issue first in the Expo issue tracker.
- name: 📃 Documentation Issue
url: https://github.com/facebook/react-native-website/issues
about: Please report documentation issues in the React Native website repository.
- name: 📦 Metro Issue
url: https://github.com/facebook/metro/issues/new
about: |
If you've encountered a module resolution problem, e.g. "Error: Unable to resolve module ...", or something else that might be related to Metro, please open an issue in the Metro repo instead.
- name: 🤔 Questions and Help
url: https://reactnative.dev/help
about: Looking for help with your app? Please refer to the React Native community's support resources.
- name: 💫 New Architecture - Questions & Technical Deep dive insights
url: https://github.com/reactwg/react-native-new-architecture
about: Questions and doubts related to technical questions for the New Architecture should be directed to the Working Group. Instructions on how to join are available in the README.
- name: 🚀 Discussions and Proposals
url: https://github.com/react-native-community/discussions-and-proposals
about: Discuss the future of React Native in the React Native community's discussions and proposals repository.
@@ -1,76 +0,0 @@
name: 🔍 Debugger - Bug Report
description: Report a bug with React Native DevTools and the New Debugger
labels: ["Needs: Triage :mag:", "Debugging"]
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-community/cli info`
description: Run `npx @react-native-community/cli info` in your terminal, copy and paste the results here.
placeholder: |
Paste the output of `npx @react-native-community/cli 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: 22.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**.
+14
View File
@@ -0,0 +1,14 @@
---
name: "📃 Documentation Issue"
about: Documentation issues are handled in https://github.com/facebook/react-native-website.
title: 'Docs:'
labels: 'Type: Docs'
---
🚨 Please do not open a documentation issue in the core React Native repository. 🚨
The React Native website is hosted on a separate repository. You may let the
team know about any issues with the documentation by opening an issue there:
- https://github.com/facebook/react-native-website
- https://github.com/facebook/react-native-website/issues
@@ -1,135 +0,0 @@
name: 💫 New Architecture - Bug Report
description: Report a reproducible bug or a build issue when using the New Architecture (Fabric & TurboModules) in React Native.
labels: ["Needs: Triage :mag:", "Type: New Architecture"]
body:
- type: markdown
attributes:
value: "## New Architecture Related Bugs"
- type: markdown
attributes:
value: |
Thank you for taking the time to report an issue for [the New Architecture of React Native](https://reactnative.dev/docs/the-new-architecture/landing-page),
your contribution will help make the framework better for everyone.
If you're **NOT** using the New Architecture, please use this [other bug type](https://github.com/facebook/react-native/issues/new?template=bug_report.yml).
Do not attempt to open a bug in this category if you're not using the New Architecture as your bug will be closed.
Make sure that your issue:
* Have a **valid reproducer** (See [How to report a bug](https://reactnative.dev/contributing/how-to-report-a-bug)).
* Is tested against the [**latest stable**](https://github.com/facebook/react-native/releases/) of React Native.
🚨 IMPORTANT: Due to the extreme number of bugs we receive, issues **without a reproducer** or for an [**unsupported versions**](https://github.com/reactwg/react-native-releases#which-versions-are-currently-supported) of React Native **will be closed**.
- 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 reproduce the issue.
placeholder: |
1. Install the application with `yarn android`
2. Click on the button on the Home
3. Notice the crash
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.73.0"
validations:
required: true
- type: dropdown
id: platforms
attributes:
label: Affected Platforms
description: Please select which platform you're developing to, and which OS you're using for building.
multiple: true
options:
- Runtime - Android
- Runtime - iOS
- Runtime - Web
- Runtime - Desktop
- Build - MacOS
- Build - Windows
- Build - Linux
- Other (please specify)
validations:
required: true
- type: dropdown
id: areas
attributes:
label: Areas
description: Which areas of the New Architecture are affected by this bug report?
multiple: true
options:
- Fabric - The New Renderer
- TurboModule - The New Native Module System
- JSI - Javascript Interface
- Bridgeless - The New Initialization Flow
- Codegen
- Other (please specify)
validations:
required: true
- type: textarea
id: react-native-info
attributes:
label: Output of `npx @react-native-community/cli info`
description: Run `npx @react-native-community/cli info` in your terminal, copy and paste the results here.
placeholder: |
Paste the output of `npx @react-native-community/cli 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: 22.14.0
...
render: text
validations:
required: true
- type: textarea
id: stacktrace
attributes:
label: Stacktrace or Logs
description: Please provide a stacktrace or a log of your crash or failure
render: text
placeholder: |
Paste your stacktraces and logs here. They might look like:
java.lang.UnsatisfiedLinkError: couldn't find DSO to load: libfabricjni.so caused by: com.facebook.react.fabric.StateWrapperImpl result: 0
at com.facebook.soloader.SoLoader.g(Unknown Source:341)
at com.facebook.soloader.SoLoader.t(Unknown Source:124)
at com.facebook.soloader.SoLoader.s(Unknown Source:2)
at com.facebook.soloader.SoLoader.q(Unknown Source:42)
at com.facebook.soloader.SoLoader.p(Unknown Source:1)
...
validations:
required: true
- type: input
id: reproducer
attributes:
label: MANDATORY Reproducer
description: A link to either a failing RNTesterPlayground.js file, an Expo Snack or a public repository from [this template](https://github.com/react-native-community/reproducer-react-native) that reproduces this bug. Reproducers are **mandatory**, issues without a reproducer will be closed.
placeholder: "https://github.com/<myuser>/<myreproducer>"
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**.
+34
View File
@@ -0,0 +1,34 @@
---
name: "🤔 Questions and Help"
about: The issue tracker is not for questions. Please ask questions on https://stackoverflow.com/questions/tagged/react-native.
title: 'Question: '
labels: 'Type: Question'
---
🚨 The issue tracker is not for questions. 🚨
As it happens, support requests that are created as issues are likely to be closed. We want to make sure you are able to find the help you seek. Please take a look at the following resources.
## Coding Questions
### https://stackoverflow.com/questions/tagged/react-native
If you have a coding question related to React Native, it might be better suited for Stack Overflow. It's a great place to browse through frequent questions about using React Native, as well as ask for help with specific questions.
## Talk to other React Native developers
### https://www.reactiflux.com/
Reactiflux is an active community of React and React Native developers. If you are looking for immediate assistance or have a general question about React Native, the #react-native channel is a good place to start.
If you want to participate in casual discussions about the use of React Native, consider participating in one of the following forums:
- Discord Community: https://discord.gg/0ZcbPKXt5bZjGY5n
- Spectrum Chat: https://spectrum.chat/react-native
- Facebook Group: https://www.facebook.com/groups/react.native.community
If you'd like to discuss topics related to the future of React Native, or would like to propose a new feature or change before sending a pull request, please check out the discussions and proposals repo:
- https://github.com/react-native-community/discussions-and-proposals
> For a full list of community resources, check out React Native's Community page at https://facebook.github.io/react-native/help.
+6 -12
View File
@@ -1,21 +1,15 @@
<!-- Thanks for submitting a pull request! We appreciate you spending the time to work on these changes. Please provide enough information so that others can review your pull request. The three fields below are mandatory. -->
## Summary:
## Summary
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->
## Changelog:
## Changelog
<!-- Help reviewers and the release process by writing your own changelog entry.
<!-- Help reviewers and the release process by writing your own changelog entry. See https://github.com/facebook/react-native/wiki/Changelog for an example. -->
Pick one each for the category and type tags:
[CATEGORY] [TYPE] - Message
[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message
## Test Plan
For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->
## Test Plan:
<!-- Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes the user interface. -->
<!-- Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes UI. -->
-23
View File
@@ -1,23 +0,0 @@
<!-- Template for pre-release GitHub release -->
<!-- TODO Post about this release to https://github.com/reactwg/react-native-releases/discussions) -->
- <!-- TODO List out notable picks for this patch -->
---
To test it, run:
npx react-native init RN__SHORT_VERSION__ --version __VERSION__
---
You can participate in the conversation on the status of this release in the [working group](https://github.com/reactwg/react-native-releases/discussions).
---
To help you upgrade to this version, you can use the [upgrade helper](https://react-native-community.github.io/upgrade-helper/) ⚛️
---
See changes from this release in the [changelog PR](https://github.com/facebook/react-native/labels/%F0%9F%93%9D%20Changelog)
+2 -2
View File
@@ -27,9 +27,9 @@ If you'd like to discuss topics related to the future of React Native, please ch
If you want to participate in casual discussions about the use of React Native, consider participating in one of the following forums:
- [Reactiflux Discord Server](https://www.reactiflux.com)
- [Reactiflux Discord Server](https://www.reactiflux)
- [Spectrum Chat](https://spectrum.chat/react-native)
- [React Native Community Facebook Group](https://www.facebook.com/groups/react.native.community)
> For a full list of community resources, check out [React Native's Community page](https://reactnative.dev/help).
> For a full list of community resources, check out [React Native's Community page](https://facebook.github.io/react-native/help).
-95
View File
@@ -1,95 +0,0 @@
name: build-android
description: This action builds android
inputs:
release-type:
required: true
description: The type of release we are building. It could be nightly, release or dry-run
gradle-cache-encryption-key:
description: "The encryption key needed to store the Gradle Configuration cache"
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
uses: ./.github/actions/yarn-install
- name: Set React Native Version
# We don't want to set the version for stable branches, because this has been
# already set from the 'create release' commits on the release branch.
if: ${{ !endsWith(github.ref_name, '-stable') }}
shell: bash
run: node ./scripts/releases/set-rn-artifacts-version.js --build-type ${{ inputs.release-type }}
- name: Setup gradle
uses: ./.github/actions/setup-gradle
with:
cache-read-only: "false"
cache-encryption-key: ${{ inputs.gradle-cache-encryption-key }}
- name: Restore Android ccache
uses: actions/cache/restore@v4
with:
path: /github/home/.cache/ccache
key: v2-ccache-android-${{ github.job }}-${{ github.ref }}-${{ hashFiles('packages/react-native/ReactAndroid/**/*.cpp', 'packages/react-native/ReactAndroid/**/*.h', 'packages/react-native/ReactCommon/**/*.cpp', 'packages/react-native/ReactAndroid/**/CMakeLists.txt', 'packages/react-native/ReactCommon/**/CMakeLists.txt') }}
restore-keys: |
v2-ccache-android-${{ github.job }}-${{ github.ref }}-
v2-ccache-android-${{ github.job }}-
v2-ccache-android-
- name: Show ccache stats
shell: bash
run: ccache -s -v
- name: Build and publish all the Android Artifacts to /tmp/maven-local
shell: bash
run: |
if [[ "${{ inputs.release-type }}" == "dry-run" ]]; then
# dry-run: we only build ARM64 to save time/resources. For release/nightlies the default is to build all archs.
export ORG_GRADLE_PROJECT_reactNativeArchitectures="arm64-v8a,x86" # x86 is required for E2E testing
TASKS="publishAllToMavenTempLocal build"
elif [[ "${{ inputs.release-type }}" == "nightly" ]]; then
# nightly: we set isSnapshot to true so artifacts are sent to the right repository on Maven Central.
export ORG_GRADLE_PROJECT_isSnapshot="true"
TASKS="publishAllToMavenTempLocal publishAndroidToSonatype build"
else
# release: we want to build all archs (default)
TASKS="publishAllToMavenTempLocal publishAndroidToSonatype build"
fi
./gradlew $TASKS -PenableWarningsAsErrors=true
- name: Save Android ccache
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, '-stable') }}
uses: actions/cache/save@v4
with:
path: /github/home/.cache/ccache
key: v2-ccache-android-${{ github.job }}-${{ github.ref }}-${{ hashFiles('packages/react-native/ReactAndroid/**/*.cpp', 'packages/react-native/ReactAndroid/**/*.h', 'packages/react-native/ReactCommon/**/*.cpp', 'packages/react-native/ReactAndroid/**/CMakeLists.txt', 'packages/react-native/ReactCommon/**/CMakeLists.txt') }}
- name: Show ccache stats
shell: bash
run: ccache -s -v
- name: Upload Maven Artifacts
uses: actions/upload-artifact@v4.3.4
with:
name: maven-local
path: /tmp/maven-local
- name: Upload test results
if: ${{ always() }}
uses: actions/upload-artifact@v4.3.4
with:
name: build-android-results
compression-level: 1
path: |
packages/react-native-gradle-plugin/react-native-gradle-plugin/build/reports
packages/react-native-gradle-plugin/settings-plugin/build/reports
packages/react-native/ReactAndroid/build/reports
- name: Upload RNTester APK - hermes-debug
if: ${{ always() }}
uses: actions/upload-artifact@v4.3.4
with:
name: rntester-debug
path: packages/rn-tester/android/app/build/outputs/apk/debug/
compression-level: 0
- name: Upload RNTester APK - hermes-release
if: ${{ always() }}
uses: actions/upload-artifact@v4.3.4
with:
name: rntester-release
path: packages/rn-tester/android/app/build/outputs/apk/release/
compression-level: 0
@@ -1,87 +0,0 @@
name: build-npm-package
description: This action builds the NPM package and uploads it to Maven
inputs:
release-type:
required: true
description: The type of release we are building. It could be nightly, release or dry-run
gha-npm-token:
required: false
description: The GHA npm token, required only to publish to npm
default: ''
gradle-cache-encryption-key:
description: The encryption key needed to store the Gradle Configuration cache
runs:
using: composite
steps:
- name: Setup git safe folders
shell: bash
run: git config --global --add safe.directory '*'
- name: Download ReactNativeDependencies
uses: actions/download-artifact@v4
with:
pattern: ReactNativeDependencies*
path: ./packages/react-native/ReactAndroid/external-artifacts/artifacts
merge-multiple: true
- name: Download ReactCore artifacts
uses: actions/download-artifact@v4
with:
pattern: ReactCore*
path: ./packages/react-native/ReactAndroid/external-artifacts/artifacts
merge-multiple: true
- name: Print Artifacts Directory
shell: bash
run: ls -lR ./packages/react-native/ReactAndroid/external-artifacts/artifacts/
- name: Setup gradle
uses: ./.github/actions/setup-gradle
with:
cache-encryption-key: ${{ inputs.gradle-cache-encryption-key }}
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Install dependencies
uses: ./.github/actions/yarn-install
- name: Build packages
shell: bash
run: yarn build
- name: Build types
shell: bash
run: yarn build-types --skip-snapshot
# Continue with publish steps
- name: Set npm credentials
if: ${{ inputs.release-type == 'release' ||
inputs.release-type == 'nightly' }}
shell: bash
run: echo "//registry.npmjs.org/:_authToken=${{ inputs.gha-npm-token }}" > ~/.npmrc
- name: Publish NPM
shell: bash
run: |
echo "GRADLE_OPTS = $GRADLE_OPTS"
# We can't have a separate step because each command is executed in a separate shell
# so variables exported in a command are not visible in another.
if [[ "${{ inputs.release-type }}" == "dry-run" ]]; then
export ORG_GRADLE_PROJECT_reactNativeArchitectures="arm64-v8a"
else
export ORG_GRADLE_PROJECT_reactNativeArchitectures="armeabi-v7a,arm64-v8a,x86,x86_64"
fi
node ./scripts/releases-ci/publish-npm.js -t ${{ inputs.release-type }}
- name: Upload npm logs
uses: actions/upload-artifact@v4.3.4
with:
name: npm-logs
path: ~/.npm/_logs
- name: Build release package as a job artifact
if: ${{ inputs.release-type == 'dry-run' }}
shell: bash
run: |
mkdir -p build
FILENAME=$(cd packages/react-native; npm pack | tail -1)
mv "packages/react-native/$FILENAME" build/
echo "$FILENAME" > build/react-native-package-version
- name: Upload release package
uses: actions/upload-artifact@v4.3.4
if: ${{ inputs.release-type == 'dry-run' }}
with:
name: react-native-package
path: build
-46
View File
@@ -1,46 +0,0 @@
name: create_release
description: Creates a new React Native release
inputs:
version:
description: "The version of React Native we want to release. For example 0.75.0-rc.0"
required: true
is-latest-on-npm:
description: "Whether we want to tag this release as latest on NPM"
required: true
default: "false"
dry-run:
description: "Whether the job should be executed in dry-run mode or not"
default: "true"
runs:
using: composite
steps:
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Yarn install
uses: ./.github/actions/yarn-install
- name: Configure Git
shell: bash
run: |
git config --local user.email "bot@reactnative.dev"
git config --local user.name "React Native Bot"
- name: Creating release commit
shell: bash
run: |
node scripts/releases/create-release-commit.js \
--reactNativeVersion "${{ inputs.version }}" \
--tagAsLatestRelease "${{ inputs.is-latest-on-npm }}" \
--dryRun "${{ inputs.dry-run }}"
GIT_PAGER=cat git show HEAD
- name: Update "latest" tag if needed
shell: bash
if: ${{ inputs.is-latest-on-npm == 'true' }}
run: |
git tag -d "latest"
git push origin :latest
git tag -a "latest" -m "latest"
- name: Pushing release commit
shell: bash
if: ${{ inputs.dry-run == 'false' }}
run: |
CURR_BRANCH="$(git branch --show-current)"
git push origin "$CURR_BRANCH" --follow-tags
@@ -1,23 +0,0 @@
name: diff-js-api-breaking-changes
description: Check for breaking changes in the public React Native JS API
runs:
using: composite
steps:
- name: Fetch snapshot from PR head
shell: bash
env:
SCRATCH_DIR: ${{ runner.temp }}/diff-js-api-breaking-changes
run: |
mkdir $SCRATCH_DIR
git fetch --depth=1 origin ${{ github.event.pull_request.head.sha }}
git show ${{ github.event.pull_request.head.sha }}:packages/react-native/ReactNativeApi.d.ts > $SCRATCH_DIR/ReactNativeApi-after.d.ts \
|| echo "" > $SCRATCH_DIR/ReactNativeApi.d.ts
- name: Run breaking change detection
shell: bash
env:
SCRATCH_DIR: ${{ runner.temp }}/diff-js-api-breaking-changes
run: |
node ./scripts/js-api/diff-api-snapshot \
${{ github.workspace }}/packages/react-native/ReactNativeApi.d.ts \
$SCRATCH_DIR/ReactNativeApi-after.d.ts \
> $SCRATCH_DIR/output.json
-55
View File
@@ -1,55 +0,0 @@
name: lint
description: Runs all the linters in the codebase
inputs:
node-version:
description: "The node.js version to use"
required: false
default: "22"
github-token:
description: "The GitHub token used by pull-bot"
required: true
runs:
using: composite
steps:
- name: Setup node.js
uses: ./.github/actions/setup-node
with:
node-version: ${{ inputs.node-version }}
- name: Run yarn install
uses: ./.github/actions/yarn-install
- name: Run linters against modified files (analysis-bot)
shell: bash
run: yarn lint-ci
env:
GITHUB_TOKEN: ${{ inputs.github-token }}
GITHUB_PR_NUMBER: ${{ github.event.number }}
- name: Lint code
shell: bash
run: ./.github/workflow-scripts/exec_swallow_error.sh yarn lint --format junit -o ./reports/junit/eslint/results.xml
- name: Lint file structure
shell: bash
run: ./.github/workflow-scripts/lint_files.sh
- name: Verify not committing repo after running build
shell: bash
run: yarn run build --validate
- name: Run flowcheck
shell: bash
run: yarn flow-check
- name: Run typescript check
shell: bash
run: yarn test-typescript
- name: Check license
shell: bash
run: ./.github/workflow-scripts/check_license.sh
- name: Check formatting
shell: bash
run: yarn run format-check
- name: Lint markdown
shell: bash
run: yarn run lint-markdown
- name: Build types
shell: bash
run: yarn build-types --skip-snapshot
- name: Run typescript check of generated types
shell: bash
run: yarn test-generated-typescript
@@ -1,84 +0,0 @@
name: Maestro E2E Android
description: Runs E2E Tests on Android using Maestro
inputs:
app-path:
required: true
description: The path to the .apk file
app-id:
required: true
description: The id of the app to test
maestro-flow:
required: true
description: the folder that contains the maestro tests
install-java:
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:
- name: Installing Maestro
shell: bash
run: export MAESTRO_VERSION=1.40.0; curl -Ls "https://get.maestro.mobile.dev" | bash
- name: Set up JDK 17
if: ${{ inputs.install-java == 'true' }}
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'zulu'
- name: Enable KVM group perms
shell: bash
run: |
# ubuntu machines have hardware acceleration available and when we try to create an emulator, the script pauses asking for user input
# These lines set the rules to reply automatically to that question and unblock the creation of the emulator.
# source: https://github.com/ReactiveCircus/android-emulator-runner?tab=readme-ov-file#running-hardware-accelerated-emulators-on-linux-runners
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
id: run-tests
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 24
arch: x86
ram-size: '8192M'
heap-size: '4096M'
disk-size: '10G'
cores: '4'
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
- name: Store tests result
uses: actions/upload-artifact@v4.3.4
if: always()
with:
name: e2e_android_${{ steps.normalize-app-id.outputs.app-id }}_report_${{ inputs.flavor }}_NewArch
path: |
report.xml
screen.mp4
- name: Store Logs
if: steps.run-tests.outcome == 'failure'
uses: actions/upload-artifact@v4.3.4
with:
name: maestro-logs-android-${{ steps.normalize-app-id.outputs.app-id }}-${{ inputs.flavor }}-NewArch
path: /tmp/MaestroLogs
-84
View File
@@ -1,84 +0,0 @@
name: Maestro E2E iOS
description: Runs E2E Tests on iOS using Maestro
inputs:
app-path:
required: true
description: The path to the .app file
app-id:
required: true
description: The id of the app to test
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:
- name: Installing Maestro
shell: bash
run: export MAESTRO_VERSION=1.40.0; curl -Ls "https://get.maestro.mobile.dev" | bash
- name: Installing Maestro dependencies
shell: bash
run: |
brew tap facebook/fb
brew install facebook/fb/idb-companion
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'zulu'
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Run yarn install
uses: ./.github/actions/yarn-install
- name: Start Metro in Debug
shell: bash
if: ${{ inputs.flavor == 'Debug' }}
run: |
# build codegen or we will see a redbox
./packages/react-native-codegen/scripts/oss/build.sh
cd ${{ inputs.working-directory }}
yarn start &
sleep 5 # to give metro time to load
- name: Run tests
id: run-tests
shell: bash
run: |
# Avoid exit from the job if one of the command returns an error.
# Maestro can fail in case of flakyness, we have some retry logic.
set +e
node .github/workflow-scripts/maestro-ios.js \
"${{ inputs.app-path }}" \
"${{ inputs.app-id }}" \
"${{ inputs.maestro-flow }}" \
"Hermes" \
"${{ inputs.flavor }}" \
"${{ inputs.working-directory }}"
- name: Store video record
if: always()
uses: actions/upload-artifact@v4.3.4
with:
name: e2e_ios_${{ inputs.app-id }}_report_${{ inputs.flavor }}_NewArch
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
with:
name: maestro-logs-${{ inputs.app-id }}-${{ inputs.flavor }}-NewArch
path: /tmp/MaestroLogs
@@ -1,22 +0,0 @@
name: prepare-ios-tests
description: Prepare iOS Tests
runs:
using: composite
steps:
- name: Run Ruby Tests
shell: bash
run: |
cd packages/react-native/scripts
sh run_ruby_tests.sh
- name: Boot iPhone Simulator
shell: bash
run: source scripts/.tests.env && xcrun simctl boot "$IOS_DEVICE" || true
- name: "Brew: Tap wix/brew"
shell: bash
run: brew tap wix/brew
- name: brew install applesimutils watchman
shell: bash
run: brew install applesimutils watchman
- name: Configure Watchman
shell: bash
run: echo "{}" > .watchmanconfig
@@ -1,83 +0,0 @@
name: Run Fantom Tests
inputs:
release-type:
required: true
description: The type of release we are building. It could be nightly, release or dry-run
gradle-cache-encryption-key:
description: "The encryption key needed to store the Gradle Configuration cache"
runs:
using: composite
steps:
- name: Install dependencies
shell: bash
run: |
sudo apt update
sudo apt install -y git cmake openssl libssl-dev clang
- 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
uses: ./.github/actions/yarn-install
- name: Setup gradle
uses: ./.github/actions/setup-gradle
with:
cache-read-only: "false"
cache-encryption-key: ${{ inputs.gradle-cache-encryption-key }}
- name: Restore Fantom ccache
uses: actions/cache/restore@v4
with:
path: /github/home/.cache/ccache
key: v2-ccache-fantom-${{ github.job }}-${{ github.ref }}-${{ hashFiles(
'packages/react-native/ReactAndroid/**/*.cpp',
'packages/react-native/ReactAndroid/**/*.h',
'packages/react-native/ReactAndroid/**/CMakeLists.txt',
'packages/react-native/ReactCommon/**/*.cpp',
'packages/react-native/ReactCommon/**/*.h',
'packages/react-native/ReactCommon/**/CMakeLists.txt',
'private/react-native-fantom/tester/**/*.cpp',
'private/react-native-fantom/tester/**/*.h',
'private/react-native-fantom/tester/**/CMakeLists.txt'
) }}
restore-keys: |
v2-ccache-fantom-${{ github.job }}-${{ github.ref }}-
v2-ccache-fantom-${{ github.job }}-
v2-ccache-fantom-
- name: Show ccache stats
shell: bash
run: ccache -s -v
- name: Run Fantom Tests
shell: bash
run: yarn fantom
env:
CC: clang
CXX: clang++
- name: Save Fantom ccache
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, '-stable') }}
uses: actions/cache/save@v4
with:
path: /github/home/.cache/ccache
key: v2-ccache-fantom-${{ github.job }}-${{ github.ref }}-${{ hashFiles(
'packages/react-native/ReactAndroid/**/*.cpp',
'packages/react-native/ReactAndroid/**/*.h',
'packages/react-native/ReactAndroid/**/CMakeLists.txt',
'packages/react-native/ReactCommon/**/*.cpp',
'packages/react-native/ReactCommon/**/*.h',
'packages/react-native/ReactCommon/**/CMakeLists.txt',
'private/react-native-fantom/tester/**/*.cpp',
'private/react-native-fantom/tester/**/*.h',
'private/react-native-fantom/tester/**/CMakeLists.txt'
) }}
- name: Show ccache stats
shell: bash
run: ccache -s -v
- name: Upload test results
if: ${{ always() }}
uses: actions/upload-artifact@v4.3.4
with:
name: run-fantom-tests-results
compression-level: 1
path: |
private/react-native-fantom/build/reports
-23
View File
@@ -1,23 +0,0 @@
name: Setup gradle
description: "Set up your GitHub Actions workflow with a specific version of gradle"
inputs:
cache-read-only:
description: "Whether the Gradle Cache should be in read-only mode so this job won't be allowed to write to it"
default: "true"
cache-encryption-key:
description: "The encryption key needed to store the Gradle Configuration cache"
runs:
using: "composite"
steps:
- name: Setup gradle
uses: gradle/actions/setup-gradle@v4
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`).
cache-read-only: ${{ (github.ref != 'refs/heads/main' && !contains(github.ref, '-stable')) || inputs.cache-read-only == 'true' }}
# Similarly, for those jobs we want to start with a clean cache so it doesn't grow without limits (this is the negation of the previous condition).
cache-write-only: ${{ (github.ref == 'refs/heads/main' || contains(github.ref, '-stable')) && inputs.cache-read-only != 'true' }}
add-job-summary-as-pr-comment: on-failure
# Encryption key for the Gradle Configuration Cache.
# See https://docs.gradle.org/8.6/userguide/configuration_cache.html#config_cache:secrets:configuring_encryption_key
cache-encryption-key: ${{ inputs.cache-encryption-key }}
-15
View File
@@ -1,15 +0,0 @@
name: Setup node.js
description: 'Set up your GitHub Actions workflow with a specific version of node.js'
inputs:
node-version:
description: 'The node.js version to use'
required: false
default: '22.14.0'
runs:
using: "composite"
steps:
- name: Setup node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: yarn
-36
View File
@@ -1,36 +0,0 @@
name: Setup xcode
description: 'Set up your GitHub Actions workflow with a specific version of xcode'
inputs:
xcode-version:
description: 'The xcode version to use'
required: false
default: '16.2.0'
platform:
description: 'The platform to use. Valid values are: ios, ios-simulator, macos, mac-catalyst, tvos, tvos-simulator, xros, xros-simulator'
required: false
default: 'macos'
runs:
using: "composite"
steps:
- name: Setup xcode
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd
with:
xcode-version: ${{ inputs.xcode-version }}
- name: Setup Platform ${{ inputs.platform }}
if: ${{ inputs.platform != 'macos' && inputs.platform != 'mac-catalyst' }}
shell: bash
run: |
# https://github.com/actions/runner-images/issues/12541
sudo xcodebuild -runFirstLaunch
sudo xcrun simctl list
# Install platform based on the platform
if [[ "${{ inputs.platform }}" == "xros" || "${{ inputs.platform }}" == "xros-simulator" ]]; then
sudo xcodebuild -downloadPlatform visionOS
elif [[ "${{ inputs.platform }}" == "tvos" || "${{ inputs.platform }}" == "tvos-simulator" ]]; then
sudo xcodebuild -downloadPlatform tvOS
else
sudo xcodebuild -downloadPlatform iOS
fi
sudo xcodebuild -runFirstLaunch
@@ -1,81 +0,0 @@
name: test-ios-helloworld
description: Test iOS Hello World
inputs:
use-frameworks:
description: The dependency building and linking strategy to use. Must be one of "StaticLibraries", "DynamicFrameworks"
default: StaticLibraries
ruby-version:
description: The version of ruby that must be used
default: 2.6.10
flavor:
description: The flavor of the build. Must be one of "Debug", "Release".
default: Debug
runs:
using: composite
steps:
- name: Setup xcode
uses: ./.github/actions/setup-xcode
with:
platform: ios
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Run yarn install
uses: ./.github/actions/yarn-install
- name: Setup ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ inputs.ruby-version }}
- name: Set nightly Hermes versions
shell: bash
run: |
node ./scripts/releases/use-hermes-nightly.js
- name: Run yarn install again, with the correct hermes version
uses: ./.github/actions/yarn-install
- name: Download ReactNativeDependencies
uses: actions/download-artifact@v4
with:
name: ReactNativeDependencies${{ inputs.flavor }}.xcframework.tar.gz
path: /tmp/third-party
- name: Print third-party folder
shell: bash
run: ls -lR /tmp/third-party
- name: Download React Native Prebuilds
uses: actions/download-artifact@v4
with:
name: ReactCore${{ inputs.flavor }}.xcframework.tar.gz
path: /tmp/ReactCore
- name: Print ReactCore folder
shell: bash
run: ls -lR /tmp/ReactCore
- name: Install iOS dependencies - Configuration ${{ inputs.flavor }};
shell: bash
run: |
cd private/helloworld
args=()
if [[ ${{ inputs.use-frameworks }} == "DynamicFrameworks" ]]; then
args+=(--frameworks dynamic)
fi
export RCT_USE_LOCAL_RN_DEP="/tmp/third-party/ReactNativeDependencies${{ inputs.flavor }}.xcframework.tar.gz"
export RCT_TESTONLY_RNCORE_TARBALL_PATH="/tmp/ReactCore/ReactCore${{ inputs.flavor }}.xcframework.tar.gz"
yarn bootstrap ios "${args[@]}" | cat
- name: Run Helloworld tests
shell: bash
run: |
cd private/helloworld
yarn test
- name: Build HelloWorld project
shell: bash
run: |
cd private/helloworld
args=()
if [[ ${{ inputs.flavor }} == "Release" ]]; then
args+=(--prod)
fi
yarn build ios "${args[@]}" | cat
yarn bundle ios "${args[@]}" | cat
@@ -1,121 +0,0 @@
name: test-ios-rntester
description: Test iOS RNTester
inputs:
use-frameworks:
description: The dependency building and linking strategy to use. Must be one of "StaticLibraries", "DynamicFrameworks"
default: StaticLibraries
ruby-version:
description: The version of ruby that must be used
default: 2.6.10
run-unit-tests:
description: whether unit tests should run or not.
default: "false"
flavor:
description: The flavor of the build. Must be one of "Debug", "Release".
default: Debug
run-e2e-tests:
description: Whether we want to run E2E tests or not
required: false
default: false
runs:
using: composite
steps:
- name: Setup xcode
uses: ./.github/actions/setup-xcode
with:
platform: ios
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Run yarn
uses: ./.github/actions/yarn-install
- name: Setup ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ inputs.ruby-version }}
- name: Set nightly Hermes versions
shell: bash
run: |
node ./scripts/releases/use-hermes-nightly.js
- name: Run yarn install again, with the correct hermes version
uses: ./.github/actions/yarn-install
- name: Prepare IOS Tests
if: ${{ inputs.run-unit-tests == 'true' }}
uses: ./.github/actions/prepare-ios-tests
- name: Download ReactNativeDependencies
uses: actions/download-artifact@v4
with:
name: ReactNativeDependencies${{ inputs.flavor }}.xcframework.tar.gz
path: /tmp/third-party/
- name: Print third-party folder
shell: bash
run: ls -lR /tmp/third-party
- name: Download React Native Prebuilds
uses: actions/download-artifact@v4
with:
name: ReactCore${{ inputs.flavor }}.xcframework.tar.gz
path: /tmp/ReactCore
- name: Print ReactCore folder
shell: bash
run: ls -lR /tmp/ReactCore
- name: Install CocoaPods dependencies
shell: bash
run: |
export RCT_USE_LOCAL_RN_DEP="/tmp/third-party/ReactNativeDependencies${{ inputs.flavor }}.xcframework.tar.gz"
export RCT_TESTONLY_RNCORE_TARBALL_PATH="/tmp/ReactCore/ReactCore${{ inputs.flavor }}.xcframework.tar.gz"
if [[ ${{ inputs.use-frameworks }} == "DynamicFrameworks" ]]; then
export USE_FRAMEWORKS=dynamic
fi
cd packages/rn-tester
bundle install
bundle exec pod update hermes-engine --no-repo-update
- name: Build RNTester
shell: bash
run: |
xcodebuild \
-scheme "RNTester" \
-workspace packages/rn-tester/RNTesterPods.xcworkspace \
-configuration "${{ inputs.flavor }}" \
-sdk "iphonesimulator" \
-destination "generic/platform=iOS Simulator" \
-derivedDataPath "/tmp/RNTesterBuild"
echo "Print path to *.app file"
APP_PATH=$(find "/tmp/RNTesterBuild" -type d -name "*.app")
echo "App found at $APP_PATH"
echo "app-path=$APP_PATH" >> $GITHUB_ENV
- name: "Run Tests: iOS Unit and Integration Tests"
if: ${{ inputs.run-unit-tests == 'true' }}
shell: bash
run: yarn test-ios
- name: Zip Derived data folder
if: ${{ inputs.run-unit-tests == 'true' }}
shell: bash
run: |
echo "zipping tests results"
cd /Users/distiller/Library/Developer/Xcode
XCRESULT_PATH=$(find . -name '*.xcresult')
tar -zcvf xcresults.tar.gz $XCRESULT_PATH
- name: Upload artifact
uses: actions/upload-artifact@v4.3.4
if: ${{ inputs.run-unit-tests == 'true' }}
with:
name: xcresults
path: /Users/distiller/Library/Developer/Xcode/xcresults.tar.gz
- name: Upload RNTester App
if: ${{ inputs.use-frameworks == 'StaticLibraries' && inputs.ruby-version == '2.6.10' }} # This is needed to avoid conflicts with the artifacts
uses: actions/upload-artifact@v4.3.4
with:
name: RNTesterApp-NewArch-${{ inputs.flavor }}
path: ${{ env.app-path }}
- name: Store test results
if: ${{ inputs.run-unit-tests == 'true' }}
uses: actions/upload-artifact@v4.3.4
with:
name: test-results
path: ./reports/junit
-26
View File
@@ -1,26 +0,0 @@
name: test-js
description: Runs all the JS tests in the codebase
inputs:
node-version:
description: "The node.js version to use"
required: false
default: "22"
runs:
using: composite
steps:
- name: Setup node.js
uses: ./.github/actions/setup-node
with:
node-version: ${{ inputs.node-version }}
- name: Yarn install
uses: ./.github/actions/yarn-install
- name: Run Tests - JavaScript Tests
shell: bash
run: node ./scripts/run-ci-javascript-tests.js --maxWorkers 2
- name: Upload test results
if: ${{ always() }}
uses: actions/upload-artifact@v4.3.4
with:
name: test-js-results
compression-level: 1
path: ./reports/junit
-20
View File
@@ -1,20 +0,0 @@
name: yarn-install
runs:
using: composite
steps:
- name: Install dependencies
shell: bash
run: |
MAX_ATTEMPTS=2
ATTEMPT=0
WAIT_TIME=20
while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
yarn install --non-interactive --frozen-lockfile && break
echo "yarn install failed. Retrying in $WAIT_TIME seconds..."
sleep $WAIT_TIME
ATTEMPT=$((ATTEMPT + 1))
done
if [ $ATTEMPT -eq $MAX_ATTEMPTS ]; then
echo "All attempts to invoke yarn install failed - Aborting the workflow"
exit 1
fi
+26
View File
@@ -0,0 +1,26 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 90
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- Good first issue
- "Type: Discussion"
- Partner
- Core Team
- "Help Wanted :octocat:"
- "Impact: Regression"
- "Resolution: PR Submitted"
- "Resolution: Backlog"
# Label to use when marking an issue as stale
staleLabel: Stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs.
You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open.
Thank you for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information.
only: issues
@@ -1,374 +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 {
_verifyTagExists,
_extractChangelog,
_computeBody,
_createDraftReleaseOnGitHub,
} = require('../createDraftRelease');
const fs = require('fs');
const silence = () => {};
const mockFetch = jest.fn();
jest.mock('../utils.js', () => ({
log: silence,
}));
global.fetch = mockFetch;
describe('Create Draft Release', () => {
beforeEach(jest.clearAllMocks);
describe('#_verifyTagExists', () => {
it('throws if the tag does not exists', async () => {
const token = 'token';
mockFetch.mockReturnValueOnce(Promise.resolve({status: 404}));
await expect(_verifyTagExists('0.77.1')).rejects.toThrowError(
`Tag v0.77.1 does not exist`,
);
expect(mockFetch).toHaveBeenCalledTimes(1);
expect(mockFetch).toHaveBeenCalledWith(
'https://github.com/facebook/react-native/releases/tag/v0.77.1',
);
});
});
describe('#_extractChangelog', () => {
it(`extracts changelog from CHANGELOG.md`, async () => {
const mockedReturnValue = `# Changelog
## v0.77.2
- [PR #1234](https://github.com/facebook/react-native/pull/1234) - Some change
- [PR #5678](https://github.com/facebook/react-native/pull/5678) - Some other change
## v0.77.1
### Breaking Changes
- [PR #9012](https://github.com/facebook/react-native/pull/9012) - Some other change
#### Android
- [PR #3456](https://github.com/facebook/react-native/pull/3456) - Some other change
- [PR #3457](https://github.com/facebook/react-native/pull/3457) - Some other change
#### iOS
- [PR #3436](https://github.com/facebook/react-native/pull/3436) - Some other change
- [PR #3437](https://github.com/facebook/react-native/pull/3437) - Some other change
### Fixed
- [PR #9012](https://github.com/facebook/react-native/pull/9012) - Some other change
#### Android
- [PR #3456](https://github.com/facebook/react-native/pull/3456) - Some other change
#### iOS
- [PR #3437](https://github.com/facebook/react-native/pull/3437) - Some other change
## v0.77.0
- [PR #3456](https://github.com/facebook/react-native/pull/3456) - Some other change
## v0.76.0
- [PR #7890](https://github.com/facebook/react-native/pull/7890) - Some other change`;
jest.spyOn(fs, 'readFileSync').mockImplementationOnce(func => {
return mockedReturnValue;
});
const changelog = _extractChangelog('0.77.1');
expect(changelog).toEqual(`## v0.77.1
### Breaking Changes
- [PR #9012](https://github.com/facebook/react-native/pull/9012) - Some other change
#### Android
- [PR #3456](https://github.com/facebook/react-native/pull/3456) - Some other change
- [PR #3457](https://github.com/facebook/react-native/pull/3457) - Some other change
#### iOS
- [PR #3436](https://github.com/facebook/react-native/pull/3436) - Some other change
- [PR #3437](https://github.com/facebook/react-native/pull/3437) - Some other change
### Fixed
- [PR #9012](https://github.com/facebook/react-native/pull/9012) - Some other change
#### Android
- [PR #3456](https://github.com/facebook/react-native/pull/3456) - Some other change
#### iOS
- [PR #3437](https://github.com/facebook/react-native/pull/3437) - Some other change`);
});
it('does not extract changelog for rc.0', async () => {
const changelog = _extractChangelog('0.77.0-rc.0');
expect(changelog).toEqual('');
});
it('does not extract changelog for 0.X.0', async () => {
const changelog = _extractChangelog('0.77.0');
expect(changelog).toEqual('');
});
});
describe('#_computeBody', () => {
it('computes body for release when no hermes versions are passed', async () => {
const version = '0.77.1';
const changelog = `## v${version}
### Breaking Changes
- [PR #9012](https://github.com/facebook/react-native/pull/9012) - Some other change
#### Android
- [PR #3456](https://github.com/facebook/react-native/pull/3456) - Some other change
- [PR #3457](https://github.com/facebook/react-native/pull/3457) - Some other change
#### iOS
- [PR #3436](https://github.com/facebook/react-native/pull/3436) - Some other change
- [PR #3437](https://github.com/facebook/react-native/pull/3437) - Some other change`;
const body = _computeBody(changelog, version);
expect(body).toEqual(`${changelog}
---
Hermes dSYMS:
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${version}/hermes-ios-${version}-hermes-framework-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${version}/hermes-ios-${version}-hermes-framework-dSYM-release.tar.gz)
Hermes V1 dSYMS:
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${version}/hermes-ios-${version}-hermes-framework-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${version}/hermes-ios-${version}-hermes-framework-dSYM-release.tar.gz)
ReactNativeDependencies dSYMs:
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-release.tar.gz)
ReactNative Core dSYMs:
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-release.tar.gz)
---
You can file issues or pick requests against this release [here](https://github.com/reactwg/react-native-releases/issues/new/choose).
---
To help you upgrade to this version, you can use the [Upgrade Helper](https://react-native-community.github.io/upgrade-helper/) ⚛️.
---
View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/react-native/blob/main/CHANGELOG.md).`);
});
it('computes body for release when hermes versions are passed', async () => {
const version = '0.77.1';
const hermesVersion = '0.15.0';
const hermesV1Version = '250829098.0.2';
const changelog = `## v${version}
### Breaking Changes
- [PR #9012](https://github.com/facebook/react-native/pull/9012) - Some other change
#### Android
- [PR #3456](https://github.com/facebook/react-native/pull/3456) - Some other change
- [PR #3457](https://github.com/facebook/react-native/pull/3457) - Some other change
#### iOS
- [PR #3436](https://github.com/facebook/react-native/pull/3436) - Some other change
- [PR #3437](https://github.com/facebook/react-native/pull/3437) - Some other change`;
const body = _computeBody(
changelog,
version,
hermesVersion,
hermesV1Version,
);
expect(body).toEqual(`${changelog}
---
Hermes dSYMS:
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesVersion}/hermes-ios-${hermesVersion}-hermes-framework-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesVersion}/hermes-ios-${hermesVersion}-hermes-framework-dSYM-release.tar.gz)
Hermes V1 dSYMS:
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesV1Version}/hermes-ios-${hermesV1Version}-hermes-framework-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesV1Version}/hermes-ios-${hermesV1Version}-hermes-framework-dSYM-release.tar.gz)
ReactNativeDependencies dSYMs:
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-release.tar.gz)
ReactNative Core dSYMs:
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-release.tar.gz)
---
You can file issues or pick requests against this release [here](https://github.com/reactwg/react-native-releases/issues/new/choose).
---
To help you upgrade to this version, you can use the [Upgrade Helper](https://react-native-community.github.io/upgrade-helper/) ⚛️.
---
View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/react-native/blob/main/CHANGELOG.md).`);
});
});
describe('#_createDraftReleaseOnGitHub', () => {
it('creates a draft release on GitHub', async () => {
const version = '0.77.1';
const url = 'https://api.github.com/repos/facebook/react-native/releases';
const token = 'token';
const headers = {
Accept: 'Accept: application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
Authorization: `Bearer ${token}`,
};
const body = `Draft release body`;
const latest = true;
const fetchBody = JSON.stringify({
tag_name: `v${version}`,
name: `${version}`,
body: body,
draft: true,
prerelease: false,
make_latest: `${latest}`,
});
mockFetch.mockReturnValueOnce(
Promise.resolve({
status: 201,
json: () =>
Promise.resolve({
id: 1,
html_url:
'https://github.com/facebook/react-native/releases/tag/v0.77.1',
}),
}),
);
const response = await _createDraftReleaseOnGitHub(
version,
body,
latest,
token,
);
expect(mockFetch).toHaveBeenCalledTimes(1);
expect(mockFetch).toHaveBeenCalledWith(
`https://api.github.com/repos/facebook/react-native/releases`,
{
method: 'POST',
headers: headers,
body: fetchBody,
},
);
expect(response).toEqual({
id: 1,
html_url:
'https://github.com/facebook/react-native/releases/tag/v0.77.1',
});
});
it('creates a draft release for prerelease on GitHub', async () => {
const version = '0.77.0-rc.2';
const url = 'https://api.github.com/repos/facebook/react-native/releases';
const token = 'token';
const headers = {
Accept: 'Accept: application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
Authorization: `Bearer ${token}`,
};
const body = `Draft release body`;
const latest = true;
const fetchBody = JSON.stringify({
tag_name: `v${version}`,
name: `${version}`,
body: body,
draft: true,
prerelease: true,
make_latest: `${latest}`,
});
mockFetch.mockReturnValueOnce(
Promise.resolve({
status: 201,
json: () =>
Promise.resolve({
id: 1,
html_url:
'https://github.com/facebook/react-native/releases/tag/v0.77.1',
}),
}),
);
const response = await _createDraftReleaseOnGitHub(
version,
body,
latest,
token,
);
expect(mockFetch).toHaveBeenCalledTimes(1);
expect(mockFetch).toHaveBeenCalledWith(
`https://api.github.com/repos/facebook/react-native/releases`,
{
method: 'POST',
headers: headers,
body: fetchBody,
},
);
expect(response).toEqual({
id: 1,
html_url:
'https://github.com/facebook/react-native/releases/tag/v0.77.1',
});
});
it('throws if the post failes', async () => {
const version = '0.77.0-rc.2';
const url = 'https://api.github.com/repos/facebook/react-native/releases';
const token = 'token';
const headers = {
Accept: 'Accept: application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
Authorization: `Bearer ${token}`,
};
const body = `Draft release body`;
const latest = true;
const fetchBody = JSON.stringify({
tag_name: `v${version}`,
name: `${version}`,
body: body,
draft: true,
prerelease: true,
make_latest: `${latest}`,
});
mockFetch.mockReturnValueOnce(
Promise.resolve({
status: 401,
}),
);
await expect(
_createDraftReleaseOnGitHub(version, body, latest, token),
).rejects.toThrowError();
expect(mockFetch).toHaveBeenCalledTimes(1);
expect(mockFetch).toHaveBeenCalledWith(
`https://api.github.com/repos/facebook/react-native/releases`,
{
method: 'POST',
headers: headers,
body: fetchBody,
},
);
});
});
});
@@ -1,83 +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 {extractIssueOncalls} = require('../extractIssueOncalls');
const userMap = {
'@g': '1785',
'@c': '1781',
'@s': '1272',
'@d': '1332',
'@m': '9555',
'@p': '6097',
'@f': '7565',
};
const schedule = {
'2025-04-01': ['@m', '@f'],
'2025-04-08': ['@g', '@d'],
};
describe('extractIssueOncalls', () => {
beforeEach(() => {
jest.clearAllMocks();
jest.useFakeTimers('modern');
});
afterEach(() => {
jest.useRealTimers();
});
it('extracts m and f on 6 of April', () => {
jest.setSystemTime(new Date(2025, 3, 6));
const oncalls = extractIssueOncalls(schedule, userMap);
expect(oncalls).toEqual([userMap['@m'], userMap['@f']]);
});
it('extracts m and f on 7 of April', () => {
jest.setSystemTime(new Date(2025, 3, 7));
const oncalls = extractIssueOncalls(schedule, userMap);
expect(oncalls).toEqual([userMap['@m'], userMap['@f']]);
});
it('extracts g and d on 8 of April', () => {
jest.setSystemTime(new Date(2025, 3, 8));
const oncalls = extractIssueOncalls(schedule, userMap);
expect(oncalls).toEqual([userMap['@g'], userMap['@d']]);
});
it('extracts g and d on 9 of April', () => {
jest.setSystemTime(new Date(2025, 3, 9));
const oncalls = extractIssueOncalls(schedule, userMap);
expect(oncalls).toEqual([userMap['@g'], userMap['@d']]);
});
it('extracts g and d on 10 of April', () => {
jest.setSystemTime(new Date(2025, 3, 10));
const oncalls = extractIssueOncalls(schedule, userMap);
expect(oncalls).toEqual([userMap['@g'], userMap['@d']]);
});
it('extracts g and d on 11 of April', () => {
jest.setSystemTime(new Date(2025, 3, 11));
const oncalls = extractIssueOncalls(schedule, userMap);
expect(oncalls).toEqual([userMap['@g'], userMap['@d']]);
});
it('extracts g and d on 12 of April', () => {
jest.setSystemTime(new Date(2025, 3, 12));
const oncalls = extractIssueOncalls(schedule, userMap);
expect(oncalls).toEqual([userMap['@g'], userMap['@d']]);
});
it('extracts g and d on 13 of April', () => {
jest.setSystemTime(new Date(2025, 3, 13));
const oncalls = extractIssueOncalls(schedule, userMap);
expect(oncalls).toEqual([userMap['@g'], userMap['@d']]);
});
});
@@ -1,251 +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 {
generateChangelog,
_computePreviousVersionFrom,
_generateChangelog,
_pushCommit,
_createPR,
} = require('../generateChangelog');
const silence = () => {};
const mockGetNpmPackageInfo = jest.fn();
const mockExecSync = jest.fn();
const mockRun = jest.fn();
const mockFetch = jest.fn();
const mockExit = jest.fn();
jest.mock('../utils.js', () => ({
log: silence,
run: mockRun,
getNpmPackageInfo: mockGetNpmPackageInfo,
}));
process.exit = mockExit;
global.fetch = mockFetch;
describe('Generate Changelog', () => {
beforeEach(jest.clearAllMocks);
describe('_computePreviousVersionFrom', () => {
it('returns rc.0 when rc is 1', async () => {
const currentVersion = '0.78.0-rc.1';
const expectedVersion = '0.78.0-rc.0';
const receivedVersion = await _computePreviousVersionFrom(currentVersion);
expect(receivedVersion).toEqual(expectedVersion);
});
it('returns previous rc version when rc is > 1', async () => {
const currentVersion = '0.78.0-rc.5';
const expectedVersion = '0.78.0-rc.4';
const receivedVersion = await _computePreviousVersionFrom(currentVersion);
expect(receivedVersion).toEqual(expectedVersion);
});
it('returns previous patch version when rc is 0', async () => {
const currentVersion = '0.78.0-rc.0';
const expectedVersion = '0.77.1';
mockGetNpmPackageInfo.mockReturnValueOnce(
Promise.resolve({version: '0.77.1'}),
);
const receivedVersion = await _computePreviousVersionFrom(currentVersion);
expect(receivedVersion).toEqual(expectedVersion);
});
it('returns patch 0 when patch is 1', async () => {
const currentVersion = '0.78.1';
const expectedVersion = '0.78.0';
const receivedVersion = await _computePreviousVersionFrom(currentVersion);
expect(receivedVersion).toEqual(expectedVersion);
});
it('returns previous patch when patch is > 1', async () => {
const currentVersion = '0.78.5';
const expectedVersion = '0.78.4';
const receivedVersion = await _computePreviousVersionFrom(currentVersion);
expect(receivedVersion).toEqual(expectedVersion);
});
it('returns null when patch is 0', async () => {
const currentVersion = '0.78.0';
const receivedVersion = await _computePreviousVersionFrom(currentVersion);
expect(receivedVersion).toBeNull();
});
it("throws an error when the version can't be parsed", async () => {
const currentVersion = '0.78.0-rc0';
await expect(
_computePreviousVersionFrom(currentVersion),
).rejects.toThrow();
});
});
describe('_generateChangelog', () => {
it('calls git in the right order', async () => {
const currentVersion = '0.79.0-rc5';
const previousVersion = '0.79.0-rc4';
const token = 'token';
expectedCommandArgs = [
'@rnx-kit/rn-changelog-generator',
'--base',
`v${previousVersion}`,
'--compare',
`v${currentVersion}`,
'--repo',
'.',
'--changelog',
'./CHANGELOG.md',
'--token',
`${token}`,
];
_generateChangelog(previousVersion, currentVersion, token);
expect(mockRun).toHaveBeenCalledTimes(4);
expect(mockRun).toHaveBeenNthCalledWith(1, 'git checkout main');
expect(mockRun).toHaveBeenNthCalledWith(2, 'git fetch');
expect(mockRun).toHaveBeenNthCalledWith(3, 'git pull origin main');
expect(mockRun).toHaveBeenNthCalledWith(
4,
`npx ${expectedCommandArgs.join(' ')}`,
);
});
});
describe('_pushCommit', () => {
it('calls git in the right order', async () => {
const currentVersion = '0.79.0-rc5';
_pushCommit(currentVersion);
expect(mockRun).toHaveBeenCalledTimes(4);
expect(mockRun).toHaveBeenNthCalledWith(
1,
`git checkout -b changelog/v${currentVersion}`,
);
expect(mockRun).toHaveBeenNthCalledWith(2, 'git add CHANGELOG.md');
expect(mockRun).toHaveBeenNthCalledWith(
3,
`git commit -m "[RN][Changelog] Add changelog for v${currentVersion}"`,
);
expect(mockRun).toHaveBeenNthCalledWith(
4,
`git push origin changelog/v${currentVersion}`,
);
});
});
describe('_createPR', () => {
it('throws error when status is not 201', async () => {
const currentVersion = '0.79.0-rc5';
const token = 'token';
mockFetch.mockReturnValueOnce(Promise.resolve({status: 401}));
const headers = {
Accept: 'Accept: application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
Authorization: `Bearer ${token}`,
};
const content = `
## Summary
Add Changelog for ${currentVersion}
## Changelog:
[Internal] - Add Changelog for ${currentVersion}
## Test Plan:
N/A`;
const body = {
title: `[RN][Changelog] Add changelog for v${currentVersion}`,
head: `changelog/v${currentVersion}`,
base: 'main',
body: content,
};
await expect(_createPR(currentVersion, token)).rejects.toThrow();
expect(mockFetch).toHaveBeenCalledTimes(1);
expect(mockFetch).toHaveBeenCalledWith(
'https://api.github.com/repos/facebook/react-native/pulls',
{
method: 'POST',
headers: headers,
body: JSON.stringify(body),
},
);
});
it('Returns the pr url', async () => {
const currentVersion = '0.79.0-rc5';
const token = 'token';
const expectedPrURL =
'https://github.com/facebook/react-native/pulls/1234';
const returnedObject = {
status: 201,
json: () => Promise.resolve({html_url: expectedPrURL}),
};
mockFetch.mockReturnValueOnce(Promise.resolve(returnedObject));
const headers = {
Accept: 'Accept: application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
Authorization: `Bearer ${token}`,
};
const content = `
## Summary
Add Changelog for ${currentVersion}
## Changelog:
[Internal] - Add Changelog for ${currentVersion}
## Test Plan:
N/A`;
const body = {
title: `[RN][Changelog] Add changelog for v${currentVersion}`,
head: `changelog/v${currentVersion}`,
base: 'main',
body: content,
};
const receivedPrURL = await _createPR(currentVersion, token);
expect(mockFetch).toHaveBeenCalledTimes(1);
expect(mockFetch).toHaveBeenCalledWith(
'https://api.github.com/repos/facebook/react-native/pulls',
{
method: 'POST',
headers: headers,
body: JSON.stringify(body),
},
);
expect(receivedPrURL).toEqual(expectedPrURL);
});
});
});
@@ -1,129 +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 mockVerifyPublishedPackage = jest.fn();
const silence = () => {};
jest.mock('../utils.js', () => ({
log: silence,
run: mockRun,
sleep: mockSleep,
getNpmPackageInfo: mockGetNpmPackageInfo,
}));
jest.mock('../verifyPublishedPackage.js', () => ({
verifyPublishedPackage: mockVerifyPublishedPackage,
}));
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;
const version = '0.77.0';
await verifyPublishedTemplate(version, NOT_LATEST);
expect(mockVerifyPublishedPackage).toHaveBeenCalledWith(
'@react-native-community/template',
version,
null,
18,
);
});
it('waits on npm updating version and latest tag', async () => {
const IS_LATEST = true;
const version = '0.77.0';
await verifyPublishedTemplate(version, IS_LATEST);
expect(mockVerifyPublishedPackage).toHaveBeenCalledWith(
'@react-native-community/template',
version,
'latest',
18,
);
});
describe('retries', () => {
it('will timeout if npm does not update package version after a set number of retries', async () => {
const RETRIES = 2;
(await verifyPublishedTemplate('0.77.0', true, RETRIES),
expect(mockVerifyPublishedPackage).toHaveBeenCalledWith(
'@react-native-community/template',
'0.77.0',
'latest',
2,
));
});
});
});
@@ -1,87 +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 {verifyArtifactsAreOnMaven} = require('../verifyArtifactsAreOnMaven');
const mockSleep = jest.fn();
const silence = () => {};
const mockFetch = jest.fn();
const mockExit = jest.fn();
jest.mock('../utils.js', () => ({
log: silence,
sleep: mockSleep,
}));
process.exit = mockExit;
global.fetch = mockFetch;
describe('#verifyArtifactsAreOnMaven', () => {
beforeEach(jest.clearAllMocks);
it('waits for the packages to be published on maven when version has no v', async () => {
mockSleep.mockReturnValueOnce(Promise.resolve()).mockImplementation(() => {
throw new Error('Should not be called again!');
});
mockFetch
.mockReturnValueOnce(Promise.resolve({status: 404}))
.mockReturnValueOnce(Promise.resolve({status: 200}));
const version = '0.78.1';
await verifyArtifactsAreOnMaven(version);
expect(mockSleep).toHaveBeenCalledTimes(1);
expect(mockFetch).toHaveBeenCalledWith(
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1/react-native-artifacts-0.78.1.pom',
);
});
it('waits for the packages to be published on maven, when version starts with v', async () => {
mockSleep.mockReturnValueOnce(Promise.resolve()).mockImplementation(() => {
throw new Error('Should not be called again!');
});
mockFetch
.mockReturnValueOnce(Promise.resolve({status: 404}))
.mockReturnValueOnce(Promise.resolve({status: 200}));
const version = 'v0.78.1';
await verifyArtifactsAreOnMaven(version);
expect(mockSleep).toHaveBeenCalledTimes(1);
expect(mockFetch).toHaveBeenCalledWith(
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1/react-native-artifacts-0.78.1.pom',
);
});
it('passes immediately if packages are already on Maven', async () => {
mockFetch.mockReturnValueOnce(Promise.resolve({status: 200}));
const version = '0.78.1';
await verifyArtifactsAreOnMaven(version);
expect(mockSleep).toHaveBeenCalledTimes(0);
expect(mockFetch).toHaveBeenCalledWith(
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1/react-native-artifacts-0.78.1.pom',
);
});
it('tries 90 times and then exits', async () => {
mockSleep.mockReturnValue(Promise.resolve());
mockFetch.mockReturnValue(Promise.resolve({status: 404}));
const version = '0.78.1';
await verifyArtifactsAreOnMaven(version);
expect(mockSleep).toHaveBeenCalledTimes(90);
expect(mockExit).toHaveBeenCalledWith(1);
expect(mockFetch).toHaveBeenCalledWith(
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1/react-native-artifacts-0.78.1.pom',
);
});
});
@@ -1,135 +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 {verifyPublishedPackage} = require('../verifyPublishedPackage');
const mockRun = jest.fn();
const mockSleep = jest.fn();
const mockGetNpmPackageInfo = jest.fn();
const silence = () => {};
const REACT_NATIVE_PACKAGE = 'react-native';
jest.mock('../utils.js', () => ({
log: silence,
run: mockRun,
sleep: mockSleep,
getNpmPackageInfo: mockGetNpmPackageInfo,
}));
describe('#verifyPublishedPackage', () => {
beforeEach(jest.clearAllMocks);
it("waits on npm updating for version and not 'latest'", async () => {
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.78.0';
await verifyPublishedPackage(REACT_NATIVE_PACKAGE, version, null);
expect(mockGetNpmPackageInfo).toHaveBeenLastCalledWith(
REACT_NATIVE_PACKAGE,
version,
);
});
it('waits on npm updating version and latest tag', async () => {
const version = '0.78.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 verifyPublishedPackage(REACT_NATIVE_PACKAGE, version, 'latest');
expect(mockGetNpmPackageInfo).toHaveBeenCalledWith(
REACT_NATIVE_PACKAGE,
'latest',
);
});
it('waits on npm updating version and next tag', async () => {
const version = '0.78.0-rc.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 verifyPublishedPackage(REACT_NATIVE_PACKAGE, version, 'next');
expect(mockGetNpmPackageInfo).toHaveBeenCalledWith(
REACT_NATIVE_PACKAGE,
'next',
);
});
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(() =>
verifyPublishedPackage(
REACT_NATIVE_PACKAGE,
'0.77.0',
'latest',
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 verifyPublishedPackage(
REACT_NATIVE_PACKAGE,
'0.77.0',
'latest',
RETRIES,
);
}).rejects.toThrowError('process.exit(1) called!');
expect(mockGetNpmPackageInfo).toHaveBeenCalledTimes(RETRIES);
});
});
});
@@ -1,109 +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 {verifyReleaseOnNpm} = require('../verifyReleaseOnNpm');
const mockVerifyPublishedPackage = jest.fn();
const silence = () => {};
jest.mock('../utils.js', () => ({
log: silence,
sleep: silence,
}));
jest.mock('../verifyPublishedPackage.js', () => ({
verifyPublishedPackage: mockVerifyPublishedPackage,
}));
describe('#verifyReleaseOnNPM', () => {
beforeEach(jest.clearAllMocks);
it("waits on npm updating for version and not 'latest'", async () => {
const NOT_LATEST = false;
const version = '0.78.0';
await verifyReleaseOnNpm(version, NOT_LATEST);
expect(mockVerifyPublishedPackage).toHaveBeenLastCalledWith(
'react-native',
version,
null,
18,
);
});
it('waits on npm updating version and latest tag', async () => {
const IS_LATEST = true;
const version = '0.78.0';
await verifyReleaseOnNpm(version, IS_LATEST);
expect(mockVerifyPublishedPackage).toHaveBeenCalledWith(
'react-native',
version,
'latest',
18,
);
});
it('waits on npm updating version, not latest and next tag', async () => {
const IS_LATEST = false;
const version = '0.78.0-rc.0';
await verifyReleaseOnNpm(version, IS_LATEST);
expect(mockVerifyPublishedPackage).toHaveBeenCalledWith(
'react-native',
version,
'next',
18,
);
});
it('waits on npm updating version, latest and next tag', async () => {
const IS_LATEST = true;
const version = '0.78.0-rc.0';
await verifyReleaseOnNpm(version, IS_LATEST);
expect(mockVerifyPublishedPackage).toHaveBeenCalledWith(
'react-native',
version,
'next',
18,
);
});
describe('timeouts', () => {
it('will timeout if npm does not update package version after a set number of retries', async () => {
const RETRIES = 2;
(await verifyReleaseOnNpm('0.77.0', true, RETRIES),
expect(mockVerifyPublishedPackage).toHaveBeenCalledWith(
'react-native',
'0.77.0',
'latest',
2,
));
});
it('will timeout if npm does not update latest tag after a set number of retries', async () => {
const RETRIES = 7;
const IS_LATEST = true;
await verifyReleaseOnNpm('0.77.0', IS_LATEST, RETRIES);
expect(mockVerifyPublishedPackage).toHaveBeenCalledWith(
'react-native',
'0.77.0',
'latest',
7,
);
});
});
});
-130
View File
@@ -1,130 +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
*/
module.exports = async (github, context, labelWithContext) => {
const closeIssue = async () => {
await github.rest.issues.update({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
state: 'closed',
});
};
const addComment = async comment => {
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment,
});
};
const requestAuthorFeedback = async () => {
// Remove the triage label if it exists (ignore the 404 if not; it's not expected to always be there)
try {
await github.rest.issues.removeLabel({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
name: 'Needs: Triage :mag:',
});
} catch {}
await github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ['Needs: Author Feedback'],
});
};
switch (labelWithContext.label) {
case 'Type: Invalid':
await addComment(
`> [!CAUTION]\n` +
`> **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.`,
);
await closeIssue();
return;
case 'Type: Question':
await addComment(
`> [!NOTE]\n` +
`> **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]\n` +
`> **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 'Type: Docs':
await addComment(
`> [!NOTE]\n` +
`> **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.`,
);
await closeIssue();
return;
case 'Type: Expo':
await addComment(
`> [!NOTE]\n` +
`> **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.`,
);
await closeIssue();
return;
case 'Needs: Issue Template':
await addComment(
`> [!WARNING]\n` +
`> **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.`,
);
await requestAuthorFeedback();
return;
case 'Needs: Environment Info':
await addComment(
`> [!WARNING]\n` +
`> **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.`,
);
await requestAuthorFeedback();
return;
case 'Needs: Version Info':
await addComment(
`> [!WARNING]\n` +
`> **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.`,
);
await requestAuthorFeedback();
return;
case 'Needs: Repro':
await addComment(
`> [!WARNING]\n` +
`> **Missing reproducer**: We could not detect a reproducible example in your issue report. Reproducers are **mandatory** and we can accept only one of those as a valid reproducer: <br/><ul><li>For majority of bugs: 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><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></ul><br/>You can read more about about it on our website: [How to report a bug](https://reactnative.dev/contributing/how-to-report-a-bug).`,
);
await requestAuthorFeedback();
return;
case 'Type: Unsupported Version':
await addComment(
`> [!WARNING]\n` +
`> **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.`,
);
await requestAuthorFeedback();
return;
case 'Type: Too Old Version':
await addComment(
`> [!CAUTION]\n` +
`> **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.`,
);
await closeIssue();
return;
default:
// No action needed
return;
}
};
@@ -1,153 +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
*/
module.exports = async (github, context) => {
const issue = context.payload.issue;
const title = issue?.title?.toLowerCase();
if (!title) return;
const addLabels = async labelsToAdd => {
await github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: labelsToAdd,
});
};
const labelsToAdd = [];
for (const component of components) {
if (title.includes(component.toLowerCase())) {
labelsToAdd.push(`Component: ${component}`);
}
}
for (const api of apis) {
if (title.includes(api.toLowerCase())) {
labelsToAdd.push(`API: ${api}`);
}
}
for (const topic of Object.keys(topics)) {
if (title.includes(topic.toLowerCase())) {
labelsToAdd.push(topics[topic]);
}
}
if (labelsToAdd.length > 0) {
await addLabels(labelsToAdd);
}
};
const labelAndroid = 'Platform: Android';
const labelIos = 'Platform: iOS';
const labelTvos = 'Platform: tvOS';
const labelNetworking = '🌐Networking';
const labelBundler = '📦Bundler';
const labelCli = '💻CLI';
const labelRegression = 'Impact: Regression';
const components = [
'ActivityIndicator',
'Button',
'DatePickerIOS',
'DrawerLayoutAndroid',
'FlatList',
'Image',
'ImageBackground',
'InputAccessoryView',
'KeyboardAvoidingView',
'ListView',
'MaskedViewIOS',
'Modal',
'NavigatorIOS',
'Picker',
'PickerIOS',
'ProgressBarAndroid',
'ProgressViewIOS',
'RefreshControl',
'SafeAreaView',
'ScrollView',
'SectionList',
'SegmentedControlIOS',
'Slider',
'SnapshotViewIOS',
'StatusBar',
'Switch',
'TabBarIOS',
'TextInput',
'ToolbarAndroid',
'TouchableHighlight',
'TouchableNativeFeedback',
'TouchableOpacity',
'TouchableWithoutFeedback',
'ViewPagerAndroid',
'VirtualizedList',
'WebView',
];
const apis = [
'AccessibilityInfo',
'ActionSheetIOS',
'Alert',
'AlertIOS',
'Animated',
'AppRegistry',
'AppState',
'AsyncStorage',
'BackAndroid',
'BackHandler',
'CameraRoll',
'Clipboard',
'DatePickerAndroid',
'Dimensions',
'Easing',
'Geolocation',
'ImageEditor',
'ImagePickerIOS',
'ImageStore',
'InteractionManager',
'Keyboard',
'LayoutAnimation',
'Linking',
'ListViewDataSource',
'NetInfo',
'PanResponder',
'PermissionsAndroid',
'PixelRatio',
'PushNotificationIOS',
'Settings',
'Share',
'StatusBarIOS',
'StyleSheet',
'Systrace',
'TimePickerAndroid',
'ToastAndroid',
'Transforms',
'Vibration',
'VibrationIOS',
];
const topics = {
Flow: 'Flow',
'Flow-Strict': 'Flow',
xhr: labelNetworking,
netinfo: labelNetworking,
fetch: labelNetworking,
okhttp: labelNetworking,
http: labelNetworking,
bundle: labelBundler,
bundling: labelBundler,
packager: labelBundler,
'unable to resolve module': labelBundler,
android: labelAndroid,
ios: labelIos,
tvos: labelTvos,
'react-native-cli': labelCli,
'react-native upgrade': labelCli,
'react-native link': labelCli,
regression: labelRegression,
};
-24
View File
@@ -1,24 +0,0 @@
#!/bin/bash
# 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.
export GITHUB_OWNER=-facebook
export GITHUB_REPO=-react-native
{
echo eslint
npm run lint --silent -- --format=json
echo flow
npm run flow-check --silent --json
} | node private/react-native-bots/code-analysis-bot.js
STATUS=$?
if [ $STATUS == 0 ]; then
echo "Code analyzed successfully."
else
echo "Code analysis failed, error status $STATUS."
fi
exit $STATUS
@@ -1,25 +0,0 @@
#!/bin/bash
# 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.
GITHUB_OWNER=-facebook
GITHUB_REPO=-react-native
export GITHUB_OWNER
export GITHUB_REPO
if [ -x "$(command -v shellcheck)" ]; then
IFS=$'\n'
find . \
-type f \
-not -path "*node_modules*" \
-not -path "*third-party*" \
-name '*.sh' \
-exec sh -c 'shellcheck "$1"' -- {} \;
else
echo 'shellcheck is not installed. See https://github.com/facebook/react-native/wiki/Development-Dependencies#shellcheck for instructions.'
exit 1
fi
@@ -1,105 +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 NEEDS_REPRO_LABEL = 'Needs: Repro';
const NEEDS_AUTHOR_FEEDBACK_LABEL = 'Needs: Author Feedback';
const SKIP_ISSUES_OLDER_THAN = '2023-07-01T00:00:00Z';
module.exports = async (github, context) => {
const issueData = {
issue_number: context.payload.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
};
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;
if (isDateBefore(issueDate, SKIP_ISSUES_OLDER_THAN)) {
return;
}
const maintainerChangedLabel = await hasMaintainerChangedLabel(
github,
issueData,
author,
);
if (maintainerChangedLabel) {
return;
}
const entities = [issue.data, ...comments.data];
// Look for Snack or a GH repo associated with the user that added an issue or comment
const hasValidReproducer = entities.some(entity => {
const hasPullRequestRepoLink = containsPattern(
entity.body,
`https?:\/\/github\.com\/facebook\/react-native\/pull\/\d+\/?`,
);
const hasExpoSnackLink = containsPattern(
entity.body,
`https?:\\/\\/snack\\.expo\\.dev\\/[^\\s)\\]]+`,
);
const hasGithubRepoLink = containsPattern(
entity.body,
`https?:\\/\\/github\\.com\\/(${entity.user.login})\\/[^/]+\\/?\\s?`,
);
return hasPullRequestRepoLink || hasExpoSnackLink || hasGithubRepoLink;
});
if (hasValidReproducer) {
try {
await github.rest.issues.removeLabel({
...issueData,
name: NEEDS_REPRO_LABEL,
});
} catch (error) {
if (!/Label does not exist/.test(error.message)) {
throw error;
}
}
} else {
await github.rest.issues.addLabels({
...issueData,
labels: [NEEDS_REPRO_LABEL, NEEDS_AUTHOR_FEEDBACK_LABEL],
});
}
};
function containsPattern(body, pattern) {
const regexp = new RegExp(pattern, 'gm');
return body.search(regexp) !== -1;
}
// Prevents the bot from responding when maintainer has changed the 'Needs: Repro' label
async function hasMaintainerChangedLabel(github, issueData, author) {
const timeline = await github.rest.issues.listEventsForTimeline(issueData);
const labeledEvents = timeline.data.filter(
event => event.event === 'labeled' || event.event === 'unlabeled',
);
const userEvents = labeledEvents.filter(event => event.actor.type !== 'Bot');
return userEvents.some(
event =>
event.actor.login !== author && event.label.name === NEEDS_REPRO_LABEL,
);
}
function isDateBefore(firstDate, secondDate) {
const date1 = new Date(firstDate);
const date2 = new Date(secondDate);
return date1.getTime() < date2.getTime();
}
@@ -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 {log, run} = require('./utils');
const fs = require('fs');
function _headers(token) {
return {
Accept: 'Accept: application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
Authorization: `Bearer ${token}`,
};
}
function _extractChangelog(version) {
if (version.endsWith('.0')) {
// for RC.0 and for the release of a new stable minor, the changelog is too long
// to be added in a release. The release body is usually something shorter.
// See for example the release for 0.76.0 or 0.77.0:
// 0.76: https://github.com/facebook/react-native/releases/tag/v0.76.0
// 0.77: https://github.com/facebook/react-native/releases/tag/v0.77.0
return '';
}
const changelog = String(fs.readFileSync('CHANGELOG.md', 'utf8')).split('\n');
const changelogStarts = changelog.indexOf(`## v${version}`);
let changelogEnds = changelogStarts;
// Scan the changelog to find the next version
for (var line = changelogStarts + 1; line < changelog.length; line++) {
if (changelog[line].startsWith('## ')) {
changelogEnds = line;
break;
}
}
return changelog.slice(changelogStarts, changelogEnds).join('\n').trim();
}
function _computeBody(changelog, version, hermesVersion, hermesV1Version) {
hermesVersion = hermesVersion ?? version;
hermesV1Version = hermesV1Version ?? version;
return `${changelog}
---
Hermes dSYMS:
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesVersion}/hermes-ios-${hermesVersion}-hermes-framework-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesVersion}/hermes-ios-${hermesVersion}-hermes-framework-dSYM-release.tar.gz)
Hermes V1 dSYMS:
- [Debug](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesV1Version}/hermes-ios-${hermesV1Version}-hermes-framework-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/hermes/hermes-ios/${hermesV1Version}/hermes-ios-${hermesV1Version}-hermes-framework-dSYM-release.tar.gz)
ReactNativeDependencies dSYMs:
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-dependencies-dSYM-release.tar.gz)
ReactNative Core dSYMs:
- [Debug](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-debug.tar.gz)
- [Release](https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/${version}/react-native-artifacts-${version}-reactnative-core-release.tar.gz)
---
You can file issues or pick requests against this release [here](https://github.com/reactwg/react-native-releases/issues/new/choose).
---
To help you upgrade to this version, you can use the [Upgrade Helper](https://react-native-community.github.io/upgrade-helper/) ⚛️.
---
View the whole changelog in the [CHANGELOG.md file](https://github.com/facebook/react-native/blob/main/CHANGELOG.md).`;
}
async function _verifyTagExists(version) {
const url = `https://github.com/facebook/react-native/releases/tag/v${version}`;
const response = await fetch(url);
if (response.status === 404) {
throw new Error(`Tag v${version} does not exist`);
}
}
async function _createDraftReleaseOnGitHub(version, body, latest, token) {
const url = 'https://api.github.com/repos/facebook/react-native/releases';
const method = 'POST';
const headers = _headers(token);
const fetchBody = JSON.stringify({
tag_name: `v${version}`,
name: `${version}`,
body: body,
draft: true, // NEVER CHANGE this value to false. If false, it will publish the release, and send a GH notification to all the subscribers.
prerelease: version.includes('-rc.') ? true : false,
make_latest: `${latest}`,
});
const response = await fetch(url, {
method,
headers,
body: fetchBody,
});
if (response.status !== 201) {
throw new Error(
`Failed to create the release: ${response.status} ${response.statusText}`,
);
}
const data = await response.json();
const {html_url, id} = data;
return {
html_url,
id,
};
}
function moveToChangelogBranch(version) {
log(`Moving to changelog branch: changelog/v${version}`);
run(`git checkout -b changelog/v${version}`);
}
async function createDraftRelease(
version,
latest,
token,
hermesVersion,
hermesV1Version,
) {
if (version.startsWith('v')) {
version = version.substring(1);
}
_verifyTagExists(version);
moveToChangelogBranch(version);
const changelog = _extractChangelog(version);
const body = _computeBody(changelog, version, hermesVersion, hermesV1Version);
const release = await _createDraftReleaseOnGitHub(
version,
body,
latest,
token,
);
log(`Created draft release: ${release.html_url}, ID ${release.id}`);
return release;
}
module.exports = {
createDraftRelease,
// Exported for testing purposes
_verifyTagExists,
_extractChangelog,
_computeBody,
_createDraftReleaseOnGitHub,
};
@@ -1,86 +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 fs = require('fs');
const MSEC_IN_DAY = 1000 * 60 * 60 * 24;
function formatUsers(users) {
console.log(`${users[0]} ${users[1]}`.trim());
}
function extractUsersFromScheduleAndDate(schedule, userMap, date) {
const year = date.getFullYear();
const month = date.getMonth() + 1; // 0 is January, 1 is February
const day = date.getDate();
const dateStr = `${year}-${month < 10 ? `0${month}` : month}-${day < 10 ? `0${day}` : day}`;
const user1 = userMap[schedule[dateStr][0]];
const user2 = userMap[schedule[dateStr][1]];
return [user1, user2];
}
/**
* You can invoke this script by doing:
* ```
* node .github/workflow-scripts/extractIssueOncalls.js $DATA
* ```
*
* the $DATA is stored in the github secrets as ONCALL_SCHEDULE variable.
* The format of the data is:
* ```
* {
* \"userMap\": {
* \"discord_handle1\": \"discord_id1\",
* \"discord_handle2\": \"discord_id2\",
* ...
* },
* \"schedule\": {
* \"2025-07-29\": [\"discord_handle1\", \"discord_handle2\"],
* \"2025-08-05\": [\"discord_handle3\", \"discord_handle4\"],
* ...
* }
* ```
*
* When uploading the secret, make sure that the JSON strings are escaped!
* The script will fail otherwise, because GitHub will remove the `"` characters.
*/
function main() {
const configuration = process.argv[2];
const {userMap, schedule} = JSON.parse(configuration);
extractIssueOncalls(schedule, userMap);
}
function extractIssueOncalls(schedule, userMap) {
const now = new Date();
const dayOfTheWeek = now.getDay(); // 0 is Sunday, 1 is Monday, etc.
let users;
if (dayOfTheWeek === 2) {
// exact match in the schedule
users = extractUsersFromScheduleAndDate(schedule, userMap, now);
} else if (dayOfTheWeek < 2) {
// sunday
// go to the tuesday of the last week
const lastWeekTuesday = new Date(now - (5 + dayOfTheWeek) * MSEC_IN_DAY);
users = extractUsersFromScheduleAndDate(schedule, userMap, lastWeekTuesday);
} else if (dayOfTheWeek > 1) {
// go to the previous tuesday
const thisWeekTuesday = new Date(now - (dayOfTheWeek - 2) * MSEC_IN_DAY);
users = extractUsersFromScheduleAndDate(schedule, userMap, thisWeekTuesday);
}
formatUsers(users);
return users;
}
if (require.main === module) {
void main();
}
module.exports = {
extractIssueOncalls,
};
@@ -1,120 +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 {log, getNpmPackageInfo, run} = require('./utils');
async function _computePreviousVersionFrom(version) {
log(`Computing previous version from: ${version}`);
const regex = /^0\.(\d+)\.(\d+)(-rc\.(\d+))?$/;
const match = version.match(regex);
if (!match) {
throw new Error(`Invalid version format: ${version}`);
}
const minor = match[1];
const patch = match[2];
const rc = match[4];
if (rc) {
if (Number(rc) > 0) {
return `0.${minor}.${patch}-rc.${Number(rc) - 1}`;
}
//fetch latest version on NPM
const latestPkg = await getNpmPackageInfo('react-native', 'latest');
return latestPkg.version;
} else {
if (Number(patch) === 0) {
// No need to generate the changelog for 0.X.0 as we already generated it from RCs
log(
`Skipping changelog generation for ${version} as we already have it from the RCs`,
);
return null;
}
return `0.${minor}.${Number(patch) - 1}`;
}
}
function _generateChangelog(previousVersion, version, token) {
log(`Generating changelog for ${version} from ${previousVersion}`);
run('git checkout main');
run('git fetch');
run('git pull origin main');
const generateChangelogComand = `npx @rnx-kit/rn-changelog-generator --base v${previousVersion} --compare v${version} --repo . --changelog ./CHANGELOG.md --token ${token}`;
run(generateChangelogComand);
}
function _pushCommit(version) {
log(`Pushing commit to changelog/v${version}`);
run(`git checkout -b changelog/v${version}`);
run('git add CHANGELOG.md');
run(`git commit -m "[RN][Changelog] Add changelog for v${version}"`);
run(`git push origin changelog/v${version}`);
}
async function _createPR(version, token) {
log('Creating changelog pr');
const url = 'https://api.github.com/repos/facebook/react-native/pulls';
const body = `
## Summary
Add Changelog for ${version}
## Changelog:
[Internal] - Add Changelog for ${version}
## Test Plan:
N/A`;
const response = await fetch(url, {
method: 'POST',
headers: {
Accept: 'Accept: application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
title: `[RN][Changelog] Add changelog for v${version}`,
head: `changelog/v${version}`,
base: 'main',
body: body,
}),
});
if (response.status !== 201) {
throw new Error(
`Failed to create PR: ${response.status} ${response.statusText}`,
);
}
const data = await response.json();
return data.html_url;
}
async function generateChangelog(version, token) {
if (version.startsWith('v')) {
version = version.substring(1);
}
const previousVersion = await _computePreviousVersionFrom(version);
if (previousVersion) {
log(`Previous version is ${previousVersion}`);
_generateChangelog(previousVersion, version, token);
_pushCommit(version);
const prURL = await _createPR(version, token);
log(`Created PR: ${prURL}`);
}
}
module.exports = {
generateChangelog,
// Exported only for testing purposes:
_computePreviousVersionFrom,
_generateChangelog,
_pushCommit,
_createPR,
};
-12
View File
@@ -1,12 +0,0 @@
#!/bin/bash
# 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.
set -e
if git ls-files | grep -E '\.npmignore$'; then
echo "Error: Found unexpected .npmignore file(s). Please use package.json#files instead."
exit 1
fi
-152
View File
@@ -1,152 +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 fs = require('fs');
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];
const MAX_ATTEMPTS = 3;
async function executeFlowWithRetries(flow, currentAttempt) {
try {
console.info(`Executing flow: ${flow}`);
const timeout = 1000 * 60 * 10; // 10 minutes
childProcess.execSync(
`MAESTRO_DRIVER_STARTUP_TIMEOUT=120000 $HOME/.maestro/bin/maestro test ${flow} --format junit -e APP_ID=${APP_ID} --debug-output /tmp/MaestroLogs`,
{stdio: 'inherit', timeout},
);
} catch (err) {
if (currentAttempt < MAX_ATTEMPTS) {
console.info(`Retrying...`);
await executeFlowWithRetries(flow, currentAttempt + 1);
} else {
throw err;
}
}
}
async function executeFlowInFolder(flowFolder) {
const files = fs.readdirSync(flowFolder);
for (const file of files) {
const filePath = `${flowFolder}/${file}`;
if (fs.lstatSync(filePath).isDirectory()) {
await executeFlowInFolder(filePath);
} else {
await executeFlowWithRetries(filePath, 0);
}
}
}
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,
});
metroProcess.unref();
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'});
if (IS_DEBUG) {
console.info('Wait For App to warm from Metro');
await sleep(10000);
}
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 {
//check if MAESTRO_FLOW is a folder
if (
fs.existsSync(MAESTRO_FLOW) &&
fs.lstatSync(MAESTRO_FLOW).isDirectory()
) {
await executeFlowInFolder(MAESTRO_FLOW);
} else {
await executeFlowWithRetries(MAESTRO_FLOW, 0);
}
} 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`);
}
}
if (error) {
throw error;
}
process.exit();
}
function sleep(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
main();
-176
View File
@@ -1,176 +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 fs = require('fs');
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} jsengine - The JSEngine to use for the test
@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 !== 6) {
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 JS_ENGINE = args[3];
const IS_DEBUG = args[4] === 'Debug';
const WORKING_DIRECTORY = args[5];
const MAX_ATTEMPTS = 5;
function launchSimulator(simulatorName) {
console.log(`Launching simulator ${simulatorName}`);
try {
childProcess.execSync(`xcrun simctl boot "${simulatorName}"`);
} catch (error) {
if (
!error.message.includes('Unable to boot device in current state: Booted')
) {
throw error;
}
}
}
function installAppOnSimulator(appPath) {
console.log(`Installing app at path ${appPath}`);
childProcess.execSync(`xcrun simctl install booted "${appPath}"`);
}
function extractSimulatorUDID() {
console.log('Retrieving device UDID');
const command = `xcrun simctl list devices booted -j | jq -r '[.devices[]] | add | first | .udid'`;
const udid = String(childProcess.execSync(command)).trim();
console.log(`UDID is ${udid}`);
return udid;
}
function bringSimulatorInForeground() {
console.log('Bringing simulator in foreground');
childProcess.execSync('open -a simulator');
}
function sleep(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
async function launchAppOnSimulator(appId, udid, isDebug) {
console.log('Launch the app');
childProcess.execSync(`xcrun simctl launch "${udid}" "${appId}"`);
if (isDebug) {
console.log('Wait for metro to warm');
await sleep(20 * 1000);
}
}
function startVideoRecording(jsengine, currentAttempt) {
console.log(
`Start video record using pid: video_record_${currentAttempt}.pid`,
);
const recordingArgs =
`simctl io booted recordVideo video_record_${currentAttempt}.mov`.split(
' ',
);
const recordingProcess = childProcess.spawn('xcrun', recordingArgs, {
detached: true,
stdio: 'ignore',
});
return recordingProcess;
}
function stopVideoRecording(recordingProcess) {
if (!recordingProcess) {
console.log("Passed a null recording process. Can't kill it");
return;
}
console.log(`Stop video record using pid: ${recordingProcess.pid}`);
recordingProcess.kill('SIGINT');
}
function executeTestsWithRetries(
appId,
udid,
maestroFlow,
jsengine,
currentAttempt,
) {
const recProcess = startVideoRecording(jsengine, currentAttempt);
try {
const timeout = 1000 * 60 * 10; // 10 minutes
const command = `$HOME/.maestro/bin/maestro --udid="${udid}" test "${maestroFlow}" --format junit -e APP_ID="${appId}"`;
console.log(command);
childProcess.execSync(`MAESTRO_DRIVER_STARTUP_TIMEOUT=1500000 ${command}`, {
stdio: 'inherit',
timeout,
});
stopVideoRecording(recProcess);
} catch (error) {
// Can't put this in the finally block because it will be executed after the
// recursive call of executeTestsWithRetries
stopVideoRecording(recProcess);
if (currentAttempt < MAX_ATTEMPTS) {
executeTestsWithRetries(
appId,
udid,
maestroFlow,
jsengine,
currentAttempt + 1,
);
} else {
console.error(`Failed to execute flow after ${MAX_ATTEMPTS} attempts.`);
throw error;
}
}
}
async function main() {
console.info('\n==============================');
console.info('Running tests for iOS with the following parameters:');
console.info(`APP_PATH: ${APP_PATH}`);
console.info(`APP_ID: ${APP_ID}`);
console.info(`MAESTRO_FLOW: ${MAESTRO_FLOW}`);
console.info(`JS_ENGINE: ${JS_ENGINE}`);
console.info(`IS_DEBUG: ${IS_DEBUG}`);
console.info(`WORKING_DIRECTORY: ${WORKING_DIRECTORY}`);
console.info('==============================\n');
const simulatorName = 'iPhone 16 Pro';
launchSimulator(simulatorName);
installAppOnSimulator(APP_PATH);
const udid = extractSimulatorUDID();
bringSimulatorInForeground();
await launchAppOnSimulator(APP_ID, udid, IS_DEBUG);
executeTestsWithRetries(APP_ID, udid, MAESTRO_FLOW, JS_ENGINE, 1);
console.log('Test finished');
process.exit(0);
}
main();
@@ -1,85 +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, log} = require('./utils.js');
const {verifyPublishedPackage} = require('./verifyPublishedPackage.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 MAX_RETRIES = 3 * 6; // 18 attempts. Waiting between attempt: 10 s. Total time: 3 mins.
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,
) => {
try {
if (version.startsWith('v')) {
version = version.slice(1);
}
await verifyPublishedPackage(
TEMPLATE_NPM_PKG,
version,
latest ? 'latest' : null,
retries,
);
} catch (e) {
console.error(e.message);
process.exit(1);
}
};
-33
View File
@@ -1,33 +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');
const log = (...args) => console.log(...args);
async function getNpmPackageInfo(pkg, versionOrTag) {
return fetch(`https://registry.npmjs.org/${pkg}/${versionOrTag}`).then(resp =>
resp.json(),
);
}
async function sleep(seconds) {
return new Promise(resolve => setTimeout(resolve, seconds * 1000));
}
function run(cmd) {
return execSync(cmd, 'utf8').toString().trim();
}
module.exports = {
log,
getNpmPackageInfo,
sleep,
run,
};
@@ -1,43 +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 {log, sleep} = require('./utils');
const SLEEP_S = 60; // 1 minute
const MAX_RETRIES = 90; // 90 attempts. Waiting between attempt: 1 min. Total time: 90 min.
const ARTIFACT_URL =
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/';
const ARTIFACT_NAME = 'react-native-artifacts-';
async function verifyArtifactsAreOnMaven(version, retries = MAX_RETRIES) {
if (version.startsWith('v')) {
version = version.substring(1);
}
const artifactUrl = `${ARTIFACT_URL}${version}/${ARTIFACT_NAME}${version}.pom`;
for (let currentAttempt = 1; currentAttempt <= retries; currentAttempt++) {
const response = await fetch(artifactUrl);
if (response.status !== 200) {
log(
`${currentAttempt}) Artifact's for version ${version} are not on maven yet.\nURL: ${artifactUrl}\nLet's wait a minute and try again.\n`,
);
await sleep(SLEEP_S);
} else {
return;
}
}
log(
`We waited 90 minutes for the artifacts to be on Maven. Check https://status.maven.org/ if there are issues wth the service.`,
);
process.exit(1);
}
module.exports = {verifyArtifactsAreOnMaven};
@@ -1,63 +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 {log, getNpmPackageInfo, sleep} = require('./utils');
const SLEEP_S = 10;
const MAX_RETRIES = 3 * 6; // 18 attempts. Waiting between attempt: 10 s. Total time: 3 mins.
async function verifyPublishedPackage(
packageName,
version,
tag = null,
retries = MAX_RETRIES,
) {
log(`🔍 Is ${packageName}@${version} on npm?`);
let count = retries;
while (count-- > 0) {
try {
const json = await getNpmPackageInfo(packageName, tag ? tag : version);
log(`🎉 Found ${packageName}@${version} on npm`);
if (!tag) {
return;
}
// check for next tag
if (tag === 'next' && json.version === version) {
log(`🎉 ${packageName}@next → ${version} on npm`);
return;
}
// Check for latest tag
if (tag === 'latest' && json.version === version) {
log(`🎉 ${packageName}@latest → ${version} on npm`);
return;
}
log(
`🐌 ${packageName}@${tag}${json.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 ${packageName}@${version} on npm`;
if (tag) {
msg += ` and ${tag} tag points to this version.`;
}
log(msg);
process.exit(1);
}
module.exports = {
verifyPublishedPackage,
};
@@ -1,30 +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, log} = require('./utils.js');
const {verifyPublishedPackage} = require('./verifyPublishedPackage.js');
const REACT_NATIVE_NPM_PKG = 'react-native';
const MAX_RETRIES = 3 * 6; // 18 attempts. Waiting between attempt: 10 s. Total time: 3 mins.
/**
* Will verify that @latest, @next 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.verifyReleaseOnNpm = async (
version,
latest = false,
retries = MAX_RETRIES,
) => {
const tag = version.includes('-rc.') ? 'next' : latest ? 'latest' : null;
if (version.startsWith('v')) {
version = version.slice(1);
}
await verifyPublishedPackage(REACT_NATIVE_NPM_PKG, version, tag, retries);
};
-112
View File
@@ -1,112 +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
*/
module.exports = async (github, context) => {
const issue = context.payload.issue;
const issueVersionUnparsed =
getReactNativeVersionFromIssueBodyIfExists(issue);
const issueVersion = parseVersionFromString(issueVersionUnparsed);
// Nightly versions are always supported
if (reportedVersionIsNightly(issueVersionUnparsed, issueVersion)) return;
if (!issueVersion) {
return {label: 'Needs: Version Info'};
}
// Ensure the version matches one we support
const recentReleases = (
await github.rest.repos.listReleases({
owner: context.repo.owner,
repo: context.repo.repo,
})
).data.map(release => release.name);
const latestRelease = (
await github.rest.repos.getLatestRelease({
owner: context.repo.owner,
repo: context.repo.repo,
})
).data;
const latestVersion = parseVersionFromString(latestRelease.name);
// We want to "insta-close" an issue if RN version provided is too old. And encourage users to upgrade.
if (isVersionTooOld(issueVersion, latestVersion)) {
return {label: 'Type: Too Old Version'};
}
if (!isVersionSupported(issueVersion, latestVersion)) {
return {label: 'Type: Unsupported Version'};
}
};
/**
* Check if the RN version provided in an issue is supported.
*
* "We support `N-2` minor versions, and the `latest` major".
*/
function isVersionSupported(actualVersion, latestVersion) {
return (
actualVersion.major >= latestVersion.major &&
actualVersion.minor >= latestVersion.minor - 2
);
}
/**
* Check if the RN version provided in an issue is too old.
* "We support `N-2` minor versions, and the `latest` major".
*
* A RN version is *too old* if it's:
* - `1` or more *major* behind the *latest major*.
* - `5` or more *minor* behind the *latest minor* in the *same major*. Less aggressive.
* (e.g. If `0.72.0` is the current latest then `0.67.0` and lower is too old for `0.72.0`)
*/
function isVersionTooOld(actualVersion, latestVersion) {
return (
latestVersion.major - actualVersion.major >= 1 ||
latestVersion.minor - actualVersion.minor >= 5
);
}
function getReactNativeVersionFromIssueBodyIfExists(issue) {
if (!issue || !issue.body) return;
const rnVersionRegex = /React Native Version[\r\n]+(?<version>.+)[\r\n]*/;
const rnVersionMatch = issue.body.match(rnVersionRegex);
if (!rnVersionMatch || !rnVersionMatch.groups.version) return;
return rnVersionMatch.groups.version;
}
function reportedVersionIsNightly(unparsedVersionString, version) {
if (!unparsedVersionString && !version) return false;
const nightlyRegex = /nightly/i;
const nightlyMatch = unparsedVersionString.match(nightlyRegex);
const versionIsNightly = nightlyMatch && nightlyMatch[0];
const versionIsZero =
version && version.major == 0 && version.minor == 0 && version.patch == 0;
return versionIsZero || versionIsNightly;
}
function parseVersionFromString(version) {
if (!version) return;
// This will match the standard x.x.x semver format, as well as the non-standard prerelease x.x.x-rc.x
const semverRegex =
/(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(-[rR]{1}[cC]{1}\.(?<prerelease>\d+))?/;
const versionMatch = version.match(semverRegex);
if (!versionMatch) return;
const {major, minor, patch, prerelease} = versionMatch.groups;
return {
major: parseInt(major),
minor: parseInt(minor),
patch: parseInt(patch),
prerelease: parseInt(prerelease),
};
}
-27
View File
@@ -1,27 +0,0 @@
name: Automatic Rebase
# This workflow is used to automatically rebase a PR when a comment is made
# containing the text "/rebase". It uses the cirrus-actions/rebase action.
# See https://github.com/cirrus-actions/rebase
on:
issue_comment:
types: [created]
permissions:
contents: read
jobs:
rebase:
name: Rebase
permissions:
contents: write # for cirrus-actions/rebase to push code to rebase
pull-requests: read # for cirrus-actions/rebase to get info about PR
runs-on: ubuntu-latest
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase')
steps:
- name: Checkout the latest code
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0 # otherwise, you will fail to push refs to dest repo
- name: Automatic Rebase
uses: cirrus-actions/rebase@1.8
env:
GITHUB_TOKEN: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
-45
View File
@@ -1,45 +0,0 @@
name: Bump Podfile.lock
on:
workflow_call: # this directive allow us to call this workflow from other workflows
jobs:
bump-podfile-lock:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Install dependencies
uses: ./.github/actions/yarn-install
- name: Configure git
run: |
git config --local user.email "bot@reactnative.dev"
git config --local user.name "React Native Bot"
- name: Setup xcode
uses: ./.github/actions/setup-xcode
with:
platform: 'ios'
- name: Extract branch name
run: |
TAG="${{ github.ref_name }}";
BRANCH_NAME=$(echo "$TAG" | sed -E 's/v([0-9]+\.[0-9]+)\.[0-9]+(-rc\.[0-9]+)?/\1-stable/')
echo "Branch Name is $BRANCH_NAME"
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
- name: Checkout release branch
run: |
git checkout "$BRANCH_NAME"
git fetch
git pull origin "$BRANCH_NAME"
- name: Bump podfile.lock
run: |
cd packages/rn-tester
bundle install
bundle exec pod update hermes-engine --no-repo-update
- name: Commit changes
run: |
git add packages/rn-tester/Podfile.lock
git commit -m "[LOCAL] Bump Podfile.lock"
git push origin "$BRANCH_NAME"
-20
View File
@@ -1,20 +0,0 @@
name: Keep Github Actions Cache < 10GB
on:
workflow_dispatch:
schedule:
# Run every 2hrs during weekdays
- cron: "0 0/2 * * 1-5"
jobs:
cache-cleaner:
if: github.repository == 'facebook/react-native'
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: ./.github/actions/setup-node
- name: Trim the cache
run: node scripts/clean-gha-cache.js
@@ -1,19 +0,0 @@
name: Check for reproducer
# This workflow is triggered when issue is created or edited.
on:
issues:
types: [opened, edited]
jobs:
check-for-reproducer:
runs-on: ubuntu-latest
if: |
github.repository == 'facebook/react-native' && github.event.issue.pull_request == null && github.event.issue.state == 'open' && !contains(github.event.issue.labels.*.name, ':open_umbrella: Umbrella')
steps:
- uses: actions/checkout@v4
- uses: actions/github-script@v6
with:
github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
script: |
const checkForReproducer = require('./.github/workflow-scripts/checkForReproducer.js')
await checkForReproducer(github, context)
-63
View File
@@ -1,63 +0,0 @@
name: Label closed PR as merged and leave a comment
on:
push
permissions:
contents: read
pull-requests: write
jobs:
comment-and-label:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
steps:
- uses: actions/github-script@v6
with:
github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
script: |
if(!context.payload.commits || !context.payload.commits.length) return;
const sha = context.payload.commits[0].id;
const {commit, author} = (await github.rest.repos.getCommit({
ref: sha,
owner: context.repo.owner,
repo: context.repo.repo,
})).data;
// Looking at the commit message, checks which PR number, if any, was closed by this commit
const getClosedPrIfExists = (commit) => {
if(!commit || !commit.message) return;
const prClosingRegex = /Closes https:\/\/github.com\/facebook\/react-native\/pull\/([0-9]+)|Pull Request resolved: https:\/\/github.com\/facebook\/react-native\/pull\/([0-9]+)/;
const prClosingMatch = commit.message.match(prClosingRegex);
if(!prClosingMatch || (!prClosingMatch[1] && ! prClosingMatch[2])) return;
return prClosingMatch[1] ?? prClosingMatch[2];
};
const closedPrNumber = getClosedPrIfExists(commit);
if(!closedPrNumber) return;
const pr = (await github.rest.pulls.get({
pull_number: closedPrNumber,
owner: context.repo.owner,
repo: context.repo.repo,
})).data;
const authorName = author?.login ? `@${author.login}` : commit.author.name;
github.rest.issues.createComment({
issue_number: closedPrNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: `This pull request was successfully merged by ${authorName} in **${sha}**\n\n<sup>[When will my fix make it into a release?](https://github.com/reactwg/react-native-releases/blob/main/docs/faq.md#when-will-my-fix-make-it-into-a-release) | [How to file a pick request?](https://github.com/reactwg/react-native-releases/blob/main/docs/faq.md#how-to-open-a-pick-request)</sup>`
});
// If the PR has already been processed (labeled as Merged), skip it
const mergedLabel = "Merged";
if(pr.labels && pr.labels.some(label => label.name === mergedLabel)) return;
github.rest.issues.addLabels({
issue_number: closedPrNumber,
owner: context.repo.owner,
repo: context.repo.repo,
labels: [mergedLabel]
});
@@ -1,53 +0,0 @@
name: Create Draft Release
on:
workflow_call:
inputs:
hermesVersion:
required: false
type: string
description: The version of Hermes to use for this release (eg. 0.15.0). If not specified, it will use React Native Version
hermesV1Version:
required: false
type: string
description: The version of Hermes V1 to use for this release (eg. 250829098.0.2). If not specified, it will use React Native Version
jobs:
create-draft-release:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Install dependencies
uses: ./.github/actions/yarn-install
- name: Configure Git
shell: bash
run: |
git config --local user.email "bot@reactnative.dev"
git config --local user.name "React Native Bot"
- name: Create draft release
uses: actions/github-script@v6
id: create-draft-release
with:
script: |
const {createDraftRelease} = require('./.github/workflow-scripts/createDraftRelease.js');
const version = '${{ github.ref_name }}';
const {isLatest} = require('./.github/workflow-scripts/publishTemplate.js');
return (await createDraftRelease(version, isLatest(), '${{secrets.REACT_NATIVE_BOT_GITHUB_TOKEN}}', ${{ inputs.hermesVersion }}, ${{ inputs.hermesV1Version }})).id;
result-encoding: string
- name: Upload release assets for DotSlash
uses: actions/github-script@v6
env:
RELEASE_ID: ${{ steps.create-draft-release.outputs.result }}
with:
script: |
const {uploadReleaseAssetsForDotSlashFiles} = require('./scripts/releases/upload-release-assets-for-dotslash.js');
const version = '${{ github.ref_name }}';
await uploadReleaseAssetsForDotSlashFiles({
version,
token: '${{secrets.REACT_NATIVE_BOT_GITHUB_TOKEN}}',
releaseId: process.env.RELEASE_ID,
});
-57
View File
@@ -1,57 +0,0 @@
name: Create release
on:
workflow_dispatch:
inputs:
version:
description: "The version of React Native we want to release. For example 0.75.0-rc.0"
required: true
type: string
is-latest-on-npm:
description: "Whether we want to tag this release as latest on NPM"
required: true
type: boolean
default: false
dry-run:
description: "Whether the job should be executed in dry-run mode or not"
type: boolean
default: true
jobs:
create_release:
if: github.repository == 'facebook/react-native'
runs-on: ubuntu-latest
steps:
- name: Checkout
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: |
BRANCH="$(git branch --show-current)"
PATTERN='^0\.[0-9]+-stable$'
if [[ $BRANCH =~ $PATTERN ]]; then
echo "On a stable branch"
echo "ON_STABLE_BRANCH=true" >> $GITHUB_OUTPUT
fi
- name: Print output
run: echo "ON_STABLE_BRANCH ${{steps.check_stable_branch.outputs.ON_STABLE_BRANCH}}"
- name: Check if tag already exists
id: check_if_tag_exists
run: |
TAG="v${{ inputs.version }}"
TAG_EXISTS=$(git tag -l "$TAG")
if [[ -n "$TAG_EXISTS" ]]; then
echo "Version tag already exists!"
echo "TAG_EXISTS=true" >> $GITHUB_OUTPUT
fi
- name: Execute Prepare Release
if: ${{ steps.check_stable_branch.outputs.ON_STABLE_BRANCH && !steps.check_if_tag_exists.outputs.TAG_EXISTS }}
uses: ./.github/actions/create-release
with:
version: ${{ inputs.version }}
is-latest-on-npm: ${{ inputs.is-latest-on-npm }}
dry-run: ${{ inputs.dry-run }}
-31
View File
@@ -1,31 +0,0 @@
name: Run Danger on PR
on:
pull_request_target:
types: [opened, edited, reopened, synchronize]
permissions:
actions: write
checks: write
contents: write
issues: write
pull-requests: write
statuses: write
jobs:
danger:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: ./.github/actions/setup-node
- name: Run yarn install
uses: ./.github/actions/yarn-install
- name: Run diff-js-api-breaking-changes
uses: ./.github/actions/diff-js-api-breaking-changes
- name: Danger
run: yarn danger ci --use-github-checks --failOnErrors
working-directory: private/react-native-bots
env:
DANGER_GITHUB_API_TOKEN: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
-28
View File
@@ -1,28 +0,0 @@
name: Generate Changelog
on:
workflow_call:
jobs:
generate-changelog:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Install dependencies
uses: ./.github/actions/yarn-install
- name: Configure Git
shell: bash
run: |
git config --local user.email "bot@reactnative.dev"
git config --local user.name "React Native Bot"
- name: Generate Changelog
uses: actions/github-script@v6
with:
script: |
const {generateChangelog} = require('./.github/workflow-scripts/generateChangelog');
const version = '${{ github.ref_name }}';
await generateChangelog(version, '${{secrets.REACT_NATIVE_BOT_GITHUB_TOKEN}}');
-41
View File
@@ -1,41 +0,0 @@
name: Monitor React Native New Issues
on:
schedule:
- cron: "0 0,6,12,18 * * *"
workflow_dispatch:
# Reminder for when we have to update the schedule (before Jan 2026):
# the secrets.ONCALL_SCHEDULE secret must be on a single line and must have all the `"` escaped as `\"`.
# Only a meta engineer can update it through the OSS internal portal.
jobs:
monitor-issues:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node.js
uses: ./.github/actions/setup-node
- name: Install dependencies
uses: ./.github/actions/yarn-install
- name: Extract next oncall
run: |
ONCALLS=$(node ./.github/workflow-scripts/extractIssueOncalls.js "${{ secrets.ONCALL_SCHEDULE }}")
ONCALL1=$(echo $ONCALLS | cut -d ' ' -f 1)
ONCALL2=$(echo $ONCALLS | cut -d ' ' -f 2)
echo "oncall1=$ONCALL1" >> $GITHUB_ENV
echo "oncall2=$ONCALL2" >> $GITHUB_ENV
- name: Monitor New Issues
uses: react-native-community/repo-monitor@v1.0.1
with:
task: "monitor-issues"
git_secret: ${{ secrets.GITHUB_TOKEN }}
notifier: "discord"
fetch_data_interval: 6
repo_owner: "facebook"
repo_name: "react-native"
discord_webhook_url: "${{ secrets.DISCORD_WEBHOOK_URL }}"
discord_id_type: "user"
discord_ids: "${{ env.oncall1 }},${{ env.oncall2 }}"
-28
View File
@@ -1,28 +0,0 @@
name: Issue Needs Attention
# This workflow is triggered on issue comments.
on:
issue_comment:
types: [created]
permissions:
contents: read
jobs:
applyNeedsAttentionLabel:
permissions:
contents: read # for actions/checkout to fetch code
issues: write # for react-native-community/needs-attention to label issues
name: Apply Needs Attention Label
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
steps:
- uses: actions/checkout@v4
- name: Apply Needs Attention Label
uses: react-native-community/needs-attention@v2.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
response-required-label: "Needs: Author Feedback"
needs-attention-label: "Needs: Attention"
id: needs-attention
- name: Result
run: echo '${{ steps.needs-attention.outputs.result }}'
-88
View File
@@ -1,88 +0,0 @@
name: Nightly
on:
workflow_dispatch:
# nightly build @ 2:15 AM UTC
schedule:
- cron: "15 2 * * *"
jobs:
set_release_type:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
outputs:
RELEASE_TYPE: ${{ steps.set_release_type.outputs.RELEASE_TYPE }}
env:
EVENT_NAME: ${{ github.event_name }}
REF: ${{ github.ref }}
steps:
- id: set_release_type
run: |
echo "Setting release type to nightly"
echo "RELEASE_TYPE=nightly" >> $GITHUB_OUTPUT
prebuild_apple_dependencies:
if: github.repository == 'facebook/react-native'
uses: ./.github/workflows/prebuild-ios-dependencies.yml
secrets: inherit
prebuild_react_native_core:
uses: ./.github/workflows/prebuild-ios-core.yml
with:
use-hermes-nightly: true
secrets: inherit
needs: [prebuild_apple_dependencies]
build_android:
runs-on: 8-core-ubuntu
if: github.repository == 'facebook/react-native'
needs: [set_release_type]
container:
image: reactnativecommunity/react-native-android:latest
env:
TERM: "dumb"
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }}
ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }}
ORG_GRADLE_PROJECT_SONATYPE_USERNAME: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_USERNAME }}
ORG_GRADLE_PROJECT_SONATYPE_PASSWORD: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_PASSWORD }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build Android
uses: ./.github/actions/build-android
with:
release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
build_npm_package:
runs-on: 8-core-ubuntu
needs:
[
set_release_type,
build_android,
prebuild_apple_dependencies,
prebuild_react_native_core,
]
container:
image: reactnativecommunity/react-native-android:latest
env:
TERM: "dumb"
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
# By default we only build ARM64 to save time/resources. For release/nightlies, we override this value to build all archs.
ORG_GRADLE_PROJECT_reactNativeArchitectures: "arm64-v8a"
env:
GHA_NPM_TOKEN: ${{ secrets.GHA_NPM_TOKEN }}
ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }}
ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }}
ORG_GRADLE_PROJECT_SONATYPE_USERNAME: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_USERNAME }}
ORG_GRADLE_PROJECT_SONATYPE_PASSWORD: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_PASSWORD }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build and Publish NPM Package
uses: ./.github/actions/build-npm-package
with:
release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
gha-npm-token: ${{ env.GHA_NPM_TOKEN }}
gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
-60
View File
@@ -1,60 +0,0 @@
name: On Issue Labeled
# This workflow is triggered when a label is added to an issue.
on:
issues:
types: [labeled]
permissions:
contents: write
issues: write
jobs:
# Runs automatic checks on issues labeled with "Needs: Triage",
# then invokes actOnLabel to react to any added labels
triage-issue:
runs-on: ubuntu-latest
if: "${{ github.repository == 'facebook/react-native' && contains(github.event.label.name, 'Needs: Triage :mag:') }}"
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Verify RN version
uses: actions/github-script@v6
with:
github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
script: |
const verifyVersion = require('./.github/workflow-scripts/verifyVersion.js')
const labelWithContext = await verifyVersion(github, context);
if(labelWithContext && labelWithContext.label) {
await github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: [labelWithContext.label]
})
const actOnLabel = require('./.github/workflow-scripts/actOnLabel.js')
await actOnLabel(github, context, labelWithContext)
}
- name: Add descriptive label
uses: actions/github-script@v6
with:
github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
script: |
const addDescriptiveLabel = require('./.github/workflow-scripts/addDescriptiveLabels.js')
await addDescriptiveLabel(github, context);
# Reacts to the label that triggered this workflow (added manually or via other workflows)
act-on-label:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
steps:
- uses: actions/checkout@v4
- uses: actions/github-script@v6
with:
github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
script: |
const actOnLabel = require('./.github/workflow-scripts/actOnLabel.js')
await actOnLabel(github, context, {label: context.payload.label.name})
-198
View File
@@ -1,198 +0,0 @@
name: Prebuild iOS Dependencies
on:
workflow_call: # this directive allow us to call this workflow from other workflows
inputs:
use-hermes-nightly:
description: 'Whether to use the hermes nightly build or read the version from the versions.properties file'
type: boolean
required: false
default: false
jobs:
build-rn-slice:
runs-on: macos-15
strategy:
fail-fast: false
matrix:
flavor: ['Debug', 'Release']
slice: [
'ios',
'ios-simulator',
'mac-catalyst',
]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Restore cache if present
id: restore-ios-slice
uses: actions/cache/restore@v4
with:
key: v3-ios-core-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift', 'packages/react-native/scripts/ios-prebuild/*.js', 'packages/react-native/scripts/ios-prebuild.js', 'packages/react-native/React/**/*', 'packages/react-native/ReactCommon/**/*', 'packages/react-native/Libraries/**/*') }}
path: packages/react-native/
- name: Setup node.js
if: steps.restore-ios-slice.outputs.cache-hit != 'true'
uses: ./.github/actions/setup-node
- name: Setup xcode
if: steps.restore-ios-slice.outputs.cache-hit != 'true'
uses: ./.github/actions/setup-xcode
with:
platform: ${{ matrix.slice }}
- name: Yarn Install
if: steps.restore-ios-slice.outputs.cache-hit != 'true'
uses: ./.github/actions/yarn-install
- name: Set Hermes version
shell: bash
run: |
if [ "${{ inputs.use-hermes-nightly }}" == "true" ]; then
HERMES_VERSION="nightly"
else
HERMES_VERSION=$(sed -n 's/^HERMES_VERSION_NAME=//p' packages/react-native/sdks/hermes-engine/version.properties)
fi
echo "Using Hermes version: $HERMES_VERSION"
echo "HERMES_VERSION=$HERMES_VERSION" >> $GITHUB_ENV
- name: Download ReactNativeDependencies
uses: actions/download-artifact@v4
with:
name: ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
path: /tmp/third-party/
- name: Extract ReactNativeDependencies
if: steps.restore-ios-slice.outputs.cache-hit != 'true'
shell: bash
run: |
# Extract ReactNativeDependencies
tar -xzf /tmp/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz -C /tmp/third-party/
# Create destination folder
mkdir -p packages/react-native/third-party/
# Move the XCFramework in the destination directory
mv /tmp/third-party/packages/react-native/third-party/ReactNativeDependencies.xcframework packages/react-native/third-party/ReactNativeDependencies.xcframework
VERSION=$(jq -r '.version' packages/react-native/package.json)
echo "$VERSION-${{matrix.flavor}}" > "packages/react-native/third-party/version.txt"
cat "packages/react-native/third-party/version.txt"
# Check destination directory
ls -lR packages/react-native/third-party/
- name: Setup the workspace
if: steps.restore-ios-slice.outputs.cache-hit != 'true'
shell: bash
run: |
cd packages/react-native
node scripts/ios-prebuild.js -s -f "${{ matrix.flavor }}"
- name: Build React Native
if: steps.restore-ios-slice.outputs.cache-hit != 'true'
shell: bash
run: |
# This is going to be replaced by a CLI script
cd packages/react-native
node scripts/ios-prebuild -b -f "${{ matrix.flavor }}" -p "${{ matrix.slice }}"
- name: Upload headers
uses: actions/upload-artifact@v4
with:
name: prebuild-ios-core-headers-${{ matrix.flavor }}-${{ matrix.slice }}
path:
packages/react-native/.build/headers
- name: Upload artifacts
uses: actions/upload-artifact@v4.3.4
with:
name: prebuild-ios-core-slice-${{ matrix.flavor }}-${{ matrix.slice }}
path: |
packages/react-native/.build/output/spm/${{ matrix.flavor }}/Build/Products
- name: Save Cache
uses: actions/cache/save@v4
if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode
with:
key: v3-ios-core-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift', 'packages/react-native/scripts/ios-prebuild/*.js', 'packages/react-native/scripts/ios-prebuild.js', 'packages/react-native/React/**/*', 'packages/react-native/ReactCommon/**/*', 'packages/react-native/Libraries/**/*') }}
path: |
packages/react-native/.build/output/spm/${{ matrix.flavor }}/Build/Products
packages/react-native/.build/headers
compose-xcframework:
runs-on: macos-15
needs: [build-rn-slice]
strategy:
fail-fast: false
matrix:
flavor: ['Debug', 'Release']
env:
REACT_ORG_CODE_SIGNING_P12_CERT: ${{ secrets.REACT_ORG_CODE_SIGNING_P12_CERT }}
REACT_ORG_CODE_SIGNING_P12_CERT_PWD: ${{ secrets.REACT_ORG_CODE_SIGNING_P12_CERT_PWD }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Restore cache if present
id: restore-ios-xcframework
uses: actions/cache/restore@v4
with:
path: packages/react-native/.build/output/xcframeworks
key: v2-ios-core-xcframework-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift', 'packages/react-native/scripts/ios-prebuild/*.js', 'packages/react-native/scripts/ios-prebuild.js', 'packages/react-native/React/**/*', 'packages/react-native/ReactCommon/**/*', 'packages/react-native/Libraries/**/*') }}
- name: Setup node.js
if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
uses: ./.github/actions/setup-node
- name: Setup xcode
if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
uses: ./.github/actions/setup-xcode
with:
xcode-version: '16.2.0'
- name: Yarn Install
if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
uses: ./.github/actions/yarn-install
- name: Download slice artifacts
if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
uses: actions/download-artifact@v4
with:
pattern: prebuild-ios-core-slice-${{ matrix.flavor }}-*
path: packages/react-native/.build/output/spm/${{ matrix.flavor }}/Build/Products
merge-multiple: true
- name: Download headers
if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
uses: actions/download-artifact@v4
with:
pattern: prebuild-ios-core-headers-${{ matrix.flavor }}-*
path: packages/react-native/.build/headers
merge-multiple: true
- name: Setup Keychain
if: ${{ steps.restore-ios-xcframework.outputs.cache-hit != 'true' && env.REACT_ORG_CODE_SIGNING_P12_CERT != '' }}
uses: apple-actions/import-codesign-certs@v3 # https://github.com/marketplace/actions/import-code-signing-certificates
with:
p12-file-base64: ${{ secrets.REACT_ORG_CODE_SIGNING_P12_CERT }}
p12-password: ${{ secrets.REACT_ORG_CODE_SIGNING_P12_CERT_PWD }}
- name: Create XCFramework
if: ${{ steps.restore-ios-xcframework.outputs.cache-hit != 'true' && env.REACT_ORG_CODE_SIGNING_P12_CERT == '' }}
run: |
cd packages/react-native
node scripts/ios-prebuild -c -f "${{ matrix.flavor }}"
- name: Create and Sign XCFramework
if: ${{ steps.restore-ios-xcframework.outputs.cache-hit != 'true' && env.REACT_ORG_CODE_SIGNING_P12_CERT != '' }}
run: |
cd packages/react-native
node scripts/ios-prebuild -c -f "${{ matrix.flavor }}" -i "React Org"
- name: Compress and Rename XCFramework
if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
run: |
cd packages/react-native/.build/output/xcframeworks/${{matrix.flavor}}
tar -cz -f ../ReactCore${{matrix.flavor}}.xcframework.tar.gz React.xcframework
- name: Compress and Rename dSYM
if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
run: |
cd packages/react-native/.build/output/xcframeworks/${{matrix.flavor}}/Symbols
tar -cz -f ../../ReactCore${{ matrix.flavor }}.framework.dSYM.tar.gz .
- name: Upload XCFramework Artifact
uses: actions/upload-artifact@v4
with:
name: ReactCore${{ matrix.flavor }}.xcframework.tar.gz
path: packages/react-native/.build/output/xcframeworks/ReactCore${{matrix.flavor}}.xcframework.tar.gz
- name: Upload dSYM Artifact
uses: actions/upload-artifact@v4
with:
name: ReactCore${{ matrix.flavor }}.framework.dSYM.tar.gz
path: packages/react-native/.build/output/xcframeworks/ReactCore${{matrix.flavor}}.framework.dSYM.tar.gz
- name: Save cache if present
if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode
uses: actions/cache/save@v4
with:
path: |
packages/react-native/.build/output/xcframeworks/ReactCore${{matrix.flavor}}.xcframework.tar.gz
packages/react-native/.build/output/xcframeworks/ReactCore${{matrix.flavor}}.framework.dSYM.tar.gz
key: v2-ios-core-xcframework-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift', 'packages/react-native/scripts/ios-prebuild/*.js', 'packages/react-native/scripts/ios-prebuild.js', 'packages/react-native/React/**/*', 'packages/react-native/ReactCommon/**/*', 'packages/react-native/Libraries/**/*') }}
@@ -1,197 +0,0 @@
name: Prebuild iOS Dependencies
on:
workflow_call: # this directive allow us to call this workflow from other workflows
jobs:
prepare_workspace:
name: Prepare workspace
runs-on: macos-15
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Restore cache if present
id: restore-ios-prebuilds
uses: actions/cache/restore@v4
with:
path: packages/react-native/third-party/
key: v3-ios-dependencies-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
enableCrossOsArchive: true
- name: Yarn Install
if: steps.restore-ios-prebuilds.outputs.cache-hit != 'true'
uses: ./.github/actions/yarn-install
- name: Prepare Dependencies
if: steps.restore-ios-prebuilds.outputs.cache-hit != 'true'
run: |
node scripts/releases/prepare-ios-prebuilds.js -s
- name: Generate Package.swift
if: steps.restore-ios-prebuilds.outputs.cache-hit != 'true'
run: |
node scripts/releases/prepare-ios-prebuilds.js -w
- name: Upload Artifacts
uses: actions/upload-artifact@v4.3.4
with:
name: ios-prebuilds-workspace
path: packages/react-native/third-party/
- name: Save Cache
uses: actions/cache/save@v4
if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode
with:
key: v3-ios-dependencies-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
enableCrossOsArchive: true
path: packages/react-native/third-party/
build-apple-slices:
name: Build Apple Slice
runs-on: macos-15
needs: [prepare_workspace]
strategy:
fail-fast: false
matrix:
flavor: ['Debug', 'Release']
slice: ['ios',
'ios-simulator',
'macos',
'mac-catalyst',
'tvos',
'tvos-simulator',
'xros',
'xros-simulator']
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Restore slice folder
id: restore-slice-folder
uses: actions/cache/restore@v4
with:
path: packages/react-native/third-party/.build/Build/Products
key: v3-ios-dependencies-slice-folder-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
- name: Setup xcode
if: steps.restore-slice-folder.outputs.cache-hit != 'true'
uses: ./.github/actions/setup-xcode
with:
platform: ${{ matrix.slice }}
- name: Yarn Install
if: steps.restore-slice-folder.outputs.cache-hit != 'true'
uses: ./.github/actions/yarn-install
- name: Restore workspace
if: steps.restore-slice-folder.outputs.cache-hit != 'true'
uses: actions/download-artifact@v4
with:
name: ios-prebuilds-workspace
path: packages/react-native/third-party/
- name: Print third-party folder structure
if: steps.restore-slice-folder.outputs.cache-hit != 'true'
run: ls -lR packages/react-native/third-party
- name: Build slice ${{ matrix.slice }} for ${{ matrix.flavor }}
if: steps.restore-slice-folder.outputs.cache-hit != 'true'
run: node scripts/releases/prepare-ios-prebuilds.js -b -p ${{ matrix.slice }} -r ${{ matrix.flavor }}
- name: Upload Artifacts
uses: actions/upload-artifact@v4.3.4
with:
name: prebuild-slice-${{ matrix.flavor }}-${{ matrix.slice }}
path: |
packages/react-native/third-party/.build/Build/Products
- name: Save Cache
uses: actions/cache/save@v4
if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode
with:
key: v3-ios-dependencies-slice-folder-${{ matrix.slice }}-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
enableCrossOsArchive: true
path: |
packages/react-native/third-party/.build/Build/Products
create-xcframework:
name: Prepare XCFramework
runs-on: macos-15
needs: [build-apple-slices]
strategy:
fail-fast: false
matrix:
flavor: [Debug, Release]
env:
REACT_ORG_CODE_SIGNING_P12_CERT: ${{ secrets.REACT_ORG_CODE_SIGNING_P12_CERT }}
REACT_ORG_CODE_SIGNING_P12_CERT_PWD: ${{ secrets.REACT_ORG_CODE_SIGNING_P12_CERT_PWD }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Setup xcode
uses: ./.github/actions/setup-xcode
with:
xcode-version: '16.1'
- name: Restore XCFramework
id: restore-xcframework
uses: actions/cache/restore@v4
with:
path: |
packages/react-native/third-party/
key: v3-ios-dependencies-xcframework-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
# If cache hit, we already have our binary. We don't need to do anything.
- name: Yarn Install
if: steps.restore-xcframework.outputs.cache-hit != 'true'
uses: ./.github/actions/yarn-install
- name: Restore workspace
if: steps.restore-xcframework.outputs.cache-hit != 'true'
uses: actions/download-artifact@v4
with:
name: ios-prebuilds-workspace
path: packages/react-native/third-party/
- name: Download slices
if: steps.restore-xcframework.outputs.cache-hit != 'true'
uses: actions/download-artifact@v4
with:
pattern: prebuild-slice-${{ matrix.flavor }}-*
path: packages/react-native/third-party/.build/Build/Products
merge-multiple: true
- name: Setup Keychain
if: ${{ steps.restore-xcframework.outputs.cache-hit != 'true' && env.REACT_ORG_CODE_SIGNING_P12_CERT != '' }}
uses: apple-actions/import-codesign-certs@v3 # https://github.com/marketplace/actions/import-code-signing-certificates
with:
p12-file-base64: ${{ secrets.REACT_ORG_CODE_SIGNING_P12_CERT }}
p12-password: ${{ secrets.REACT_ORG_CODE_SIGNING_P12_CERT_PWD }}
- name: Create XCFramework
if: ${{ steps.restore-xcframework.outputs.cache-hit != 'true' && env.REACT_ORG_CODE_SIGNING_P12_CERT == '' }}
run: node scripts/releases/prepare-ios-prebuilds.js -c
- name: Create and Sign XCFramework
if: ${{ steps.restore-xcframework.outputs.cache-hit != 'true' && env.REACT_ORG_CODE_SIGNING_P12_CERT != '' }}
run: node scripts/releases/prepare-ios-prebuilds.js -c -i "React Org"
- name: Compress and Rename XCFramework
if: steps.restore-xcframework.outputs.cache-hit != 'true'
run: |
tar -cz -f packages/react-native/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz \
packages/react-native/third-party/ReactNativeDependencies.xcframework
- name: Show Symbol folder content
if: steps.restore-xcframework.outputs.cache-hit != 'true'
run: ls -lR packages/react-native/third-party/Symbols
- name: Compress and Rename dSYM
if: steps.restore-xcframework.outputs.cache-hit != 'true'
run: |
cd packages/react-native/third-party/Symbols/
tar -cz -f ../ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz .
mv ../ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz ./ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz
- name: Upload XCFramework Artifact
uses: actions/upload-artifact@v4
with:
name: ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
path: packages/react-native/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
- name: Upload dSYM Artifact
uses: actions/upload-artifact@v4
with:
name: ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz
path: |
packages/react-native/third-party/Symbols/ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz
- name: Save XCFramework in Cache
if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode
uses: actions/cache/save@v4
with:
path: |
packages/react-native/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
packages/react-native/third-party/ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz
key: v3-ios-dependencies-xcframework-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
@@ -1,29 +0,0 @@
name: Publish Bumped Packages
on:
push:
branches:
- "main"
- "*-stable"
jobs:
publish_bumped_packages:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
env:
GHA_NPM_TOKEN: ${{ secrets.GHA_NPM_TOKEN }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Run Yarn Install
uses: ./.github/actions/yarn-install
- name: Build packages
run: yarn build
- name: Build types
run: yarn build-types --skip-snapshot
- name: Set NPM auth token
run: echo "//registry.npmjs.org/:_authToken=$GHA_NPM_TOKEN" > ~/.npmrc
- name: Find and publish all bumped packages
run: node ./scripts/releases-ci/publish-updated-packages.js
-147
View File
@@ -1,147 +0,0 @@
name: Publish Release
on:
push:
tags:
- "v0.*.*" # This should match v0.X.Y
- "v0.*.*-rc.*" # This should match v0.X.Y-RC.0
jobs:
set_release_type:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
outputs:
RELEASE_TYPE: ${{ steps.set_release_type.outputs.RELEASE_TYPE }}
env:
EVENT_NAME: ${{ github.event_name }}
REF: ${{ github.ref }}
steps:
- id: set_release_type
run: |
echo "Setting release type to release"
echo "RELEASE_TYPE=release" >> $GITHUB_OUTPUT
set_hermes_versions:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
outputs:
HERMES_VERSION: ${{ steps.set_hermes_versions.outputs.HERMES_VERSION }}
HERMES_V1_VERSION: ${{ steps.set_hermes_versions.outputs.HERMES_V1_VERSION }}
steps:
- name: Checkout
uses: actions/checkout@v4
- id: set_hermes_versions
run: |
echo "Setting hermes versions to latest"
hermes_version=$(grep -oE 'HERMES_VERSION_NAME=([0-9]+\.[0-9]+\.[0-9]+)' packages/react-native/sdks/hermes-engine/version.properties | cut -d'=' -f2)
hermes_v1_version=$(grep -oE 'HERMES_V1_VERSION_NAME=([0-9]+\.[0-9]+\.[0-9]+)' packages/react-native/sdks/hermes-engine/version.properties | cut -d'=' -f2)
echo "HERMES_VERSION=$hermes_version" >> $GITHUB_OUTPUT
echo "HERMES_V1_VERSION=$hermes_v1_version" >> $GITHUB_OUTPUT
- name: Print hermes versions
run: |
echo "HERMES_VERSION=${{ steps.set_hermes_versions.outputs.HERMES_VERSION }}"
echo "HERMES_V1_VERSION=${{ steps.set_hermes_versions.outputs.HERMES_V1_VERSION }}"
prebuild_apple_dependencies:
if: github.repository == 'facebook/react-native'
uses: ./.github/workflows/prebuild-ios-dependencies.yml
secrets: inherit
prebuild_react_native_core:
uses: ./.github/workflows/prebuild-ios-core.yml
secrets: inherit
needs: [prebuild_apple_dependencies]
build_npm_package:
runs-on: 8-core-ubuntu
needs:
[
set_release_type,
prebuild_apple_dependencies,
prebuild_react_native_core,
]
container:
image: reactnativecommunity/react-native-android:latest
env:
TERM: "dumb"
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
# By default we only build ARM64 to save time/resources. For release/nightlies, we override this value to build all archs.
ORG_GRADLE_PROJECT_reactNativeArchitectures: "arm64-v8a"
env:
GHA_NPM_TOKEN: ${{ secrets.GHA_NPM_TOKEN }}
ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }}
ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }}
ORG_GRADLE_PROJECT_SONATYPE_USERNAME: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_USERNAME }}
ORG_GRADLE_PROJECT_SONATYPE_PASSWORD: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_PASSWORD }}
REACT_NATIVE_BOT_GITHUB_TOKEN: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
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:
release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
gha-npm-token: ${{ env.GHA_NPM_TOKEN }}
gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
- 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);
- 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());
- 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 \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: Bearer $REACT_NATIVE_BOT_GITHUB_TOKEN" \
-d "{\"event_type\": \"publish\", \"client_payload\": { \"version\": \"${{ github.ref_name }}\" }}"
- name: Verify Release is on NPM
timeout-minutes: 3
uses: actions/github-script@v6
with:
github-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
script: |
const {verifyReleaseOnNpm} = require('./.github/workflow-scripts/verifyReleaseOnNpm.js');
const {isLatest} = require('./.github/workflow-scripts/publishTemplate.js');
const version = "${{ github.ref_name }}";
await verifyReleaseOnNpm(version, isLatest());
- name: Verify that artifacts are on Maven
uses: actions/github-script@v6
with:
script: |
const {verifyArtifactsAreOnMaven} = require('./.github/workflow-scripts/verifyArtifactsAreOnMaven.js');
const version = "${{ github.ref_name }}";
await verifyArtifactsAreOnMaven(version);
generate_changelog:
needs: build_npm_package
uses: ./.github/workflows/generate-changelog.yml
secrets: inherit
bump_podfile_lock:
needs: build_npm_package
uses: ./.github/workflows/bump-podfile-lock.yml
secrets: inherit
create_draft_release:
needs: [generate_changelog, set_hermes_versions]
uses: ./.github/workflows/create-draft-release.yml
secrets: inherit
with:
hermesVersion: ${{ needs.set_hermes_versions.outputs.HERMES_VERSION }}
hermesV1Version: ${{ needs.set_hermes_versions.outputs.HERMES_V1_VERSION }}
-20
View File
@@ -1,20 +0,0 @@
name: Retry workflow
# Based on https://stackoverflow.com/a/78314483
on:
workflow_dispatch:
inputs:
run_id:
required: true
jobs:
rerun:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
steps:
- name: rerun ${{ inputs.run_id }}
env:
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh run watch ${{ inputs.run_id }} > /dev/null 2>&1
gh run rerun ${{ inputs.run_id }} --failed
-77
View File
@@ -1,77 +0,0 @@
name: Stale bot
on:
schedule:
- cron: "*/10 5 * * *"
jobs:
stale:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
days-before-stale: 180
stale-issue-message: 'This issue is stale because it has been open for 180 days with no activity. It will be closed in 7 days unless you comment on it or remove the "Stale" label.'
stale-pr-message: 'This PR is stale because it has been open for 180 days with no activity. It will be closed in 7 days unless you comment on it or remove the "Stale" label.'
close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.'
close-pr-message: 'This PR was closed because it has been stalled for 7 days with no activity.'
exempt-issue-labels: 'Help Wanted :octocat:, Good first issue, Never gets stale, Issue: Author Provided Repro'
exempt-pr-labels: 'Help Wanted :octocat:, Never gets stale'
stale-asc:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
ascending: true
repo-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
days-before-stale: 180
stale-issue-message: 'This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.'
stale-pr-message: 'This PR is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.'
close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.'
close-pr-message: 'This PR was closed because it has been stalled for 7 days with no activity.'
exempt-issue-labels: 'Help Wanted :octocat:, Good first issue, Never gets stale, Issue: Author Provided Repro'
exempt-pr-labels: 'Help Wanted :octocat:, Never gets stale'
stale-needs-author-feedback:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
any-of-labels: 'Needs: Author Feedback'
days-before-stale: 24
stale-issue-message: "This issue is waiting for author's feedback since 24 days. Please provide the requested feedback or this will be closed in 7 days."
stale-pr-message: "This PR is waiting for author's feedback since 24 days. Please provide the requested feedback or this will be closed in 7 days"
close-issue-message: "This issue was closed because the author hasn't provided the requested feedback after 7 days."
close-pr-message: "This PR was closed because the author hasn't provided the requested feedback after 7 days."
exempt-issue-labels: "Help Wanted :octocat:, Good first issue, Never gets stale, Issue: Author Provided Repro"
exempt-pr-labels: "Help Wanted :octocat:, Never gets stale"
stale-needs-author-feedback-asc:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
ascending: true
repo-token: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN }}
any-of-labels: 'Needs: Author Feedback'
days-before-stale: 24
stale-issue-message: "This issue is waiting for author's feedback since 24 days. Please provide the requested feedback or this will be closed in 7 days."
stale-pr-message: "This PR is waiting for author's feedback since 24 days. Please provide the requested feedback or this will be closed in 7 days"
close-issue-message: "This issue was closed because the author hasn't provided the requested feedback after 7 days."
close-pr-message: "This PR was closed because the author hasn't provided the requested feedback after 7 days."
exempt-issue-labels: "Help Wanted :octocat:, Good first issue, Never gets stale, Issue: Author Provided Repro"
exempt-pr-labels: "Help Wanted :octocat:, Never gets stale"
-526
View File
@@ -1,526 +0,0 @@
name: Test All
on:
workflow_dispatch:
pull_request:
push:
branches:
- main
- "*-stable"
jobs:
set_release_type:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
outputs:
RELEASE_TYPE: ${{ steps.set_release_type.outputs.RELEASE_TYPE }}
env:
EVENT_NAME: ${{ github.event_name }}
REF: ${{ github.ref }}
steps:
- id: set_release_type
run: |
if [[ $EVENT_NAME == "schedule" ]]; then
echo "Setting release type to nightly"
echo "RELEASE_TYPE=nightly" >> $GITHUB_OUTPUT
elif [[ $EVENT_NAME == "push" && $REF == refs/tags/v* ]]; then
echo "Setting release type to release"
echo "RELEASE_TYPE=release" >> $GITHUB_OUTPUT
else
echo "Setting release type to dry-run"
echo "RELEASE_TYPE=dry-run" >> $GITHUB_OUTPUT
fi
echo "Should I run E2E tests? ${{ inputs.run-e2e-tests }}"
prebuild_apple_dependencies:
if: github.repository == 'facebook/react-native'
uses: ./.github/workflows/prebuild-ios-dependencies.yml
secrets: inherit
prebuild_react_native_core:
uses: ./.github/workflows/prebuild-ios-core.yml
with:
use-hermes-nightly: ${{ !endsWith(github.ref_name, '-stable') }}
secrets: inherit
needs: [prebuild_apple_dependencies]
test_ios_rntester_ruby_3_2_0:
runs-on: macos-15
needs:
[prebuild_apple_dependencies, prebuild_react_native_core]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run it
uses: ./.github/actions/test-ios-rntester
with:
ruby-version: "3.2.0"
flavor: Debug
test_ios_rntester:
runs-on: macos-15-large
needs:
[prebuild_apple_dependencies, prebuild_react_native_core]
continue-on-error: true
strategy:
fail-fast: false
matrix:
flavor: [Debug, Release]
frameworks: [StaticLibraries, DynamicFrameworks]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run it
uses: ./.github/actions/test-ios-rntester
with:
use-frameworks: ${{ matrix.frameworks }}
flavor: ${{ matrix.flavor }}
test_e2e_ios_rntester:
runs-on: macos-15-large
needs:
[test_ios_rntester]
strategy:
fail-fast: false
matrix:
flavor: [Debug, Release]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: ./.github/actions/setup-node
- name: Download App
uses: actions/download-artifact@v4
with:
name: RNTesterApp-NewArch-${{ matrix.flavor }}
path: /tmp/RNTesterBuild/RNTester.app
- name: Check downloaded folder content
run: ls -lR /tmp/RNTesterBuild
- name: Setup xcode
uses: ./.github/actions/setup-xcode
with:
platform: ios
- name: Run E2E Tests
uses: ./.github/actions/maestro-ios
with:
app-path: "/tmp/RNTesterBuild/RNTester.app"
app-id: com.meta.RNTester.localDevelopment
maestro-flow: ./packages/rn-tester/.maestro/
flavor: ${{ matrix.flavor }}
test_e2e_ios_templateapp:
runs-on: macos-15-large
needs: [build_npm_package, prebuild_apple_dependencies]
strategy:
fail-fast: false
matrix:
flavor: [Debug, Release]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup xcode
uses: ./.github/actions/setup-xcode
with:
platform: ios
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Run yarn
uses: ./.github/actions/yarn-install
- name: Setup ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6.10
- name: Download React Native Package
uses: actions/download-artifact@v4
with:
name: react-native-package
path: /tmp/react-native-tmp
- name: Print /tmp folder
run: ls -lR /tmp/react-native-tmp
- name: Download ReactNativeDependencies
uses: actions/download-artifact@v4
with:
name: ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
path: /tmp/third-party
- name: Print third-party folder
shell: bash
run: ls -lR /tmp/third-party
- name: Download React Native Prebuilds
uses: actions/download-artifact@v4
with:
name: ReactCore${{ matrix.flavor }}.xcframework.tar.gz
path: /tmp/ReactCore
- name: Print ReactCore folder
shell: bash
run: ls -lR /tmp/ReactCore
- name: Configure git
shell: bash
run: |
git config --global user.email "react-native-bot@meta.com"
git config --global user.name "React Native Bot"
- name: Prepare artifacts
run: |
REACT_NATIVE_PKG=$(find /tmp/react-native-tmp -type f -name "*.tgz")
echo "React Native tgs is $REACT_NATIVE_PKG"
# 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
cd /tmp/RNTestProject/ios
bundle install
NEW_ARCH_ENABLED=1
export RCT_USE_LOCAL_RN_DEP=/tmp/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
# Disable prebuilds for now, as they are causing issues with E2E tests for 0.82-stable branch
# export RCT_TESTONLY_RNCORE_TARBALL_PATH="/tmp/ReactCore/ReactCore${{ matrix.flavor }}.xcframework.tar.gz"
RCT_NEW_ARCH_ENABLED=$NEW_ARCH_ENABLED bundle exec pod install
xcodebuild \
-scheme "RNTestProject" \
-workspace RNTestProject.xcworkspace \
-configuration "${{ matrix.flavor }}" \
-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-id: org.reactjs.native.example.RNTestProject
maestro-flow: ./scripts/e2e/.maestro/
flavor: ${{ matrix.flavor }}
working-directory: /tmp/RNTestProject
test_e2e_android_templateapp:
runs-on: 4-core-ubuntu
needs: build_npm_package
strategy:
fail-fast: false
matrix:
flavor: [debug, release]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Run yarn
uses: ./.github/actions/yarn-install
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'zulu'
- name: Download Maven Local
uses: actions/download-artifact@v4
with:
name: maven-local
path: /tmp/react-native-tmp/maven-local
- name: Download React Native Package
uses: actions/download-artifact@v4
with:
name: react-native-package
path: /tmp/react-native-tmp
- 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"
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
echo "Feed maven local to gradle.properties"
cd /tmp/RNTestProject
echo "react.internal.mavenLocalRepo=$MAVEN_LOCAL" >> android/gradle.properties
# 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
- name: Run E2E Tests
uses: ./.github/actions/maestro-android
timeout-minutes: 60
with:
app-path: /tmp/RNTestProject/android/app/build/outputs/apk/${{ matrix.flavor }}/app-${{ matrix.flavor }}.apk
app-id: com.rntestproject
maestro-flow: ./scripts/e2e/.maestro/
install-java: 'false'
flavor: ${{ matrix.flavor }}
working-directory: /tmp/RNTestProject
run_fantom_tests:
runs-on: 8-core-ubuntu
needs: [set_release_type]
container:
image: reactnativecommunity/react-native-android:latest
env:
TERM: "dumb"
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }}
ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build and Test Fantom
uses: ./.github/actions/run-fantom-tests
with:
release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
build_android:
runs-on: 8-core-ubuntu
needs: [set_release_type]
container:
image: reactnativecommunity/react-native-android:latest
env:
TERM: "dumb"
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }}
ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build Android
uses: ./.github/actions/build-android
with:
release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
test_e2e_android_rntester:
runs-on: 4-core-ubuntu
needs: [build_android]
strategy:
fail-fast: false
matrix:
flavor: [debug, release]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Install node dependencies
uses: ./.github/actions/yarn-install
- name: Download APK
uses: actions/download-artifact@v4
with:
name: rntester-${{ matrix.flavor }}
path: ./packages/rn-tester/android/app/build/outputs/apk/${{ matrix.flavor }}/
- name: Print folder structure
run: ls -lR ./packages/rn-tester/android/app/build/outputs/apk/${{ matrix.flavor }}/
- name: Run E2E Tests
uses: ./.github/actions/maestro-android
timeout-minutes: 60
with:
app-path: ./packages/rn-tester/android/app/build/outputs/apk/${{ matrix.flavor }}/app-x86-${{ matrix.flavor }}.apk
app-id: com.facebook.react.uiapp
maestro-flow: ./packages/rn-tester/.maestro
flavor: ${{ matrix.flavor }}
build_npm_package:
runs-on: 8-core-ubuntu
needs:
[
set_release_type,
build_android,
prebuild_apple_dependencies,
prebuild_react_native_core,
]
container:
image: reactnativecommunity/react-native-android:latest
env:
TERM: "dumb"
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build NPM Package
uses: ./.github/actions/build-npm-package
with:
release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}
gradle-cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
test_android_helloworld:
runs-on: 4-core-ubuntu
needs: build_npm_package
container:
image: reactnativecommunity/react-native-android:latest
env:
# Set the encoding to resolve a known character encoding issue with decompressing tar.gz files in conatiners
# via Gradle: https://github.com/gradle/gradle/issues/23391#issuecomment-1878979127
LC_ALL: C.UTF8
YARN_ENABLE_IMMUTABLE_INSTALLS: false
TERM: "dumb"
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
TARGET_ARCHITECTURE: "arm64-v8a"
continue-on-error: true
strategy:
fail-fast: false
matrix:
flavor: [Debug, Release]
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:
name: react-native-package
path: build
- name: Download maven-local artifact
uses: actions/download-artifact@v4.1.3
with:
name: maven-local
path: /tmp/maven-local
- name: Setup gradle
uses: ./.github/actions/setup-gradle
with:
cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
- name: Run yarn install
uses: ./.github/actions/yarn-install
- name: Set nightly Hermes versions
shell: bash
run: |
node ./scripts/releases/use-hermes-nightly.js
- name: Run yarn install again, with the correct hermes version
uses: ./.github/actions/yarn-install
- name: Prepare the Helloworld application
shell: bash
run: node ./scripts/e2e/init-project-e2e.js --useHelloWorld --pathToLocalReactNative "$GITHUB_WORKSPACE/build/$(cat build/react-native-package-version)"
- name: Build the Helloworld application for ${{ matrix.flavor }} with Architecture set to New Architecture.
shell: bash
run: |
cd private/helloworld/android
args=()
if [[ ${{ matrix.flavor }} == "Release" ]]; then
args+=(--prod)
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
with:
name: helloworld-apk-${{ matrix.flavor }}-NewArch-hermes
path: ./private/helloworld/android/app/build/outputs/apk/
compression-level: 0
test_ios_helloworld_with_ruby_3_2_0:
runs-on: macos-15
needs: [prebuild_apple_dependencies, prebuild_react_native_core]
env:
PROJECT_NAME: iOSTemplateProject
YARN_ENABLE_IMMUTABLE_INSTALLS: false
steps:
- name: Checkout
uses: actions/checkout@v4
- uses: ./.github/actions/test-ios-helloworld
with:
ruby-version: 3.2.0
flavor: Debug
test_ios_helloworld:
runs-on: macos-15
needs: [prebuild_apple_dependencies, prebuild_react_native_core]
strategy:
matrix:
flavor: [Debug, Release]
use_frameworks: [StaticLibraries, DynamicFrameworks]
exclude:
# This config is tested with Ruby 3.2.0. Let's not double test it.
- flavor: Debug
use_frameworks: StaticLibraries
env:
PROJECT_NAME: iOSTemplateProject
YARN_ENABLE_IMMUTABLE_INSTALLS: false
steps:
- name: Checkout
uses: actions/checkout@v4
- uses: ./.github/actions/test-ios-helloworld
with:
flavor: ${{ matrix.flavor }}
use-frameworks: ${{ matrix.use_frameworks }}
test_js:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
strategy:
fail-fast: false
matrix:
node-version: ["24.4.1", "22", "20.19.4"]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Test JS
uses: ./.github/actions/test-js
with:
node-version: ${{ matrix.node-version }}
lint:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run all the linters
uses: ./.github/actions/lint
with:
github-token: ${{ env.GH_TOKEN }}
# This job should help with the E2E flakyness.
# In case E2E tests fails, it launches a new retry-workflow workflow, passing the current run_id as input.
# The retry-workflow reruns only the failed jobs of the current test-all workflow using
# ```
# gh run rerun ${{ inputs.run_id }} --failed
# ```
# From https://stackoverflow.com/a/78314483 it seems like that adding the extra workflow
# rather then calling directly this command should improve stability of this solution.
# This is exactly the same as rerunning failed tests from the GH UI, but automated.
rerun-failed-jobs:
runs-on: ubuntu-latest
needs: [test_e2e_ios_rntester, test_e2e_android_rntester, test_e2e_ios_templateapp, test_e2e_android_templateapp]
if: ${{ github.ref == 'refs/heads/main' && always() }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Rerun failed jobs in the current workflow
env:
GH_TOKEN: ${{ github.token }}
run: |
SHOULD_RETRY=${{fromJSON(github.run_attempt) < 3}}
if [[ $SHOULD_RETRY == "false" ]]; then
exit 0
fi
RNTESTER_ANDROID_FAILED=${{ needs.test_e2e_android_rntester.result == 'failure' }}
TEMPLATE_ANDROID_FAILED=${{ needs.test_e2e_android_templateapp.result == 'failure' }}
RNTESTER_IOS_FAILED=${{ needs.test_e2e_ios_rntester.result == 'failure' }}
TEMPLATE_IOS_FAILED=${{ needs.test_e2e_ios_templateapp.result == 'failure' }}
echo "RNTESTER_ANDROID_FAILED: $RNTESTER_ANDROID_FAILED"
echo "TEMPLATE_ANDROID_FAILED: $TEMPLATE_ANDROID_FAILED"
echo "RNTESTER_IOS_FAILED: $RNTESTER_IOS_FAILED"
echo "TEMPLATE_IOS_FAILED: $TEMPLATE_IOS_FAILED"
if [[ $RNTESTER_ANDROID_FAILED == "true" || $TEMPLATE_ANDROID_FAILED == "true" || $RNTESTER_IOS_FAILED == "true" || $TEMPLATE_IOS_FAILED == "true" ]]; then
echo "Rerunning failed jobs in the current workflow"
gh workflow run retry-workflow.yml -F run_id=${{ github.run_id }}
fi
@@ -1,49 +0,0 @@
name: Validate DotSlash Artifacts
on:
workflow_dispatch:
release:
types: [published]
push:
branches:
- main
paths:
- packages/debugger-shell/bin/react-native-devtools
- "scripts/releases/**"
- package.json
- yarn.lock
pull_request:
branches:
- main
paths:
- packages/debugger-shell/bin/react-native-devtools
- "scripts/releases/**"
- package.json
- yarn.lock
# Same time as the nightly build: 2:15 AM UTC
schedule:
- cron: "15 2 * * *"
jobs:
validate-dotslash-artifacts:
runs-on: ubuntu-latest
if: github.repository == 'facebook/react-native'
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Install dependencies
uses: ./.github/actions/yarn-install
- name: Configure Git
shell: bash
run: |
git config --local user.email "bot@reactnative.dev"
git config --local user.name "React Native Bot"
- name: Validate DotSlash artifacts
uses: actions/github-script@v6
with:
script: |
const {validateDotSlashArtifacts} = require('./scripts/releases/validate-dotslash-artifacts.js');
await validateDotSlashArtifacts();
+16 -122
View File
@@ -20,43 +20,21 @@ DerivedData
*.ipa
*.xcuserstate
project.xcworkspace
**/.xcode.env.local
# Gradle
/build/
/packages/rn-tester/build
/packages/rn-tester/android/app/.cxx/
/packages/rn-tester/android/app/build/
/packages/rn-tester/android/app/gradle/
/packages/rn-tester/android/app/gradlew
/packages/rn-tester/android/app/gradlew.bat
/packages/react-native/build/
/packages/react-native/ReactAndroid/build/
/packages/react-native/ReactAndroid/.cxx/
/packages/react-native/ReactAndroid/gradle/
/packages/react-native/ReactAndroid/gradlew
/packages/react-native/ReactAndroid/gradlew.bat
/packages/react-native/ReactAndroid/external-artifacts/build/
/packages/react-native/ReactAndroid/external-artifacts/artifacts/
/packages/react-native/ReactAndroid/hermes-engine/build/
/packages/react-native/ReactAndroid/hermes-engine/.cxx/
/private/helloworld/android/app/build/
/private/helloworld/android/build/
/packages/react-native-popup-menu-android/android/build/
/RNTester/android/app/build/
/RNTester/android/app/gradle/
/RNTester/android/app/gradlew
/RNTester/android/app/gradlew.bat
/ReactAndroid/build/
# Buck
.buckd
buck-out
/.lsp.buckd
/.lsp-buck-out
/packages/react-native/ReactAndroid/src/main/jni/prebuilt/lib/
/packages/react-native/ReactAndroid/src/main/gen
/.cpplsp.buckd
# Android Studio
.project
.settings
.classpath
/ReactAndroid/src/main/jni/prebuilt/lib/armeabi-v7a/
/ReactAndroid/src/main/jni/prebuilt/lib/x86/
/ReactAndroid/src/main/gen
# Watchman
.watchmanconfig
@@ -66,116 +44,32 @@ buck-out
.gradle
local.properties
*.iml
/packages/react-native/android/*
!/packages/react-native/android/README.md
.kotlin/
/android/
# Node
node_modules
*.log
.nvm
/bots/node_modules/
package-lock.json
# OS X
.DS_Store
# Test generated files
/ReactAndroid/src/androidTest/assets/AndroidTestBundle.js
*.js.meta
/coverage
/third-party
# Test Reports
/reports
# Stack Dumps generated when programs crash (Ex. bash.exe.stackdump on Win)
*.stackdump
# Root dir shouldn't have Xcode project
/*.xcodeproj
# ReactCommon subdir shouldn't have Xcode project
/packages/react-native/ReactCommon/**/*.xcodeproj
/ReactCommon/**/*.xcodeproj
RNTester/build
# Libs that shouldn't have Xcode project
/packages/react-native/Libraries/FBLazyVector/**/*.xcodeproj
/packages/react-native/Libraries/Required/**/*.xcodeproj
/packages/react-native/React/CoreModules/**/*.xcodeproj
/packages/react-native/React/FBReactNativeSpec/**/*.xcodeproj
/packages/react-native-codegen/**/*.xcodeproj
/packages/rn-tester/**/*.xcodeproj
# Ruby Gems (Bundler)
/packages/react-native/vendor
/private/helloworld/vendor
.ruby-version
/**/.ruby-version
vendor/
# iOS / CocoaPods
/private/helloworld/ios/build/
/private/helloworld/ios/Pods/
/private/helloworld/ios/Podfile.lock
/packages/rn-tester/bin/
/packages/rn-tester/cache/
/packages/rn-tester/extensions/
/packages/rn-tester/gems/
/packages/rn-tester/specifications/
/packages/rn-tester/Gemfile.lock
/packages/**/RCTLegacyInteropComponents.mm
/packages/sourcemap.ios.map
# Ignore RNTester specific Pods, but keep the __offline_mirrors__ here.
/packages/rn-tester/Pods/*
!/packages/rn-tester/Pods/__offline_mirrors_hermes__
!/packages/rn-tester/Pods/__offline_mirrors_jsc__
# Swift Package build folder
/packages/react-native/.build
/packages/react-native/.swiftpm
/packages/react-native/React/includes/
# @react-native/codegen
/packages/react-native/React/FBReactNativeSpec/
/packages/react-native-codegen/lib
/packages/react-native-codegen/tmp/
/packages/rn-tester/NativeModuleExample/ScreenshotManagerSpec*
/**/RCTThirdPartyFabricComponentsProvider.*
# @react-native/codegen-typescript-test
/private/react-native-codegen-typescript-test/lib
# Additional SDKs
/packages/react-native/sdks/download
/packages/react-native/sdks/hermes
/packages/react-native/sdks/hermesc
/packages/react-native/sdks/hermes-engine/hermes-engine-from-local-source-dir.tar.gz
# iOS prebuilds
/packages/react-native/third-party/
fix_*.patch
*.xcframework
# Visual Studio Code (config dir - if present, this merges user defined
# workspace settings on top of react-native.code-workspace)
/.vscode
# Visual Studio
.vs
# Android memory profiler files
*.hprof
# Temporary files created by Metro to check the health of the file watcher
.metro-health-check*
# Jest Integration
/private/react-native-fantom/build/
/private/react-native-fantom/.out/
/private/react-native-fantom/tester/build/
# [Experimental] Generated TS type definitions
/packages/**/types_generated/
/packages/debugger-shell/build/
/packages/*/dist/
# CocoaPods
/template/ios/Pods/
/template/ios/Podfile.lock
-43
View File
@@ -1,43 +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
*/
import relativeLinksRule from 'markdownlint-rule-relative-links';
const config = {
config: {
default: false,
'heading-increment': true,
'no-reversed-links': true,
'no-missing-space-atx': true,
'no-duplicate-heading': {
siblings_only: true,
},
'single-title': true,
'no-trailing-punctuation': true,
'no-space-in-emphasis': true,
'no-space-in-code': true,
'no-space-in-links': true,
'fenced-code-language': true,
'first-line-heading': true,
'no-empty-links': true,
'no-alt-text': true,
'link-fragments': true,
'table-column-count': true,
// The rest of default rules are already handled by prettier
// Custom rules
'relative-links': true,
},
globs: ['**/__docs__/*.md'],
ignores: ['**/node_modules', '__docs__/README-template.md'],
customRules: [relativeLinksRule],
};
export default config;
+1
View File
@@ -0,0 +1 @@
8.11.3
-12
View File
@@ -1,12 +0,0 @@
# Ignore Pods
**/Pods
# Ignore hermes as it is downloaded from the react_native_pods
**/sdks/hermes
**/sdks/downloads
packages/*/dist
vendor
packages/**/types_generated/
packages/react-native-codegen/e2e/__test_fixtures__/modules/NativeEnumTurboModule.js

Some files were not shown because too many files have changed in this diff Show More