Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
165 changes: 165 additions & 0 deletions .github/actions/android-play-store-manifest-check/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
name: 'Android Play Store manifest validation'
description: >
Builds the prodRelease variant used for Play uploads (same manifest merge path), runs Android Lint
on that variant, produces a signed release bundle using the repo debug keystore via AGP signing
injection, and runs bundletool validate on the AAB.

runs:
using: composite
steps:
- name: Set up JDK 17
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00
with:
distribution: temurin
java-version: '17'

# Third-party actions such as android-actions/setup-android are not allowlisted for this org;
# install SDK components with Google's cmdline-tools + sdkmanager (same packages as android/build.gradle).
- name: Cache Gradle
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-android-manifest-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-android-manifest-

- name: Cache Android SDK
id: android-sdk-cache
uses: actions/cache@v4
with:
path: ~/android-sdk
key: ${{ runner.os }}-android-sdk-manifest-v2-cmd11076708-api35-ndk26.1-cmake322

- name: Install Android SDK (cmdline-tools + packages)
if: steps.android-sdk-cache.outputs.cache-hit != 'true'
shell: bash
run: |
set -euo pipefail
CMDLINE_TOOLS_BUILD=11076708
SDK_ROOT="${ANDROID_SDK_ROOT:-$HOME/android-sdk}"
mkdir -p "$SDK_ROOT"
TMPZIP="$(mktemp)"
curl -fsSL -o "$TMPZIP" \
"https://dl.google.com/android/repository/commandlinetools-linux-${CMDLINE_TOOLS_BUILD}_latest.zip"
rm -rf "$SDK_ROOT/cmdline-tools"
unzip -q "$TMPZIP" -d "$SDK_ROOT/cmdline-tools-staging"
rm -f "$TMPZIP"
mkdir -p "$SDK_ROOT/cmdline-tools"
mv "$SDK_ROOT/cmdline-tools-staging/cmdline-tools" "$SDK_ROOT/cmdline-tools/latest"
rm -rf "$SDK_ROOT/cmdline-tools-staging"

SDKMANAGER="$SDK_ROOT/cmdline-tools/latest/bin/sdkmanager"
# yes exits with SIGPIPE when sdkmanager closes stdin; with pipefail that fails the step.
set +o pipefail
yes | "$SDKMANAGER" --sdk_root="$SDK_ROOT" --licenses >/dev/null
set -o pipefail
"$SDKMANAGER" --sdk_root="$SDK_ROOT" \
"platform-tools" \
"platforms;android-33" \
"platforms;android-34" \
"platforms;android-35" \
"build-tools;33.0.0" \
"build-tools;34.0.0" \
"build-tools;35.0.0" \
"ndk;26.1.10909125" \
"cmake;3.22.1"

- name: Configure Android SDK environment
shell: bash
run: |
SDK_ROOT="${ANDROID_SDK_ROOT:-$HOME/android-sdk}"
echo "ANDROID_SDK_ROOT=${SDK_ROOT}" >> "$GITHUB_ENV"
echo "ANDROID_HOME=${SDK_ROOT}" >> "$GITHUB_ENV"
echo "${SDK_ROOT}/cmdline-tools/latest/bin" >> "$GITHUB_PATH"
echo "${SDK_ROOT}/platform-tools" >> "$GITHUB_PATH"

- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: yarn

- name: Restore .metamask folder
id: restore-metamask
uses: actions/cache@v4
with:
path: .metamask
key: .metamask-${{ hashFiles('package.json', 'yarn.lock') }}

- name: Install Foundry if cache missed
if: steps.restore-metamask.outputs.cache-hit != 'true'
shell: bash
run: yarn install:foundryup

- name: Install Yarn dependencies with retry
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 #v3.0.2
with:
timeout_minutes: 10
max_attempts: 3
retry_wait_seconds: 30
command: yarn install --immutable

- name: Project setup for CI (Android tooling path)
shell: bash
run: yarn setup:github-ci --no-build-ios

- name: Write google-services.json
shell: bash
run: |
set -euo pipefail
# Caller workflow must set GOOGLE_SERVICES_B64_ANDROID (job env from GitHub secret).
if [[ -z "${GOOGLE_SERVICES_B64_ANDROID:-}" ]]; then
echo "::error::GOOGLE_SERVICES_B64_ANDROID is not set; cannot run Play-shaped Android build."
exit 1
fi
echo -n "$GOOGLE_SERVICES_B64_ANDROID" | base64 -d > android/app/google-services.json

- name: Configure Gradle for GitHub Actions
shell: bash
run: cp android/gradle.properties.github android/gradle.properties

- name: Cache bundletool
id: bundletool-cache
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/bundletool-all.jar
key: bundletool-1.18.3-jar

- name: Download bundletool
if: steps.bundletool-cache.outputs.cache-hit != 'true'
shell: bash
env:
BUNDLETOOL_URL: https://github.com/google/bundletool/releases/download/1.18.3/bundletool-all-1.18.3.jar
run: curl -fsSL -o "${RUNNER_TEMP}/bundletool-all.jar" "$BUNDLETOOL_URL"

- name: Lint, bundle (debug-signed), validate with bundletool
shell: bash
env:
SENTRY_DISABLE_AUTO_UPLOAD: true
run: |
set -euo pipefail
STORE_FILE="${GITHUB_WORKSPACE}/android/keystores/debug.keystore"
cd android
chmod +x ./gradlew
./gradlew \
:app:lintProdRelease \
:app:bundleProdRelease \
--no-daemon \
--stacktrace \
-Pandroid.injected.signing.store.file="$STORE_FILE" \
-Pandroid.injected.signing.store.password=android \
-Pandroid.injected.signing.key.alias=androiddebugkey \
-Pandroid.injected.signing.key.password=android

# Exactly one AAB for prodRelease (main prod Play track).
shopt -s nullglob
aabs=( "$GITHUB_WORKSPACE/android/app/build/outputs/bundle/prodRelease/"*.aab )
shopt -u nullglob
if [[ "${#aabs[@]}" -ne 1 ]]; then
echo "::error::Expected exactly one .aab under prodRelease; found ${#aabs[@]}"
find "$GITHUB_WORKSPACE/android/app/build/outputs/bundle/prodRelease" -maxdepth 2 -print || true
exit 1
fi
echo "Validating bundle: ${aabs[0]}"
java -jar "${RUNNER_TEMP}/bundletool-all.jar" validate --bundle="${aabs[0]}"
41 changes: 41 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,47 @@ jobs:
SCRIPT_NAME="build:${{ matrix.platform }}:${SCRIPT_BASE//-/:}"
yarn "$SCRIPT_NAME"

# Prod Play–shaped Android: lint merged prodRelease manifest, then validate the AAB produced above (bundletool).
# Skips e2e (no AAB) and Debug dev builds. Mirrors former ci.yml android-play-store-manifest-check without a second bundle.
- name: Cache bundletool (Android Play bundle validation)
id: bundletool-cache-play-check
if: >-
success() &&
matrix.platform == 'android' &&
env.CONFIGURATION != 'Debug' &&
env.METAMASK_BUILD_TYPE == 'main' &&
env.METAMASK_ENVIRONMENT != 'e2e'
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/bundletool-all.jar
key: bundletool-1.18.3-jar

- name: Android Play Store lint and bundle validation (prodRelease, non-blocking)
if: >-
success() &&
matrix.platform == 'android' &&
env.CONFIGURATION != 'Debug' &&
env.METAMASK_BUILD_TYPE == 'main' &&
env.METAMASK_ENVIRONMENT != 'e2e'
env:
SENTRY_DISABLE_AUTO_UPLOAD: true
run: node scripts/android-play-store-check-slack.mjs

- name: Upload Android Play Store Slack report (main-rc only)
if: >-
success() &&
matrix.platform == 'android' &&
inputs.build_name == 'main-rc' &&
env.CONFIGURATION != 'Debug' &&
env.METAMASK_BUILD_TYPE == 'main' &&
env.METAMASK_ENVIRONMENT != 'e2e'
uses: actions/upload-artifact@v4
with:
name: android-play-store-check-slack
path: android-play-store-check-slack.md
if-no-files-found: warn
retention-days: 14

# Rename build artifacts (ios_simulator_path / ios_ipa_path / ios_archive_path / android_*_path outputs)
- name: Rename ${{ matrix.platform }} artifacts
if: success()
Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/slack-rc-notification.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ on:
type: string
default: ''

permissions:
actions: read
contents: read

jobs:
slack-notification:
name: Post Slack Notification
Expand All @@ -46,6 +50,15 @@ jobs:
with:
ref: ${{ inputs.source_branch }}
fetch-depth: 0

- name: Download Android Play Store check report (optional)
id: download-play-store-check
continue-on-error: true
uses: actions/download-artifact@v4
with:
name: android-play-store-check-slack
path: android-play-store-check-out

- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
Expand All @@ -71,3 +84,4 @@ jobs:
ANDROID_PUBLIC_URL: ${{ secrets.ANDROID_PUBLIC_BUCKET_URL }}
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
PR_NUMBER: ${{ inputs.pr_number }}
ANDROID_PLAY_STORE_CHECK_MRKDWN_FILE: ${{ github.workspace }}/android-play-store-check-out/android-play-store-check-slack.md
4 changes: 3 additions & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,9 @@ def reactNativeArchitectures() {

android {
ndkVersion rootProject.ext.ndkVersion

lint {
baseline = file("lint-baseline.xml")
}
buildToolsVersion rootProject.ext.buildToolsVersion
compileSdk rootProject.ext.compileSdkVersion

Expand Down
Loading
Loading