-
-
Notifications
You must be signed in to change notification settings - Fork 408
feat(metro): add metro-plugin-rock and migrate examples to Rock #4652
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
zackarychapple
merged 18 commits into
module-federation:main
from
jbroma:refactor/plugin-rock-migration
Apr 29, 2026
Merged
Changes from 7 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
0c190b1
feat(metro): add metro-plugin-rock for ROCKjs integration
jbroma c7326fe
refactor(metro): migrate example apps and CI from RNEF to ROCKjs
jbroma e2c8580
chore: add changeset for metro-plugin-rock
jbroma 3893b00
chore: split changeset into separate rock and rnef entries
jbroma c7f6b01
docs(metro): update website docs for Rock integration
jbroma c4895bb
fix(metro): use providerGitHub() instead of deprecated shorthand
jbroma bdea246
fix(metro): use local Rock actions with working-directory fix
jbroma be653ec
ci: retrigger e2e
jbroma 77e0537
chore(metro): revert to upstream Rock actions with TODO for working-d…
jbroma f0e6ad0
chore: merge main and resolve conflicts
jbroma 0351c8f
fix(metro): pin Rock actions to commits with working-directory fix
jbroma 3123aef
chore(metro): pin Rock actions to v3 commits
jbroma f309828
fix(metro): use full SHA for pinned Rock actions
jbroma 1d5c81b
ci: retrigger e2e
jbroma c5cfb76
fix(metro): setup Java without Gradle cache to prevent Android e2e hang
jbroma 150ea0e
ci: retrigger e2e
jbroma 3b15af9
Merge remote-tracking branch 'origin/main' into refactor/plugin-rock-…
jbroma 5837907
Merge remote-tracking branch 'origin/main' into refactor/plugin-rock-…
jbroma File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@module-federation/metro-plugin-rock': minor | ||
| --- | ||
|
|
||
| feat(metro): add metro-plugin-rock for Rock integration |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@module-federation/metro-plugin-rnef': patch | ||
| --- | ||
|
|
||
| chore(metro): deprecate metro-plugin-rnef in favor of metro-plugin-rock |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,328 @@ | ||
| name: 'Rock Remote Build - Android' | ||
| description: 'Local fork of callstackincubator/android@v3 with working-directory fix' | ||
|
|
||
| inputs: | ||
| github-token: | ||
| description: 'GitHub Token' | ||
| required: true | ||
| working-directory: | ||
| description: 'Working directory for the build command' | ||
| required: false | ||
| default: '.' | ||
| validate-gradle-wrapper: | ||
| description: 'Whether to validate the Gradle wrapper' | ||
| required: false | ||
| default: true | ||
| setup-java: | ||
| description: 'Whether to run actions/setup-java action' | ||
| required: false | ||
| default: true | ||
| variant: | ||
| description: 'Build variant' | ||
| required: false | ||
| default: 'debug' | ||
| rock-build-extra-params: | ||
| description: 'Extra parameters to pass to "rock build:android"' | ||
| required: false | ||
| sign: | ||
| description: 'Whether to sign the build with release keystore' | ||
| required: false | ||
| re-sign: | ||
| description: Re-sign the app bundle with new JS bundle | ||
| required: false | ||
| keystore-base64: | ||
| description: 'Base64 version of the release keystore' | ||
| required: false | ||
| keystore-file: | ||
| description: 'Path to the keystore file' | ||
| required: false | ||
| keystore-store-file: | ||
| description: 'Keystore store file name' | ||
| required: false | ||
| keystore-store-password: | ||
| description: 'Keystore store password' | ||
| required: false | ||
| keystore-key-alias: | ||
| description: 'Keystore key alias' | ||
| required: false | ||
| keystore-key-password: | ||
| description: 'Keystore key password' | ||
| required: false | ||
| keystore-path: | ||
| description: 'Path within the Android source directory where the keystore should be placed' | ||
| required: false | ||
| default: 'release.keystore' | ||
| comment-bot: | ||
| description: 'Whether to send a comment under PR with the link to the generated build' | ||
| required: false | ||
| default: true | ||
|
|
||
| outputs: | ||
| artifact-url: | ||
| description: 'URL of the relevant Android build artifact (could be cached)' | ||
| value: ${{ steps.upload-artifact.outputs.artifact-url || env.ARTIFACT_URL }} | ||
| artifact-id: | ||
| description: 'ID of the relevant Android build artifact (could be cached)' | ||
| value: ${{ steps.upload-artifact.outputs.artifact-id || env.ARTIFACT_ID }} | ||
|
|
||
| runs: | ||
| using: 'composite' | ||
| steps: | ||
| - name: Validate Inputs | ||
| run: | | ||
| if [ "${{ inputs.sign }}" == "true" ]; then | ||
| if [ -z "${{ inputs.keystore-file }}" ] && [ -z "${{ inputs.keystore-base64 }}" ]; then | ||
| echo "Either 'keystore-file' or 'keystore-base64' is required for signed builds." | ||
| exit 1 | ||
| fi | ||
| if [ -n "${{ inputs.keystore-file }}" ] && [ ! -f "${{ inputs.keystore-file }}" ]; then | ||
| echo "Keystore file '${{ inputs.keystore-file }}' does not exist." | ||
| exit 1 | ||
| fi | ||
| if [ -z "${{ inputs.keystore-store-file }}" ]; then | ||
| echo " Input 'keystore-store-file' is required for signed builds." | ||
| exit 1 | ||
| fi | ||
| if [ -z "${{ inputs.keystore-store-password }}" ]; then | ||
| echo "Input 'keystore-store-password' is required for signed builds." | ||
| exit 1 | ||
| fi | ||
| if [ -z "${{ inputs.keystore-key-alias }}" ]; then | ||
| echo "Input 'keystore-key-alias' is required for signed builds." | ||
| exit 1 | ||
| fi | ||
| if [ -z "${{ inputs.keystore-key-password }}" ]; then | ||
| echo "Input 'keystore-key-password' is required for signed builds." | ||
| exit 1 | ||
| fi | ||
| fi | ||
| shell: bash | ||
|
|
||
| - name: Native Fingerprint | ||
| id: fingerprint | ||
| run: | | ||
| FINGERPRINT_OUTPUT=$(npx rock fingerprint -p android --raw) || (echo "$FINGERPRINT_OUTPUT" && exit 1) | ||
| echo "FINGERPRINT=$FINGERPRINT_OUTPUT" >> $GITHUB_ENV | ||
| shell: bash | ||
| working-directory: ${{ inputs.working-directory }} | ||
|
|
||
| - name: Get Provider Name | ||
| run: | | ||
| PROVIDER_NAME=$(npx rock remote-cache get-provider-name) || (echo "$PROVIDER_NAME" && exit 1) | ||
| echo "PROVIDER_NAME=$PROVIDER_NAME" >> $GITHUB_ENV | ||
| shell: bash | ||
| working-directory: ${{ inputs.working-directory }} | ||
|
|
||
| - name: Populate GitHub Token in Cache | ||
| if: ${{ env.PROVIDER_NAME == 'GitHub' }} | ||
| run: | | ||
| mkdir -p .rock/cache | ||
| echo "{\"githubToken\": \"${{ inputs.github-token }}\"}" > .rock/cache/project.json | ||
| shell: bash | ||
| working-directory: ${{ inputs.working-directory }} | ||
|
|
||
| - name: Check if PR-related artifact exists | ||
| if: ${{ github.event_name == 'pull_request' && inputs.re-sign == 'true' }} | ||
| run: | | ||
| ARTIFACT_TRAITS="${{ inputs.variant }},${{ github.event.pull_request.number}}" | ||
| echo "ARTIFACT_TRAITS=$ARTIFACT_TRAITS" >> $GITHUB_ENV | ||
| OUTPUT=$(npx rock remote-cache list -p android --traits "${ARTIFACT_TRAITS}" --json) || (echo "$OUTPUT" && exit 1) | ||
| if [ "$OUTPUT" ]; then | ||
| echo "ARTIFACT_URL=$(echo "$OUTPUT" | jq -r '.url')" >> $GITHUB_ENV | ||
| echo "ARTIFACT_ID=$(echo "$OUTPUT" | jq -r '.id')" >> $GITHUB_ENV | ||
| echo "ARTIFACT_NAME=$(echo "$OUTPUT" | jq -r '.name')" >> $GITHUB_ENV | ||
| fi | ||
| shell: bash | ||
| working-directory: ${{ inputs.working-directory }} | ||
|
|
||
| - name: Check if regular artifact exists | ||
| if: ${{ !env.ARTIFACT_NAME }} | ||
| run: | | ||
| ARTIFACT_TRAITS="${{ inputs.variant }}" | ||
| echo "ARTIFACT_TRAITS=$ARTIFACT_TRAITS" >> $GITHUB_ENV | ||
| OUTPUT=$(npx rock remote-cache list -p android --traits "${ARTIFACT_TRAITS}" --json) || (echo "$OUTPUT" && exit 1) | ||
| if [ "$OUTPUT" ]; then | ||
| echo "ARTIFACT_URL=$(echo "$OUTPUT" | jq -r '.url')" >> $GITHUB_ENV | ||
| echo "ARTIFACT_ID=$(echo "$OUTPUT" | jq -r '.id')" >> $GITHUB_ENV | ||
| echo "ARTIFACT_NAME=$(echo "$OUTPUT" | jq -r '.name')" >> $GITHUB_ENV | ||
| fi | ||
| shell: bash | ||
| working-directory: ${{ inputs.working-directory }} | ||
|
|
||
| - name: Set Artifact Name (if not set) | ||
| if: ${{ !env.ARTIFACT_NAME }} | ||
| run: | | ||
| ARTIFACT_TRAITS_HYPHENATED=$(echo "$ARTIFACT_TRAITS" | tr ',' '-') | ||
| ARTIFACT_TRAITS_HYPHENATED_FINGERPRINT="${ARTIFACT_TRAITS_HYPHENATED}-${FINGERPRINT}" | ||
| echo "ARTIFACT_NAME=rock-android-${ARTIFACT_TRAITS_HYPHENATED_FINGERPRINT}" >> $GITHUB_ENV | ||
| shell: bash | ||
|
|
||
| - name: Install Java | ||
| if: ${{ inputs.setup-java == 'true' && !env.ARTIFACT_URL }} | ||
| uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 | ||
| with: | ||
| java-version: 17 | ||
| distribution: adopt | ||
| cache: gradle | ||
|
|
||
| - name: Validate Gradle wrapper | ||
| if: ${{ inputs.validate-gradle-wrapper == 'true' && !env.ARTIFACT_URL }} | ||
| uses: gradle/actions/wrapper-validation@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 | ||
|
|
||
| - name: Create local gradle.properties | ||
| if: ${{ !env.ARTIFACT_URL && inputs.sign }} | ||
| run: | | ||
| mkdir -p $HOME/.gradle | ||
| touch $HOME/.gradle/gradle.properties | ||
| echo "android.injected.signing.store.file=${{ inputs.keystore-store-file }}" >> $HOME/.gradle/gradle.properties | ||
| echo "android.injected.signing.store.password=${{ inputs.keystore-store-password }}" >> $HOME/.gradle/gradle.properties | ||
| echo "android.injected.signing.key.alias=${{ inputs.keystore-key-alias }}" >> $HOME/.gradle/gradle.properties | ||
| echo "android.injected.signing.key.password=${{ inputs.keystore-key-password }}" >> $HOME/.gradle/gradle.properties | ||
| echo "ROCK_UPLOAD_STORE_FILE=${{ inputs.keystore-store-file }}" >> $HOME/.gradle/gradle.properties | ||
| echo "ROCK_UPLOAD_STORE_PASSWORD=${{ inputs.keystore-store-password }}" >> $HOME/.gradle/gradle.properties | ||
| echo "ROCK_UPLOAD_KEY_ALIAS=${{ inputs.keystore-key-alias }}" >> $HOME/.gradle/gradle.properties | ||
| echo "ROCK_UPLOAD_KEY_PASSWORD=${{ inputs.keystore-key-password }}" >> $HOME/.gradle/gradle.properties | ||
| shell: bash | ||
|
|
||
| - name: Determine Android sourceDir and appName | ||
| if: ${{ !env.ARTIFACT_URL }} | ||
| run: | | ||
| JSON_OUTPUT=$(npx rock config -p android) || (echo "$JSON_OUTPUT" && exit 1) | ||
| echo "$JSON_OUTPUT" | jq -r '.project' | ||
| ANDROID_SOURCE_DIR=$(echo "$JSON_OUTPUT" | jq -r '.project.android.sourceDir') | ||
| APP_NAME=$(echo "$JSON_OUTPUT" | jq -r '.project.android.appName') | ||
| echo "ANDROID_SOURCE_DIR=$ANDROID_SOURCE_DIR" >> $GITHUB_ENV | ||
| echo "APP_NAME=$APP_NAME" >> $GITHUB_ENV | ||
| shell: bash | ||
| working-directory: ${{ inputs.working-directory }} | ||
|
|
||
| - name: Decode and store keystore file | ||
| if: ${{ !env.ARTIFACT_URL && inputs.sign }} | ||
| run: | | ||
| if [ -n "$APP_NAME" ]; then | ||
| KEYSTORE_TARGET_PATH="$ANDROID_SOURCE_DIR/$APP_NAME/${{ inputs.keystore-path }}" | ||
| else | ||
| KEYSTORE_TARGET_PATH="$ANDROID_SOURCE_DIR/${{ inputs.keystore-path }}" | ||
| fi | ||
| echo "Keystore target path before normalizing: $KEYSTORE_TARGET_PATH" | ||
| KEYSTORE_TARGET_PATH=$(realpath -m "$KEYSTORE_TARGET_PATH") | ||
| echo "Keystore target path after normalizing: $KEYSTORE_TARGET_PATH" | ||
| mkdir -p "$(dirname "$KEYSTORE_TARGET_PATH")" || { | ||
| echo "Failed to create keystore directory: $(dirname "$KEYSTORE_TARGET_PATH")" | ||
| exit 1 | ||
| } | ||
| if [ -n "${{ inputs.keystore-file }}" ]; then | ||
| cp "${{ inputs.keystore-file }}" "$KEYSTORE_TARGET_PATH" | ||
| echo "Successfully copied keystore file to target path: $KEYSTORE_TARGET_PATH" | ||
| else | ||
| echo "${{ inputs.keystore-base64 }}" | base64 --decode > "$KEYSTORE_TARGET_PATH" | ||
| echo "Successfully copied keystore base64 to target path: $KEYSTORE_TARGET_PATH" | ||
| fi | ||
| shell: bash | ||
| working-directory: ${{ inputs.working-directory }} | ||
|
|
||
| - name: Build Android | ||
| if: ${{ !env.ARTIFACT_URL }} | ||
| run: | | ||
| npx rock build:android \ | ||
| --variant "${{ inputs.variant }}" \ | ||
| ${{ inputs.rock-build-extra-params }} | ||
| shell: bash | ||
| working-directory: ${{ inputs.working-directory }} | ||
|
|
||
| - name: Find Build Artifact | ||
| if: ${{ !env.ARTIFACT_URL }} | ||
| run: | | ||
| APK_PATH=$(find $ANDROID_SOURCE_DIR/$APP_NAME/build/outputs -name '*.apk' | head -1 ) | ||
| echo APK_PATH $APK_PATH | ||
| echo "ARTIFACT_PATH=$APK_PATH" >> $GITHUB_ENV | ||
| shell: bash | ||
| working-directory: ${{ inputs.working-directory }} | ||
|
|
||
| - name: Download and Unpack APK | ||
| if: ${{ env.ARTIFACT_URL && inputs.re-sign == 'true' }} | ||
| run: | | ||
| DOWNLOAD_OUTPUT=$(npx rock remote-cache download --name ${{ env.ARTIFACT_NAME }} --json) || (echo "$DOWNLOAD_OUTPUT" && exit 1) | ||
| APK_PATH=$(echo "$DOWNLOAD_OUTPUT" | jq -r '.path') | ||
| echo "ARTIFACT_PATH=$APK_PATH" >> $GITHUB_ENV | ||
| shell: bash | ||
| working-directory: ${{ inputs.working-directory }} | ||
|
|
||
| - name: Re-sign APK | ||
| if: ${{ env.ARTIFACT_URL && inputs.re-sign == 'true' }} | ||
| run: | | ||
| npx rock sign:android ${{ env.ARTIFACT_PATH }} \ | ||
| --build-jsbundle | ||
| shell: bash | ||
| working-directory: ${{ inputs.working-directory }} | ||
|
|
||
| - name: Update Artifact Name for re-signed builds | ||
| if: ${{ env.ARTIFACT_URL && inputs.re-sign == 'true' }} | ||
| run: | | ||
| if [ "${{ github.event_name }}" = "pull_request" ]; then | ||
| IDENTIFIER="${{ github.event.pull_request.number }}" | ||
| else | ||
| IDENTIFIER=$(echo "$GITHUB_SHA" | cut -c1-7) | ||
| fi | ||
| ARTIFACT_TRAITS="${{ inputs.variant }},${IDENTIFIER}" | ||
| ARTIFACT_TRAITS_HYPHENATED=$(echo "$ARTIFACT_TRAITS" | tr ',' '-') | ||
| ARTIFACT_TRAITS_HYPHENATED_FINGERPRINT="${ARTIFACT_TRAITS_HYPHENATED}-${FINGERPRINT}" | ||
| echo "ARTIFACT_NAME=rock-android-${ARTIFACT_TRAITS_HYPHENATED_FINGERPRINT}" >> $GITHUB_ENV | ||
| echo "ARTIFACT_TRAITS=$ARTIFACT_TRAITS" >> $GITHUB_ENV | ||
| shell: bash | ||
|
|
||
| - name: Find artifact URL again before uploading | ||
| run: | | ||
| OUTPUT=$(npx rock remote-cache list --name ${{ env.ARTIFACT_NAME }} --json) || (echo "$OUTPUT" && exit 1) | ||
| if [ -z "$OUTPUT" ]; then | ||
| echo "No artifact found" | ||
| else | ||
| echo "ARTIFACT_URL=$(echo "$OUTPUT" | jq -r '.url')" >> $GITHUB_ENV | ||
| echo "ARTIFACT_ID=$(echo "$OUTPUT" | jq -r '.id')" >> $GITHUB_ENV | ||
| fi | ||
| shell: bash | ||
| working-directory: ${{ inputs.working-directory }} | ||
|
|
||
| - name: Upload Artifact to GitHub | ||
| id: upload-artifact | ||
| if: ${{ env.PROVIDER_NAME == 'GitHub' && (!env.ARTIFACT_URL || inputs.re-sign == 'true') }} | ||
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | ||
| with: | ||
| name: ${{ env.ARTIFACT_NAME }} | ||
| path: ${{ env.ARTIFACT_PATH }} | ||
| if-no-files-found: error | ||
|
|
||
| - name: Upload Artifact to Remote Cache for re-signed builds | ||
| if: ${{ env.PROVIDER_NAME != 'GitHub' && inputs.re-sign == 'true' }} | ||
| run: | | ||
| OUTPUT=$(npx rock remote-cache upload --name ${{ env.ARTIFACT_NAME }} --binary-path ${{ env.ARTIFACT_PATH }} --json --verbose) || (echo "$OUTPUT" && exit 1) | ||
| echo "ARTIFACT_URL=$(echo "$OUTPUT" | jq -r '.url')" >> $GITHUB_ENV | ||
| shell: bash | ||
| working-directory: ${{ inputs.working-directory }} | ||
|
|
||
| - name: Upload Artifact to Remote Cache for regular builds | ||
| if: ${{ env.PROVIDER_NAME != 'GitHub' && inputs.re-sign != 'true' && !env.ARTIFACT_URL }} | ||
| run: | | ||
| OUTPUT=$(npx rock remote-cache upload --name ${{ env.ARTIFACT_NAME }} --json --verbose) || (echo "$OUTPUT" && exit 1) | ||
| echo "ARTIFACT_URL=$(echo "$OUTPUT" | jq -r '.url')" >> $GITHUB_ENV | ||
| shell: bash | ||
| working-directory: ${{ inputs.working-directory }} | ||
|
|
||
| - name: Delete Old Re-Signed Artifacts | ||
| if: ${{ env.ARTIFACT_URL && inputs.re-sign == 'true' && github.event_name == 'pull_request' }} | ||
| run: | | ||
| npx rock remote-cache delete --name ${{ env.ARTIFACT_NAME }} --all-but-latest --json | ||
| shell: bash | ||
| working-directory: ${{ inputs.working-directory }} | ||
|
|
||
| - name: Clean Up Keystore and gradle properties (signed builds only) | ||
| if: ${{ !env.ARTIFACT_URL && inputs.sign }} | ||
| run: | | ||
| rm $HOME/.gradle/gradle.properties | ||
| if [ -n "$APP_NAME" ]; then | ||
| rm "$ANDROID_SOURCE_DIR/$APP_NAME/${{ inputs.keystore-path }}" | ||
| else | ||
| rm "$ANDROID_SOURCE_DIR/${{ inputs.keystore-path }}" | ||
| fi | ||
| shell: bash | ||
| working-directory: ${{ inputs.working-directory }} | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.