diff --git a/build.gradle.kts b/build.gradle.kts index 4ed9ea7dc9a2..f5e150bf738f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -100,6 +100,22 @@ tasks.register("publishAllToMavenTempLocal") { ":packages:react-native:ReactAndroid:hermes-engine:publishAllPublicationsToMavenTempLocalRepository") } +// Added to allow us to publish patched Android JARs to Gitlab. This is part +// of the "Patching React Native" process at: +// https://www.notion.so/wanderlog/Patching-React-Native-17b4797ed24d481eb2155c9daec1ba98?source=copy_link +tasks.register("publishAllToGitLab") { + description = "Publish all the release artifacts to a GitLab Maven Repository." + + val gitlabKey = project.property("gitlabPrivateToken") as? String + if (gitlabKey == null) { + throw IllegalStateException("gitlabPrivateToken property is not set. Set it in your ~/.gradle/gradle.properties file to a full-access token") + } + + // The Release pubName is derived by searching for MavenPublication in the codebase + dependsOn(":packages:react-native:ReactAndroid:publishAllPublicationsToGitLabRepository") + dependsOn(":packages:react-native:ReactAndroid:hermes-engine:publishAllPublicationsToGitLabRepository") +} + tasks.register("publishAndroidToSonatype") { description = "Publish the Android artifacts to Sonatype (Maven Central or Snapshot repository)" dependsOn(":packages:react-native:ReactAndroid:publishToSonatype") diff --git a/packages/react-native/ReactAndroid/publish.gradle b/packages/react-native/ReactAndroid/publish.gradle index 32287a7c8139..99c190415f72 100644 --- a/packages/react-native/ReactAndroid/publish.gradle +++ b/packages/react-native/ReactAndroid/publish.gradle @@ -68,6 +68,27 @@ publishing { name = "mavenTempLocal" url = mavenTempLocalUrl } + + // Added to allow us to publish patched Android JARs to Gitlab. This + // is part of the "Patching React Native" process at: + // https://www.notion.so/wanderlog/Patching-React-Native-17b4797ed24d481eb2155c9daec1ba98?source=copy_link + // + // Added based on https://docs.gitlab.com/ee/user/packages/gradle_repository/#authenticate-with-a-personal-access-token-or-deploy-token-in-gradle + // to publish our forked package to Maven + maven { + // URL modified based on https://docs.gitlab.com/ee/api/packages/maven.html#upload-a-package-file + // Project ID is obtained from the itineraries project on Gitlab + url = "https://gitlab.com/api/v4/projects/9347980/packages/maven" + name = "GitLab" + // Modified based on https://stackoverflow.com/a/61339469 + credentials(HttpHeaderCredentials) { + name = "Private-Token" + value = project.property("gitlabPrivateToken") + } + authentication { + header(HttpHeaderAuthentication) + } + } } if (signingKey && signingPwd) { diff --git a/scripts/build-package.js b/scripts/build-package.js new file mode 100644 index 000000000000..9ad557f2f0b4 --- /dev/null +++ b/scripts/build-package.js @@ -0,0 +1,132 @@ +// @flow +const { + downloadHermesSourceTarball, + expandHermesSourceTarball, +} = require('../packages/react-native/scripts/hermes/hermes-utils'); +const { REPO_ROOT } = require('./consts'); +const fs = require('fs'); +const { rm } = require('fs/promises'); +const {cp, exec} = require('shelljs'); + +/** + * This script is used as a part of Patching React Native. See: + * https://www.notion.so/wanderlog/Patching-React-Native-17b4797ed24d481eb2155c9daec1ba98?source=copy_link + * + * This section goes over how we created it: + * ["How did we figure out the steps for Create scripts for building patched React Native](https://www.notion.so/wanderlog/Patching-React-Native-17b4797ed24d481eb2155c9daec1ba98?source=copy_link#2aef9a6861f68016a0def8edec2d3d5a) + * + * This code is largely copied from other files per the comments below. + * + * If this script fails, we can debug it by running it with `CI=true` to see + * all the intermediate commands the Shell scripts run, since the scripts + * enable `set -x` when `CI` is set. + */ +async function buildPackage() { + const reactNativePackagePath = `${REPO_ROOT}/packages/react-native`; + + // This part of the code downloads the Hermes source code and expands it. + // Start copied from scripts/release-testing/utils/testing-utils.js + const hermesCoreSourceFolder = `${reactNativePackagePath}/sdks/hermes`; + + if (!fs.existsSync(hermesCoreSourceFolder)) { + console.info('The Hermes source folder is missing. Downloading...'); + downloadHermesSourceTarball(); + expandHermesSourceTarball(); + } + + // need to move the scripts inside the local hermes cloned folder + // cp sdks/hermes-engine/utils/*.sh /utils/. + cp( + `${reactNativePackagePath}/sdks/hermes-engine/hermes-engine.podspec`, + `${reactNativePackagePath}/sdks/hermes/hermes-engine.podspec`, + ); + cp( + `${reactNativePackagePath}/sdks/hermes-engine/hermes-utils.rb`, + `${reactNativePackagePath}/sdks/hermes/hermes-utils.rb`, + ); + cp( + `${reactNativePackagePath}/sdks/hermes-engine/utils/*.sh`, + `${reactNativePackagePath}/sdks/hermes/utils/.`, + ); + // End copied from scripts/release-testing/utils/testing-utils.js + + // Builds the types_generated. We figured this out by asking: + // "What code in this project creates the types_generated directory?" + exec('yarn build-types', {cwd: REPO_ROOT}); + + // Builds the FBReactNativeSpec. We figured this out by asking: + // "What code in this project creates the FBReactNativeSpec directory?" + exec('yarn install && yarn prepack', {cwd: reactNativePackagePath}); + // We don't need the README.md file + await rm(`${reactNativePackagePath}/README.md`); + + // build-mac-framework.sh builds hermes and hermesc binaries for MacOS. + // I figured this out by: + // + // 1. Running the code in `buildAllArtifacts` below (uncomment the line) + // below + // 2. Running `find . -name hermes` and seeing that the file was in + // `./packages/react-native/sdks/hermes/build_macosx/bin/hermes` + // 3. Finding references to build_macosx and seeing it was likely created + // by the build_apple_framework function + // 4. Finding callers of the build_apple_framework function + + // MAC_DEPLOYMENT_TARGET is used by get_mac_deployment_target in + // build-mac-framework.sh. The value to set is taken from + // publish-release.yml + process.env.MAC_DEPLOYMENT_TARGET = "10.15"; + exec( + 'bash ./utils/build-mac-framework.sh', + {cwd: `${reactNativePackagePath}/sdks/hermes`}, + ); + + // Uncomment this to build all the artifacts for Hermes, including ones that we + // don't need. + // buildAllArtifacts(hermesCoreSourceFolder); + + // We figured out the files to copy by running: + // `find . -name hermesc` and and `find . -name hermes | grep bin` + // + // We figured out the destination directory by looking at the the paths in + // the official React Native NPM package: https://www.npmjs.com/package/react-native/v/0.81.5?activeTab=code + const hermesDir = `${reactNativePackagePath}/sdks/hermes/build_macosx/bin`; + const hermescDir = `${reactNativePackagePath}/sdks/hermes/build_host_hermesc/bin`; + const destinationDir = `${reactNativePackagePath}/sdks/hermesc/osx-bin`; + console.info(`Copying files from ${hermesDir} to ${destinationDir}`); + console.info(`Copying files from ${hermescDir} to ${destinationDir}`); + await fs.promises.mkdir(destinationDir, { recursive: true }); + cp('-r', `${hermesDir}/*`, `${destinationDir}/`); + cp('-r', `${hermescDir}/*`, `${destinationDir}/`); +} + +/** + * This function builds all the artifacts for Hermes, including ones that we + * don't need. We used it initially to figure out which subtasks built the hermes + * and hermesc binaries. + */ +// eslint-disable-next-line no-unused-vars +function buildAllArtifacts(hermesCoreSourceFolder) { + // These versions were copied from publish-release.yml + process.env.IOS_DEPLOYMENT_TARGET = '15.1'; + process.env.MAC_DEPLOYMENT_TARGET = '10.15'; + process.env.XROS_DEPLOYMENT_TARGET = '1.0'; + + // Start copied from scripts/release-testing/utils/testing-utils.js + const jsiFolder = `${reactNativePackagePath}/ReactCommon/jsi`; + + const buildTypeiOSArtifacts = 'Debug'; + + // the android ones get set into /private/tmp/maven-local + const localMavenPath = '/private/tmp/maven-local'; + + // Generate native files for iOS + generateiOSArtifacts( + jsiFolder, + hermesCoreSourceFolder, + buildTypeiOSArtifacts, + localMavenPath, + ); + // End copied from scripts/release-testing/utils/testing-utils.js +} + +buildPackage(); diff --git a/scripts/move-react-native-package.sh b/scripts/move-react-native-package.sh new file mode 100755 index 000000000000..fb9537decfb7 --- /dev/null +++ b/scripts/move-react-native-package.sh @@ -0,0 +1,138 @@ +#!/bin/bash + +set -e + +SAVED_ROOT_FILES_NAME="saved-root-files" + +# Parse command line arguments +help_text_and_exit() { + cat < originalFiles.txt` + # 3. Installing our fork of react-native + # 4. Running the same command to list the files again + # 5. Diffing the two files to see what was missed + sed -E -i '' '/^\/?vendor/d' "$REPO_ROOT/.gitignore" + sed -E -i '' '/^\/?sdks\/hermesc/d' "$REPO_ROOT/.gitignore" + sed -i '' '/types_generated/d' "$REPO_ROOT/.gitignore" + sed -i '' '/FBReactNativeSpec/d' "$REPO_ROOT/.gitignore" + echo "/saved-root-files/" >> "$REPO_ROOT/.gitignore" + + echo "Moving all files to $SAVED_ROOT_FILES_PATH" + for item in "$REPO_ROOT"/*; do + item_name=$(basename "$item") + # Skip the directory itself + if [ "$item_name" != "$SAVED_ROOT_FILES_NAME" ]; then + echo "- Moving $item_name to $SAVED_ROOT_FILES_PATH" + mv -f "$item" "$SAVED_ROOT_FILES_PATH/" + fi + done + + echo "Moving /packages/react-native contents to root..." + + mv -f "$SAVED_ROOT_FILES_PATH/packages/react-native"/* "$REPO_ROOT/" + + echo "Script completed successfully" + +# Reverse moves +else + echo "Reversing operations: moving files from $SAVED_ROOT_FILES_NAME back to root..." + + if [ ! -d "$SAVED_ROOT_FILES_PATH" ]; then + echo "Error: $SAVED_ROOT_FILES_NAME directory not found. Nothing to reverse." + exit 1 + fi + + echo "Moving react-native package contents to within saved-root-files/packages" # Ensure the directory exists + mkdir -p "$SAVED_ROOT_FILES_PATH/packages/react-native" + + for item in "$REPO_ROOT"/*; do + item_name=$(basename "$item") + if [ "$item_name" != "$SAVED_ROOT_FILES_NAME" ]; then + echo "- Moving $item_name back to packages/react-native" + mv -f "$item" "$SAVED_ROOT_FILES_NAME/packages/react-native/" + fi + done + + echo "Moving .gitignore back to root" + mv -f "$SAVED_ROOT_FILES_PATH/.gitignore" "$REPO_ROOT/.gitignore" + + echo "Moving all files back to root" + mv -f "$SAVED_ROOT_FILES_PATH"/* "$REPO_ROOT/" + + echo "Deleting $SAVED_ROOT_FILES_NAME" + rm -rf "$SAVED_ROOT_FILES_PATH" + + echo "Reverse operation completed successfully" + exit 0 +fi