diff --git a/.github/scripts/getNewPatchedRNVersion.sh b/.github/scripts/getNewPatchedRNVersion.sh new file mode 100755 index 000000000000..49345e71b1c5 --- /dev/null +++ b/.github/scripts/getNewPatchedRNVersion.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +if [ -z "$GITHUB_TOKEN" ]; then + echo "GITHUB_TOKEN env variable is not set" + exit 1 +fi + +if [[ "$IS_HYBRID_BUILD" == "true" ]]; then + readonly PACKAGE="react-hybrid" +else + readonly PACKAGE="react-standalone" +fi + +VERSION="$(jq -r '.dependencies["react-native"]' package.json)" +readonly VERSION + +# List all versions of the package +PACKAGE_VERSIONS="$(gh api "/orgs/Expensify/packages/maven/com.expensify.${PACKAGE}.react-android/versions" --paginate --jq '.[].name')" + +# Filter only versions matching the base React Native version +PACKAGE_VERSIONS="$(echo "$PACKAGE_VERSIONS" | grep "$VERSION")" + +# Grab the highest patch version from there +LATEST_PATCHED_VERSION="$(echo "$PACKAGE_VERSIONS" | sort | tail -n1)" + +if [[ -n "$LATEST_PATCHED_VERSION" ]]; then + PATCH_ITERATION=${LATEST_PATCHED_VERSION##*-} + INCREMENTED_PATCH_ITERATION=$((PATCH_ITERATION + 1)) + echo "${VERSION}-${INCREMENTED_PATCH_ITERATION}" +else + echo "$VERSION-0" +fi diff --git a/.github/workflows/publishReactNativeAndroidArtifacts.yml b/.github/workflows/publishReactNativeAndroidArtifacts.yml new file mode 100644 index 000000000000..30c2f05ecd61 --- /dev/null +++ b/.github/workflows/publishReactNativeAndroidArtifacts.yml @@ -0,0 +1,139 @@ +name: Publish React Native Android Artifacts + +on: + push: + branches: + - main + paths: + - package.json + - patches/react-native+*.patch + - patches/@react-native+*.patch + - Mobile-Expensify + +jobs: + publish: + runs-on: ${{ github.repository_owner == 'Expensify' && 'ubuntu-latest-xl' || 'ubuntu-latest' }} + strategy: + matrix: + is_hybrid: [true, false] + steps: + # v4 + - name: Checkout + uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 + with: + submodules: ${{ matrix.is_hybrid }} + ref: ${{ github.event.before }} + + - name: Get previous App commit hash + id: getOldAppHash + run: echo "HASH=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + + - name: Get previous Mobile-Expensify commit hash + if: ${{ matrix.is_hybrid == 'true' }} + id: getOldMobileExpensifyHash + run: echo "HASH=$(git rev-parse :Mobile-Expensify)" >> "$GITHUB_OUTPUT" + + - name: Get previous react-native version + id: getOldVersion + run: echo "VERSION=$(jq -r '.dependencies["react-native"]' package.json)" >> "$GITHUB_OUTPUT" + + - name: Checkout new ref + run: | + git fetch origin ${{ github.event.after }} --depth=1 + git checkout ${{ github.event.after }} + git submodule update + + - name: Get new App commit hash + id: getNewAppHash + run: echo "HASH=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + + - name: Get new Mobile-Expensify commit hash + if: ${{ matrix.is_hybrid == 'true' }} + id: getNewMobileExpensifyHash + run: echo "HASH=$(git rev-parse :Mobile-Expensify)" >> "$GITHUB_OUTPUT" + + - name: Get new react-native version + id: getNewVersion + run: echo "VERSION=$(jq -r '.dependencies["react-native"]' package.json)" >> "$GITHUB_OUTPUT" + + - name: Check if version changed + id: didVersionChange + run: | + readonly DID_VERSION_CHANGE=${{ steps.getOldVersion.outputs.VERSION != steps.getNewVersion.outputs.VERSION && 'true' || 'false' }} + echo "DID_VERSION_CHANGE=$DID_VERSION_CHANGE" >> "$GITHUB_OUTPUT" + if [[ "$DID_VERSION_CHANGE" == 'true' ]]; then + echo "::notice::Detected react-native version bump (${{ steps.getOldVersion.outputs.VERSION }} -> ${{ steps.getNewVersion.outputs.VERSION }})" + fi + + - name: Check if patches changed + id: didPatchesChange + run: | + if git diff --exit-code --name-only ${{ steps.getOldAppHash.outputs.HASH }}..${{ steps.getNewAppHash.outputs.HASH }} -- patches/react-native+*.patch patches/@react-native+*.patch; then + echo "::notice::Detected changes in patches" + echo "DID_PATCHES_CHANGE=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + + if [[ '${{ matrix.is_hybrid }}' == 'true' ]]; then + if git -C Mobile-Expensify diff --exit-code --name-only ${{ steps.getOldMobileExpensifyHash.outputs.HASH }}..${{ steps.getNewMobileExpensifyHash.outputs.HASH }} -- patches/react-native+*.patch patches/@react-native+*.patch; then + echo "::notice::Detected changes in patches" + echo "DID_PATCHES_CHANGE=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + fi + + echo "DID_PATCHES_CHANGE=false" >> "$GITHUB_OUTPUT" + + - name: Check if we should build and publish the package + id: shouldPublish + run: | + if [[ '${{ steps.didVersionChange.outputs.DID_VERSION_CHANGE }}' == 'true' || '${{ steps.didPatchesChange.outputs.DID_PATCHES_CHANGE }}' == 'true' ]]; then + echo "SHOULD_PUBLISH=true" >> "$GITHUB_OUTPUT" + else + echo "::notice::No relevant changes, skipping publishing a new React Native build" + echo "SHOULD_PUBLISH=false" >> "$GITHUB_OUTPUT" + fi + + - name: Setup Node + if: ${{ steps.shouldPublish.outputs.SHOULD_PUBLISH == 'true' }} + uses: ./.github/actions/composite/setupNode + with: + IS_HYBRID_BUILD: ${{ matrix.is_hybrid }} + + # v4 + - name: Setup Java + if: ${{ steps.shouldPublish.outputs.SHOULD_PUBLISH == 'true' }} + uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 + with: + distribution: oracle + java-version: 17 + + # v4 + - name: Setup Gradle + if: ${{ steps.shouldPublish.outputs.SHOULD_PUBLISH == 'true' }} + uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 + + - name: Determine new patched RN version + if: ${{ steps.shouldPublish.outputs.SHOULD_PUBLISH == 'true' }} + id: getNewPatchedVersion + run: echo "NEW_PATCHED_VERSION=$(./.github/scripts/getNewPatchedRNVersion.sh)" >> "$GITHUB_OUTPUT" + env: + GITHUB_TOKEN: ${{ github.token }} + IS_HYBRID_BUILD: ${{ matrix.is_hybrid }} + + - name: Build and publish RN artifacts + if: ${{ steps.shouldPublish.outputs.SHOULD_PUBLISH == 'true' }} + working-directory: ${{ matrix.is_hybrid == 'true' && 'Mobile-Expensify/Android' || 'android' }} + run: | + echo "Starting artifacts build for ${{ matrix.is_hybrid == 'true' && 'HybridApp' || 'NewDot Standalone' }}" + echo "Version: ${{ env.PATCHED_VERSION }}" + echo "Commit hash: ${{ env.COMMIT_HASH }}" + export ORG_GRADLE_PROJECT_reactNativeArchitectures="armeabi-v7a,arm64-v8a,x86,x86_64" + ./gradlew buildReactNativeArtifacts -x lint -x test -x check + ./gradlew publishReactNativeArtifacts + env: + GH_PUBLISH_ACTOR: ${{ github.actor }} + GH_PUBLISH_TOKEN: ${{ github.token }} + IS_HYBRID_BUILD: ${{ matrix.is_hybrid }} + PATCHED_VERSION: ${{ steps.getNewPatchedVersion.outputs.NEW_PATCHED_VERSION }} + COMMIT_HASH: ${{ github.event.after }} diff --git a/android/build.gradle b/android/build.gradle index fdd6b5ab2e45..0bbb4f8f611d 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -78,3 +78,11 @@ allprojects { } apply plugin: "com.facebook.react.rootproject" + +task buildReactNativeArtifacts { + dependsOn(gradle.includedBuild('react-native').task(':packages:react-native:ReactAndroid:build')) +} + +task publishReactNativeArtifacts { + dependsOn(gradle.includedBuild('react-native').task(':packages:react-native:ReactAndroid:publishReleasePublicationToMavenRepository')) +} diff --git a/patches/react-native+0.77.1+025.patch b/patches/react-native+0.77.1+025.patch new file mode 100644 index 000000000000..60c7e59ce0df --- /dev/null +++ b/patches/react-native+0.77.1+025.patch @@ -0,0 +1,73 @@ +diff --git a/node_modules/react-native/.DS_Store b/node_modules/react-native/.DS_Store +new file mode 100644 +index 0000000..60811a9 +Binary files /dev/null and b/node_modules/react-native/.DS_Store differ +diff --git a/node_modules/react-native/ReactAndroid/.DS_Store b/node_modules/react-native/ReactAndroid/.DS_Store +new file mode 100644 +index 0000000..8bfcb73 +Binary files /dev/null and b/node_modules/react-native/ReactAndroid/.DS_Store differ +diff --git a/node_modules/react-native/ReactAndroid/publish.gradle b/node_modules/react-native/ReactAndroid/publish.gradle +index 32287a7..5607be3 100644 +--- a/node_modules/react-native/ReactAndroid/publish.gradle ++++ b/node_modules/react-native/ReactAndroid/publish.gradle +@@ -13,7 +13,11 @@ def signingKey = findProperty("SIGNING_KEY") + def signingPwd = findProperty("SIGNING_PWD") + + def reactAndroidProjectDir = project(':packages:react-native:ReactAndroid').projectDir +-def mavenTempLocalUrl = "file:///tmp/maven-local" ++def mavenURL = "https://maven.pkg.github.com/Expensify/App" ++ ++def patchedVersion = System.getenv("PATCHED_VERSION") ++def isHybridBuild = System.getenv("IS_HYBRID_BUILD")?.toBoolean() ++def publishingGroupId = isHybridBuild ? "com.expensify.react-standalone" : "com.expensify.react-hybrid" + + publishing { + publications { +@@ -26,12 +30,14 @@ publishing { + } + } + ++ groupId = publishingGroupId ++ + // We populate the publishing version using the project version, + // appending -SNAPSHOT if on nightly or prerelase. + if (isSnapshot) { +- version = this.version + "-SNAPSHOT" ++ version = patchedVersion + "-SNAPSHOT" + } else { +- version = this.version ++ version = patchedVersion + } + + pom { +@@ -39,10 +45,14 @@ publishing { + description = "A framework for building native apps with React" + url = "https://github.com/facebook/react-native" + ++ properties = [ ++ "commitHash": System.getenv("COMMIT_HASH"), ++ ] ++ + developers { + developer { +- id = "facebook" +- name = "Facebook" ++ id = "expensify" ++ name = "Expensify" + } + } + +@@ -65,8 +75,11 @@ publishing { + + repositories { + maven { +- name = "mavenTempLocal" +- url = mavenTempLocalUrl ++ url = mavenURL ++ credentials { ++ username = System.getenv("GH_PUBLISH_ACTOR") ++ password = System.getenv("GH_PUBLISH_TOKEN") ++ } + } + } +