Skip to content

Commit e6caa4c

Browse files
Qbandevbsgrigorovalucardzom
authored
ci: add namespace gradle cache trial Android E2E APK (#30054)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** This adds a scoped trial for Namespace Gradle remote build cache on the Android E2E APK build path. The workflow configures Namespace Gradle cache only when `runner_provider=namespace` and the native Android build path is active. The generated Namespace init script is passed through `GRADLE_INIT_SCRIPT` to `scripts/build.sh`, where it is added to the Android E2E APK Gradle invocation as `--init-script`. Current runner behavior stays unchanged: the Namespace setup step is skipped, `GRADLE_INIT_SCRIPT` is empty, and the existing Gradle command shape is preserved. The non-E2E AAB release build path is intentionally unchanged. ### Validation summary This validation uses Android E2E APK builds from commit `5a8b29d6895875799466b489abe957f7bdf914ee`: - Namespace warm-cache run: https://github.com/MetaMask/metamask-mobile/actions/runs/25792837744 - Forced current-runner native build: https://github.com/MetaMask/metamask-mobile/actions/runs/25786062492/attempts/3 Important caveat: this is a validation comparison, not a production benchmark. The primary metric for this ticket is Android E2E APK job wall time because it measures the CI job as executed, including setup, cache restore/configuration, Gradle execution, and artifact handling. The data proves the scoped Namespace Gradle cache path works for the Android E2E APK build. It does not prove Namespace is faster than the existing current-runner path. The current-runner comparison was run through a PR-event native Gradle path so the existing current-runner behavior could be checked without enabling the Namespace setup. #### Results and evidence | Question | Evidence | Conclusion | | --- | --- | --- | | Did the Namespace run build the Android E2E APK successfully? | Namespace APK job: https://github.com/MetaMask/metamask-mobile/actions/runs/25792837744/job/75762901387. Log summary: `BUILD SUCCESSFUL in 12m 13s`; `3647 actionable tasks: 2146 executed, 1501 from cache`. | Yes. Namespace built the APK and restored many Gradle tasks from cache. | | Did the current-runner path still build the Android E2E APK successfully? | Current APK job: https://github.com/MetaMask/metamask-mobile/actions/runs/25786062492/job/75802755963. Log summary: `BUILD SUCCESSFUL in 4m 16s`; `3647 actionable tasks: 2155 executed, 1492 from cache`. | Yes. The existing current-runner native Gradle path still works without the Namespace setup. | | Was cache behavior comparable between the two valid jobs? | Namespace restored `1501 from cache`; current runner restored `1492 from cache`. | Yes. Both native Gradle builds restored a similar number of tasks from cache. | | Does this prove Namespace is faster? | Primary metric: APK job wall time was `14m 13s` on Namespace and `12m 44s` on current runner. Diagnostic metric: Gradle's own build timer was `12m 13s` on Namespace and `4m 16s` on current runner. Both jobs ran native Gradle on the same commit, but they used different cache plumbing: Namespace cache setup plus Gradle init script vs the existing current-runner Gradle cache restore path. | No. Current runner was faster in this sample. The APK job wall-time difference was about `1m 29s`; the Gradle command timer is useful diagnostic evidence but not the primary CI metric. This PR should remain a scoped compatibility/cache-path trial. | To claim performance gains, use a dedicated benchmark design. The current PR should stay scoped to validating that the official Namespace Gradle setup can be wired into the Android E2E APK path without changing current-runner behavior. ## **Changelog** CHANGELOG entry: null ## **Related issues** Refs: INFRA-3626 ## **Manual testing steps** ```gherkin Feature: Namespace Gradle cache trial for Android E2E APK builds Scenario: Current runner Android E2E build path remains unchanged Given CI is manually dispatched from this branch with runner_provider=current And the Android E2E APK job requires a fresh native build When the Build Android E2E APKs job runs Then the Namespace Gradle remote cache setup step should be skipped And the Gradle command should not include --init-script And the existing current-runner Gradle cache behavior should remain unchanged Scenario: Namespace Android E2E build path configures Gradle remote cache Given CI is manually dispatched from this branch with runner_provider=namespace And the Android E2E APK job requires a fresh native build When the Build Android E2E APKs job runs Then the Namespace Gradle remote cache setup step should create a Gradle init script under RUNNER_TEMP And the Gradle APK invocation should include --init-script for that generated file And Gradle logs should show build-cache task reuse Scenario: Namespace warm-cache behavior is measurable Given CI is manually dispatched twice from the same branch and SHA with runner_provider=namespace When the second Android E2E APK job runs Then the Gradle task cache count should be comparable or better than the first Namespace run And Android smoke tests should be able to consume the generated APK artifacts ``` ## **Screenshots/Recordings** ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) CI-only change. No app runtime behavior is changed, so device runtime performance instrumentation is not applicable. - [x] Android CI validation was run through manually dispatched Android E2E APK and smoke workflows. - [x] No app runtime code path was modified. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk because it changes the Android E2E CI build invocation and introduces a conditional Gradle `--init-script` path that could affect build determinism or fail if the init script is missing/misconfigured on Namespace runners. > > **Overview** > Adds a scoped Namespace Gradle *remote build cache* setup step to the Android E2E APK GitHub Actions workflow when `runner_provider=namespace` and a full native build is required. > > Plumbs the generated init script through `GRADLE_INIT_SCRIPT` and updates `scripts/build.sh` to optionally pass `--init-script` to the Android `./gradlew` invocation, leaving non-Namespace runners and the non-E2E AAB release path unchanged. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 527653f. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Borislav Grigorov <11405770+bsgrigorov@users.noreply.github.com> Co-authored-by: Ale Som <560018+alucardzom@users.noreply.github.com>
1 parent e6070d9 commit e6caa4c

2 files changed

Lines changed: 16 additions & 1 deletion

File tree

.github/workflows/build-android-e2e.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,14 @@ jobs:
329329
# sibling "Restore Gradle dependencies from branch cache" step above.
330330
key: gradle-main-${{ env.GRADLE_CACHE_VERSION }}-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
331331

332+
- name: Configure Namespace Gradle remote cache
333+
id: namespace-gradle-cache
334+
if: ${{ inputs.runner_provider == 'namespace' && steps.gate.outputs.needs-native-build == 'true' }}
335+
run: |
336+
nsc cache gradle setup --init-gradle "$RUNNER_TEMP/namespace-gradle-init.gradle"
337+
echo "init-script=$RUNNER_TEMP/namespace-gradle-init.gradle" >> "$GITHUB_OUTPUT"
338+
shell: bash
339+
332340
- name: Build Android E2E APKs
333341
if: ${{ steps.gate.outputs.needs-native-build == 'true' }}
334342
run: |
@@ -346,6 +354,7 @@ jobs:
346354
IGNORE_BOXLOGS_DEVELOPMENT: true
347355
GITHUB_CI: 'true'
348356
CI: 'true'
357+
GRADLE_INIT_SCRIPT: ${{ steps.namespace-gradle-cache.outputs.init-script }}
349358
NODE_OPTIONS: '--max-old-space-size=4096'
350359
# Limit Metro workers to prevent OOM (each worker uses ~3GB)
351360
METRO_MAX_WORKERS: '4'

scripts/build.sh

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@ generateAndroidBinary() {
493493
local testBuildTypeArg=""
494494
# Define Gradle logging flags for E2E builds
495495
local gradleLoggingFlags=""
496+
# Optional Gradle init script used by Namespace remote build cache trials.
497+
local -a gradleInitScriptArg=()
496498

497499
# Check if configuration is valid
498500
if [ "$configuration" != "Debug" ] && [ "$configuration" != "Release" ] ; then
@@ -508,6 +510,10 @@ generateAndroidBinary() {
508510
exit 1
509511
fi
510512

513+
if [ -n "${GRADLE_INIT_SCRIPT:-}" ] ; then
514+
gradleInitScriptArg=(--init-script "$GRADLE_INIT_SCRIPT")
515+
fi
516+
511517
if [ "$configuration" = "Debug" ] || [ "$METAMASK_ENVIRONMENT" = "e2e" ] ; then
512518
# Define assemble test APK task
513519
assembleTestApkTask="app:assemble${flavor}${configuration}AndroidTest"
@@ -533,7 +539,7 @@ generateAndroidBinary() {
533539

534540
# Generate Android APKs
535541
echo "Generating Android binary for ($flavor) flavor with ($configuration) configuration"
536-
./gradlew $assembleApkTask $assembleTestApkTask $testBuildTypeArg $reactNativeArchitecturesArg $gradleLoggingFlags $exUpdatesArgs
542+
./gradlew "${gradleInitScriptArg[@]}" $assembleApkTask $assembleTestApkTask $testBuildTypeArg $reactNativeArchitecturesArg $gradleLoggingFlags $exUpdatesArgs
537543

538544
# Skip AAB bundle for E2E environments - AAB cannot be installed on emulators
539545
# and is only needed for Play Store distribution

0 commit comments

Comments
 (0)