Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/add-metro-plugin-rock.md
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
1 change: 1 addition & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@module-federation/treeshake-frontend",
"@module-federation/metro",
"@module-federation/metro-plugin-rnef",
"@module-federation/metro-plugin-rock",
"@module-federation/metro-plugin-rnc-cli"
]
],
Expand Down
5 changes: 5 additions & 0 deletions .changeset/deprecate-metro-plugin-rnef.md
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
328 changes: 328 additions & 0 deletions .github/actions/rock-android/action.yml
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 }}
Comment thread
jbroma marked this conversation as resolved.
Outdated
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 }}
Loading
Loading