From 4c25468a56e4e3a08e984c7233b0d063f2320209 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Tue, 25 Nov 2025 20:08:17 +0100 Subject: [PATCH 01/34] Reapply "Merge pull request #70396 from callstack-internal/set-up-remote-ad-hoc-builds" This reverts commit 0c2ed1af1fd3f18e356d46e17f773928cd0f0429. --- .github/workflows/testBuild.yml | 134 +++++++++++++++++--------------- 1 file changed, 72 insertions(+), 62 deletions(-) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index a1de9107f02d..7c0781023091 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -199,7 +199,7 @@ jobs: needs: [prep, getMobileExpensifyPR, getMobileExpensifyRef] runs-on: ubuntu-latest-xl outputs: - S3_APK_PATH: ${{ steps.exportAndroidS3Path.outputs.S3_APK_PATH }} + ROCK_APK_PATH: ${{ steps.rock-remote-build-android.outputs.artifact-url }} steps: - name: Checkout # v4 @@ -276,37 +276,25 @@ jobs: ANDROID_UPLOAD_KEYSTORE_ALIAS: op://${{ vars.OP_VAULT }}/Repository-Secrets/ANDROID_UPLOAD_KEYSTORE_ALIAS ANDROID_UPLOAD_KEY_PASSWORD: op://${{ vars.OP_VAULT }}/Repository-Secrets/ANDROID_UPLOAD_KEY_PASSWORD - - name: Build Android app - id: build + - name: Rock Remote Build - Android + id: rock-remote-build-android + uses: callstackincubator/android@1a7d52dfe3ca195ccbe5ad2f06c15f2fc3835115 env: - ANDROID_UPLOAD_KEYSTORE_PASSWORD: ${{ steps.load-credentials.outputs.ANDROID_UPLOAD_KEYSTORE_PASSWORD }} - ANDROID_UPLOAD_KEYSTORE_ALIAS: ${{ steps.load-credentials.outputs.ANDROID_UPLOAD_KEYSTORE_ALIAS }} - ANDROID_UPLOAD_KEY_PASSWORD: ${{ steps.load-credentials.outputs.ANDROID_UPLOAD_KEY_PASSWORD }} - GITHUB_ACTOR: ${{ github.actor }} GITHUB_TOKEN: ${{ github.token }} - run: bundle exec fastlane android build_adhoc_hybrid - - - name: Configure AWS Credentials - # v4 - uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 + IS_HYBRID_APP: true with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: us-east-1 - - - name: Upload Android AdHoc build to S3 - run: bundle exec fastlane android upload_s3 - env: - S3_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY_ID }} - S3_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - S3_BUCKET: ad-hoc-expensify-cash - S3_REGION: us-east-1 - - - name: Export S3 path - id: exportAndroidS3Path - run: | - # $s3APKPath is set from within the Fastfile, android upload_s3 lane - echo "S3_APK_PATH=$s3APKPath" >> "$GITHUB_OUTPUT" + variant: 'Adhoc' + sign: true + re-sign: true + keystore-file: './upload-key.keystore' + keystore-store-file: 'upload-key.keystore' + keystore-store-password: ${{ steps.load-credentials.outputs.ANDROID_UPLOAD_KEYSTORE_PASSWORD }} + keystore-key-alias: ${{ steps.load-credentials.outputs.ANDROID_UPLOAD_KEYSTORE_ALIAS }} + keystore-key-password: ${{ steps.load-credentials.outputs.ANDROID_UPLOAD_KEY_PASSWORD }} + # Specify the path (relative to the Android source directory) where the keystore should be placed. + keystore-path: '../tools/buildtools/upload-key.keystore' + comment-bot: false + rock-build-extra-params: '--extra-params -PreactNativeArchitectures=arm64-v8a,x86_64' iosHybrid: name: Build and deploy iOS for testing @@ -316,7 +304,7 @@ jobs: DEVELOPER_DIR: /Applications/Xcode_26.0.app/Contents/Developer runs-on: macos-15-xlarge outputs: - IOS_PATH: ${{ steps.export-ios-path.outputs.IOS_PATH }} + ROCK_IOS_PATH: ${{ steps.rock-remote-build-ios.outputs.artifact-url }} steps: - name: Checkout # v4 @@ -382,6 +370,7 @@ jobs: # v1 uses: 1password/install-cli-action@143a85f84a90555d121cde2ff5872e393a47ab9f + - name: Load files from 1Password env: OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }} @@ -391,36 +380,57 @@ jobs: op read "op://${{ vars.OP_VAULT }}/OldApp_AdHoc_Notification_Service/OldApp_AdHoc_Notification_Service.mobileprovision" --force --out-file ./OldApp_AdHoc_Notification_Service.mobileprovision op read "op://${{ vars.OP_VAULT }}/New Expensify Distribution Certificate/Certificates.p12" --force --out-file ./Certificates.p12 - - name: Build AdHoc app - run: bundle exec fastlane ios build_adhoc_hybrid + - name: Create ExportOptions.plist + run: | + cat > Mobile-Expensify/iOS/ExportOptions.plist << 'EOF' + + + + + method + ad-hoc + provisioningProfiles + + com.expensify.expensifylite.adhoc + (OldApp) AdHoc + com.expensify.expensifylite.adhoc.SmartScanExtension + (OldApp) AdHoc: Share Extension + com.expensify.expensifylite.adhoc.NotificationServiceExtension + (OldApp) AdHoc: Notification Service + + + + EOF + + - name: Rock Remote Build - iOS + id: rock-remote-build-ios + uses: callstackincubator/ios@08a533dbeda6adec39f94d08d820091514d1f7af env: - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} - - - name: Configure AWS Credentials - # v4 - uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 + GITHUB_TOKEN: ${{ github.token }} + IS_HYBRID_APP: true with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: us-east-1 - - - name: Upload AdHoc build to S3 - run: bundle exec fastlane ios upload_s3 - env: - S3_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY_ID }} - S3_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - S3_BUCKET: ad-hoc-expensify-cash - S3_REGION: us-east-1 - - - name: Export iOS path - id: export-ios-path - run: | - content_ios="$(cat ./ios_paths.json)" - content_ios="${content_ios//'%'/'%25'}" - content_ios="${content_ios//$'\n'/'%0A'}" - content_ios="${content_ios//$'\r'/'%0D'}" - ios_path=$(echo "$content_ios" | jq -r '.html_path') - echo "IOS_PATH=$ios_path" >> "$GITHUB_OUTPUT" + destination: device + re-sign: true + ad-hoc: true + scheme: 'Expensify AdHoc' + configuration: 'AdHoc' + certificate-file: './Certificates.p12' + provisioning-profiles: | + [ + { + "name": "(OldApp) AdHoc", + "file": "./OldApp_AdHoc.mobileprovision" + }, + { + "name": "(OldApp) AdHoc: Share Extension", + "file": "./OldApp_AdHoc_Share_Extension.mobileprovision" + }, + { + "name": "(OldApp) AdHoc: Notification Service", + "file": "./OldApp_AdHoc_Notification_Service.mobileprovision" + } + ] + comment-bot: false postGithubComment: runs-on: ubuntu-latest @@ -449,8 +459,8 @@ jobs: ANDROID: ${{ needs.androidHybrid.result }} IOS: ${{ needs.iosHybrid.result }} WEB: ${{ needs.web.result }} - ANDROID_LINK: ${{ needs.androidHybrid.outputs.S3_APK_PATH }} - IOS_LINK: ${{ needs.iosHybrid.outputs.IOS_PATH }} + ANDROID_LINK: ${{ needs.androidHybrid.outputs.ROCK_APK_PATH }} + IOS_LINK: ${{ needs.iosHybrid.outputs.ROCK_IOS_PATH }} WEB_LINK: https://${{ inputs.APP_PULL_REQUEST_NUMBER }}.pr-testing.expensify.com - name: Publish links to apps for download on Expensify/Mobile-Expensify PR @@ -462,5 +472,5 @@ jobs: GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} ANDROID: ${{ needs.androidHybrid.result }} IOS: ${{ needs.iosHybrid.result }} - ANDROID_LINK: ${{ needs.androidHybrid.outputs.S3_APK_PATH }} - IOS_LINK: ${{ needs.iosHybrid.outputs.IOS_PATH }} + ANDROID_LINK: ${{ needs.androidHybrid.outputs.ROCK_APK_PATH }} + IOS_LINK: ${{ needs.iosHybrid.outputs.ROCK_IOS_PATH }} From a47843e68b124811338ec31315cf8a0f1e5e4663 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Tue, 25 Nov 2025 20:13:37 +0100 Subject: [PATCH 02/34] update callstackincubator actions to latest --- .github/workflows/testBuild.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index 7c0781023091..247d35294997 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -278,7 +278,7 @@ jobs: - name: Rock Remote Build - Android id: rock-remote-build-android - uses: callstackincubator/android@1a7d52dfe3ca195ccbe5ad2f06c15f2fc3835115 + uses: callstackincubator/android@c04be7b6078d62620958c7420634a984a40f0bb5 env: GITHUB_TOKEN: ${{ github.token }} IS_HYBRID_APP: true @@ -404,7 +404,7 @@ jobs: - name: Rock Remote Build - iOS id: rock-remote-build-ios - uses: callstackincubator/ios@08a533dbeda6adec39f94d08d820091514d1f7af + uses: callstackincubator/ios@7c072d8d6acaa7cc3b038f9f6c5a81bb54da10c7 env: GITHUB_TOKEN: ${{ github.token }} IS_HYBRID_APP: true From e03443e8b8bd972be274d4e824172b37bb9abcfc Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Wed, 26 Nov 2025 08:15:50 +0100 Subject: [PATCH 03/34] Add Configure AWS Credentials step --- .github/workflows/testBuild.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index 247d35294997..a5b38726e44e 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -276,6 +276,15 @@ jobs: ANDROID_UPLOAD_KEYSTORE_ALIAS: op://${{ vars.OP_VAULT }}/Repository-Secrets/ANDROID_UPLOAD_KEYSTORE_ALIAS ANDROID_UPLOAD_KEY_PASSWORD: op://${{ vars.OP_VAULT }}/Repository-Secrets/ANDROID_UPLOAD_KEY_PASSWORD + + - name: Configure AWS Credentials + # v4 + uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + - name: Rock Remote Build - Android id: rock-remote-build-android uses: callstackincubator/android@c04be7b6078d62620958c7420634a984a40f0bb5 @@ -402,6 +411,14 @@ jobs: EOF + - name: Configure AWS Credentials + # v4 + uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + - name: Rock Remote Build - iOS id: rock-remote-build-ios uses: callstackincubator/ios@7c072d8d6acaa7cc3b038f9f6c5a81bb54da10c7 From cbaf1868bd3895611cda9d15e51c1dcdad976261 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Wed, 26 Nov 2025 08:18:20 +0100 Subject: [PATCH 04/34] restore missing SENTRY_AUTH_TOKEN --- .github/workflows/testBuild.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index a5b38726e44e..a20df6aa0fd7 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -290,6 +290,7 @@ jobs: uses: callstackincubator/android@c04be7b6078d62620958c7420634a984a40f0bb5 env: GITHUB_TOKEN: ${{ github.token }} + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} IS_HYBRID_APP: true with: variant: 'Adhoc' @@ -424,6 +425,7 @@ jobs: uses: callstackincubator/ios@7c072d8d6acaa7cc3b038f9f6c5a81bb54da10c7 env: GITHUB_TOKEN: ${{ github.token }} + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} IS_HYBRID_APP: true with: destination: device From c3a5f4bb2075037ce2e768c1e41bcf2e2c4044b3 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Mon, 1 Dec 2025 15:49:21 +0100 Subject: [PATCH 05/34] add ios testBuild.yaml fix --- .github/workflows/testBuild.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index a20df6aa0fd7..8fd0f9167dd4 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -427,6 +427,9 @@ jobs: GITHUB_TOKEN: ${{ github.token }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} IS_HYBRID_APP: true + # Forces React Native to build from source to include our custom patches + RCT_USE_RN_DEP: 0 + RCT_USE_PREBUILT_RNCORE: 0 with: destination: device re-sign: true @@ -450,6 +453,7 @@ jobs: } ] comment-bot: false + rock-build-extra-params: '--ad-hoc' postGithubComment: runs-on: ubuntu-latest From a3af759ce0397d401f5f4af9e9b54293cf085300 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Mon, 1 Dec 2025 16:00:54 +0100 Subject: [PATCH 06/34] add additional rock logs --- ...k-js+provider-s3+0.11.9+003+add logs.patch | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 patches/@rock-js/provider-s3/@rock-js+provider-s3+0.11.9+003+add logs.patch diff --git a/patches/@rock-js/provider-s3/@rock-js+provider-s3+0.11.9+003+add logs.patch b/patches/@rock-js/provider-s3/@rock-js+provider-s3+0.11.9+003+add logs.patch new file mode 100644 index 000000000000..b9c78681df70 --- /dev/null +++ b/patches/@rock-js/provider-s3/@rock-js+provider-s3+0.11.9+003+add logs.patch @@ -0,0 +1,27 @@ +diff --git a/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.js b/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.js +index 60f915a..4c47aeb 100644 +--- a/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.js ++++ b/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.js +@@ -148,10 +148,22 @@ export class S3BuildCache { + ]; + } + async upload({ artifactName, uploadArtifactName, }) { ++ console.log('TEST uploadArtifactName STARTS, artifactName: ', artifactName); + const key = uploadArtifactName + ? `${this.directory}/${uploadArtifactName}` + : `${this.directory}/${artifactName}.zip`; + const presignedUrl = await getSignedUrl(this.s3, new clientS3.GetObjectCommand({ Bucket: this.bucket, Key: key }), { expiresIn: this.linkExpirationTime }); ++ ++ console.log('TEST uploadArtifactName from S3, JSON: ', JSON.stringify({ ++ name: artifactName, ++ url: presignedUrl, ++ }, null, 2)); ++ ++ console.log(JSON.stringify({ ++ name: artifactName, ++ url: presignedUrl, ++ })); ++ + return { + name: artifactName, + url: presignedUrl, From dcfc3f4ac74f923225b2842e374e918256b5cd5f Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Tue, 2 Dec 2025 09:11:55 +0100 Subject: [PATCH 07/34] remove ad-hoc flag --- .github/workflows/testBuild.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index 8fd0f9167dd4..00905b61abde 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -453,7 +453,6 @@ jobs: } ] comment-bot: false - rock-build-extra-params: '--ad-hoc' postGithubComment: runs-on: ubuntu-latest From c2d5c5c2833dea4532af5654c6d0ef33fc816ede Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Tue, 2 Dec 2025 11:45:45 +0100 Subject: [PATCH 08/34] point to fork gh actions with additional logs --- .github/workflows/testBuild.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index 00905b61abde..0122533a8d31 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -287,7 +287,7 @@ jobs: - name: Rock Remote Build - Android id: rock-remote-build-android - uses: callstackincubator/android@c04be7b6078d62620958c7420634a984a40f0bb5 + uses: LukasMod/android@3be6519b7646c62d0472a49aa519ee3295ea475a env: GITHUB_TOKEN: ${{ github.token }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} @@ -422,7 +422,7 @@ jobs: - name: Rock Remote Build - iOS id: rock-remote-build-ios - uses: callstackincubator/ios@7c072d8d6acaa7cc3b038f9f6c5a81bb54da10c7 + uses: LukasMod/ios@bb1c811684e1139cdc2e903335dcb9ff3e04517d env: GITHUB_TOKEN: ${{ github.token }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} From ccae09d71c6eed893f13e4cdaca12c51ca9c9e7b Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Tue, 2 Dec 2025 14:48:04 +0100 Subject: [PATCH 09/34] fix quoting, remove rock logs --- .github/workflows/testBuild.yml | 2 +- ...k-js+provider-s3+0.11.9+003+add logs.patch | 27 ------------------- 2 files changed, 1 insertion(+), 28 deletions(-) delete mode 100644 patches/@rock-js/provider-s3/@rock-js+provider-s3+0.11.9+003+add logs.patch diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index 0122533a8d31..d75ef69f8bb5 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -422,7 +422,7 @@ jobs: - name: Rock Remote Build - iOS id: rock-remote-build-ios - uses: LukasMod/ios@bb1c811684e1139cdc2e903335dcb9ff3e04517d + uses: LukasMod/ios@0d20641874f92a0dc6df69e0fdc42767b98db4aa env: GITHUB_TOKEN: ${{ github.token }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} diff --git a/patches/@rock-js/provider-s3/@rock-js+provider-s3+0.11.9+003+add logs.patch b/patches/@rock-js/provider-s3/@rock-js+provider-s3+0.11.9+003+add logs.patch deleted file mode 100644 index b9c78681df70..000000000000 --- a/patches/@rock-js/provider-s3/@rock-js+provider-s3+0.11.9+003+add logs.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff --git a/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.js b/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.js -index 60f915a..4c47aeb 100644 ---- a/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.js -+++ b/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.js -@@ -148,10 +148,22 @@ export class S3BuildCache { - ]; - } - async upload({ artifactName, uploadArtifactName, }) { -+ console.log('TEST uploadArtifactName STARTS, artifactName: ', artifactName); - const key = uploadArtifactName - ? `${this.directory}/${uploadArtifactName}` - : `${this.directory}/${artifactName}.zip`; - const presignedUrl = await getSignedUrl(this.s3, new clientS3.GetObjectCommand({ Bucket: this.bucket, Key: key }), { expiresIn: this.linkExpirationTime }); -+ -+ console.log('TEST uploadArtifactName from S3, JSON: ', JSON.stringify({ -+ name: artifactName, -+ url: presignedUrl, -+ }, null, 2)); -+ -+ console.log(JSON.stringify({ -+ name: artifactName, -+ url: presignedUrl, -+ })); -+ - return { - name: artifactName, - url: presignedUrl, From a9b913be0f6edd65613ac634d3621c6b08c2cfd9 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Tue, 2 Dec 2025 16:39:19 +0100 Subject: [PATCH 10/34] remove duplicated android build command --- .github/workflows/testBuild.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index c90aa926a5f4..bfefb7288b3f 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -276,17 +276,6 @@ jobs: ANDROID_UPLOAD_KEYSTORE_ALIAS: op://${{ vars.OP_VAULT }}/Repository-Secrets/ANDROID_UPLOAD_KEYSTORE_ALIAS ANDROID_UPLOAD_KEY_PASSWORD: op://${{ vars.OP_VAULT }}/Repository-Secrets/ANDROID_UPLOAD_KEY_PASSWORD - - name: Build Android app - id: build - env: - ANDROID_UPLOAD_KEYSTORE_PASSWORD: ${{ steps.load-credentials.outputs.ANDROID_UPLOAD_KEYSTORE_PASSWORD }} - ANDROID_UPLOAD_KEYSTORE_ALIAS: ${{ steps.load-credentials.outputs.ANDROID_UPLOAD_KEYSTORE_ALIAS }} - ANDROID_UPLOAD_KEY_PASSWORD: ${{ steps.load-credentials.outputs.ANDROID_UPLOAD_KEY_PASSWORD }} - GITHUB_ACTOR: ${{ github.actor }} - GITHUB_TOKEN: ${{ github.token }} - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} - run: bundle exec fastlane android build_adhoc_hybrid - - name: Configure AWS Credentials # v4 uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 From 0e5d79e8fa665260177aa7a06468f9d3c91a5b6b Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Wed, 3 Dec 2025 12:38:29 +0100 Subject: [PATCH 11/34] update rock gh steps logic, add debug step --- .github/workflows/testBuild.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index bfefb7288b3f..098d7ff6f8a5 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -286,7 +286,7 @@ jobs: - name: Rock Remote Build - Android id: rock-remote-build-android - uses: LukasMod/android@3be6519b7646c62d0472a49aa519ee3295ea475a + uses: LukasMod/android@68969e0075f437f7cc5fdf4cbfa328be246382cf env: GITHUB_TOKEN: ${{ github.token }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} @@ -421,7 +421,7 @@ jobs: - name: Rock Remote Build - iOS id: rock-remote-build-ios - uses: LukasMod/ios@0d20641874f92a0dc6df69e0fdc42767b98db4aa + uses: LukasMod/ios@319ee53ea1ac4c673e42cca1083e647fe6ddd6a0 env: GITHUB_TOKEN: ${{ github.token }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} From 9f5821332663fd68570df8a8a7f144552d298afe Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Wed, 3 Dec 2025 15:11:23 +0100 Subject: [PATCH 12/34] strip sensitive params from artifact URLs --- .github/workflows/testBuild.yml | 41 +++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index 098d7ff6f8a5..e5c4ef7a0291 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -199,7 +199,7 @@ jobs: needs: [prep, getMobileExpensifyPR, getMobileExpensifyRef] runs-on: ubuntu-latest-xl outputs: - ROCK_APK_PATH: ${{ steps.rock-remote-build-android.outputs.artifact-url }} + ROCK_APK_PATH: ${{ steps.strip-android-url.outputs.clean-url }} steps: - name: Checkout # v4 @@ -305,6 +305,19 @@ jobs: comment-bot: false rock-build-extra-params: '--extra-params -PreactNativeArchitectures=arm64-v8a,x86_64' + - name: Strip sensitive params from Android artifact URL + id: strip-android-url + run: | + FULL_URL="${{ steps.rock-remote-build-android.outputs.artifact-url }}" + echo "=== Android URL Transform Debug ===" + echo "Input URL: $FULL_URL" + # Remove query string (everything after ?) + CLEAN_URL="${FULL_URL%%\?*}" + echo "After removing query string: $CLEAN_URL" + echo "=== Final Android URL ===" + echo "clean-url=$CLEAN_URL" >> $GITHUB_OUTPUT + echo "Clean URL: $CLEAN_URL" + iosHybrid: name: Build and deploy iOS for testing if: ${{ inputs.IOS }} @@ -313,7 +326,7 @@ jobs: DEVELOPER_DIR: /Applications/Xcode_26.0.app/Contents/Developer runs-on: macos-15-xlarge outputs: - ROCK_IOS_PATH: ${{ steps.rock-remote-build-ios.outputs.artifact-url }} + ROCK_IOS_PATH: ${{ steps.strip-ios-url.outputs.clean-url }} steps: - name: Checkout # v4 @@ -453,6 +466,30 @@ jobs: ] comment-bot: false + - name: Strip sensitive params from iOS artifact URL + id: strip-ios-url + run: | + FULL_URL="${{ steps.rock-remote-build-ios.outputs.artifact-url }}" + echo "=== iOS URL Transform Debug ===" + echo "Input URL: $FULL_URL" + # Remove query string (everything after ?) + CLEAN_URL="${FULL_URL%%\?*}" + echo "After removing query string: $CLEAN_URL" + # Remove .zip extension + CLEAN_URL="${CLEAN_URL%.zip}" + echo "After removing .zip: $CLEAN_URL" + # Extract base URL (everything up to the artifact name) + BASE_URL="${CLEAN_URL%/*}" + echo "Base URL: $BASE_URL" + # Extract artifact name (last part of path) + ARTIFACT_NAME="${CLEAN_URL##*/}" + echo "Artifact name: $ARTIFACT_NAME" + # Build final URL: base + /ad-hoc/ + artifact name + /index.html + CLEAN_URL="${BASE_URL}/ad-hoc/${ARTIFACT_NAME}/index.html" + echo "=== Final iOS URL ===" + echo "clean-url=$CLEAN_URL" >> $GITHUB_OUTPUT + echo "Clean URL: $CLEAN_URL" + postGithubComment: runs-on: ubuntu-latest if: always() From a8a1ac05532e36e72031013fcfde69a2b0ae4360 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Fri, 5 Dec 2025 13:41:42 +0100 Subject: [PATCH 13/34] add adhoc android flag with forked rock --- .github/workflows/testBuild.yml | 5 +- package-lock.json | 289 +++++++++++++------------------- package.json | 4 +- 3 files changed, 124 insertions(+), 174 deletions(-) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index e5c4ef7a0291..5129cccf71a9 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -286,7 +286,7 @@ jobs: - name: Rock Remote Build - Android id: rock-remote-build-android - uses: LukasMod/android@68969e0075f437f7cc5fdf4cbfa328be246382cf + uses: LukasMod/android@c3070214406d788305c3998e2a07055666370b0f env: GITHUB_TOKEN: ${{ github.token }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} @@ -295,6 +295,7 @@ jobs: variant: 'Adhoc' sign: true re-sign: true + ad-hoc: true keystore-file: './upload-key.keystore' keystore-store-file: 'upload-key.keystore' keystore-store-password: ${{ steps.load-credentials.outputs.ANDROID_UPLOAD_KEYSTORE_PASSWORD }} @@ -434,7 +435,7 @@ jobs: - name: Rock Remote Build - iOS id: rock-remote-build-ios - uses: LukasMod/ios@319ee53ea1ac4c673e42cca1083e647fe6ddd6a0 + uses: LukasMod/ios@77e2325c8ec386326708216545821d851bf065cf env: GITHUB_TOKEN: ${{ github.token }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} diff --git a/package-lock.json b/package-lock.json index abea8001ae40..757b3db8e433 100644 --- a/package-lock.json +++ b/package-lock.json @@ -184,10 +184,12 @@ "@react-native/babel-preset": "0.81.4", "@react-native/metro-config": "0.81.4", "@react-navigation/devtools": "^6.0.10", + "@rock-js/config": "0.11.9", "@rock-js/platform-android": "0.11.9", "@rock-js/platform-ios": "0.11.9", "@rock-js/plugin-metro": "0.11.9", "@rock-js/provider-s3": "0.11.9", + "@rock-js/tools": "0.11.9", "@sentry/webpack-plugin": "4.6.0", "@storybook/addon-a11y": "^8.6.9", "@storybook/addon-essentials": "^8.6.9", @@ -280,7 +282,7 @@ "react-refresh": "^0.14.2", "react-test-renderer": "19.1.0", "reassure": "^1.0.0-rc.4", - "rock": "0.11.9", + "rock": "github:LukasMod/rock#feat/adhoc-android-dist-3", "semver": "7.5.2", "setimmediate": "^1.0.5", "shellcheck": "^1.1.0", @@ -13227,17 +13229,109 @@ } }, "node_modules/@rock-js/provider-github": { - "version": "0.11.9", - "resolved": "https://registry.npmjs.org/@rock-js/provider-github/-/provider-github-0.11.9.tgz", - "integrity": "sha512-fchHu0Zg7oNbI2GfFcwvQIkGZ4/lHYyxRDYdR+iARrhL0zKK1EPCCk/S8kI3pC9Sm33fQhelZbqcIqW6gh6z/A==", + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/@rock-js/provider-github/-/provider-github-0.11.12.tgz", + "integrity": "sha512-fqLOltizyqzWZhd5QBd6SPppFMP06TpGbqDMkF8fuoWkIAQU2Kw0vcVBFSQBueaxgCUD9qNeFiwjnMpN+d4PjQ==", "dev": true, "license": "MIT", "dependencies": { - "@rock-js/tools": "^0.11.9", + "@rock-js/tools": "^0.11.12", "ts-regex-builder": "^1.8.2", "tslib": "^2.3.0" } }, + "node_modules/@rock-js/provider-github/node_modules/@rock-js/tools": { + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/@rock-js/tools/-/tools-0.11.12.tgz", + "integrity": "sha512-YQTlH2IJRYCoBk82h2qqf/QcZK/CvNtBZfcu30iJvXWMEQYYPKgixyqXNodxn55mJBczGUbFzSDePp8xaH0www==", + "dev": true, + "license": "MIT", + "dependencies": { + "@clack/prompts": "^0.11.0", + "adm-zip": "^0.5.16", + "appdirsjs": "^1.2.7", + "fs-fingerprint": "^0.11.0", + "is-unicode-supported": "^2.1.0", + "nano-spawn": "^0.2.0", + "picocolors": "^1.1.1", + "string-argv": "^0.3.2", + "tar": "^7.5.1", + "tslib": "^2.3.0" + } + }, + "node_modules/@rock-js/provider-github/node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@rock-js/provider-github/node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@rock-js/provider-github/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/@rock-js/provider-github/node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@rock-js/provider-github/node_modules/tar": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz", + "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@rock-js/provider-github/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/@rock-js/provider-s3": { "version": "0.11.9", "resolved": "https://registry.npmjs.org/@rock-js/provider-s3/-/provider-s3-0.11.9.tgz", @@ -32893,6 +32987,16 @@ "semver": "^7.3.5" } }, + "node_modules/node-apk": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/node-apk/-/node-apk-1.2.1.tgz", + "integrity": "sha512-I0TY1x5m1pkFzjYdaGrrAu/Mh9qnnk2/BoMAU6bvBxTTD/oNQyTWbu3LTdONgV2rnLHf23jJ00Y/VV4BzZ6YXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-forge": "^1.3.1" + } + }, "node_modules/node-dir": { "version": "0.1.17", "dev": true, @@ -36748,9 +36852,8 @@ "license": "BSD-3-Clause" }, "node_modules/rock": { - "version": "0.11.9", - "resolved": "https://registry.npmjs.org/rock/-/rock-0.11.9.tgz", - "integrity": "sha512-unehLkQIzyK/Py7ZaCuFUpx4sIbbFcnzfbLh0R50VVauCvnmMLy3brEm42ezrY2O6W2v5kzvxHO/dHdCZmtWxw==", + "version": "0.0.0", + "resolved": "git+ssh://git@github.com/LukasMod/rock.git#1ff71092c0ad4b2e4fc2f73597ad82d7455ebcec", "dev": true, "license": "MIT", "dependencies": { @@ -36759,85 +36862,12 @@ "@rock-js/tools": "^0.11.9", "adm-zip": "^0.5.16", "commander": "^12.1.0", + "node-apk": "^1.2.1", "tar": "^7.5.1", - "tslib": "^2.3.0" + "tslib": "^2.8.1" }, "bin": { - "rock": "dist/src/bin.js" - } - }, - "node_modules/rock/node_modules/@react-native-community/cli-config": { - "version": "20.0.2", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-20.0.2.tgz", - "integrity": "sha512-OuSAyqTv0MBbRqSyO+80IKasHnwLESydZBTrLjIGwGhDokMH07mZo8Io2H8X300WWa57LC2L8vQf73TzGS3ikQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@react-native-community/cli-tools": "20.0.2", - "chalk": "^4.1.2", - "cosmiconfig": "^9.0.0", - "deepmerge": "^4.3.0", - "fast-glob": "^3.3.2", - "joi": "^17.2.1" - } - }, - "node_modules/rock/node_modules/@react-native-community/cli-tools": { - "version": "20.0.2", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-20.0.2.tgz", - "integrity": "sha512-bPYhRYggW9IIM8pvrZF/0r6HaxCyEWDn6zfPQPMWlkQUwkzFZ8GBY/M7yiHgDzozWKPT4DqZPumrq806Vcksow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vscode/sudo-prompt": "^9.0.0", - "appdirsjs": "^1.2.4", - "chalk": "^4.1.2", - "execa": "^5.0.0", - "find-up": "^5.0.0", - "launch-editor": "^2.9.1", - "mime": "^2.4.1", - "ora": "^5.4.1", - "prompts": "^2.4.2", - "semver": "^7.5.2" - } - }, - "node_modules/rock/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/rock/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/rock/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "rock": "packages/cli/dist/src/bin.js" } }, "node_modules/rock/node_modules/chownr": { @@ -36850,76 +36880,6 @@ "node": ">=18" } }, - "node_modules/rock/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/rock/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/rock/node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.1", - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/rock/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/rock/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/rock/node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", @@ -36943,25 +36903,12 @@ "node": ">= 18" } }, - "node_modules/rock/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/rock/node_modules/tar": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz", - "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz", + "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", diff --git a/package.json b/package.json index 93dec9abff9f..87147c899534 100644 --- a/package.json +++ b/package.json @@ -251,10 +251,12 @@ "@react-native/babel-preset": "0.81.4", "@react-native/metro-config": "0.81.4", "@react-navigation/devtools": "^6.0.10", + "@rock-js/config": "0.11.9", "@rock-js/platform-android": "0.11.9", "@rock-js/platform-ios": "0.11.9", "@rock-js/plugin-metro": "0.11.9", "@rock-js/provider-s3": "0.11.9", + "@rock-js/tools": "0.11.9", "@sentry/webpack-plugin": "4.6.0", "@storybook/addon-a11y": "^8.6.9", "@storybook/addon-essentials": "^8.6.9", @@ -347,7 +349,7 @@ "react-refresh": "^0.14.2", "react-test-renderer": "19.1.0", "reassure": "^1.0.0-rc.4", - "rock": "0.11.9", + "rock": "github:LukasMod/rock#feat/adhoc-android-dist-3", "semver": "7.5.2", "setimmediate": "^1.0.5", "shellcheck": "^1.1.0", From 65f149e2223bb81cf37bb2d15bd4fb81df8c48a4 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Fri, 5 Dec 2025 14:08:42 +0100 Subject: [PATCH 14/34] add buildAdhocIndexUrl --- .github/scripts/buildAdhocIndexUrl.sh | 48 ++++++++++++++++++++++++++ .github/workflows/testBuild.yml | 49 ++++++--------------------- 2 files changed, 58 insertions(+), 39 deletions(-) create mode 100755 .github/scripts/buildAdhocIndexUrl.sh diff --git a/.github/scripts/buildAdhocIndexUrl.sh b/.github/scripts/buildAdhocIndexUrl.sh new file mode 100755 index 000000000000..db9cd0497490 --- /dev/null +++ b/.github/scripts/buildAdhocIndexUrl.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# Transform artifact URL to clean installation page URL (index.html) +# Usage: ./buildAdhocIndexUrl.sh +# Output: Prints the clean URL to stdout + +FULL_URL="$1" + +if [ -z "$FULL_URL" ]; then + echo "Error: No URL provided" >&2 + echo "Usage: $0 " >&2 + exit 1 +fi + +echo "=== URL Transform Debug ===" +echo "Input URL: $FULL_URL" + +# Remove query string (everything after ?) +CLEAN_URL="${FULL_URL%%\?*}" +echo "After removing query string: $CLEAN_URL" + +# Remove .zip extension +CLEAN_URL="${CLEAN_URL%.zip}" +echo "After removing .zip: $CLEAN_URL" + +# Extract base URL (everything up to the artifact name) +BASE_URL="${CLEAN_URL%/*}" +echo "Base URL: $BASE_URL" + +# Extract artifact name (last part of path) +ARTIFACT_NAME="${CLEAN_URL##*/}" +echo "Artifact name: $ARTIFACT_NAME" + +# Build final URL: base + /ad-hoc/ + artifact name + /index.html +CLEAN_URL="${BASE_URL}/ad-hoc/${ARTIFACT_NAME}/index.html" +echo "=== Final URL ===" +echo "Clean URL: $CLEAN_URL" + + +echo "::notice::📄 File URL (IPA/APK): $FULL_URL" +echo "::notice::🔗 Adhoc Index URL: $CLEAN_URL" + + +# Output for GitHub Actions +if [ -n "$GITHUB_OUTPUT" ]; then + echo "clean-url=$CLEAN_URL" >> "$GITHUB_OUTPUT" +fi + diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index 5129cccf71a9..78e91f8c09ad 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -199,7 +199,7 @@ jobs: needs: [prep, getMobileExpensifyPR, getMobileExpensifyRef] runs-on: ubuntu-latest-xl outputs: - ROCK_APK_PATH: ${{ steps.strip-android-url.outputs.clean-url }} + ROCK_ANDROID_ADHOC_INDEX_URL: ${{ steps.build-android-adhoc-index-url.outputs.clean-url }} steps: - name: Checkout # v4 @@ -306,18 +306,9 @@ jobs: comment-bot: false rock-build-extra-params: '--extra-params -PreactNativeArchitectures=arm64-v8a,x86_64' - - name: Strip sensitive params from Android artifact URL - id: strip-android-url - run: | - FULL_URL="${{ steps.rock-remote-build-android.outputs.artifact-url }}" - echo "=== Android URL Transform Debug ===" - echo "Input URL: $FULL_URL" - # Remove query string (everything after ?) - CLEAN_URL="${FULL_URL%%\?*}" - echo "After removing query string: $CLEAN_URL" - echo "=== Final Android URL ===" - echo "clean-url=$CLEAN_URL" >> $GITHUB_OUTPUT - echo "Clean URL: $CLEAN_URL" + - name: Build Android artifact Adhoc Index URL + id: build-android-adhoc-index-url + run: ./.github/scripts/buildAdhocIndexUrl.sh "${{ steps.rock-remote-build-android.outputs.artifact-url }}" iosHybrid: name: Build and deploy iOS for testing @@ -327,7 +318,7 @@ jobs: DEVELOPER_DIR: /Applications/Xcode_26.0.app/Contents/Developer runs-on: macos-15-xlarge outputs: - ROCK_IOS_PATH: ${{ steps.strip-ios-url.outputs.clean-url }} + ROCK_IOS_ADHOC_INDEX_URL: ${{ steps.build-ios-adhoc-index-url.outputs.clean-url }} steps: - name: Checkout # v4 @@ -467,29 +458,9 @@ jobs: ] comment-bot: false - - name: Strip sensitive params from iOS artifact URL - id: strip-ios-url - run: | - FULL_URL="${{ steps.rock-remote-build-ios.outputs.artifact-url }}" - echo "=== iOS URL Transform Debug ===" - echo "Input URL: $FULL_URL" - # Remove query string (everything after ?) - CLEAN_URL="${FULL_URL%%\?*}" - echo "After removing query string: $CLEAN_URL" - # Remove .zip extension - CLEAN_URL="${CLEAN_URL%.zip}" - echo "After removing .zip: $CLEAN_URL" - # Extract base URL (everything up to the artifact name) - BASE_URL="${CLEAN_URL%/*}" - echo "Base URL: $BASE_URL" - # Extract artifact name (last part of path) - ARTIFACT_NAME="${CLEAN_URL##*/}" - echo "Artifact name: $ARTIFACT_NAME" - # Build final URL: base + /ad-hoc/ + artifact name + /index.html - CLEAN_URL="${BASE_URL}/ad-hoc/${ARTIFACT_NAME}/index.html" - echo "=== Final iOS URL ===" - echo "clean-url=$CLEAN_URL" >> $GITHUB_OUTPUT - echo "Clean URL: $CLEAN_URL" + - name: Build iOS artifact Adhoc Index URL + id: build-ios-adhoc-index-url + run: ./.github/scripts/buildAdhocIndexUrl.sh "${{ steps.rock-remote-build-ios.outputs.artifact-url }}" postGithubComment: runs-on: ubuntu-latest @@ -531,5 +502,5 @@ jobs: GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} ANDROID: ${{ needs.androidHybrid.result }} IOS: ${{ needs.iosHybrid.result }} - ANDROID_LINK: ${{ needs.androidHybrid.outputs.ROCK_APK_PATH }} - IOS_LINK: ${{ needs.iosHybrid.outputs.ROCK_IOS_PATH }} + ANDROID_LINK: ${{ needs.androidHybrid.outputs.ROCK_ANDROID_ADHOC_INDEX_URL }} + IOS_LINK: ${{ needs.iosHybrid.outputs.ROCK_IOS_ADHOC_INDEX_URL }} From a618655ea0a2d794daff61f9faf1a8109fe290c1 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Fri, 5 Dec 2025 16:27:22 +0100 Subject: [PATCH 15/34] fix passing output variables --- .github/scripts/buildAdhocIndexUrl.sh | 48 --------------------------- .github/workflows/testBuild.yml | 16 ++++----- 2 files changed, 8 insertions(+), 56 deletions(-) delete mode 100755 .github/scripts/buildAdhocIndexUrl.sh diff --git a/.github/scripts/buildAdhocIndexUrl.sh b/.github/scripts/buildAdhocIndexUrl.sh deleted file mode 100755 index db9cd0497490..000000000000 --- a/.github/scripts/buildAdhocIndexUrl.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash - -# Transform artifact URL to clean installation page URL (index.html) -# Usage: ./buildAdhocIndexUrl.sh -# Output: Prints the clean URL to stdout - -FULL_URL="$1" - -if [ -z "$FULL_URL" ]; then - echo "Error: No URL provided" >&2 - echo "Usage: $0 " >&2 - exit 1 -fi - -echo "=== URL Transform Debug ===" -echo "Input URL: $FULL_URL" - -# Remove query string (everything after ?) -CLEAN_URL="${FULL_URL%%\?*}" -echo "After removing query string: $CLEAN_URL" - -# Remove .zip extension -CLEAN_URL="${CLEAN_URL%.zip}" -echo "After removing .zip: $CLEAN_URL" - -# Extract base URL (everything up to the artifact name) -BASE_URL="${CLEAN_URL%/*}" -echo "Base URL: $BASE_URL" - -# Extract artifact name (last part of path) -ARTIFACT_NAME="${CLEAN_URL##*/}" -echo "Artifact name: $ARTIFACT_NAME" - -# Build final URL: base + /ad-hoc/ + artifact name + /index.html -CLEAN_URL="${BASE_URL}/ad-hoc/${ARTIFACT_NAME}/index.html" -echo "=== Final URL ===" -echo "Clean URL: $CLEAN_URL" - - -echo "::notice::📄 File URL (IPA/APK): $FULL_URL" -echo "::notice::🔗 Adhoc Index URL: $CLEAN_URL" - - -# Output for GitHub Actions -if [ -n "$GITHUB_OUTPUT" ]; then - echo "clean-url=$CLEAN_URL" >> "$GITHUB_OUTPUT" -fi - diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index 632ea9c7a2dd..522f07c13b61 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -270,7 +270,7 @@ jobs: needs: [prep, getMobileExpensifyPR, getMobileExpensifyRef] runs-on: ubuntu-latest-xl outputs: - ROCK_ANDROID_ADHOC_INDEX_URL: ${{ steps.build-android-adhoc-index-url.outputs.clean-url }} + ROCK_ANDROID_ADHOC_INDEX_URL: ${{ steps.set-artifact-url.outputs.ARTIFACT_URL }} steps: - name: Checkout # v4 @@ -377,9 +377,9 @@ jobs: comment-bot: false rock-build-extra-params: '--extra-params -PreactNativeArchitectures=arm64-v8a,x86_64' - - name: Build Android artifact Adhoc Index URL - id: build-android-adhoc-index-url - run: ./.github/scripts/buildAdhocIndexUrl.sh "${{ steps.rock-remote-build-android.outputs.artifact-url }}" + - name: Set artifact URL output + id: set-artifact-url + run: echo "ARTIFACT_URL=$ARTIFACT_URL" >> "$GITHUB_OUTPUT" iosHybrid: name: Build and deploy iOS for testing @@ -389,7 +389,7 @@ jobs: DEVELOPER_DIR: /Applications/Xcode_26.0.app/Contents/Developer runs-on: macos-15-xlarge outputs: - ROCK_IOS_ADHOC_INDEX_URL: ${{ steps.build-ios-adhoc-index-url.outputs.clean-url }} + ROCK_IOS_ADHOC_INDEX_URL: ${{ steps.set-artifact-url.outputs.ARTIFACT_URL }} steps: - name: Checkout # v4 @@ -529,9 +529,9 @@ jobs: ] comment-bot: false - - name: Build iOS artifact Adhoc Index URL - id: build-ios-adhoc-index-url - run: ./.github/scripts/buildAdhocIndexUrl.sh "${{ steps.rock-remote-build-ios.outputs.artifact-url }}" + - name: Set artifact URL output + id: set-artifact-url + run: echo "ARTIFACT_URL=$ARTIFACT_URL" >> "$GITHUB_OUTPUT" postGithubComment: runs-on: ubuntu-latest From c333cf1f54f3adc504e0b532c6583c2af5d474f5 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Wed, 10 Dec 2025 10:05:30 +0100 Subject: [PATCH 16/34] remove unused steps in favor of Rock --- .github/workflows/testBuild.yml | 43 --------------------------------- 1 file changed, 43 deletions(-) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index 522f07c13b61..075cef680277 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -308,19 +308,6 @@ jobs: sed -i 's/ENVIRONMENT=staging/ENVIRONMENT=adhoc/' .env.adhoc echo "APP_PULL_REQUEST_NUMBER=$PULL_REQUEST_NUMBER" >> .env.adhoc - - name: Setup Java - # v4 - uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 - with: - distribution: 'oracle' - java-version: '17' - - - name: Setup Ruby - # v1.229.0 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 - with: - bundler-cache: true - - name: Install 1Password CLI # v1 uses: 1password/install-cli-action@143a85f84a90555d121cde2ff5872e393a47ab9f @@ -422,40 +409,10 @@ jobs: sed -i '' 's/ENVIRONMENT=staging/ENVIRONMENT=adhoc/' .env.adhoc echo "PULL_REQUEST_NUMBER=$PULL_REQUEST_NUMBER" >> .env.adhoc - - name: Setup Ruby - # v1.229.0 - uses: ruby/setup-ruby@354a1ad156761f5ee2b7b13fa8e09943a5e8d252 - with: - bundler-cache: true - - - name: Install New Expensify Gems - run: bundle install - - - name: Cache Pod dependencies - # v4 - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 - id: pods-cache - with: - path: Mobile-Expensify/iOS/Pods - key: ${{ runner.os }}-pods-cache-${{ hashFiles('Mobile-Expensify/iOS/Podfile.lock', 'firebase.json') }} - - - name: Compare Podfile.lock and Manifest.lock - id: compare-podfile-and-manifest - run: echo "IS_PODFILE_SAME_AS_MANIFEST=${{ hashFiles('Mobile-Expensify/iOS/Podfile.lock') == hashFiles('Mobile-Expensify/iOS/Manifest.lock') }}" >> "$GITHUB_OUTPUT" - - - name: Install cocoapods - uses: nick-fields/retry@3f757583fb1b1f940bc8ef4bf4734c8dc02a5847 - if: steps.pods-cache.outputs.cache-hit != 'true' || steps.compare-podfile-and-manifest.outputs.IS_PODFILE_SAME_AS_MANIFEST != 'true' || steps.setup-node.outputs.cache-hit != 'true' - with: - timeout_minutes: 10 - max_attempts: 5 - command: npm run pod-install - - name: Install 1Password CLI # v1 uses: 1password/install-cli-action@143a85f84a90555d121cde2ff5872e393a47ab9f - - name: Load files from 1Password env: OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }} From 0b2837355d44e577f595a37c86244a476053805a Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Wed, 10 Dec 2025 11:17:39 +0100 Subject: [PATCH 17/34] use updated actions --- .github/workflows/testBuild.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index 075cef680277..20ef186129b9 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -344,7 +344,7 @@ jobs: - name: Rock Remote Build - Android id: rock-remote-build-android - uses: LukasMod/android@c3070214406d788305c3998e2a07055666370b0f + uses: LukasMod/android@fd2a5c37d909dbe2f63564c54c6c409bc667df7e env: GITHUB_TOKEN: ${{ github.token }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} @@ -454,7 +454,7 @@ jobs: - name: Rock Remote Build - iOS id: rock-remote-build-ios - uses: LukasMod/ios@77e2325c8ec386326708216545821d851bf065cf + uses: LukasMod/ios@75aeadfcb0ae8407cfa654cd9c840976683a9c24 env: GITHUB_TOKEN: ${{ github.token }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} From 0b14c06523a8a725fcb960109835846d7f340734 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Wed, 10 Dec 2025 18:51:14 +0100 Subject: [PATCH 18/34] add resign rock logs --- ...platform-android+0.11.9+002+add-logs.patch | 156 +++++++++++++ ...rm-apple-helpers+0.11.9+002+add-logs.patch | 207 ++++++++++++++++++ 2 files changed, 363 insertions(+) create mode 100644 patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+add-logs.patch create mode 100644 patches/@rock-js/platform-apple-helpers/@rock-js+platform-apple-helpers+0.11.9+002+add-logs.patch diff --git a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+add-logs.patch b/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+add-logs.patch new file mode 100644 index 000000000000..70174567e68a --- /dev/null +++ b/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+add-logs.patch @@ -0,0 +1,156 @@ +diff --git a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js +index bf00b00..dddcd13 100644 +--- a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js ++++ b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js +@@ -1,6 +1,6 @@ + import fs from 'node:fs'; + import path from 'node:path'; +-import { colorLink, getDotRockPath, intro, outro, relativeToCwd, RockError, spawn, spinner, } from '@rock-js/tools'; ++import { colorLink, getDotRockPath, intro, logger, outro, relativeToCwd, RockError, spawn, spinner, } from '@rock-js/tools'; + import AdmZip from 'adm-zip'; + import { findAndroidBuildTool, getAndroidBuildToolsPath } from '../../paths.js'; + import { buildJsBundle } from './bundle.js'; +@@ -17,12 +17,20 @@ export async function signAndroid(options) { + if (options.buildJsBundle) { + const bundleOutputPath = path.join(tempPath, 'index.android.bundle'); + loader.start('Building JS bundle...'); ++ logger.log(`Building bundle to: ${bundleOutputPath}`); ++ logger.log(`Assets destination: ${path.join(tempPath, 'res')}`); ++ logger.log(`Use Hermes: ${options.useHermes ?? true}`); + await buildJsBundle({ + bundleOutputPath, + assetsDestPath: path.join(tempPath, 'res'), + sourcemapOutputPath: path.join(tempPath, 'index.android.bundle.packager.map'), + useHermes: options.useHermes ?? true, + }); ++ // Log bundle info after building ++ if (fs.existsSync(bundleOutputPath)) { ++ const bundleSize = fs.statSync(bundleOutputPath).size; ++ logger.log(`Built bundle size: ${bundleSize} bytes`); ++ } + loader.stop(`Built JS bundle: ${colorLink(relativeToCwd(bundleOutputPath))}`); + options.jsBundlePath = bundleOutputPath; + } +@@ -30,10 +38,29 @@ export async function signAndroid(options) { + const tempArchivePath = path.join(tempPath, `output-app.${extension}`); + loader.start(`Initializing output ${extension.toUpperCase()}...`); + try { ++ logger.log(`Reading APK: ${options.binaryPath}`); + const zip = new AdmZip(options.binaryPath); ++ // Log APK contents before modification ++ const entries = zip.getEntries(); ++ logger.log(`APK contains ${entries.length} entries`); ++ // Log signature-related files ++ const signatureFiles = entries.filter((e) => e.entryName.startsWith('META-INF/') && ++ (e.entryName.endsWith('.SF') || ++ e.entryName.endsWith('.RSA') || ++ e.entryName.endsWith('.DSA') || ++ e.entryName === 'META-INF/MANIFEST.MF')); ++ logger.log(`Found ${signatureFiles.length} signature files: ${signatureFiles.map((f) => f.entryName).join(', ')}`); ++ // Log bundle compression ++ const bundleEntry = entries.find((e) => e.entryName === 'assets/index.android.bundle'); ++ if (bundleEntry) { ++ const compressionMethod = bundleEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; ++ logger.log(`Original bundle compression: ${compressionMethod} (method=${bundleEntry.header.method})`); ++ } + // Remove old signature files + zip.deleteFile('META-INF/*'); ++ logger.log(`Removed META-INF/* files`); + zip.writeZip(tempArchivePath); ++ logger.log(`Wrote temporary APK: ${tempArchivePath}`); + } + catch (error) { + throw new RockError(`Failed to initialize output file: ${options.outputPath}`, { cause: error.stderr }); +@@ -79,11 +106,32 @@ function validateOptions(options) { + } + async function replaceJsBundle({ archivePath, jsBundlePath, }) { + try { ++ logger.log(`Replacing bundle in: ${archivePath}`); ++ logger.log(`New bundle path: ${jsBundlePath}`); ++ logger.log(`Bundle size: ${fs.statSync(jsBundlePath).size} bytes`); + const zip = new AdmZip(archivePath); + const assetsPath = isAab(archivePath) ? 'base/assets' : 'assets'; +- zip.deleteFile(path.join(assetsPath, 'index.android.bundle')); ++ const bundlePath = path.join(assetsPath, 'index.android.bundle'); ++ // Log old bundle info ++ const oldEntry = zip.getEntry(bundlePath); ++ if (oldEntry) { ++ const oldMethod = oldEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; ++ logger.log(`Old bundle compression: ${oldMethod} (method=${oldEntry.header.method})`); ++ logger.log(`Old bundle size: ${oldEntry.header.size} bytes`); ++ } ++ zip.deleteFile(bundlePath); ++ logger.log(`Deleted old bundle: ${bundlePath}`); + zip.addLocalFile(jsBundlePath, assetsPath, 'index.android.bundle'); ++ logger.log(`Added new bundle using addLocalFile()`); ++ // Log new bundle info ++ const newEntry = zip.getEntry(bundlePath); ++ if (newEntry) { ++ const newMethod = newEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; ++ logger.log(`New bundle compression: ${newMethod} (method=${newEntry.header.method})`); ++ logger.log(`New bundle compressed size: ${newEntry.header.compressedSize} bytes`); ++ } + zip.writeZip(archivePath); ++ logger.log(`Wrote updated APK: ${archivePath}`); + } + catch (error) { + throw new RockError(`Failed to replace JS bundle in destination file: ${archivePath}`, { cause: error }); +@@ -111,8 +159,15 @@ Please follow instructions at: https://reactnative.dev/docs/set-up-your-environm + inputArchivePath, + outputPath, + ]; ++ logger.log(`Running zipalign: ${zipAlignPath} ${zipalignArgs.join(' ')}`); ++ logger.log(`Input: ${inputArchivePath}`); ++ logger.log(`Output: ${outputPath}`); + try { +- await spawn(zipAlignPath, zipalignArgs); ++ const result = await spawn(zipAlignPath, zipalignArgs); ++ logger.log(`zipalign completed successfully`); ++ if (result.stdout) { ++ logger.log(`zipalign output: ${result.stdout}`); ++ } + } + catch (error) { + throw new RockError(`Failed to align archive file: ${zipAlignPath} ${zipalignArgs.join(' ')}`, { cause: error.stderr }); +@@ -139,8 +194,41 @@ Please follow instructions at: https://reactnative.dev/docs/set-up-your-environm + ...(isAab(binaryPath) ? ['--min-sdk-version', '36'] : []), + binaryPath, + ]; ++ logger.log(`Running apksigner: ${apksignerPath}`); ++ logger.log(`Signing: ${binaryPath}`); ++ logger.log(`Keystore: ${keystorePath}`); ++ logger.log(`Key alias: ${keyAlias || 'default'}`); + try { + await spawn(apksignerPath, apksignerArgs); ++ logger.log(`apksigner completed successfully`); ++ // Verify the signature ++ logger.log(`Verifying signature...`); ++ const verifyResult = await spawn(apksignerPath, [ ++ 'verify', ++ '-v', ++ binaryPath, ++ ]); ++ logger.log(`Signature verification: ${verifyResult.stdout}`); ++ // Check what signature schemes were applied ++ const zip = new AdmZip(binaryPath); ++ const entries = zip.getEntries(); ++ const v1Files = entries.filter((e) => e.entryName.startsWith('META-INF/') && ++ (e.entryName.endsWith('.SF') || ++ e.entryName.endsWith('.RSA') || ++ e.entryName.endsWith('.DSA') || ++ e.entryName === 'META-INF/MANIFEST.MF')); ++ logger.log(`V1 signature files present: ${v1Files.length > 0 ? 'YES' : 'NO'}`); ++ if (v1Files.length > 0) { ++ logger.log(`V1 files: ${v1Files.map((f) => f.entryName).join(', ')}`); ++ } ++ // Log final bundle compression ++ const bundleEntry = entries.find((e) => e.entryName === 'assets/index.android.bundle'); ++ if (bundleEntry) { ++ const compressionMethod = bundleEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; ++ logger.log(`Final bundle compression: ${compressionMethod} (method=${bundleEntry.header.method})`); ++ logger.log(`Final bundle size: ${bundleEntry.header.size} bytes`); ++ logger.log(`Final bundle compressed size: ${bundleEntry.header.compressedSize} bytes`); ++ } + } + catch (error) { + throw new RockError(`Failed to sign APK file: ${apksignerPath} ${apksignerArgs.join(' ')}`, { cause: error.stderr }); diff --git a/patches/@rock-js/platform-apple-helpers/@rock-js+platform-apple-helpers+0.11.9+002+add-logs.patch b/patches/@rock-js/platform-apple-helpers/@rock-js+platform-apple-helpers+0.11.9+002+add-logs.patch new file mode 100644 index 000000000000..5926ff37b365 --- /dev/null +++ b/patches/@rock-js/platform-apple-helpers/@rock-js+platform-apple-helpers+0.11.9+002+add-logs.patch @@ -0,0 +1,207 @@ +diff --git a/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/modifyApp.js b/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/modifyApp.js +index fa2ac99..03582f4 100644 +--- a/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/modifyApp.js ++++ b/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/modifyApp.js +@@ -19,16 +19,33 @@ export const modifyApp = async (options) => { + const appPaths = getAppPaths(options.outputPath ?? options.appPath); + if (options.buildJsBundle) { + loader.start('Building JS bundle'); ++ logger.log(`Building bundle to: ${appPaths.jsBundle}`); ++ logger.log(`Assets destination: ${appPaths.assetsDest}`); ++ logger.log(`Use Hermes: ${options.useHermes ?? true}`); + await buildJsBundle({ + bundleOutputPath: appPaths.jsBundle, + assetsDestPath: appPaths.assetsDest, + useHermes: options.useHermes ?? true, + }); ++ // Log bundle info after building ++ if (fs.existsSync(appPaths.jsBundle)) { ++ const bundleSize = fs.statSync(appPaths.jsBundle).size; ++ logger.log(`Built bundle size: ${bundleSize} bytes`); ++ } + loader.stop(`Built JS bundle: ${colorLink(relativeToCwd(appPaths.jsBundle))}`); + } + else if (options.jsBundlePath) { + loader.start('Replacing JS bundle'); ++ logger.log(`Replacing bundle: ${appPaths.jsBundle}`); ++ logger.log(`New bundle: ${options.jsBundlePath}`); ++ logger.log(`New bundle size: ${fs.statSync(options.jsBundlePath).size} bytes`); ++ // Log old bundle info ++ if (fs.existsSync(appPaths.jsBundle)) { ++ const oldSize = fs.statSync(appPaths.jsBundle).size; ++ logger.log(`Old bundle size: ${oldSize} bytes`); ++ } + fs.copyFileSync(options.jsBundlePath, appPaths.jsBundle); ++ logger.log(`Bundle replaced successfully`); + loader.stop(`Replaced JS bundle with ${colorLink(relativeToCwd(options.jsBundlePath))}`); + } + logger.log(`Modified APP file with new JS bundle. Available at: ${colorLink(relativeToCwd(options.outputPath ?? options.appPath))}`); +diff --git a/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/modifyIpa.js b/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/modifyIpa.js +index 88e9fef..f18b12b 100644 +--- a/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/modifyIpa.js ++++ b/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/modifyIpa.js +@@ -17,16 +17,33 @@ export const modifyIpa = async (options) => { + const appPaths = getAppPaths(appPath); + if (options.buildJsBundle) { + loader.start('Building JS bundle'); ++ logger.log(`Building bundle to: ${appPaths.jsBundle}`); ++ logger.log(`Assets destination: ${appPaths.assetsDest}`); ++ logger.log(`Use Hermes: ${options.useHermes ?? true}`); + await buildJsBundle({ + bundleOutputPath: appPaths.jsBundle, + assetsDestPath: appPaths.assetsDest, + useHermes: options.useHermes ?? true, + }); ++ // Log bundle info after building ++ if (fs.existsSync(appPaths.jsBundle)) { ++ const bundleSize = fs.statSync(appPaths.jsBundle).size; ++ logger.log(`Built bundle size: ${bundleSize} bytes`); ++ } + loader.stop(`Built JS bundle: ${colorLink(relativeToCwd(appPaths.jsBundle))}`); + } + else if (options.jsBundlePath) { + loader.start('Replacing JS bundle'); ++ logger.log(`Replacing bundle: ${appPaths.jsBundle}`); ++ logger.log(`New bundle: ${options.jsBundlePath}`); ++ logger.log(`New bundle size: ${fs.statSync(options.jsBundlePath).size} bytes`); ++ // Log old bundle info ++ if (fs.existsSync(appPaths.jsBundle)) { ++ const oldSize = fs.statSync(appPaths.jsBundle).size; ++ logger.log(`Old bundle size: ${oldSize} bytes`); ++ } + fs.copyFileSync(options.jsBundlePath, appPaths.jsBundle); ++ logger.log(`Bundle replaced successfully`); + loader.stop(`Replaced JS bundle with ${colorLink(relativeToCwd(options.jsBundlePath))}`); + } + // 3. Sign the IPA contents +@@ -35,7 +52,7 @@ export const modifyIpa = async (options) => { + if (!identity) { + const currentIdentity = await getIdentityFromProvisioningPlist(tempPaths.provisioningPlist); + if (currentIdentity) { +- logger.debug(`Extracted identity from provisioning profile: ${currentIdentity}`); ++ logger.log(`Extracted identity from provisioning profile: ${currentIdentity}`); + } + identity = await promptSigningIdentity(currentIdentity); + } +@@ -52,10 +69,26 @@ export const modifyIpa = async (options) => { + tempPaths.entitlementsPlist, + appPath, + ]; ++ logger.log(`Running codesign with identity: ${identity}`); ++ logger.log(`Signing: ${appPath}`); ++ logger.log(`Entitlements: ${tempPaths.entitlementsPlist}`); + try { +- await spawn('codesign', codeSignArgs, { cwd: tempPaths.content }); ++ const result = await spawn('codesign', codeSignArgs, { cwd: tempPaths.content }); ++ logger.log(`codesign completed successfully`); ++ if (result.stdout) { ++ logger.log(`codesign output: ${result.stdout}`); ++ } ++ // Verify the signature ++ logger.log(`Verifying signature...`); ++ const verifyResult = await spawn('codesign', [ ++ '--verify', ++ '--verbose', ++ appPath, ++ ]); ++ logger.log(`Signature verification: ${verifyResult.stdout || 'OK'}`); + } + catch (error) { ++ logger.error(`codesign failed: ${error.stderr}`); + throw new RockError('Codesign failed', { + cause: error.stderr, + }); +diff --git a/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/utils.js b/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/utils.js +index cfc9a22..a91b66b 100644 +--- a/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/utils.js ++++ b/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/utils.js +@@ -1,6 +1,6 @@ +-import { existsSync, mkdirSync, rmSync } from 'node:fs'; ++import { existsSync, mkdirSync, rmSync, statSync } from 'node:fs'; + import path from 'node:path'; +-import { findDirectoriesWithPattern, getDotRockPath, RockError, } from '@rock-js/tools'; ++import { findDirectoriesWithPattern, getDotRockPath, logger, RockError, } from '@rock-js/tools'; + import AdmZip from 'adm-zip'; + /** + * Temporary paths for sign operation. +@@ -40,12 +40,27 @@ export function getAppPaths(appPath) { + * @returns Path to .app directory (package) inside the IPA file. + */ + export const unpackIpa = (ipaPath, destination) => { ++ logger.log(`Unpacking IPA: ${ipaPath}`); ++ logger.log(`IPA size: ${statSync(ipaPath).size} bytes`); ++ logger.log(`Destination: ${destination}`); + if (existsSync(destination)) { + rmSync(destination, { recursive: true, force: true }); + } + mkdirSync(destination, { recursive: true }); + const zip = new AdmZip(ipaPath); ++ const entries = zip.getEntries(); ++ logger.log(`IPA contains ${entries.length} entries`); ++ // Log bundle info if present ++ const bundleEntry = entries.find((e) => e.entryName.includes('main.jsbundle')); ++ if (bundleEntry) { ++ const compressionMethod = bundleEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; ++ logger.log(`Original bundle: ${bundleEntry.entryName}`); ++ logger.log(`Original bundle compression: ${compressionMethod} (method=${bundleEntry.header.method})`); ++ logger.log(`Original bundle size: ${bundleEntry.header.size} bytes`); ++ logger.log(`Original bundle compressed size: ${bundleEntry.header.compressedSize} bytes`); ++ } + zip.extractAllTo(destination, true); ++ logger.log(`Extracted to: ${destination}`); + const payloadPath = `${destination}/Payload`; + if (!existsSync(payloadPath)) { + throw new Error('Payload folder not found in the extracted IPA file'); +@@ -54,6 +69,13 @@ export const unpackIpa = (ipaPath, destination) => { + if (!appPath) { + throw new RockError(`.app package not found in the extracted IPA file ${payloadPath}`); + } ++ logger.log(`Found .app at: ${appPath}`); ++ // Log bundle file info if exists ++ const jsBundlePath = path.join(appPath, 'main.jsbundle'); ++ if (existsSync(jsBundlePath)) { ++ const bundleSize = statSync(jsBundlePath).size; ++ logger.log(`Extracted bundle size: ${bundleSize} bytes`); ++ } + return appPath; + }; + /** +@@ -63,12 +85,37 @@ export const unpackIpa = (ipaPath, destination) => { + * @returns Path to the output IPA file. + */ + export const packIpa = (contentPath, ipaPath) => { ++ logger.log(`Packing IPA from: ${contentPath}`); + if (existsSync(ipaPath)) { + rmSync(ipaPath, { recursive: true, force: true }); + } ++ // Find and log bundle info before packing ++ const appDirs = findDirectoriesWithPattern(path.join(contentPath, 'Payload'), /\.app$/); ++ if (appDirs.length > 0) { ++ const jsBundlePath = path.join(appDirs[0], 'main.jsbundle'); ++ if (existsSync(jsBundlePath)) { ++ const bundleSize = statSync(jsBundlePath).size; ++ logger.log(`Bundle to pack: ${jsBundlePath}`); ++ logger.log(`Bundle size: ${bundleSize} bytes`); ++ } ++ } + const zip = new AdmZip(); + zip.addLocalFolder(contentPath); ++ logger.log(`Added folder contents to zip`); ++ // Log what compression was applied ++ const entries = zip.getEntries(); ++ logger.log(`Packed ${entries.length} entries`); ++ const bundleEntry = entries.find((e) => e.entryName.includes('main.jsbundle')); ++ if (bundleEntry) { ++ const compressionMethod = bundleEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; ++ logger.log(`Packed bundle: ${bundleEntry.entryName}`); ++ logger.log(`Packed bundle compression: ${compressionMethod} (method=${bundleEntry.header.method})`); ++ logger.log(`Packed bundle size: ${bundleEntry.header.size} bytes`); ++ logger.log(`Packed bundle compressed size: ${bundleEntry.header.compressedSize} bytes`); ++ } + zip.writeZip(ipaPath); ++ logger.log(`Wrote IPA: ${ipaPath}`); ++ logger.log(`Final IPA size: ${statSync(ipaPath).size} bytes`); + return ipaPath; + }; + //# sourceMappingURL=utils.js.map +\ No newline at end of file From 5bcd9f0cfa8781f54e70f15ba4c0aa202109084e Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Thu, 11 Dec 2025 10:42:04 +0100 Subject: [PATCH 19/34] add android additional logs, explicit compression method --- ...atform-android+0.11.9+003+add-logs-2.patch | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+003+add-logs-2.patch diff --git a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+003+add-logs-2.patch b/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+003+add-logs-2.patch new file mode 100644 index 000000000000..5e7d30fcf5f8 --- /dev/null +++ b/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+003+add-logs-2.patch @@ -0,0 +1,80 @@ +diff --git a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js +index dddcd13..444aade 100644 +--- a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js ++++ b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js +@@ -108,30 +108,52 @@ async function replaceJsBundle({ archivePath, jsBundlePath, }) { + try { + logger.log(`Replacing bundle in: ${archivePath}`); + logger.log(`New bundle path: ${jsBundlePath}`); +- logger.log(`Bundle size: ${fs.statSync(jsBundlePath).size} bytes`); ++ const newBundleBuffer = fs.readFileSync(jsBundlePath); ++ logger.log(`Bundle size: ${newBundleBuffer.length} bytes`); + const zip = new AdmZip(archivePath); + const assetsPath = isAab(archivePath) ? 'base/assets' : 'assets'; + const bundlePath = path.join(assetsPath, 'index.android.bundle'); +- // Log old bundle info ++ // Capture original compression method BEFORE any modifications + const oldEntry = zip.getEntry(bundlePath); ++ const originalCompressionMethod = oldEntry?.header.method ?? 8; // default to DEFLATED + if (oldEntry) { +- const oldMethod = oldEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; +- logger.log(`Old bundle compression: ${oldMethod} (method=${oldEntry.header.method})`); ++ const oldMethodText = oldEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; ++ logger.log(`Old bundle compression: ${oldMethodText} (method=${oldEntry.header.method})`); + logger.log(`Old bundle size: ${oldEntry.header.size} bytes`); + } ++ // Delete the old bundle + zip.deleteFile(bundlePath); + logger.log(`Deleted old bundle: ${bundlePath}`); +- zip.addLocalFile(jsBundlePath, assetsPath, 'index.android.bundle'); +- logger.log(`Added new bundle using addLocalFile()`); +- // Log new bundle info ++ // Add new bundle and immediately configure compression BEFORE writeZip ++ zip.addFile(bundlePath, newBundleBuffer); + const newEntry = zip.getEntry(bundlePath); + if (newEntry) { +- const newMethod = newEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; +- logger.log(`New bundle compression: ${newMethod} (method=${newEntry.header.method})`); +- logger.log(`New bundle compressed size: ${newEntry.header.compressedSize} bytes`); ++ // Force compression method to match original ++ // This MUST be set before writeZip() is called ++ newEntry.header.method = originalCompressionMethod; ++ if (originalCompressionMethod === 0) { ++ // For STORED (uncompressed), set compressed size = uncompressed size ++ newEntry.header.compressedSize = newBundleBuffer.length; ++ logger.log(`Configured for STORED compression (no compression)`); ++ } ++ else { ++ logger.log(`Configured for DEFLATED compression`); ++ } ++ const method = newEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; ++ logger.log(`Set compression: ${method} (method=${newEntry.header.method})`); + } ++ // Write the modified APK + zip.writeZip(archivePath); + logger.log(`Wrote updated APK: ${archivePath}`); ++ // Verify the result by reading it back ++ const verifyZip = new AdmZip(archivePath); ++ const verifyEntry = verifyZip.getEntry(bundlePath); ++ if (verifyEntry) { ++ const finalMethod = verifyEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; ++ logger.log(`Verified - Final bundle compression: ${finalMethod} (method=${verifyEntry.header.method})`); ++ logger.log(`Verified - Final bundle size: ${verifyEntry.header.size} bytes`); ++ logger.log(`Verified - Final compressed size: ${verifyEntry.header.compressedSize} bytes`); ++ } + } + catch (error) { + throw new RockError(`Failed to replace JS bundle in destination file: ${archivePath}`, { cause: error }); +@@ -163,11 +185,8 @@ Please follow instructions at: https://reactnative.dev/docs/set-up-your-environm + logger.log(`Input: ${inputArchivePath}`); + logger.log(`Output: ${outputPath}`); + try { +- const result = await spawn(zipAlignPath, zipalignArgs); ++ await spawn(zipAlignPath, zipalignArgs); + logger.log(`zipalign completed successfully`); +- if (result.stdout) { +- logger.log(`zipalign output: ${result.stdout}`); +- } + } + catch (error) { + throw new RockError(`Failed to align archive file: ${zipAlignPath} ${zipalignArgs.join(' ')}`, { cause: error.stderr }); From 55de29a71527ccf88d4185fe5d83691f9179851b Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Thu, 11 Dec 2025 18:26:43 +0100 Subject: [PATCH 20/34] update gh android action, use keystore from input in re-sign --- .github/workflows/testBuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index 5d6557602c85..54f43a9d18ec 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -346,7 +346,7 @@ jobs: - name: Rock Remote Build - Android id: rock-remote-build-android - uses: LukasMod/android@fd2a5c37d909dbe2f63564c54c6c409bc667df7e + uses: LukasMod/android@43eccd3ece4f1e812d3097f6fc639c6945f04b73 env: GITHUB_TOKEN: ${{ github.token }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} From bc6be998dc2b34ed77a69eacbb12e67414d862f6 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Fri, 12 Dec 2025 14:13:12 +0100 Subject: [PATCH 21/34] add rock patch with zip method --- ...platform-android+0.11.9+002+add-logs.patch | 156 ------------------ ...id+0.11.9+002+use-zip-instead-admzip.patch | 63 +++++++ ...atform-android+0.11.9+003+add-logs-2.patch | 80 --------- 3 files changed, 63 insertions(+), 236 deletions(-) delete mode 100644 patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+add-logs.patch create mode 100644 patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch delete mode 100644 patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+003+add-logs-2.patch diff --git a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+add-logs.patch b/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+add-logs.patch deleted file mode 100644 index 70174567e68a..000000000000 --- a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+add-logs.patch +++ /dev/null @@ -1,156 +0,0 @@ -diff --git a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js -index bf00b00..dddcd13 100644 ---- a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js -+++ b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js -@@ -1,6 +1,6 @@ - import fs from 'node:fs'; - import path from 'node:path'; --import { colorLink, getDotRockPath, intro, outro, relativeToCwd, RockError, spawn, spinner, } from '@rock-js/tools'; -+import { colorLink, getDotRockPath, intro, logger, outro, relativeToCwd, RockError, spawn, spinner, } from '@rock-js/tools'; - import AdmZip from 'adm-zip'; - import { findAndroidBuildTool, getAndroidBuildToolsPath } from '../../paths.js'; - import { buildJsBundle } from './bundle.js'; -@@ -17,12 +17,20 @@ export async function signAndroid(options) { - if (options.buildJsBundle) { - const bundleOutputPath = path.join(tempPath, 'index.android.bundle'); - loader.start('Building JS bundle...'); -+ logger.log(`Building bundle to: ${bundleOutputPath}`); -+ logger.log(`Assets destination: ${path.join(tempPath, 'res')}`); -+ logger.log(`Use Hermes: ${options.useHermes ?? true}`); - await buildJsBundle({ - bundleOutputPath, - assetsDestPath: path.join(tempPath, 'res'), - sourcemapOutputPath: path.join(tempPath, 'index.android.bundle.packager.map'), - useHermes: options.useHermes ?? true, - }); -+ // Log bundle info after building -+ if (fs.existsSync(bundleOutputPath)) { -+ const bundleSize = fs.statSync(bundleOutputPath).size; -+ logger.log(`Built bundle size: ${bundleSize} bytes`); -+ } - loader.stop(`Built JS bundle: ${colorLink(relativeToCwd(bundleOutputPath))}`); - options.jsBundlePath = bundleOutputPath; - } -@@ -30,10 +38,29 @@ export async function signAndroid(options) { - const tempArchivePath = path.join(tempPath, `output-app.${extension}`); - loader.start(`Initializing output ${extension.toUpperCase()}...`); - try { -+ logger.log(`Reading APK: ${options.binaryPath}`); - const zip = new AdmZip(options.binaryPath); -+ // Log APK contents before modification -+ const entries = zip.getEntries(); -+ logger.log(`APK contains ${entries.length} entries`); -+ // Log signature-related files -+ const signatureFiles = entries.filter((e) => e.entryName.startsWith('META-INF/') && -+ (e.entryName.endsWith('.SF') || -+ e.entryName.endsWith('.RSA') || -+ e.entryName.endsWith('.DSA') || -+ e.entryName === 'META-INF/MANIFEST.MF')); -+ logger.log(`Found ${signatureFiles.length} signature files: ${signatureFiles.map((f) => f.entryName).join(', ')}`); -+ // Log bundle compression -+ const bundleEntry = entries.find((e) => e.entryName === 'assets/index.android.bundle'); -+ if (bundleEntry) { -+ const compressionMethod = bundleEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; -+ logger.log(`Original bundle compression: ${compressionMethod} (method=${bundleEntry.header.method})`); -+ } - // Remove old signature files - zip.deleteFile('META-INF/*'); -+ logger.log(`Removed META-INF/* files`); - zip.writeZip(tempArchivePath); -+ logger.log(`Wrote temporary APK: ${tempArchivePath}`); - } - catch (error) { - throw new RockError(`Failed to initialize output file: ${options.outputPath}`, { cause: error.stderr }); -@@ -79,11 +106,32 @@ function validateOptions(options) { - } - async function replaceJsBundle({ archivePath, jsBundlePath, }) { - try { -+ logger.log(`Replacing bundle in: ${archivePath}`); -+ logger.log(`New bundle path: ${jsBundlePath}`); -+ logger.log(`Bundle size: ${fs.statSync(jsBundlePath).size} bytes`); - const zip = new AdmZip(archivePath); - const assetsPath = isAab(archivePath) ? 'base/assets' : 'assets'; -- zip.deleteFile(path.join(assetsPath, 'index.android.bundle')); -+ const bundlePath = path.join(assetsPath, 'index.android.bundle'); -+ // Log old bundle info -+ const oldEntry = zip.getEntry(bundlePath); -+ if (oldEntry) { -+ const oldMethod = oldEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; -+ logger.log(`Old bundle compression: ${oldMethod} (method=${oldEntry.header.method})`); -+ logger.log(`Old bundle size: ${oldEntry.header.size} bytes`); -+ } -+ zip.deleteFile(bundlePath); -+ logger.log(`Deleted old bundle: ${bundlePath}`); - zip.addLocalFile(jsBundlePath, assetsPath, 'index.android.bundle'); -+ logger.log(`Added new bundle using addLocalFile()`); -+ // Log new bundle info -+ const newEntry = zip.getEntry(bundlePath); -+ if (newEntry) { -+ const newMethod = newEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; -+ logger.log(`New bundle compression: ${newMethod} (method=${newEntry.header.method})`); -+ logger.log(`New bundle compressed size: ${newEntry.header.compressedSize} bytes`); -+ } - zip.writeZip(archivePath); -+ logger.log(`Wrote updated APK: ${archivePath}`); - } - catch (error) { - throw new RockError(`Failed to replace JS bundle in destination file: ${archivePath}`, { cause: error }); -@@ -111,8 +159,15 @@ Please follow instructions at: https://reactnative.dev/docs/set-up-your-environm - inputArchivePath, - outputPath, - ]; -+ logger.log(`Running zipalign: ${zipAlignPath} ${zipalignArgs.join(' ')}`); -+ logger.log(`Input: ${inputArchivePath}`); -+ logger.log(`Output: ${outputPath}`); - try { -- await spawn(zipAlignPath, zipalignArgs); -+ const result = await spawn(zipAlignPath, zipalignArgs); -+ logger.log(`zipalign completed successfully`); -+ if (result.stdout) { -+ logger.log(`zipalign output: ${result.stdout}`); -+ } - } - catch (error) { - throw new RockError(`Failed to align archive file: ${zipAlignPath} ${zipalignArgs.join(' ')}`, { cause: error.stderr }); -@@ -139,8 +194,41 @@ Please follow instructions at: https://reactnative.dev/docs/set-up-your-environm - ...(isAab(binaryPath) ? ['--min-sdk-version', '36'] : []), - binaryPath, - ]; -+ logger.log(`Running apksigner: ${apksignerPath}`); -+ logger.log(`Signing: ${binaryPath}`); -+ logger.log(`Keystore: ${keystorePath}`); -+ logger.log(`Key alias: ${keyAlias || 'default'}`); - try { - await spawn(apksignerPath, apksignerArgs); -+ logger.log(`apksigner completed successfully`); -+ // Verify the signature -+ logger.log(`Verifying signature...`); -+ const verifyResult = await spawn(apksignerPath, [ -+ 'verify', -+ '-v', -+ binaryPath, -+ ]); -+ logger.log(`Signature verification: ${verifyResult.stdout}`); -+ // Check what signature schemes were applied -+ const zip = new AdmZip(binaryPath); -+ const entries = zip.getEntries(); -+ const v1Files = entries.filter((e) => e.entryName.startsWith('META-INF/') && -+ (e.entryName.endsWith('.SF') || -+ e.entryName.endsWith('.RSA') || -+ e.entryName.endsWith('.DSA') || -+ e.entryName === 'META-INF/MANIFEST.MF')); -+ logger.log(`V1 signature files present: ${v1Files.length > 0 ? 'YES' : 'NO'}`); -+ if (v1Files.length > 0) { -+ logger.log(`V1 files: ${v1Files.map((f) => f.entryName).join(', ')}`); -+ } -+ // Log final bundle compression -+ const bundleEntry = entries.find((e) => e.entryName === 'assets/index.android.bundle'); -+ if (bundleEntry) { -+ const compressionMethod = bundleEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; -+ logger.log(`Final bundle compression: ${compressionMethod} (method=${bundleEntry.header.method})`); -+ logger.log(`Final bundle size: ${bundleEntry.header.size} bytes`); -+ logger.log(`Final bundle compressed size: ${bundleEntry.header.compressedSize} bytes`); -+ } - } - catch (error) { - throw new RockError(`Failed to sign APK file: ${apksignerPath} ${apksignerArgs.join(' ')}`, { cause: error.stderr }); diff --git a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch b/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch new file mode 100644 index 000000000000..907e30a7cb75 --- /dev/null +++ b/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch @@ -0,0 +1,63 @@ +diff --git a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js +index bf00b00..870ac45 100644 +--- a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js ++++ b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js +@@ -78,15 +78,40 @@ function validateOptions(options) { + } + } + async function replaceJsBundle({ archivePath, jsBundlePath, }) { ++ const assetsPath = isAab(archivePath) ? 'base/assets' : 'assets'; ++ const bundleEntryPath = path.posix.join(assetsPath, 'index.android.bundle'); ++ ++ // Create staging directory matching the APK structure ++ const stagingRoot = path.join(getDotRockPath(), 'android/sign/bundle-staging'); ++ const stagedBundleDir = path.join(stagingRoot, assetsPath); ++ ++ // Clean and recreate staging ++ if (fs.existsSync(stagingRoot)) { ++ fs.rmSync(stagingRoot, { recursive: true }); ++ } ++ fs.mkdirSync(stagedBundleDir, { recursive: true }); ++ fs.copyFileSync(jsBundlePath, path.join(stagedBundleDir, 'index.android.bundle')); ++ + try { +- const zip = new AdmZip(archivePath); +- const assetsPath = isAab(archivePath) ? 'base/assets' : 'assets'; +- zip.deleteFile(path.join(assetsPath, 'index.android.bundle')); +- zip.addLocalFile(jsBundlePath, assetsPath, 'index.android.bundle'); +- zip.writeZip(archivePath); +- } +- catch (error) { +- throw new RockError(`Failed to replace JS bundle in destination file: ${archivePath}`, { cause: error }); ++ // Remove old bundle ++ try { ++ await spawn('zip', ['-d', archivePath, bundleEntryPath]); ++ } catch (error) { ++ if (error.exitCode !== 12) throw error; ++ } ++ ++ // Add new bundle with NO compression to prevent corruption ++ // Use relative path from staging root so structure is preserved ++ await spawn('zip', ['-0', '-r', archivePath, assetsPath], { ++ cwd: stagingRoot ++ }); ++ ++ } catch (error) { ++ throw new RockError(`Failed to replace JS bundle in destination file: ${archivePath}`, { cause: error.stderr ?? error }); ++ } finally { ++ if (fs.existsSync(stagingRoot)) { ++ fs.rmSync(stagingRoot, { recursive: true }); ++ } + } + } + function isSdkGTE35(versionString) { +@@ -111,6 +136,9 @@ Please follow instructions at: https://reactnative.dev/docs/set-up-your-environm + inputArchivePath, + outputPath, + ]; ++ ++ ++ console.log('zipalignArgs', zipalignArgs); + try { + await spawn(zipAlignPath, zipalignArgs); + } diff --git a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+003+add-logs-2.patch b/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+003+add-logs-2.patch deleted file mode 100644 index 5e7d30fcf5f8..000000000000 --- a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+003+add-logs-2.patch +++ /dev/null @@ -1,80 +0,0 @@ -diff --git a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js -index dddcd13..444aade 100644 ---- a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js -+++ b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js -@@ -108,30 +108,52 @@ async function replaceJsBundle({ archivePath, jsBundlePath, }) { - try { - logger.log(`Replacing bundle in: ${archivePath}`); - logger.log(`New bundle path: ${jsBundlePath}`); -- logger.log(`Bundle size: ${fs.statSync(jsBundlePath).size} bytes`); -+ const newBundleBuffer = fs.readFileSync(jsBundlePath); -+ logger.log(`Bundle size: ${newBundleBuffer.length} bytes`); - const zip = new AdmZip(archivePath); - const assetsPath = isAab(archivePath) ? 'base/assets' : 'assets'; - const bundlePath = path.join(assetsPath, 'index.android.bundle'); -- // Log old bundle info -+ // Capture original compression method BEFORE any modifications - const oldEntry = zip.getEntry(bundlePath); -+ const originalCompressionMethod = oldEntry?.header.method ?? 8; // default to DEFLATED - if (oldEntry) { -- const oldMethod = oldEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; -- logger.log(`Old bundle compression: ${oldMethod} (method=${oldEntry.header.method})`); -+ const oldMethodText = oldEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; -+ logger.log(`Old bundle compression: ${oldMethodText} (method=${oldEntry.header.method})`); - logger.log(`Old bundle size: ${oldEntry.header.size} bytes`); - } -+ // Delete the old bundle - zip.deleteFile(bundlePath); - logger.log(`Deleted old bundle: ${bundlePath}`); -- zip.addLocalFile(jsBundlePath, assetsPath, 'index.android.bundle'); -- logger.log(`Added new bundle using addLocalFile()`); -- // Log new bundle info -+ // Add new bundle and immediately configure compression BEFORE writeZip -+ zip.addFile(bundlePath, newBundleBuffer); - const newEntry = zip.getEntry(bundlePath); - if (newEntry) { -- const newMethod = newEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; -- logger.log(`New bundle compression: ${newMethod} (method=${newEntry.header.method})`); -- logger.log(`New bundle compressed size: ${newEntry.header.compressedSize} bytes`); -+ // Force compression method to match original -+ // This MUST be set before writeZip() is called -+ newEntry.header.method = originalCompressionMethod; -+ if (originalCompressionMethod === 0) { -+ // For STORED (uncompressed), set compressed size = uncompressed size -+ newEntry.header.compressedSize = newBundleBuffer.length; -+ logger.log(`Configured for STORED compression (no compression)`); -+ } -+ else { -+ logger.log(`Configured for DEFLATED compression`); -+ } -+ const method = newEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; -+ logger.log(`Set compression: ${method} (method=${newEntry.header.method})`); - } -+ // Write the modified APK - zip.writeZip(archivePath); - logger.log(`Wrote updated APK: ${archivePath}`); -+ // Verify the result by reading it back -+ const verifyZip = new AdmZip(archivePath); -+ const verifyEntry = verifyZip.getEntry(bundlePath); -+ if (verifyEntry) { -+ const finalMethod = verifyEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; -+ logger.log(`Verified - Final bundle compression: ${finalMethod} (method=${verifyEntry.header.method})`); -+ logger.log(`Verified - Final bundle size: ${verifyEntry.header.size} bytes`); -+ logger.log(`Verified - Final compressed size: ${verifyEntry.header.compressedSize} bytes`); -+ } - } - catch (error) { - throw new RockError(`Failed to replace JS bundle in destination file: ${archivePath}`, { cause: error }); -@@ -163,11 +185,8 @@ Please follow instructions at: https://reactnative.dev/docs/set-up-your-environm - logger.log(`Input: ${inputArchivePath}`); - logger.log(`Output: ${outputPath}`); - try { -- const result = await spawn(zipAlignPath, zipalignArgs); -+ await spawn(zipAlignPath, zipalignArgs); - logger.log(`zipalign completed successfully`); -- if (result.stdout) { -- logger.log(`zipalign output: ${result.stdout}`); -- } - } - catch (error) { - throw new RockError(`Failed to align archive file: ${zipAlignPath} ${zipalignArgs.join(' ')}`, { cause: error.stderr }); From 959c3b813d943989db74a1b937309ad93f5cb4ad Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Mon, 15 Dec 2025 12:13:22 +0100 Subject: [PATCH 22/34] clean up patches --- ...id+0.11.9+002+use-zip-instead-admzip.patch | 64 +++--- patches/@rock-js/platform-android/details.md | 14 ++ ...rm-apple-helpers+0.11.9+002+add-logs.patch | 207 ------------------ 3 files changed, 44 insertions(+), 241 deletions(-) delete mode 100644 patches/@rock-js/platform-apple-helpers/@rock-js+platform-apple-helpers+0.11.9+002+add-logs.patch diff --git a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch b/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch index 907e30a7cb75..a9e8069f0fb2 100644 --- a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch +++ b/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch @@ -1,63 +1,59 @@ diff --git a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js -index bf00b00..870ac45 100644 +index bf00b00..50a5307 100644 --- a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js +++ b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js -@@ -78,15 +78,40 @@ function validateOptions(options) { +@@ -30,13 +30,13 @@ export async function signAndroid(options) { + const tempArchivePath = path.join(tempPath, `output-app.${extension}`); + loader.start(`Initializing output ${extension.toUpperCase()}...`); + try { +- const zip = new AdmZip(options.binaryPath); ++ fs.mkdirSync(tempPath, { recursive: true }); ++ fs.copyFileSync(options.binaryPath, tempArchivePath); + // Remove old signature files +- zip.deleteFile('META-INF/*'); +- zip.writeZip(tempArchivePath); ++ await spawn('zip', ['-d', tempArchivePath, 'META-INF/*']); + } + catch (error) { +- throw new RockError(`Failed to initialize output file: ${options.outputPath}`, { cause: error.stderr }); ++ throw new RockError(`Failed to initialize output file: ${options.outputPath}`, { cause: error }); + } + loader.stop(`Initialized output ${extension.toUpperCase()}`); + // 3. Replace JS bundle if provided +@@ -78,16 +78,31 @@ function validateOptions(options) { } } async function replaceJsBundle({ archivePath, jsBundlePath, }) { + const assetsPath = isAab(archivePath) ? 'base/assets' : 'assets'; + const bundleEntryPath = path.posix.join(assetsPath, 'index.android.bundle'); -+ -+ // Create staging directory matching the APK structure + const stagingRoot = path.join(getDotRockPath(), 'android/sign/bundle-staging'); + const stagedBundleDir = path.join(stagingRoot, assetsPath); -+ -+ // Clean and recreate staging + if (fs.existsSync(stagingRoot)) { + fs.rmSync(stagingRoot, { recursive: true }); + } + fs.mkdirSync(stagedBundleDir, { recursive: true }); + fs.copyFileSync(jsBundlePath, path.join(stagedBundleDir, 'index.android.bundle')); -+ try { - const zip = new AdmZip(archivePath); - const assetsPath = isAab(archivePath) ? 'base/assets' : 'assets'; - zip.deleteFile(path.join(assetsPath, 'index.android.bundle')); - zip.addLocalFile(jsBundlePath, assetsPath, 'index.android.bundle'); - zip.writeZip(archivePath); -- } -- catch (error) { -- throw new RockError(`Failed to replace JS bundle in destination file: ${archivePath}`, { cause: error }); + // Remove old bundle -+ try { -+ await spawn('zip', ['-d', archivePath, bundleEntryPath]); -+ } catch (error) { -+ if (error.exitCode !== 12) throw error; -+ } -+ -+ // Add new bundle with NO compression to prevent corruption -+ // Use relative path from staging root so structure is preserved ++ await spawn('zip', ['-d', archivePath, bundleEntryPath]); ++ // Uses store-only compression (-0) to prevent bundle corruption. + await spawn('zip', ['-0', '-r', archivePath, assetsPath], { -+ cwd: stagingRoot ++ cwd: stagingRoot, + }); -+ -+ } catch (error) { -+ throw new RockError(`Failed to replace JS bundle in destination file: ${archivePath}`, { cause: error.stderr ?? error }); -+ } finally { + } + catch (error) { + throw new RockError(`Failed to replace JS bundle in destination file: ${archivePath}`, { cause: error }); + } ++ finally { + if (fs.existsSync(stagingRoot)) { + fs.rmSync(stagingRoot, { recursive: true }); + } - } ++ } } function isSdkGTE35(versionString) { -@@ -111,6 +136,9 @@ Please follow instructions at: https://reactnative.dev/docs/set-up-your-environm - inputArchivePath, - outputPath, - ]; -+ -+ -+ console.log('zipalignArgs', zipalignArgs); - try { - await spawn(zipAlignPath, zipalignArgs); - } + const match = versionString.match(/build-tools\/([\d.]+)/); diff --git a/patches/@rock-js/platform-android/details.md b/patches/@rock-js/platform-android/details.md index 8204cc4e44fc..1816bb8d509a 100644 --- a/patches/@rock-js/platform-android/details.md +++ b/patches/@rock-js/platform-android/details.md @@ -13,3 +13,17 @@ - E/App issue: https://github.com/Expensify/App/issues/74400 - PR introducing patch: https://github.com/Expensify/App/pull/73525 +### [@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch](@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch) + +- Reason: + + ``` + Fixes bundle corruption in cache and re-sign flow by replacing AdmZip with native zip commands. + The AdmZip library was applying default compression when adding files, which corrupted artifacts (native libraries). + This caused INSTALL_FAILED_CONTAINER_ERROR with size/crc32 mismatch errors on second builds using cache. + The fix uses native zip commands with -0 flag (store-only compression) to prevent bundle corruption. + ``` + +- Upstream PR/issue: https://github.com/callstackincubator/rock/pull/647 +- E/App issue: https://github.com/Expensify/App/issues/62296 +- PR introducing patch: https://github.com/Expensify/App/pull/76061 \ No newline at end of file diff --git a/patches/@rock-js/platform-apple-helpers/@rock-js+platform-apple-helpers+0.11.9+002+add-logs.patch b/patches/@rock-js/platform-apple-helpers/@rock-js+platform-apple-helpers+0.11.9+002+add-logs.patch deleted file mode 100644 index 5926ff37b365..000000000000 --- a/patches/@rock-js/platform-apple-helpers/@rock-js+platform-apple-helpers+0.11.9+002+add-logs.patch +++ /dev/null @@ -1,207 +0,0 @@ -diff --git a/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/modifyApp.js b/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/modifyApp.js -index fa2ac99..03582f4 100644 ---- a/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/modifyApp.js -+++ b/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/modifyApp.js -@@ -19,16 +19,33 @@ export const modifyApp = async (options) => { - const appPaths = getAppPaths(options.outputPath ?? options.appPath); - if (options.buildJsBundle) { - loader.start('Building JS bundle'); -+ logger.log(`Building bundle to: ${appPaths.jsBundle}`); -+ logger.log(`Assets destination: ${appPaths.assetsDest}`); -+ logger.log(`Use Hermes: ${options.useHermes ?? true}`); - await buildJsBundle({ - bundleOutputPath: appPaths.jsBundle, - assetsDestPath: appPaths.assetsDest, - useHermes: options.useHermes ?? true, - }); -+ // Log bundle info after building -+ if (fs.existsSync(appPaths.jsBundle)) { -+ const bundleSize = fs.statSync(appPaths.jsBundle).size; -+ logger.log(`Built bundle size: ${bundleSize} bytes`); -+ } - loader.stop(`Built JS bundle: ${colorLink(relativeToCwd(appPaths.jsBundle))}`); - } - else if (options.jsBundlePath) { - loader.start('Replacing JS bundle'); -+ logger.log(`Replacing bundle: ${appPaths.jsBundle}`); -+ logger.log(`New bundle: ${options.jsBundlePath}`); -+ logger.log(`New bundle size: ${fs.statSync(options.jsBundlePath).size} bytes`); -+ // Log old bundle info -+ if (fs.existsSync(appPaths.jsBundle)) { -+ const oldSize = fs.statSync(appPaths.jsBundle).size; -+ logger.log(`Old bundle size: ${oldSize} bytes`); -+ } - fs.copyFileSync(options.jsBundlePath, appPaths.jsBundle); -+ logger.log(`Bundle replaced successfully`); - loader.stop(`Replaced JS bundle with ${colorLink(relativeToCwd(options.jsBundlePath))}`); - } - logger.log(`Modified APP file with new JS bundle. Available at: ${colorLink(relativeToCwd(options.outputPath ?? options.appPath))}`); -diff --git a/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/modifyIpa.js b/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/modifyIpa.js -index 88e9fef..f18b12b 100644 ---- a/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/modifyIpa.js -+++ b/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/modifyIpa.js -@@ -17,16 +17,33 @@ export const modifyIpa = async (options) => { - const appPaths = getAppPaths(appPath); - if (options.buildJsBundle) { - loader.start('Building JS bundle'); -+ logger.log(`Building bundle to: ${appPaths.jsBundle}`); -+ logger.log(`Assets destination: ${appPaths.assetsDest}`); -+ logger.log(`Use Hermes: ${options.useHermes ?? true}`); - await buildJsBundle({ - bundleOutputPath: appPaths.jsBundle, - assetsDestPath: appPaths.assetsDest, - useHermes: options.useHermes ?? true, - }); -+ // Log bundle info after building -+ if (fs.existsSync(appPaths.jsBundle)) { -+ const bundleSize = fs.statSync(appPaths.jsBundle).size; -+ logger.log(`Built bundle size: ${bundleSize} bytes`); -+ } - loader.stop(`Built JS bundle: ${colorLink(relativeToCwd(appPaths.jsBundle))}`); - } - else if (options.jsBundlePath) { - loader.start('Replacing JS bundle'); -+ logger.log(`Replacing bundle: ${appPaths.jsBundle}`); -+ logger.log(`New bundle: ${options.jsBundlePath}`); -+ logger.log(`New bundle size: ${fs.statSync(options.jsBundlePath).size} bytes`); -+ // Log old bundle info -+ if (fs.existsSync(appPaths.jsBundle)) { -+ const oldSize = fs.statSync(appPaths.jsBundle).size; -+ logger.log(`Old bundle size: ${oldSize} bytes`); -+ } - fs.copyFileSync(options.jsBundlePath, appPaths.jsBundle); -+ logger.log(`Bundle replaced successfully`); - loader.stop(`Replaced JS bundle with ${colorLink(relativeToCwd(options.jsBundlePath))}`); - } - // 3. Sign the IPA contents -@@ -35,7 +52,7 @@ export const modifyIpa = async (options) => { - if (!identity) { - const currentIdentity = await getIdentityFromProvisioningPlist(tempPaths.provisioningPlist); - if (currentIdentity) { -- logger.debug(`Extracted identity from provisioning profile: ${currentIdentity}`); -+ logger.log(`Extracted identity from provisioning profile: ${currentIdentity}`); - } - identity = await promptSigningIdentity(currentIdentity); - } -@@ -52,10 +69,26 @@ export const modifyIpa = async (options) => { - tempPaths.entitlementsPlist, - appPath, - ]; -+ logger.log(`Running codesign with identity: ${identity}`); -+ logger.log(`Signing: ${appPath}`); -+ logger.log(`Entitlements: ${tempPaths.entitlementsPlist}`); - try { -- await spawn('codesign', codeSignArgs, { cwd: tempPaths.content }); -+ const result = await spawn('codesign', codeSignArgs, { cwd: tempPaths.content }); -+ logger.log(`codesign completed successfully`); -+ if (result.stdout) { -+ logger.log(`codesign output: ${result.stdout}`); -+ } -+ // Verify the signature -+ logger.log(`Verifying signature...`); -+ const verifyResult = await spawn('codesign', [ -+ '--verify', -+ '--verbose', -+ appPath, -+ ]); -+ logger.log(`Signature verification: ${verifyResult.stdout || 'OK'}`); - } - catch (error) { -+ logger.error(`codesign failed: ${error.stderr}`); - throw new RockError('Codesign failed', { - cause: error.stderr, - }); -diff --git a/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/utils.js b/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/utils.js -index cfc9a22..a91b66b 100644 ---- a/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/utils.js -+++ b/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/commands/sign/utils.js -@@ -1,6 +1,6 @@ --import { existsSync, mkdirSync, rmSync } from 'node:fs'; -+import { existsSync, mkdirSync, rmSync, statSync } from 'node:fs'; - import path from 'node:path'; --import { findDirectoriesWithPattern, getDotRockPath, RockError, } from '@rock-js/tools'; -+import { findDirectoriesWithPattern, getDotRockPath, logger, RockError, } from '@rock-js/tools'; - import AdmZip from 'adm-zip'; - /** - * Temporary paths for sign operation. -@@ -40,12 +40,27 @@ export function getAppPaths(appPath) { - * @returns Path to .app directory (package) inside the IPA file. - */ - export const unpackIpa = (ipaPath, destination) => { -+ logger.log(`Unpacking IPA: ${ipaPath}`); -+ logger.log(`IPA size: ${statSync(ipaPath).size} bytes`); -+ logger.log(`Destination: ${destination}`); - if (existsSync(destination)) { - rmSync(destination, { recursive: true, force: true }); - } - mkdirSync(destination, { recursive: true }); - const zip = new AdmZip(ipaPath); -+ const entries = zip.getEntries(); -+ logger.log(`IPA contains ${entries.length} entries`); -+ // Log bundle info if present -+ const bundleEntry = entries.find((e) => e.entryName.includes('main.jsbundle')); -+ if (bundleEntry) { -+ const compressionMethod = bundleEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; -+ logger.log(`Original bundle: ${bundleEntry.entryName}`); -+ logger.log(`Original bundle compression: ${compressionMethod} (method=${bundleEntry.header.method})`); -+ logger.log(`Original bundle size: ${bundleEntry.header.size} bytes`); -+ logger.log(`Original bundle compressed size: ${bundleEntry.header.compressedSize} bytes`); -+ } - zip.extractAllTo(destination, true); -+ logger.log(`Extracted to: ${destination}`); - const payloadPath = `${destination}/Payload`; - if (!existsSync(payloadPath)) { - throw new Error('Payload folder not found in the extracted IPA file'); -@@ -54,6 +69,13 @@ export const unpackIpa = (ipaPath, destination) => { - if (!appPath) { - throw new RockError(`.app package not found in the extracted IPA file ${payloadPath}`); - } -+ logger.log(`Found .app at: ${appPath}`); -+ // Log bundle file info if exists -+ const jsBundlePath = path.join(appPath, 'main.jsbundle'); -+ if (existsSync(jsBundlePath)) { -+ const bundleSize = statSync(jsBundlePath).size; -+ logger.log(`Extracted bundle size: ${bundleSize} bytes`); -+ } - return appPath; - }; - /** -@@ -63,12 +85,37 @@ export const unpackIpa = (ipaPath, destination) => { - * @returns Path to the output IPA file. - */ - export const packIpa = (contentPath, ipaPath) => { -+ logger.log(`Packing IPA from: ${contentPath}`); - if (existsSync(ipaPath)) { - rmSync(ipaPath, { recursive: true, force: true }); - } -+ // Find and log bundle info before packing -+ const appDirs = findDirectoriesWithPattern(path.join(contentPath, 'Payload'), /\.app$/); -+ if (appDirs.length > 0) { -+ const jsBundlePath = path.join(appDirs[0], 'main.jsbundle'); -+ if (existsSync(jsBundlePath)) { -+ const bundleSize = statSync(jsBundlePath).size; -+ logger.log(`Bundle to pack: ${jsBundlePath}`); -+ logger.log(`Bundle size: ${bundleSize} bytes`); -+ } -+ } - const zip = new AdmZip(); - zip.addLocalFolder(contentPath); -+ logger.log(`Added folder contents to zip`); -+ // Log what compression was applied -+ const entries = zip.getEntries(); -+ logger.log(`Packed ${entries.length} entries`); -+ const bundleEntry = entries.find((e) => e.entryName.includes('main.jsbundle')); -+ if (bundleEntry) { -+ const compressionMethod = bundleEntry.header.method === 0 ? 'STORED' : 'DEFLATED'; -+ logger.log(`Packed bundle: ${bundleEntry.entryName}`); -+ logger.log(`Packed bundle compression: ${compressionMethod} (method=${bundleEntry.header.method})`); -+ logger.log(`Packed bundle size: ${bundleEntry.header.size} bytes`); -+ logger.log(`Packed bundle compressed size: ${bundleEntry.header.compressedSize} bytes`); -+ } - zip.writeZip(ipaPath); -+ logger.log(`Wrote IPA: ${ipaPath}`); -+ logger.log(`Final IPA size: ${statSync(ipaPath).size} bytes`); - return ipaPath; - }; - //# sourceMappingURL=utils.js.map -\ No newline at end of file From ef0cea8de180355a6f70e6954f9c0c6cf01766ee Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Mon, 15 Dec 2025 15:20:17 +0100 Subject: [PATCH 23/34] patch fix --- ...id+0.11.9+002+use-zip-instead-admzip.patch | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch b/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch index a9e8069f0fb2..1dc341111384 100644 --- a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch +++ b/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch @@ -1,26 +1,30 @@ diff --git a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js -index bf00b00..50a5307 100644 +index bf00b00..42c038d 100644 --- a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js +++ b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js -@@ -30,13 +30,13 @@ export async function signAndroid(options) { +@@ -30,13 +30,16 @@ export async function signAndroid(options) { const tempArchivePath = path.join(tempPath, `output-app.${extension}`); loader.start(`Initializing output ${extension.toUpperCase()}...`); try { - const zip = new AdmZip(options.binaryPath); -+ fs.mkdirSync(tempPath, { recursive: true }); -+ fs.copyFileSync(options.binaryPath, tempArchivePath); - // Remove old signature files +- // Remove old signature files - zip.deleteFile('META-INF/*'); - zip.writeZip(tempArchivePath); -+ await spawn('zip', ['-d', tempArchivePath, 'META-INF/*']); ++ fs.mkdirSync(tempPath, { recursive: true }); ++ fs.copyFileSync(options.binaryPath, tempArchivePath); ++ // Remove old signature files (but keep service loaders and other non-signature files) ++ await spawn('zip', ['-d', tempArchivePath, 'META-INF/*.RSA', 'META-INF/*.DSA', 'META-INF/*.SF', 'META-INF/MANIFEST.MF']); } catch (error) { - throw new RockError(`Failed to initialize output file: ${options.outputPath}`, { cause: error.stderr }); -+ throw new RockError(`Failed to initialize output file: ${options.outputPath}`, { cause: error }); ++ // zip returns exit code 12 if files don't exist, which is fine for re-signing ++ if (error.exitCode !== 12) { ++ throw new RockError(`Failed to initialize output file: ${options.outputPath}`, { cause: error }); ++ } } loader.stop(`Initialized output ${extension.toUpperCase()}`); // 3. Replace JS bundle if provided -@@ -78,16 +78,31 @@ function validateOptions(options) { +@@ -78,16 +81,31 @@ function validateOptions(options) { } } async function replaceJsBundle({ archivePath, jsBundlePath, }) { From aa1e8fd98fae729c6be6d28af6df07f8c6167cbb Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Mon, 15 Dec 2025 16:13:43 +0100 Subject: [PATCH 24/34] update gh action --- .github/workflows/testBuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index 54f43a9d18ec..114c565ef1af 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -346,7 +346,7 @@ jobs: - name: Rock Remote Build - Android id: rock-remote-build-android - uses: LukasMod/android@43eccd3ece4f1e812d3097f6fc639c6945f04b73 + uses: LukasMod/android@5f0adf87de28c286c3f19e39fb923bc391445e42 env: GITHUB_TOKEN: ${{ github.token }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} From e24c9e23a76a18d697426ce768ba173f995646f8 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Mon, 15 Dec 2025 17:39:02 +0100 Subject: [PATCH 25/34] remove MET-INF deletion --- ...id+0.11.9+002+use-zip-instead-admzip.patch | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch b/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch index 1dc341111384..358fb4161313 100644 --- a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch +++ b/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch @@ -1,30 +1,26 @@ diff --git a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js -index bf00b00..42c038d 100644 +index bf00b00..1060adf 100644 --- a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js +++ b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js -@@ -30,13 +30,16 @@ export async function signAndroid(options) { +@@ -29,15 +29,8 @@ export async function signAndroid(options) { + // 2. Initialize temporary archive file const tempArchivePath = path.join(tempPath, `output-app.${extension}`); loader.start(`Initializing output ${extension.toUpperCase()}...`); - try { +- try { - const zip = new AdmZip(options.binaryPath); - // Remove old signature files - zip.deleteFile('META-INF/*'); - zip.writeZip(tempArchivePath); -+ fs.mkdirSync(tempPath, { recursive: true }); -+ fs.copyFileSync(options.binaryPath, tempArchivePath); -+ // Remove old signature files (but keep service loaders and other non-signature files) -+ await spawn('zip', ['-d', tempArchivePath, 'META-INF/*.RSA', 'META-INF/*.DSA', 'META-INF/*.SF', 'META-INF/MANIFEST.MF']); - } - catch (error) { +- } +- catch (error) { - throw new RockError(`Failed to initialize output file: ${options.outputPath}`, { cause: error.stderr }); -+ // zip returns exit code 12 if files don't exist, which is fine for re-signing -+ if (error.exitCode !== 12) { -+ throw new RockError(`Failed to initialize output file: ${options.outputPath}`, { cause: error }); -+ } - } +- } ++ fs.mkdirSync(tempPath, { recursive: true }); ++ fs.copyFileSync(options.binaryPath, tempArchivePath); loader.stop(`Initialized output ${extension.toUpperCase()}`); // 3. Replace JS bundle if provided -@@ -78,16 +81,31 @@ function validateOptions(options) { + if (options.jsBundlePath) { +@@ -78,16 +71,31 @@ function validateOptions(options) { } } async function replaceJsBundle({ archivePath, jsBundlePath, }) { From 3b5ddae039cf0f97d1c30c8dbf4a972fed96d22d Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Tue, 16 Dec 2025 09:15:15 +0100 Subject: [PATCH 26/34] remove fork from rock-remote-build-android --- .github/workflows/testBuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index 114c565ef1af..aa49593891af 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -346,7 +346,7 @@ jobs: - name: Rock Remote Build - Android id: rock-remote-build-android - uses: LukasMod/android@5f0adf87de28c286c3f19e39fb923bc391445e42 + uses: callstackincubator/android@0bbc1b7c2e1a8be1ecb4d6c744c211869823fd65 env: GITHUB_TOKEN: ${{ github.token }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} From 1c5761808c38b713ddb5375371a4dc12c72812a2 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Wed, 17 Dec 2025 09:58:55 +0100 Subject: [PATCH 27/34] remove fork from rock-remote-build-ios --- .github/workflows/testBuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index aa49593891af..34ec66c710cd 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -456,7 +456,7 @@ jobs: - name: Rock Remote Build - iOS id: rock-remote-build-ios - uses: LukasMod/ios@75aeadfcb0ae8407cfa654cd9c840976683a9c24 + uses: callstackincubator/ios@8dcef6cc275e0cf3299f5a97cde5ebd635c887d7 env: GITHUB_TOKEN: ${{ github.token }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} From 60af0c19e6ba9d0ef33ef98af09569e8a4a35f32 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Thu, 18 Dec 2025 10:18:55 +0100 Subject: [PATCH 28/34] update rock to 0.11.13, remove patches --- package-lock.json | 195 ++++-------------- package.json | 12 +- ...1.9+001+missing-app-name-hybrid-case.patch | 28 --- ...id+0.11.9+002+use-zip-instead-admzip.patch | 59 ------ patches/@rock-js/platform-android/details.md | 29 --- ...te-fingerprint-for-local-builds-only.patch | 13 -- .../platform-apple-helpers/details.md | 15 -- ...-s3+0.11.9+001+support-public-access.patch | 72 ------- ...r-s3+0.11.9+002+add-acl-upload-param.patch | 27 --- patches/@rock-js/provider-s3/details.md | 26 --- 10 files changed, 50 insertions(+), 426 deletions(-) delete mode 100644 patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+001+missing-app-name-hybrid-case.patch delete mode 100644 patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch delete mode 100644 patches/@rock-js/platform-android/details.md delete mode 100644 patches/@rock-js/platform-apple-helpers/@rock-js+platform-apple-helpers+0.11.9+001+recalculate-fingerprint-for-local-builds-only.patch delete mode 100644 patches/@rock-js/platform-apple-helpers/details.md delete mode 100644 patches/@rock-js/provider-s3/@rock-js+provider-s3+0.11.9+001+support-public-access.patch delete mode 100644 patches/@rock-js/provider-s3/@rock-js+provider-s3+0.11.9+002+add-acl-upload-param.patch delete mode 100644 patches/@rock-js/provider-s3/details.md diff --git a/package-lock.json b/package-lock.json index c6f35f631d06..940176228af8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -184,12 +184,10 @@ "@react-native/babel-preset": "0.81.4", "@react-native/metro-config": "0.81.4", "@react-navigation/devtools": "^6.0.10", - "@rock-js/config": "0.11.9", - "@rock-js/platform-android": "0.11.9", - "@rock-js/platform-ios": "0.11.9", - "@rock-js/plugin-metro": "0.11.9", - "@rock-js/provider-s3": "0.11.9", - "@rock-js/tools": "0.11.9", + "@rock-js/platform-android": "0.11.13", + "@rock-js/platform-ios": "0.11.13", + "@rock-js/plugin-metro": "0.11.13", + "@rock-js/provider-s3": "0.11.13", "@sentry/webpack-plugin": "4.6.0", "@storybook/addon-a11y": "^8.6.9", "@storybook/addon-essentials": "^8.6.9", @@ -283,7 +281,7 @@ "react-refresh": "^0.14.2", "react-test-renderer": "19.1.0", "reassure": "^1.0.0-rc.4", - "rock": "github:LukasMod/rock#feat/adhoc-android-dist-3", + "rock": "0.11.13", "semver": "7.5.2", "setimmediate": "^1.0.5", "shellcheck": "^1.1.0", @@ -12981,29 +12979,28 @@ } }, "node_modules/@rock-js/config": { - "version": "0.11.9", - "resolved": "https://registry.npmjs.org/@rock-js/config/-/config-0.11.9.tgz", - "integrity": "sha512-RMJi3l9cq6VaIacyNQZ8F7pucxukX4iBECp1yMHQx400b5c+fgsBW3O6vaMNugQXBEbqr4j79tI09G0zW3tZ2w==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@rock-js/config/-/config-0.11.13.tgz", + "integrity": "sha512-cUkJ5Tjpp6UGm7t1a1HEJ3CzB5T2JmnAwZtVY0juaRaFobk4MoJtbY+A0oaZf0Hb+fQjfde2hJcjj7CAGiMFzQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", - "@rock-js/provider-github": "^0.11.9", - "@rock-js/tools": "^0.11.9", + "@rock-js/provider-github": "^0.11.13", + "@rock-js/tools": "^0.11.13", "joi": "^17.13.3", "tslib": "^2.3.0" } }, "node_modules/@rock-js/platform-android": { - "version": "0.11.9", - "resolved": "https://registry.npmjs.org/@rock-js/platform-android/-/platform-android-0.11.9.tgz", - "integrity": "sha512-SeX4ZXi3fcfv1yMA5GbFozZOyiE5mOpg+aZhpuMLvJt+DVRiRHleegS0zMx548qXC0DJuf1J+pprXQEayF11Ww==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@rock-js/platform-android/-/platform-android-0.11.13.tgz", + "integrity": "sha512-GfbjwrjxZaechsMft2xAiKeY0ariGVqKCfT/Buryd94MPPcHpfMWJOge3xRiAYhB1pJYFnRFQCJ6qS8il3EKpA==", "dev": true, "license": "MIT", "dependencies": { "@react-native-community/cli-config-android": "^20.0.0", - "@rock-js/tools": "^0.11.9", - "adm-zip": "^0.5.16", + "@rock-js/tools": "^0.11.13", "tslib": "^2.3.0" } }, @@ -13116,31 +13113,31 @@ } }, "node_modules/@rock-js/platform-apple-helpers": { - "version": "0.11.9", - "resolved": "https://registry.npmjs.org/@rock-js/platform-apple-helpers/-/platform-apple-helpers-0.11.9.tgz", - "integrity": "sha512-T/+keSlUcZwC2Y1LdRU0EfvKdgrSKkysTOiJy1oR1hYeQruhlslvVTN+45+BCKWjsXUedTfMU+e72cU5YmsYdQ==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@rock-js/platform-apple-helpers/-/platform-apple-helpers-0.11.13.tgz", + "integrity": "sha512-5F+bA10VZ6GCs0GrTVQ0ZFLlQ9YX5loXAcOR7n2MvCfJ1oIownxzbh6HUbn5Z6ts4z3JzVg3NtoqM1prGSUtfg==", "dev": true, "license": "MIT", "dependencies": { "@react-native-community/cli-config": "^20.0.0", "@react-native-community/cli-config-apple": "^20.0.0", - "@rock-js/tools": "^0.11.9", + "@rock-js/tools": "^0.11.13", "adm-zip": "^0.5.16", "fast-xml-parser": "^4.5.0", "tslib": "^2.3.0" } }, "node_modules/@rock-js/platform-ios": { - "version": "0.11.9", - "resolved": "https://registry.npmjs.org/@rock-js/platform-ios/-/platform-ios-0.11.9.tgz", - "integrity": "sha512-RIUnbtS7k6YonUWc/Iz+Q+/oIggoYVIrcU9wElStdItJikTUBNovtKk/pVYbXR5tRZ4N6Hp7w0mvnpMZE/EqRA==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@rock-js/platform-ios/-/platform-ios-0.11.13.tgz", + "integrity": "sha512-Cqo2CrPlqtKNkbOHXhz5vnM7oOK1NlmydFrOofRlhaF0dUYUivdvNomTm1N/36sgefdfQh6hU29dKrAcR249og==", "dev": true, "license": "MIT", "dependencies": { "@react-native-community/cli-config-apple": "^20.0.0", "@react-native-community/cli-types": "^20.0.0", - "@rock-js/platform-apple-helpers": "^0.11.9", - "@rock-js/tools": "^0.11.9", + "@rock-js/platform-apple-helpers": "^0.11.13", + "@rock-js/tools": "^0.11.13", "tslib": "^2.3.0" } }, @@ -13263,14 +13260,14 @@ } }, "node_modules/@rock-js/plugin-metro": { - "version": "0.11.9", - "resolved": "https://registry.npmjs.org/@rock-js/plugin-metro/-/plugin-metro-0.11.9.tgz", - "integrity": "sha512-ZOI477DJs3bnanKph0WrzR7p/Vet2uKPDKq5acUgV6uo35dxDoehITI0JFuEp/eTdBlVBa9noZiBsshxshucmA==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@rock-js/plugin-metro/-/plugin-metro-0.11.13.tgz", + "integrity": "sha512-58rh5GtvpPD9b2+5j3llNE2z/tyz0/H6a4Kmh6reI7C+z5PyafZSjjvaMUkuYzDLbPSb+h9GhqZdBNjLGod4GQ==", "dev": true, "license": "MIT", "dependencies": { "@react-native-community/cli-server-api": "^20.0.0", - "@rock-js/tools": "^0.11.9", + "@rock-js/tools": "^0.11.13", "metro": "^0.83.1", "metro-config": "^0.83.1", "metro-core": "^0.83.1", @@ -13814,113 +13811,21 @@ } }, "node_modules/@rock-js/provider-github": { - "version": "0.11.12", - "resolved": "https://registry.npmjs.org/@rock-js/provider-github/-/provider-github-0.11.12.tgz", - "integrity": "sha512-fqLOltizyqzWZhd5QBd6SPppFMP06TpGbqDMkF8fuoWkIAQU2Kw0vcVBFSQBueaxgCUD9qNeFiwjnMpN+d4PjQ==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@rock-js/provider-github/-/provider-github-0.11.13.tgz", + "integrity": "sha512-/Ut2JLkiTqYE0n1HXOa7wnV39WIXyCuTdHewcON9WodaA8sD/9ERY8pPSUrWW7SrDVtvZWSQvAQPyqgx5fQRgw==", "dev": true, "license": "MIT", "dependencies": { - "@rock-js/tools": "^0.11.12", + "@rock-js/tools": "^0.11.13", "ts-regex-builder": "^1.8.2", "tslib": "^2.3.0" } }, - "node_modules/@rock-js/provider-github/node_modules/@rock-js/tools": { - "version": "0.11.12", - "resolved": "https://registry.npmjs.org/@rock-js/tools/-/tools-0.11.12.tgz", - "integrity": "sha512-YQTlH2IJRYCoBk82h2qqf/QcZK/CvNtBZfcu30iJvXWMEQYYPKgixyqXNodxn55mJBczGUbFzSDePp8xaH0www==", - "dev": true, - "license": "MIT", - "dependencies": { - "@clack/prompts": "^0.11.0", - "adm-zip": "^0.5.16", - "appdirsjs": "^1.2.7", - "fs-fingerprint": "^0.11.0", - "is-unicode-supported": "^2.1.0", - "nano-spawn": "^0.2.0", - "picocolors": "^1.1.1", - "string-argv": "^0.3.2", - "tar": "^7.5.1", - "tslib": "^2.3.0" - } - }, - "node_modules/@rock-js/provider-github/node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/@rock-js/provider-github/node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@rock-js/provider-github/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/@rock-js/provider-github/node_modules/minizlib": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", - "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@rock-js/provider-github/node_modules/tar": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz", - "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@rock-js/provider-github/node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, "node_modules/@rock-js/provider-s3": { - "version": "0.11.9", - "resolved": "https://registry.npmjs.org/@rock-js/provider-s3/-/provider-s3-0.11.9.tgz", - "integrity": "sha512-4hjy5jKft1L0lN6+fILtiSNr9AmWDQZU4BZI5sGeCZJBiI7qnQc8ZK/BPQgnbNX1Q6+8d5bjNPYJsPL8Ned7sw==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@rock-js/provider-s3/-/provider-s3-0.11.13.tgz", + "integrity": "sha512-gIMRwmSJrSk6mt+ODuLTenn4gwqz83s6//1PT427MML/SScGyJjwarp06HTQqA3m00Odw/9ZBEzMwSH9SNu6mw==", "dev": true, "license": "MIT", "dependencies": { @@ -13929,14 +13834,14 @@ "@aws-sdk/credential-providers": "^3.830.0", "@aws-sdk/lib-storage": "^3.830.0", "@aws-sdk/s3-request-presigner": "^3.830.0", - "@rock-js/tools": "^0.11.9", + "@rock-js/tools": "^0.11.13", "tslib": "^2.3.0" } }, "node_modules/@rock-js/tools": { - "version": "0.11.9", - "resolved": "https://registry.npmjs.org/@rock-js/tools/-/tools-0.11.9.tgz", - "integrity": "sha512-tswYFPTethkp2GxIhMVD64zOp4SX7IyFpx3gtH8rw+2gn0EP8cxkG8S+SU0+IwFRVw1Of8yARRyyzq1XVKA04w==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@rock-js/tools/-/tools-0.11.13.tgz", + "integrity": "sha512-XMNFIQU/kXEGc7EhVndBqUGLQxfZWo9nY1hKe6g7QnS8JGB0RjSvqbwjpmTdsGuc1emiB8zLbk+s0CX7aJhQ6Q==", "dev": true, "license": "MIT", "dependencies": { @@ -33987,16 +33892,6 @@ "semver": "^7.3.5" } }, - "node_modules/node-apk": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/node-apk/-/node-apk-1.2.1.tgz", - "integrity": "sha512-I0TY1x5m1pkFzjYdaGrrAu/Mh9qnnk2/BoMAU6bvBxTTD/oNQyTWbu3LTdONgV2rnLHf23jJ00Y/VV4BzZ6YXQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "node-forge": "^1.3.1" - } - }, "node_modules/node-dir": { "version": "0.1.17", "dev": true, @@ -37843,22 +37738,22 @@ "license": "BSD-3-Clause" }, "node_modules/rock": { - "version": "0.0.0", - "resolved": "git+ssh://git@github.com/LukasMod/rock.git#1ff71092c0ad4b2e4fc2f73597ad82d7455ebcec", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/rock/-/rock-0.11.13.tgz", + "integrity": "sha512-QzGmgIE+Zz3nU486garPpBB7DzgAX42oo0uvfxit1qs/d8Bi+sCk9qZTDlVQjEdJ+L9nCglx5MhgD9r5R5orvQ==", "dev": true, "license": "MIT", "dependencies": { "@react-native-community/cli-config": "^20.0.0", - "@rock-js/config": "^0.11.9", - "@rock-js/tools": "^0.11.9", + "@rock-js/config": "^0.11.13", + "@rock-js/tools": "^0.11.13", "adm-zip": "^0.5.16", "commander": "^12.1.0", - "node-apk": "^1.2.1", "tar": "^7.5.1", - "tslib": "^2.8.1" + "tslib": "^2.3.0" }, "bin": { - "rock": "packages/cli/dist/src/bin.js" + "rock": "dist/src/bin.js" } }, "node_modules/rock/node_modules/chownr": { diff --git a/package.json b/package.json index 2142c1bce9ab..9306f07776fc 100644 --- a/package.json +++ b/package.json @@ -257,12 +257,10 @@ "@react-native/babel-preset": "0.81.4", "@react-native/metro-config": "0.81.4", "@react-navigation/devtools": "^6.0.10", - "@rock-js/config": "0.11.9", - "@rock-js/platform-android": "0.11.9", - "@rock-js/platform-ios": "0.11.9", - "@rock-js/plugin-metro": "0.11.9", - "@rock-js/provider-s3": "0.11.9", - "@rock-js/tools": "0.11.9", + "@rock-js/platform-android": "0.11.13", + "@rock-js/platform-ios": "0.11.13", + "@rock-js/plugin-metro": "0.11.13", + "@rock-js/provider-s3": "0.11.13", "@sentry/webpack-plugin": "4.6.0", "@storybook/addon-a11y": "^8.6.9", "@storybook/addon-essentials": "^8.6.9", @@ -356,7 +354,7 @@ "react-refresh": "^0.14.2", "react-test-renderer": "19.1.0", "reassure": "^1.0.0-rc.4", - "rock": "github:LukasMod/rock#feat/adhoc-android-dist-3", + "rock": "0.11.13", "semver": "7.5.2", "setimmediate": "^1.0.5", "shellcheck": "^1.1.0", diff --git a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+001+missing-app-name-hybrid-case.patch b/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+001+missing-app-name-hybrid-case.patch deleted file mode 100644 index faa20f24c304..000000000000 --- a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+001+missing-app-name-hybrid-case.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff --git a/node_modules/@rock-js/platform-android/dist/src/lib/commands/runAndroid/findOutputFile.js b/node_modules/@rock-js/platform-android/dist/src/lib/commands/runAndroid/findOutputFile.js -index 2938c29..0a66a15 100644 ---- a/node_modules/@rock-js/platform-android/dist/src/lib/commands/runAndroid/findOutputFile.js -+++ b/node_modules/@rock-js/platform-android/dist/src/lib/commands/runAndroid/findOutputFile.js -@@ -1,4 +1,4 @@ --import { existsSync } from 'node:fs'; -+import { existsSync, readdirSync } from 'node:fs'; - import { logger, spawn } from '@rock-js/tools'; - import { getAdbPath } from './adb.js'; - export async function findOutputFile(androidProject, tasks, device) { -@@ -38,6 +38,17 @@ async function getInstallOutputFileName(appName, variant, buildDirectory, apkOrA - if (existsSync(`${buildDirectory}/${outputFile}`)) { - return outputFile; - } -+ -+ // check if there is a file like -debug.apk (missing app name) -+ if (existsSync(buildDirectory)) { -+ const pattern = `-${variant}.${apkOrAab}`; -+ const files = readdirSync(buildDirectory); -+ const matchingFile = files?.find((file) => file.endsWith(pattern)); -+ if (matchingFile) { -+ return matchingFile; -+ } -+ } -+ - logger.debug('Could not find the output file:', { - buildDirectory, - outputFile, diff --git a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch b/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch deleted file mode 100644 index 358fb4161313..000000000000 --- a/patches/@rock-js/platform-android/@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch +++ /dev/null @@ -1,59 +0,0 @@ -diff --git a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js -index bf00b00..1060adf 100644 ---- a/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js -+++ b/node_modules/@rock-js/platform-android/dist/src/lib/commands/signAndroid/signAndroid.js -@@ -29,15 +29,8 @@ export async function signAndroid(options) { - // 2. Initialize temporary archive file - const tempArchivePath = path.join(tempPath, `output-app.${extension}`); - loader.start(`Initializing output ${extension.toUpperCase()}...`); -- try { -- const zip = new AdmZip(options.binaryPath); -- // Remove old signature files -- zip.deleteFile('META-INF/*'); -- zip.writeZip(tempArchivePath); -- } -- catch (error) { -- throw new RockError(`Failed to initialize output file: ${options.outputPath}`, { cause: error.stderr }); -- } -+ fs.mkdirSync(tempPath, { recursive: true }); -+ fs.copyFileSync(options.binaryPath, tempArchivePath); - loader.stop(`Initialized output ${extension.toUpperCase()}`); - // 3. Replace JS bundle if provided - if (options.jsBundlePath) { -@@ -78,16 +71,31 @@ function validateOptions(options) { - } - } - async function replaceJsBundle({ archivePath, jsBundlePath, }) { -+ const assetsPath = isAab(archivePath) ? 'base/assets' : 'assets'; -+ const bundleEntryPath = path.posix.join(assetsPath, 'index.android.bundle'); -+ const stagingRoot = path.join(getDotRockPath(), 'android/sign/bundle-staging'); -+ const stagedBundleDir = path.join(stagingRoot, assetsPath); -+ if (fs.existsSync(stagingRoot)) { -+ fs.rmSync(stagingRoot, { recursive: true }); -+ } -+ fs.mkdirSync(stagedBundleDir, { recursive: true }); -+ fs.copyFileSync(jsBundlePath, path.join(stagedBundleDir, 'index.android.bundle')); - try { -- const zip = new AdmZip(archivePath); -- const assetsPath = isAab(archivePath) ? 'base/assets' : 'assets'; -- zip.deleteFile(path.join(assetsPath, 'index.android.bundle')); -- zip.addLocalFile(jsBundlePath, assetsPath, 'index.android.bundle'); -- zip.writeZip(archivePath); -+ // Remove old bundle -+ await spawn('zip', ['-d', archivePath, bundleEntryPath]); -+ // Uses store-only compression (-0) to prevent bundle corruption. -+ await spawn('zip', ['-0', '-r', archivePath, assetsPath], { -+ cwd: stagingRoot, -+ }); - } - catch (error) { - throw new RockError(`Failed to replace JS bundle in destination file: ${archivePath}`, { cause: error }); - } -+ finally { -+ if (fs.existsSync(stagingRoot)) { -+ fs.rmSync(stagingRoot, { recursive: true }); -+ } -+ } - } - function isSdkGTE35(versionString) { - const match = versionString.match(/build-tools\/([\d.]+)/); diff --git a/patches/@rock-js/platform-android/details.md b/patches/@rock-js/platform-android/details.md deleted file mode 100644 index 1816bb8d509a..000000000000 --- a/patches/@rock-js/platform-android/details.md +++ /dev/null @@ -1,29 +0,0 @@ -# `@rock-js/platform-android` patches - -### [@rock-js+platform-android+0.11.9+001+missing-app-name-hybrid-case.patch](@rock-js+platform-android+0.11.9+001+missing-app-name-hybrid-case.patch) - -- Reason: - - ``` - This patch adds a fallback mechanism to find Android build output files (APK/AAB) when the appName value is not properly read from the project structure. - In a hybrid app scenario, the Android build process generates output files with names like `Expensify-debug.apk` instead of the expected '-debug.apk' based on the project structure (no appName due to the lack of a project subfolder in Mobile-Expensify/Android). - ``` - -- Upstream PR/issue: https://github.com/callstackincubator/rock/pull/628 -- E/App issue: https://github.com/Expensify/App/issues/74400 -- PR introducing patch: https://github.com/Expensify/App/pull/73525 - -### [@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch](@rock-js+platform-android+0.11.9+002+use-zip-instead-admzip.patch) - -- Reason: - - ``` - Fixes bundle corruption in cache and re-sign flow by replacing AdmZip with native zip commands. - The AdmZip library was applying default compression when adding files, which corrupted artifacts (native libraries). - This caused INSTALL_FAILED_CONTAINER_ERROR with size/crc32 mismatch errors on second builds using cache. - The fix uses native zip commands with -0 flag (store-only compression) to prevent bundle corruption. - ``` - -- Upstream PR/issue: https://github.com/callstackincubator/rock/pull/647 -- E/App issue: https://github.com/Expensify/App/issues/62296 -- PR introducing patch: https://github.com/Expensify/App/pull/76061 \ No newline at end of file diff --git a/patches/@rock-js/platform-apple-helpers/@rock-js+platform-apple-helpers+0.11.9+001+recalculate-fingerprint-for-local-builds-only.patch b/patches/@rock-js/platform-apple-helpers/@rock-js+platform-apple-helpers+0.11.9+001+recalculate-fingerprint-for-local-builds-only.patch deleted file mode 100644 index 47096081eba0..000000000000 --- a/patches/@rock-js/platform-apple-helpers/@rock-js+platform-apple-helpers+0.11.9+001+recalculate-fingerprint-for-local-builds-only.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/utils/buildApp.js b/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/utils/buildApp.js -index 50937a5..c825b22 100644 ---- a/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/utils/buildApp.js -+++ b/node_modules/@rock-js/platform-apple-helpers/dist/src/lib/utils/buildApp.js -@@ -35,7 +35,7 @@ export async function buildApp({ args, projectConfig, pluginConfig, platformName - xcodeProject = newProjectConfig.xcodeProject; - sourceDir = newProjectConfig.sourceDir; - } -- if (didInstallPods) { -+ if (didInstallPods && args.local) { - // After installing pods the fingerprint likely changes. - // We update the artifact name to reflect the new fingerprint and store proper entry in the local cache. - artifactNameToSave = await formatArtifactName({ diff --git a/patches/@rock-js/platform-apple-helpers/details.md b/patches/@rock-js/platform-apple-helpers/details.md deleted file mode 100644 index f64143c2e071..000000000000 --- a/patches/@rock-js/platform-apple-helpers/details.md +++ /dev/null @@ -1,15 +0,0 @@ -# `@rock-js/platform-apple-helpers` patches - -### [@rock-js+platform-apple-helpers+0.11.9+001+recalculate-fingerprint-for-local-builds-only.patch](@rock-js+platform-apple-helpers+0.11.9+001+recalculate-fingerprint-for-local-builds-only.patch) - -- Reason: - - ``` - This patch prevents recalculating the fingerprint after pod installation, which caused fingerprint mismatches between CI and local builds. - Local builds with the --local flag will still recalculate the fingerprint after pod installation. - ``` - -- Upstream PR/issue: 🛑 -- E/App issue: https://github.com/Expensify/App/issues/74400 -- PR introducing patch: https://github.com/Expensify/App/pull/73525 - diff --git a/patches/@rock-js/provider-s3/@rock-js+provider-s3+0.11.9+001+support-public-access.patch b/patches/@rock-js/provider-s3/@rock-js+provider-s3+0.11.9+001+support-public-access.patch deleted file mode 100644 index d31bdf4a1afc..000000000000 --- a/patches/@rock-js/provider-s3/@rock-js+provider-s3+0.11.9+001+support-public-access.patch +++ /dev/null @@ -1,72 +0,0 @@ -diff --git a/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.d.ts b/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.d.ts -index 8c4160c..1038c91 100644 ---- a/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.d.ts -+++ b/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.d.ts -@@ -49,6 +49,10 @@ type ProviderConfig = { - * External ID when assuming a role (for additional security). - */ - externalId?: string; -+ /** -+ * If true, the provider will not sign requests and will try to access the S3 bucket without authentication. -+ */ -+ publicAccess?: boolean; - }; - export declare class S3BuildCache implements RemoteBuildCache { - name: string; -diff --git a/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.js b/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.js -index 1d9331b..1e794b9 100644 ---- a/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.js -+++ b/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.js -@@ -49,6 +49,18 @@ export class S3BuildCache { - // Use shared config file (e.g. ~/.aws/credentials) with a profile - s3Config.credentials = fromIni({ profile: config.profile }); - } -+ else if (config.publicAccess) { -+ // Access the S3 bucket without authentication -+ s3Config.signer = { -+ sign: async (request) => request, -+ }; -+ s3Config.credentials = { -+ accessKeyId: '', -+ secretAccessKey: '', -+ }; -+ } -+ -+ - this.s3 = new clientS3.S3Client(s3Config); - const awsBucket = config.bucket ?? ''; - const bucketTokens = awsBucket.split('/'); -@@ -98,15 +110,24 @@ export class S3BuildCache { - return results; - } - async download({ artifactName, }) { -- const res = await this.s3.send(new clientS3.GetObjectCommand({ -- Bucket: this.bucket, -- Key: `${this.directory}/${artifactName}.zip`, -- })); -- return new Response(toWebStream(res.Body), { -- headers: { -- 'content-length': String(res.ContentLength), -- }, -- }); -+ try{ -+ const res = await this.s3.send(new clientS3.GetObjectCommand({ -+ Bucket: this.bucket, -+ Key: `${this.directory}/${artifactName}.zip`, -+ })); -+ return new Response(toWebStream(res.Body), { -+ headers: { -+ 'content-length': String(res.ContentLength), -+ }, -+ }); -+ } -+ catch(error){ -+ if(this.config.publicAccess){ -+ // Avoid misleading Access Denied error message -+ error.message = `Build not found or not accessible to the public`; -+ } -+ throw error; -+ } - } - async delete({ artifactName, skipLatest, }) { - if (skipLatest) { diff --git a/patches/@rock-js/provider-s3/@rock-js+provider-s3+0.11.9+002+add-acl-upload-param.patch b/patches/@rock-js/provider-s3/@rock-js+provider-s3+0.11.9+002+add-acl-upload-param.patch deleted file mode 100644 index 023a5fd6713c..000000000000 --- a/patches/@rock-js/provider-s3/@rock-js+provider-s3+0.11.9+002+add-acl-upload-param.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff --git a/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.d.ts b/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.d.ts -index 1038c91..fdb2e2e 100644 ---- a/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.d.ts -+++ b/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.d.ts -@@ -53,6 +53,10 @@ type ProviderConfig = { - * If true, the provider will not sign requests and will try to access the S3 bucket without authentication. - */ - publicAccess?: boolean; -+ /** -+ * ACL (Access Control List) to use for uploaded objects -+ */ -+ acl?: clientS3.ObjectCannedACL; - }; - export declare class S3BuildCache implements RemoteBuildCache { - name: string; -diff --git a/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.js b/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.js -index 813abcd..3c31f65 100644 ---- a/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.js -+++ b/node_modules/@rock-js/provider-s3/dist/src/lib/providerS3.js -@@ -77,6 +77,7 @@ export class S3BuildCache { - Key: key, - Body: buffer, - ContentType: contentType || 'application/octet-stream', -+ ...(this.config.acl && { ACL: this.config.acl }), - Metadata: { - createdAt: new Date().toISOString(), - }, diff --git a/patches/@rock-js/provider-s3/details.md b/patches/@rock-js/provider-s3/details.md deleted file mode 100644 index ed9b6ab6ec71..000000000000 --- a/patches/@rock-js/provider-s3/details.md +++ /dev/null @@ -1,26 +0,0 @@ -# `@rock-js/provider-s3` patches - -### [@rock-js+provider-s3+0.11.9+001+support-public-access.patch](@rock-js+provider-s3+0.11.9+001+support-public-access.patch) - -- Reason: - - ``` - This patch adds support for accessing public S3 buckets without authentication. - When the `publicAccess` option is set to true, the provider will not sign requests and will attempt to access the S3 bucket without AWS credentials. This is useful for scenarios where the S3 bucket is configured for public read access. - ``` - -- Upstream PR/issue: https://github.com/callstackincubator/rock/pull/625 -- E/App issue: https://github.com/Expensify/App/issues/74400 -- PR introducing patch: https://github.com/Expensify/App/pull/73525 - -### [@rock-js+provider-s3+0.11.9+002+add-acl-upload-param.patch](@rock-js+provider-s3+0.11.9+002+add-acl-upload-param.patch) - -- Reason: - - ``` - This patch adds support for specifying an ACL (Access Control List) parameter when uploading objects to S3. - ``` - -- Upstream PR/issue: https://github.com/callstackincubator/rock/pull/626 -- E/App issue: https://github.com/Expensify/App/issues/74400 -- PR introducing patch: https://github.com/Expensify/App/pull/73525 \ No newline at end of file From b492f03b11e92d475b6a52daa3cb4d22a730f450 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Thu, 18 Dec 2025 10:20:30 +0100 Subject: [PATCH 29/34] use forked rock with feat/adhoc-android --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9306f07776fc..34f3c40f3519 100644 --- a/package.json +++ b/package.json @@ -354,7 +354,7 @@ "react-refresh": "^0.14.2", "react-test-renderer": "19.1.0", "reassure": "^1.0.0-rc.4", - "rock": "0.11.13", + "rock": "github:LukasMod/rock#feat/adhoc-android-dist-6", "semver": "7.5.2", "setimmediate": "^1.0.5", "shellcheck": "^1.1.0", From 6bfe2bcd2c4349369b8e9c2f5b338abb6adfcc41 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Thu, 18 Dec 2025 10:46:35 +0100 Subject: [PATCH 30/34] update lock --- package-lock.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 940176228af8..17774f9254a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -281,7 +281,7 @@ "react-refresh": "^0.14.2", "react-test-renderer": "19.1.0", "reassure": "^1.0.0-rc.4", - "rock": "0.11.13", + "rock": "github:LukasMod/rock#feat/adhoc-android-dist-6", "semver": "7.5.2", "setimmediate": "^1.0.5", "shellcheck": "^1.1.0", @@ -37738,22 +37738,22 @@ "license": "BSD-3-Clause" }, "node_modules/rock": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/rock/-/rock-0.11.13.tgz", - "integrity": "sha512-QzGmgIE+Zz3nU486garPpBB7DzgAX42oo0uvfxit1qs/d8Bi+sCk9qZTDlVQjEdJ+L9nCglx5MhgD9r5R5orvQ==", + "name": "workspace-root", + "version": "0.0.0", + "resolved": "git+ssh://git@github.com/LukasMod/rock.git#bb4be8d0fe222c38dd79c60e2d6149c8f0bcec26", "dev": true, "license": "MIT", "dependencies": { "@react-native-community/cli-config": "^20.0.0", - "@rock-js/config": "^0.11.13", - "@rock-js/tools": "^0.11.13", + "@rock-js/config": "0.11.13", + "@rock-js/tools": "0.11.13", "adm-zip": "^0.5.16", "commander": "^12.1.0", "tar": "^7.5.1", - "tslib": "^2.3.0" + "tslib": "^2.8.1" }, "bin": { - "rock": "dist/src/bin.js" + "rock": "packages/cli/dist/src/bin.js" } }, "node_modules/rock/node_modules/chownr": { From 515b41ab1567440979fe51ad5e1975eef7f2fdc0 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Thu, 18 Dec 2025 11:51:05 +0100 Subject: [PATCH 31/34] use forked rock from specific commit --- package-lock.json | 5 +++-- package.json | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 17774f9254a0..da76c6f5e846 100644 --- a/package-lock.json +++ b/package-lock.json @@ -281,7 +281,7 @@ "react-refresh": "^0.14.2", "react-test-renderer": "19.1.0", "reassure": "^1.0.0-rc.4", - "rock": "github:LukasMod/rock#feat/adhoc-android-dist-6", + "rock": "github:LukasMod/rock#680efe800c850cd1d84fec4e93a546c637881cf9", "semver": "7.5.2", "setimmediate": "^1.0.5", "shellcheck": "^1.1.0", @@ -37740,7 +37740,8 @@ "node_modules/rock": { "name": "workspace-root", "version": "0.0.0", - "resolved": "git+ssh://git@github.com/LukasMod/rock.git#bb4be8d0fe222c38dd79c60e2d6149c8f0bcec26", + "resolved": "git+ssh://git@github.com/LukasMod/rock.git#680efe800c850cd1d84fec4e93a546c637881cf9", + "integrity": "sha512-qwdmG9amcDsMuKd1CeqYbv9Ku0gDM7twfd/8Hc8W1TAqWGm5tDwT+YJj7Zg7mwG92V9ZRIQu++imyvDbZZ7jUQ==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 34f3c40f3519..ad34bdbc5299 100644 --- a/package.json +++ b/package.json @@ -354,7 +354,7 @@ "react-refresh": "^0.14.2", "react-test-renderer": "19.1.0", "reassure": "^1.0.0-rc.4", - "rock": "github:LukasMod/rock#feat/adhoc-android-dist-6", + "rock": "github:LukasMod/rock#680efe800c850cd1d84fec4e93a546c637881cf9", "semver": "7.5.2", "setimmediate": "^1.0.5", "shellcheck": "^1.1.0", From 5cf9351def6b2bac53edde64bc360ff1edb68621 Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Thu, 18 Dec 2025 15:07:45 +0100 Subject: [PATCH 32/34] use new usePrebuiltRNCore rock config --- .github/workflows/remote-build-ios.yml | 3 --- .github/workflows/testBuild.yml | 3 --- rock.config.mjs | 2 ++ scripts/run-build.sh | 7 +++---- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/.github/workflows/remote-build-ios.yml b/.github/workflows/remote-build-ios.yml index c2258f0b6512..795bd3dd9409 100644 --- a/.github/workflows/remote-build-ios.yml +++ b/.github/workflows/remote-build-ios.yml @@ -66,9 +66,6 @@ jobs: env: GITHUB_TOKEN: ${{ github.token }} IS_HYBRID_APP: ${{ matrix.is_hybrid_build }} - # Forces React Native to build from source to include our custom patches - RCT_USE_RN_DEP: 0 - RCT_USE_PREBUILT_RNCORE: 0 with: destination: simulator scheme: ${{ matrix.scheme }} diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index f01cc1b7e2ba..6897e796e3ca 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -492,9 +492,6 @@ jobs: GITHUB_TOKEN: ${{ github.token }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} IS_HYBRID_APP: true - # Forces React Native to build from source to include our custom patches - RCT_USE_RN_DEP: 0 - RCT_USE_PREBUILT_RNCORE: 0 with: destination: device re-sign: true diff --git a/rock.config.mjs b/rock.config.mjs index 5e4c6c142b35..9e78e6320abe 100644 --- a/rock.config.mjs +++ b/rock.config.mjs @@ -25,4 +25,6 @@ export default { env: ['USE_WEB_PROXY', 'PUSHER_DEV_SUFFIX', 'SECURE_NGROK_URL', 'NGROK_URL', 'USE_NGROK'], ignorePaths: ['Mobile-Expensify/Android/assets/app/shared/bundle.js'], }, + // Forces React Native to build from source to include our custom patches + usePrebuiltRNCore: 0, }; diff --git a/scripts/run-build.sh b/scripts/run-build.sh index 3f42d1211200..2c305ae83f1c 100755 --- a/scripts/run-build.sh +++ b/scripts/run-build.sh @@ -63,16 +63,15 @@ else fi # Check if the argument is one of the desired values -# RCT_USE_RN_DEP=0 RCT_USE_PREBUILT_RNCORE=0 - force React Native to build from source to include our custom patches case "$BUILD" in --ios) - RCT_USE_RN_DEP=0 RCT_USE_PREBUILT_RNCORE=0 npx rock run:ios --configuration $IOS_MODE --scheme "$SCHEME" --dev-server "${ROCK_FLAGS[@]}" + npx rock run:ios --configuration $IOS_MODE --scheme "$SCHEME" --dev-server "${ROCK_FLAGS[@]}" ;; --ipad) - RCT_USE_RN_DEP=0 RCT_USE_PREBUILT_RNCORE=0 npx rock run:ios --simulator "iPad Pro (12.9-inch) (6th generation)" --configuration $IOS_MODE --scheme "$SCHEME" --dev-server "${ROCK_FLAGS[@]}" + npx rock run:ios --simulator "iPad Pro (12.9-inch) (6th generation)" --configuration $IOS_MODE --scheme "$SCHEME" --dev-server "${ROCK_FLAGS[@]}" ;; --ipad-sm) - RCT_USE_RN_DEP=0 RCT_USE_PREBUILT_RNCORE=0 npx rock run:ios --simulator "iPad Pro (11-inch) (4th generation)" --configuration $IOS_MODE --scheme "$SCHEME" --dev-server "${ROCK_FLAGS[@]}" + npx rock run:ios --simulator "iPad Pro (11-inch) (4th generation)" --configuration $IOS_MODE --scheme "$SCHEME" --dev-server "${ROCK_FLAGS[@]}" ;; --android) # Check if this is an Expensify developer with WARP (only they need cert import) From e2c26f671ebea221ad6cb9b54409f3706c691e2d Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Thu, 18 Dec 2025 15:33:18 +0100 Subject: [PATCH 33/34] update rock to 0.11.14 --- package-lock.json | 91 +++++++++++++++++++++++------------------------ package.json | 10 +++--- 2 files changed, 50 insertions(+), 51 deletions(-) diff --git a/package-lock.json b/package-lock.json index da76c6f5e846..adbdc9e1f415 100644 --- a/package-lock.json +++ b/package-lock.json @@ -184,10 +184,10 @@ "@react-native/babel-preset": "0.81.4", "@react-native/metro-config": "0.81.4", "@react-navigation/devtools": "^6.0.10", - "@rock-js/platform-android": "0.11.13", - "@rock-js/platform-ios": "0.11.13", - "@rock-js/plugin-metro": "0.11.13", - "@rock-js/provider-s3": "0.11.13", + "@rock-js/platform-android": "0.11.14", + "@rock-js/platform-ios": "0.11.14", + "@rock-js/plugin-metro": "0.11.14", + "@rock-js/provider-s3": "0.11.14", "@sentry/webpack-plugin": "4.6.0", "@storybook/addon-a11y": "^8.6.9", "@storybook/addon-essentials": "^8.6.9", @@ -281,7 +281,7 @@ "react-refresh": "^0.14.2", "react-test-renderer": "19.1.0", "reassure": "^1.0.0-rc.4", - "rock": "github:LukasMod/rock#680efe800c850cd1d84fec4e93a546c637881cf9", + "rock": "0.11.14", "semver": "7.5.2", "setimmediate": "^1.0.5", "shellcheck": "^1.1.0", @@ -12979,28 +12979,28 @@ } }, "node_modules/@rock-js/config": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@rock-js/config/-/config-0.11.13.tgz", - "integrity": "sha512-cUkJ5Tjpp6UGm7t1a1HEJ3CzB5T2JmnAwZtVY0juaRaFobk4MoJtbY+A0oaZf0Hb+fQjfde2hJcjj7CAGiMFzQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@rock-js/config/-/config-0.11.14.tgz", + "integrity": "sha512-VrT9ICAVgItpK5agG7FLbWtkm2NXuWKv6NWBHFWLSU95d60XeRifC83QEcZZUafEdtmvyBBA3lx8rHExBVT0ew==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", - "@rock-js/provider-github": "^0.11.13", - "@rock-js/tools": "^0.11.13", + "@rock-js/provider-github": "^0.11.14", + "@rock-js/tools": "^0.11.14", "joi": "^17.13.3", "tslib": "^2.3.0" } }, "node_modules/@rock-js/platform-android": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@rock-js/platform-android/-/platform-android-0.11.13.tgz", - "integrity": "sha512-GfbjwrjxZaechsMft2xAiKeY0ariGVqKCfT/Buryd94MPPcHpfMWJOge3xRiAYhB1pJYFnRFQCJ6qS8il3EKpA==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@rock-js/platform-android/-/platform-android-0.11.14.tgz", + "integrity": "sha512-Ze9hM1Yxh/l12MPEXMTR11YIXehma0UojplZsykyUWFMRR8Lnu3nCMOPnLt6OSorhUaWDV8aqyetUkuO2f3t3A==", "dev": true, "license": "MIT", "dependencies": { "@react-native-community/cli-config-android": "^20.0.0", - "@rock-js/tools": "^0.11.13", + "@rock-js/tools": "^0.11.14", "tslib": "^2.3.0" } }, @@ -13113,31 +13113,31 @@ } }, "node_modules/@rock-js/platform-apple-helpers": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@rock-js/platform-apple-helpers/-/platform-apple-helpers-0.11.13.tgz", - "integrity": "sha512-5F+bA10VZ6GCs0GrTVQ0ZFLlQ9YX5loXAcOR7n2MvCfJ1oIownxzbh6HUbn5Z6ts4z3JzVg3NtoqM1prGSUtfg==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@rock-js/platform-apple-helpers/-/platform-apple-helpers-0.11.14.tgz", + "integrity": "sha512-k0rrYLoJG/Dg+RhZ2IpFzXZIfqRBudjdH9r3hgv58gnbVJa+O9T7gk0zX0QFkWsApD+nS2nCWbzUIKxpMB+J4w==", "dev": true, "license": "MIT", "dependencies": { "@react-native-community/cli-config": "^20.0.0", "@react-native-community/cli-config-apple": "^20.0.0", - "@rock-js/tools": "^0.11.13", + "@rock-js/tools": "^0.11.14", "adm-zip": "^0.5.16", "fast-xml-parser": "^4.5.0", "tslib": "^2.3.0" } }, "node_modules/@rock-js/platform-ios": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@rock-js/platform-ios/-/platform-ios-0.11.13.tgz", - "integrity": "sha512-Cqo2CrPlqtKNkbOHXhz5vnM7oOK1NlmydFrOofRlhaF0dUYUivdvNomTm1N/36sgefdfQh6hU29dKrAcR249og==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@rock-js/platform-ios/-/platform-ios-0.11.14.tgz", + "integrity": "sha512-bGbMPNgF7tz5GzsjkmMn8Hl2zO8yoFnQBxYm+wKlMDFfjfjpLUTkx+oJ/1PGCt5wer1SFVg5ENaDni6tUpFcQA==", "dev": true, "license": "MIT", "dependencies": { "@react-native-community/cli-config-apple": "^20.0.0", "@react-native-community/cli-types": "^20.0.0", - "@rock-js/platform-apple-helpers": "^0.11.13", - "@rock-js/tools": "^0.11.13", + "@rock-js/platform-apple-helpers": "^0.11.14", + "@rock-js/tools": "^0.11.14", "tslib": "^2.3.0" } }, @@ -13260,14 +13260,14 @@ } }, "node_modules/@rock-js/plugin-metro": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@rock-js/plugin-metro/-/plugin-metro-0.11.13.tgz", - "integrity": "sha512-58rh5GtvpPD9b2+5j3llNE2z/tyz0/H6a4Kmh6reI7C+z5PyafZSjjvaMUkuYzDLbPSb+h9GhqZdBNjLGod4GQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@rock-js/plugin-metro/-/plugin-metro-0.11.14.tgz", + "integrity": "sha512-4C1MTMS1Ohf5bWURQVACz/ubgei7uJAFjEu8P0tgIQhpvlqrYPXX0fuu3Ixc8ZGDX7Yra4QzsFXlPGOYM6HYJw==", "dev": true, "license": "MIT", "dependencies": { "@react-native-community/cli-server-api": "^20.0.0", - "@rock-js/tools": "^0.11.13", + "@rock-js/tools": "^0.11.14", "metro": "^0.83.1", "metro-config": "^0.83.1", "metro-core": "^0.83.1", @@ -13811,21 +13811,21 @@ } }, "node_modules/@rock-js/provider-github": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@rock-js/provider-github/-/provider-github-0.11.13.tgz", - "integrity": "sha512-/Ut2JLkiTqYE0n1HXOa7wnV39WIXyCuTdHewcON9WodaA8sD/9ERY8pPSUrWW7SrDVtvZWSQvAQPyqgx5fQRgw==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@rock-js/provider-github/-/provider-github-0.11.14.tgz", + "integrity": "sha512-6Yy4/crAxf6vC0UIKC2AmasuTu8WCBIsF/1CTTK/GPNChQ5hmdVhkac2C3APkjlIOkYzOdbWxtuY+gd2K2kp5Q==", "dev": true, "license": "MIT", "dependencies": { - "@rock-js/tools": "^0.11.13", + "@rock-js/tools": "^0.11.14", "ts-regex-builder": "^1.8.2", "tslib": "^2.3.0" } }, "node_modules/@rock-js/provider-s3": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@rock-js/provider-s3/-/provider-s3-0.11.13.tgz", - "integrity": "sha512-gIMRwmSJrSk6mt+ODuLTenn4gwqz83s6//1PT427MML/SScGyJjwarp06HTQqA3m00Odw/9ZBEzMwSH9SNu6mw==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@rock-js/provider-s3/-/provider-s3-0.11.14.tgz", + "integrity": "sha512-3GrqDpy8+yJlzPgj9vSLq2ZQI8JRrqiyXnYBshr9Ll7BN6rBKJ9arq/+c0oeBx675czCyfePvXsDk4A+jhK8PQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13834,14 +13834,14 @@ "@aws-sdk/credential-providers": "^3.830.0", "@aws-sdk/lib-storage": "^3.830.0", "@aws-sdk/s3-request-presigner": "^3.830.0", - "@rock-js/tools": "^0.11.13", + "@rock-js/tools": "^0.11.14", "tslib": "^2.3.0" } }, "node_modules/@rock-js/tools": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@rock-js/tools/-/tools-0.11.13.tgz", - "integrity": "sha512-XMNFIQU/kXEGc7EhVndBqUGLQxfZWo9nY1hKe6g7QnS8JGB0RjSvqbwjpmTdsGuc1emiB8zLbk+s0CX7aJhQ6Q==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@rock-js/tools/-/tools-0.11.14.tgz", + "integrity": "sha512-GyllbGk9YzrT7SBFuM73Ngr0p/DxvI52B7mML5naDKeruKcUrKxoyJyegnx9+8GhnlXdcBuASVUHhM9XkkpSyw==", "dev": true, "license": "MIT", "dependencies": { @@ -37738,23 +37738,22 @@ "license": "BSD-3-Clause" }, "node_modules/rock": { - "name": "workspace-root", - "version": "0.0.0", - "resolved": "git+ssh://git@github.com/LukasMod/rock.git#680efe800c850cd1d84fec4e93a546c637881cf9", - "integrity": "sha512-qwdmG9amcDsMuKd1CeqYbv9Ku0gDM7twfd/8Hc8W1TAqWGm5tDwT+YJj7Zg7mwG92V9ZRIQu++imyvDbZZ7jUQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/rock/-/rock-0.11.14.tgz", + "integrity": "sha512-+AL6eGEnStetgtQguyvxfLHe3qunoLF8jM6by96de73vVx8DTm6rn0q6+uUmCTaqdNK7EdBisS5Sf3O/kbv4zw==", "dev": true, "license": "MIT", "dependencies": { "@react-native-community/cli-config": "^20.0.0", - "@rock-js/config": "0.11.13", - "@rock-js/tools": "0.11.13", + "@rock-js/config": "^0.11.14", + "@rock-js/tools": "^0.11.14", "adm-zip": "^0.5.16", "commander": "^12.1.0", "tar": "^7.5.1", - "tslib": "^2.8.1" + "tslib": "^2.3.0" }, "bin": { - "rock": "packages/cli/dist/src/bin.js" + "rock": "dist/src/bin.js" } }, "node_modules/rock/node_modules/chownr": { diff --git a/package.json b/package.json index ad34bdbc5299..745f4349d65b 100644 --- a/package.json +++ b/package.json @@ -257,10 +257,10 @@ "@react-native/babel-preset": "0.81.4", "@react-native/metro-config": "0.81.4", "@react-navigation/devtools": "^6.0.10", - "@rock-js/platform-android": "0.11.13", - "@rock-js/platform-ios": "0.11.13", - "@rock-js/plugin-metro": "0.11.13", - "@rock-js/provider-s3": "0.11.13", + "@rock-js/platform-android": "0.11.14", + "@rock-js/platform-ios": "0.11.14", + "@rock-js/plugin-metro": "0.11.14", + "@rock-js/provider-s3": "0.11.14", "@sentry/webpack-plugin": "4.6.0", "@storybook/addon-a11y": "^8.6.9", "@storybook/addon-essentials": "^8.6.9", @@ -354,7 +354,7 @@ "react-refresh": "^0.14.2", "react-test-renderer": "19.1.0", "reassure": "^1.0.0-rc.4", - "rock": "github:LukasMod/rock#680efe800c850cd1d84fec4e93a546c637881cf9", + "rock": "0.11.14", "semver": "7.5.2", "setimmediate": "^1.0.5", "shellcheck": "^1.1.0", From 6630d68eaf2aeb775e7bcd7d48ce2025e97aaf1c Mon Sep 17 00:00:00 2001 From: Lukasz Modzelewski Date: Fri, 19 Dec 2025 08:05:06 +0100 Subject: [PATCH 34/34] bump rock to 0.12.0 --- package-lock.json | 108 +++++++++++++++++++++++----------------------- package.json | 10 ++--- 2 files changed, 59 insertions(+), 59 deletions(-) diff --git a/package-lock.json b/package-lock.json index adbdc9e1f415..8ae0cc7e4671 100644 --- a/package-lock.json +++ b/package-lock.json @@ -184,10 +184,10 @@ "@react-native/babel-preset": "0.81.4", "@react-native/metro-config": "0.81.4", "@react-navigation/devtools": "^6.0.10", - "@rock-js/platform-android": "0.11.14", - "@rock-js/platform-ios": "0.11.14", - "@rock-js/plugin-metro": "0.11.14", - "@rock-js/provider-s3": "0.11.14", + "@rock-js/platform-android": "0.12.0", + "@rock-js/platform-ios": "0.12.0", + "@rock-js/plugin-metro": "0.12.0", + "@rock-js/provider-s3": "0.12.0", "@sentry/webpack-plugin": "4.6.0", "@storybook/addon-a11y": "^8.6.9", "@storybook/addon-essentials": "^8.6.9", @@ -281,7 +281,7 @@ "react-refresh": "^0.14.2", "react-test-renderer": "19.1.0", "reassure": "^1.0.0-rc.4", - "rock": "0.11.14", + "rock": "0.12.0", "semver": "7.5.2", "setimmediate": "^1.0.5", "shellcheck": "^1.1.0", @@ -12979,28 +12979,28 @@ } }, "node_modules/@rock-js/config": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@rock-js/config/-/config-0.11.14.tgz", - "integrity": "sha512-VrT9ICAVgItpK5agG7FLbWtkm2NXuWKv6NWBHFWLSU95d60XeRifC83QEcZZUafEdtmvyBBA3lx8rHExBVT0ew==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@rock-js/config/-/config-0.12.0.tgz", + "integrity": "sha512-7tK7UUHlR+dGvjBaaMmzlkJTTPSjdI9pFUFEydcDDuTaUnHMDdz1huuYmjLohKx/NEI/6dwDE5NEN5zWDvy1tQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", - "@rock-js/provider-github": "^0.11.14", - "@rock-js/tools": "^0.11.14", + "@rock-js/provider-github": "^0.12.0", + "@rock-js/tools": "^0.12.0", "joi": "^17.13.3", "tslib": "^2.3.0" } }, "node_modules/@rock-js/platform-android": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@rock-js/platform-android/-/platform-android-0.11.14.tgz", - "integrity": "sha512-Ze9hM1Yxh/l12MPEXMTR11YIXehma0UojplZsykyUWFMRR8Lnu3nCMOPnLt6OSorhUaWDV8aqyetUkuO2f3t3A==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@rock-js/platform-android/-/platform-android-0.12.0.tgz", + "integrity": "sha512-WyAMQtqjB7SPS1oOHq4P1pSOIMMLAq0wpbYKouEGY4ZsIHKBgb4wP8iQ0rBPhZhhIw94e4o2G4BnaxqwdJaL2g==", "dev": true, "license": "MIT", "dependencies": { "@react-native-community/cli-config-android": "^20.0.0", - "@rock-js/tools": "^0.11.14", + "@rock-js/tools": "^0.12.0", "tslib": "^2.3.0" } }, @@ -13113,31 +13113,31 @@ } }, "node_modules/@rock-js/platform-apple-helpers": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@rock-js/platform-apple-helpers/-/platform-apple-helpers-0.11.14.tgz", - "integrity": "sha512-k0rrYLoJG/Dg+RhZ2IpFzXZIfqRBudjdH9r3hgv58gnbVJa+O9T7gk0zX0QFkWsApD+nS2nCWbzUIKxpMB+J4w==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@rock-js/platform-apple-helpers/-/platform-apple-helpers-0.12.0.tgz", + "integrity": "sha512-Y/skmIHt6kPL8D38EZzvLX+7jLg3ZZd+PWlJ278+B3rqDbIAG5qWkw7geAoiz+cIo5niaETxtVYzsU+us6BIgg==", "dev": true, "license": "MIT", "dependencies": { "@react-native-community/cli-config": "^20.0.0", "@react-native-community/cli-config-apple": "^20.0.0", - "@rock-js/tools": "^0.11.14", + "@rock-js/tools": "^0.12.0", "adm-zip": "^0.5.16", "fast-xml-parser": "^4.5.0", "tslib": "^2.3.0" } }, "node_modules/@rock-js/platform-ios": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@rock-js/platform-ios/-/platform-ios-0.11.14.tgz", - "integrity": "sha512-bGbMPNgF7tz5GzsjkmMn8Hl2zO8yoFnQBxYm+wKlMDFfjfjpLUTkx+oJ/1PGCt5wer1SFVg5ENaDni6tUpFcQA==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@rock-js/platform-ios/-/platform-ios-0.12.0.tgz", + "integrity": "sha512-CDZgHykqdIAP/Sr1lXcfZR7TTPyIIaVYLprP4XhCaOV7In8v78R3HgrjLYijouhMWo00DLR14d1YRe/i5NfJ+A==", "dev": true, "license": "MIT", "dependencies": { "@react-native-community/cli-config-apple": "^20.0.0", "@react-native-community/cli-types": "^20.0.0", - "@rock-js/platform-apple-helpers": "^0.11.14", - "@rock-js/tools": "^0.11.14", + "@rock-js/platform-apple-helpers": "^0.12.0", + "@rock-js/tools": "^0.12.0", "tslib": "^2.3.0" } }, @@ -13260,18 +13260,18 @@ } }, "node_modules/@rock-js/plugin-metro": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@rock-js/plugin-metro/-/plugin-metro-0.11.14.tgz", - "integrity": "sha512-4C1MTMS1Ohf5bWURQVACz/ubgei7uJAFjEu8P0tgIQhpvlqrYPXX0fuu3Ixc8ZGDX7Yra4QzsFXlPGOYM6HYJw==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@rock-js/plugin-metro/-/plugin-metro-0.12.0.tgz", + "integrity": "sha512-T4sk3CI7L4OG3tcdUz788iIzOWpWWTO2ZLOlaoUx9SfYEzJNetCARU+BQySWr6SQAgIh0o39edNyanUSe+h3TA==", "dev": true, "license": "MIT", "dependencies": { "@react-native-community/cli-server-api": "^20.0.0", - "@rock-js/tools": "^0.11.14", - "metro": "^0.83.1", - "metro-config": "^0.83.1", - "metro-core": "^0.83.1", - "metro-resolver": "^0.83.1", + "@rock-js/tools": "^0.12.0", + "metro": "^0.83.3", + "metro-config": "^0.83.3", + "metro-core": "^0.83.3", + "metro-resolver": "^0.83.3", "tslib": "^2.3.0" } }, @@ -13811,21 +13811,21 @@ } }, "node_modules/@rock-js/provider-github": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@rock-js/provider-github/-/provider-github-0.11.14.tgz", - "integrity": "sha512-6Yy4/crAxf6vC0UIKC2AmasuTu8WCBIsF/1CTTK/GPNChQ5hmdVhkac2C3APkjlIOkYzOdbWxtuY+gd2K2kp5Q==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@rock-js/provider-github/-/provider-github-0.12.0.tgz", + "integrity": "sha512-0GL/CNe2EDNWUSsTYaHCRO0+ZxSGT8hxDJaO86M6o8m0jSv49UX3xfjk8dxasslY5VxQlhT2gB7K5niH0UNFUw==", "dev": true, "license": "MIT", "dependencies": { - "@rock-js/tools": "^0.11.14", + "@rock-js/tools": "^0.12.0", "ts-regex-builder": "^1.8.2", "tslib": "^2.3.0" } }, "node_modules/@rock-js/provider-s3": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@rock-js/provider-s3/-/provider-s3-0.11.14.tgz", - "integrity": "sha512-3GrqDpy8+yJlzPgj9vSLq2ZQI8JRrqiyXnYBshr9Ll7BN6rBKJ9arq/+c0oeBx675czCyfePvXsDk4A+jhK8PQ==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@rock-js/provider-s3/-/provider-s3-0.12.0.tgz", + "integrity": "sha512-AoMYzIaq2p9p8QMWihMgK4c1ozqd5BJEEQB7MT0lAKR0suYY3YnTw3e1hSqBZsn6PmMyE+BY/9tNLuACZFluEA==", "dev": true, "license": "MIT", "dependencies": { @@ -13834,14 +13834,14 @@ "@aws-sdk/credential-providers": "^3.830.0", "@aws-sdk/lib-storage": "^3.830.0", "@aws-sdk/s3-request-presigner": "^3.830.0", - "@rock-js/tools": "^0.11.14", + "@rock-js/tools": "^0.12.0", "tslib": "^2.3.0" } }, "node_modules/@rock-js/tools": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@rock-js/tools/-/tools-0.11.14.tgz", - "integrity": "sha512-GyllbGk9YzrT7SBFuM73Ngr0p/DxvI52B7mML5naDKeruKcUrKxoyJyegnx9+8GhnlXdcBuASVUHhM9XkkpSyw==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@rock-js/tools/-/tools-0.12.0.tgz", + "integrity": "sha512-yXxkAemK2Dc745LMdWIDjO2j8w7mQsW9Nbe+kwjUaTGS6KG57tquoMkkGP5QsVpyg0+2lIFhNMKPJOlcQN58Wg==", "dev": true, "license": "MIT", "dependencies": { @@ -13904,11 +13904,11 @@ } }, "node_modules/@rock-js/tools/node_modules/tar": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz", - "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz", + "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", @@ -27310,9 +27310,9 @@ } }, "node_modules/fs-fingerprint/node_modules/yocto-queue": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", - "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", "dev": true, "license": "MIT", "engines": { @@ -37738,15 +37738,15 @@ "license": "BSD-3-Clause" }, "node_modules/rock": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/rock/-/rock-0.11.14.tgz", - "integrity": "sha512-+AL6eGEnStetgtQguyvxfLHe3qunoLF8jM6by96de73vVx8DTm6rn0q6+uUmCTaqdNK7EdBisS5Sf3O/kbv4zw==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/rock/-/rock-0.12.0.tgz", + "integrity": "sha512-MiHWE5LgVkO93yOt3qcOvBxDH9oJvBiAotsancgoM4fAb5jaAhL/pbufUkqrD0AaEp3HmBz8ZlfLKfZnKDLExA==", "dev": true, "license": "MIT", "dependencies": { "@react-native-community/cli-config": "^20.0.0", - "@rock-js/config": "^0.11.14", - "@rock-js/tools": "^0.11.14", + "@rock-js/config": "^0.12.0", + "@rock-js/tools": "^0.12.0", "adm-zip": "^0.5.16", "commander": "^12.1.0", "tar": "^7.5.1", diff --git a/package.json b/package.json index 745f4349d65b..bf4748e08829 100644 --- a/package.json +++ b/package.json @@ -257,10 +257,10 @@ "@react-native/babel-preset": "0.81.4", "@react-native/metro-config": "0.81.4", "@react-navigation/devtools": "^6.0.10", - "@rock-js/platform-android": "0.11.14", - "@rock-js/platform-ios": "0.11.14", - "@rock-js/plugin-metro": "0.11.14", - "@rock-js/provider-s3": "0.11.14", + "@rock-js/platform-android": "0.12.0", + "@rock-js/platform-ios": "0.12.0", + "@rock-js/plugin-metro": "0.12.0", + "@rock-js/provider-s3": "0.12.0", "@sentry/webpack-plugin": "4.6.0", "@storybook/addon-a11y": "^8.6.9", "@storybook/addon-essentials": "^8.6.9", @@ -354,7 +354,7 @@ "react-refresh": "^0.14.2", "react-test-renderer": "19.1.0", "reassure": "^1.0.0-rc.4", - "rock": "0.11.14", + "rock": "0.12.0", "semver": "7.5.2", "setimmediate": "^1.0.5", "shellcheck": "^1.1.0",