Skip to content

ci: reuse native e2e builds across PRs via build-source-hash + artifact lookup #29148

Open
tommasini wants to merge 11 commits into
mainfrom
ci/reusable-build-e2e
Open

ci: reuse native e2e builds across PRs via build-source-hash + artifact lookup #29148
tommasini wants to merge 11 commits into
mainfrom
ci/reusable-build-e2e

Conversation

@tommasini
Copy link
Copy Markdown
Contributor

@tommasini tommasini commented Apr 21, 2026

PR Title

ci: reuse native e2e builds across PRs via build-source-hash + artifact lookup


Description

Why. Native E2E builds are ~20 min per platform. Today, the cirruslabs/cache layer keyed by @expo/fingerprint reuses the native shell within a single branch and via a main fallback, and the existing @expo/repack-app step swaps in fresh JS on a cache hit. GitHub Actions caches are branch-scoped, though, so two unrelated PRs with byte-identical native inputs still each pay the ~20 min cost — the only cross-PR path is the main fallback, which requires main to have happened to build the matching fingerprint.

What. This PR adds a cross-PR reuse tier on top of the existing pipeline, modeled on metamask-extension#41435 and adapted to mobile's @expo/fingerprint + @expo/repack-app architecture.

  • A new post-build-source-hash job in ci.yml runs yarn fingerprint:generate and posts the result as a build-source-hash GitHub commit status on every event (including merge_group and fork PRs where the E2E builds themselves may be skipped). This guarantees the fingerprint is queryable for every commit.
  • A new composite action find-reusable-build searches the 10 most recent ci.yml runs on the head branch, then on main, for a run whose build-source-hash status matches the current fingerprint AND whose required native artifacts are still available (verified via listWorkflowRunArtifacts). Same-SHA rejection, non-success runs are filtered out, and every API call is wrapped in continue-on-error — any lookup failure falls through to a fresh build.
  • build-ios-e2e.yml and build-android-e2e.yml call the lookup after the existing GHA cache restores miss. On a match, actions/download-artifact@v4 pulls the MetaMask.app or both release.apk + release-androidTest.apk directly from the source run using its run-id. The repack + source-map upload steps' if: conditions were extended to include the reuse path.
  • Android requires both APKs because E2E consumes the androidTest APK too. If either is missing or expired, the candidate is rejected and we keep searching.

Escape hatch. A per-PR override to force a fresh native build for safety when reuse is suspected wrong:

  • Apply the force-builds label to the PR, or
  • Include [force-builds] in the head commit message.

A new composite action check-force-builds detects either, and gates the branch-scoped GHA cache restore, the main-scoped GHA cache restore, and the find-reusable-build step with its output. The build/repack steps' existing conditions naturally resolve to "build fresh, skip repack" because all three reuse outputs are empty. The override is honored only on pull_request events — in merge_group and push the merge queue always uses hash-verified reuse or fresh builds.

Documentation.

CI Native Build Reuse (Cross-PR)

This document describes how MetaMask Mobile reuses iOS .app and Android .apk
E2E build artifacts across pull requests when the native inputs haven't
changed, so unrelated PRs with identical native state skip the ~20 min native
compile entirely.

The mechanism sits on top of the existing @expo/fingerprint + @expo/repack-app
pipeline and the cirruslabs/cache GHA-cache layer. It is modeled after
metamask-extension#41435
but adapted to mobile's native-shell + repackable-JS architecture.


Problem statement

Native builds on CI are expensive (~20 min per platform). Before this change,
mobile already cached the built native shell via cirruslabs/cache, keyed by
the @expo/fingerprint hash. That cache has two scopes:

  • Current branch (read + write)
  • main fallback (read only)

GitHub Actions caches are branch-scoped: PR B cannot read PR A's cache
entry, even if they produce an identical native shell. The only cross-PR path
is the main fallback, which relies on main having happened to build
something with the matching fingerprint.

Result: two unrelated PRs that only change tests/docs rebuild the native
shell twice, even though the shells are byte-identical.

High-level flow

flowchart TD
    start[Build job starts]
    fp[Compute fingerprint]
    ghaBranch{GHA cache hit on branch?}
    ghaMain{GHA cache hit on main?}
    lookup[find-reusable-build: scan recent ci.yml runs]
    match{Matching build-source-hash AND artifact available?}
    download[actions/download-artifact with run-id]
    build[Fresh native build]
    repack[yarn build:repack - swap in fresh JS]
    upload[Upload artifact + save GHA cache]
    endNode[Done]

    start --> fp --> ghaBranch
    ghaBranch -- hit --> repack
    ghaBranch -- miss --> ghaMain
    ghaMain -- hit --> repack
    ghaMain -- miss --> lookup --> match
    match -- yes --> download --> repack
    match -- no --> build --> upload --> endNode
    repack --> upload
Loading

The three tiers in order of preference:

  1. Branch-scoped GHA cache (fastest, only reachable within the same PR
    lineage).
  2. main-scoped GHA cache (cross-PR, but only if main has built a
    matching fingerprint recently).
  3. Cross-run artifact reuse via commit-status lookup (this doc's subject;
    works across unrelated PRs).
  4. Fresh native build as the safety net.

Tiers 1 and 2 existed before. Tier 3 is the new one.

Components

scripts/generate-fingerprint.js

Thin wrapper around @expo/fingerprint's createFingerprintAsync, exposed as
yarn fingerprint:generate. Produces one hash covering native folders, Expo
config, patches, and dependency manifests. This is the content-addressable
identity of the native shell.

.github/actions/post-build-source-hash/action.yml

Composite action that:

  1. Runs yarn fingerprint:generate.
  2. Posts the hash as a GitHub commit status on the current SHA with context
    build-source-hash and description set to the hash value.

The post is wrapped in continue-on-error: true — a failure to post never
blocks the workflow.

.github/actions/find-reusable-build/action.yml

Composite action driven by actions/github-script. Given a fingerprint and a
list of required artifact names, it:

  1. Lists the 10 most recent runs of ci.yml on the head branch.
  2. For each candidate run, fetches getCombinedStatusForRef on its head SHA
    and looks for a build-source-hash status whose description matches.
  3. On a hash match, paginates listWorkflowRunArtifacts and verifies that
    every required artifact name is present and not expired.
  4. On no match, repeats the search on the base branch (main by default).
  5. Outputs found, run-id, source-sha, source-branch.

Everything is wrapped in continue-on-error: true and returns found=false
on any API error, so a lookup failure falls through to a fresh build.

.github/workflows/ci.yml

New job post-build-source-hash that runs on every event (including
merge_group and fork PRs where builds are skipped) with
permissions: statuses: write. It guarantees the hash is published for every
commit, so future runs can always look back and find it.

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

After the existing GHA cache restore steps and only if both missed, the
workflows invoke find-reusable-build and, on a match, call
actions/download-artifact@v4 with run-id + github-token to pull the
native shell from the source run directly into the expected build-output
path.

The fresh-build step is gated on
find-reusable-build.outputs.found != 'true'. The repack, source-map upload,
and downstream upload steps include the reuse branch in their if:
conditions.

Both workflows also request actions: read permission, required for
listWorkflowRuns and cross-run artifact download.

Artifact naming contract

The lookup must match exactly what the upload step produces. Current contract:

Platform Artifact names
iOS ${build_type}-${metamask_environment}-MetaMask.app
Android ${build_type}-${metamask_environment}-release.apk AND ${build_type}-${metamask_environment}-release-androidTest.apk (both must be present)

Android requires both artifacts because E2E uses the test APK too. If one is
missing or expired, the candidate run is rejected and we keep searching.

Runtime decision table

GHA branch cache GHA main cache Reuse lookup Action
HIT Repack JS into cached shell
miss HIT Repack JS into cached shell
miss miss found Download artifact from prior run, repack
miss miss not found Fresh native build

JS bundle is always rebuilt. Only the native shell is reused.

Cross-PR behavior, explained

  • Within a single PR (commits on the same branch): tier 1 hits after the
    first build of the session. Pre-existing behavior, unchanged.
  • Any PR based on main: if main has built the matching fingerprint
    recently, tier 2 hits. Pre-existing behavior, unchanged.
  • Two unrelated PRs with identical fingerprint: PR A builds first, uploads
    artifacts, and posts build-source-hash. PR B's find-reusable-build
    discovers PR A's run via the status + artifact check on the main fallback
    scan, and downloads the artifact. Tier 3 — new.

The base-branch scan uses the workflow-file's default branch (main). PRs
against other release branches can still benefit because we scan the head
branch first.

Storage implications

  • GHA cache usage: unchanged. The cirruslabs/cache@... (auto-save
    variant) writes one branch-scoped entry per successful run, same as before.
    A cache write from a reuse-path run is byte-identical to a cache write from
    a fresh-build run.
  • Artifact storage: unchanged. Upload steps are untouched. Retention
    remains 7 days.
  • Cross-run downloads: new bandwidth cost of ~200–800 MB per reuse hit,
    which substitutes for a ~20 min native compile.
  • API calls: bounded by max-candidates-per-branch (10) × 2 branches per
    build job. Negligible against the 5000 req/hr token budget.

Failure modes and fail-safes

Scenario Behavior
yarn fingerprint:generate fails post-build-source-hash job fails (not fatal to builds)
Commit-status POST fails continue-on-error: true swallows; no future lookup will match
listWorkflowRuns / status API returns an error find-reusable-build outputs found=false, fresh build runs
Artifact expired between status post and lookup hasAllArtifacts returns false, candidate rejected
Downloaded artifact is corrupt Repack or E2E step fails loudly; worst case is a rerun

There is no path in which reuse produces a stale build. The fingerprint covers
native inputs, so a hash match guarantees the native shell is a correct
function of the current source. JS is rebuilt unconditionally during repack.

Force a fresh build

Three mechanisms exist, in increasing blast radius:

1. force-builds label or [force-builds] commit tag (per-PR, recommended)

Use this when you suspect a reuse-correctness issue on a specific PR — for
example, one of the known gaps below is triggered, or you simply want to
verify a fresh build matches.

  • Apply the force-builds label to the PR, or
  • Include [force-builds] in the head commit message (anywhere, case
    sensitive).

The .github/actions/check-force-builds/action.yml
composite action runs early in both build workflows and, when either
condition is met, skips:

  • the branch-scoped GHA cache restore,
  • the main-scoped GHA cache restore, and
  • the find-reusable-build cross-run lookup.

The Build iOS E2E App / Build Android E2E APKs step then runs as if
nothing was ever cached, producing a truly fresh native binary. Repack does
not run in this path because there is no pre-built shell to swap JS into.

Scope notes:

  • Honored only on pull_request events. In merge_group and push events
    the override is intentionally ignored so the merge queue always uses
    hash-verified reuse (or fresh builds when no match exists).
  • Affects only the current run. Future runs on other PRs can still find and
    reuse artifacts uploaded by this run. If you also want to prevent future
    reuse of the output, use mechanism 3 below.

2. [skip-e2e] commit tag or skip-e2e label

Skips E2E builds (and the downstream tests) entirely. See
.github/workflows/needs-e2e-build.yml.
Not a "force-build" per se — use this when you want to bypass E2E altogether.

3. Bump the cache-version env var (repo-wide, permanent)

Increment IOS_APP_CACHE_VERSION in
.github/workflows/build-ios-e2e.yml
or CACHE_GENERATION in
.github/workflows/build-android-e2e.yml.
This busts the GHA cache for every branch and forces a fresh compile
everywhere. Reuse lookups will still find prior artifacts against the old
fingerprint — if you want to bust those too, either retire the associated
commit statuses or wait up to 7 days for artifact expiry.

Mechanism Scope Native compile JS rebundle Cache bust Cross-run reuse bust
force-builds label / tag single PR yes yes skips read skips read
[skip-e2e] / skip-e2e label single PR N/A (skipped) N/A N/A N/A
Bump *_CACHE_VERSION env repo-wide yes yes yes only on stale hash

Observability

Each reuse hit logs:

Reusing iOS build from run <id>
Source SHA: <sha>
Source branch: <branch>

find-reusable-build logs every candidate it inspects and the reason it
rejected non-matches (wrong hash, missing artifacts, wrong status). This
shows up in the Actions log for the build job.

The build-source-hash commit status itself is visible in the PR checks
panel, showing the hash value as its description.

Known fingerprint gaps

The fingerprint (via @expo/fingerprint + this repo's fingerprint.config.js)
covers the standard native inputs: contents of ios/ and android/, Expo and
React Native autolinking output, app.json / app.config.*, patches/ and
.yarn/patches, react-native's own package.json, and root package.json
scripts. For the vast majority of PRs this is sufficient — a native-affecting
dependency or patch change produces a different fingerprint, which invalidates
reuse; a pure-JS dependency change keeps the fingerprint stable and the JS
bundle is rebuilt unconditionally during repack.

Residual scenarios where reuse could theoretically produce a different binary
than a fresh build, and the fingerprint wouldn't notice:

  1. Build-time environment variables baked into the native binary (e.g.,
    GOOGLE_SERVICES_B64_*, API keys injected at Xcode/Gradle time). These
    aren't part of the fingerprint inputs. In practice they're managed per
    environment and are stable for a given ${build_type}-${metamask_environment}
    artifact name, which is part of the cache key — but an in-place value change
    (e.g., rotating a key) without a corresponding code change would be invisible
    to the fingerprint.
  2. Host-machine / toolchain drift — subtle Xcode version differences,
    CocoaPods version, Android SDK/NDK versions. Cirrus runners are pinned, but
    image updates are out-of-band of the fingerprint.
  3. Transitive JS dependency with a postinstall that modifies node_modules
    natively
    without a corresponding change in patches/, ios/, or
    android/. Rare, but possible.

If you hit any of these or suspect one, use the force-builds escape hatch
(above) to verify. If it becomes recurring, the fix is to extend
fingerprint.config.js extraSources to include the relevant input.

Non-goals (deferred)

  • [skip-builds] escape hatch for non-E2E builds.
  • PR-comment annotation indicating [reused from <sha>].
  • Expanding reuse to RC / TestFlight / BrowserStack builds.
  • Splitting the fingerprint per platform (iOS-only vs. Android-only changes).
  • Reusing unit-test runs — unit tests do not consume native artifacts, so
    this mechanism does not apply. A parallel path (path-filter skip, or a
    dedicated unit-tests-source-hash with Jest-result artifacts) would be
    needed there.

Validation

  1. Reuse hit: open two back-to-back PRs touching only tests/**. The
    second PR's build job should log Reusing build from run <id> and skip
    the native compile step.
  2. Reuse miss (correct invalidation): open a PR that touches ios/Podfile
    or android/app/build.gradle. The fingerprint changes, no candidate
    matches, fresh build runs.
  3. Artifact expiry fall-through: manually delete an artifact from a prior
    run. Subsequent lookups reject that candidate and either find another or
    fall through to a fresh build.

Files

Repo-admin follow-up (one-time). The force-builds label needs to exist in the repo before PRs can apply it; the commit-tag path works without setup:

gh label create force-builds \
  --description "Bypass native build reuse and compile fresh" \
  --color d93f0b

Scope. E2E iOS + Android only. Non-goals left for later: [skip-builds] broader escape hatch, [reused from <sha>] PR-comment annotation, RC / TestFlight / BrowserStack reuse, and unit-test reuse (different mechanism).

Changelog

CHANGELOG entry: null

Related issues

Fixes: No issue — CI infrastructure enhancement (cross-PR native build reuse + force-builds escape hatch).

Manual testing steps

Feature: Cross-PR native E2E build reuse

  Scenario: Non-native-affecting change reuses a prior native build
    Given a recent ci.yml run on the head branch or on main produced E2E artifacts
      And that run's build-source-hash commit status description equals the current fingerprint
      And the required artifacts are not yet expired
    When the build-ios-e2e or build-android-e2e job runs on this PR
    Then the Build iOS E2E App / Build Android E2E APKs step is skipped
      And Download reusable ... from prior run runs
      And Log reused iOS build source / Log reused Android build source prints "Reusing ... from run <id>"
      And Repack runs to swap in the current JS bundle
      And downstream E2E tests pass against the reused binary

  Scenario: Native-affecting change forces a fresh build
    Given this PR modifies ios/, android/, patches/, .yarn/patches/, or a native-linked dependency
    When the build workflows run
    Then the fingerprint on the build-source-hash commit status differs from main's
      And no candidate run matches in find-reusable-build
      And a fresh Build step runs
      And the new artifact is uploaded for future reuse

  Scenario: Force-builds label forces a fresh build
    Given the force-builds label is applied to this PR (or [force-builds] is in the head commit message)
    When the build workflows run on the pull_request event
    Then Check force-builds override logs "force=true because ..."
      And cache-restore, cache-restore-main, and find-reusable-build are all skipped
      And Build iOS E2E App / Build Android E2E APKs runs fresh
      And Repack is skipped

  Scenario: Force-builds override is ignored in the merge queue
    Given a PR with the force-builds label is merged into the merge queue
    When the merge_group run executes
    Then Check force-builds override logs "Event is merge_group; force-builds override is ignored ..."
      And the normal reuse tiers are evaluated

  Scenario: Artifact expiry falls through to a fresh build
    Given a matching fingerprint exists on a prior run but its artifacts have expired
    When find-reusable-build inspects the candidate
    Then hasAllArtifacts returns false
      And the candidate is rejected with a "missing artifacts" log line
      And the job falls through to a fresh build with no errors

Screenshots/Recordings

Before

N/A — CI-only change.

After

N/A — CI-only change. Observability via job logs (Reusing ... from run <id>, Posted build-source-hash=<hash>, force=true because ...).

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
    • Ideally on a mid-range device; emulator is acceptable
  • I've tested with a power user scenario
    • Use these power-user SRPs to import wallets with many accounts and tokens
  • I've instrumented key operations with Sentry traces for production performance metrics

For performance guidelines and tooling, see the Performance Guide.

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.

Note

Medium Risk
Changes CI build/reuse logic and required permissions for iOS/Android E2E artifact generation; misconfiguration could cause unexpected cache misses, wrong reuse, or flaky E2E runs (though it falls back to fresh builds on errors).

Overview
Enables cross-PR reuse of native iOS/Android E2E build outputs by publishing a canonical @expo/fingerprint as a build-source-hash commit status and using it to locate/download matching artifacts from prior ci.yml runs when branch/main caches miss.

Adds composite actions: post-build-source-hash (compute fingerprint + post commit status), find-reusable-build (search recent runs across same branch, base branch, then all pull_request runs; verify fingerprint status + required artifacts), and check-force-builds (bypass all reuse when PR has force-builds label or [force-builds] in head commit message).

Updates build-ios-e2e.yml/build-android-e2e.yml to take a source-fingerprint input (no per-runner recompute), gate cache restores/lookup on it, download reusable artifacts on a match, and expand repack/sourcemap conditions; updates ci.yml to run the new status-publishing job and plumb its output/permissions into E2E build jobs. Also narrows fingerprint.config.js to stop hashing all .github workflows/scripts (to avoid invalidating reuse) while still tracking a few specific workflow files.

Reviewed by Cursor Bugbot for commit 6dc1273. Bugbot is set up for automated code reviews on this repo. Configure here.

@tommasini tommasini self-assigned this Apr 21, 2026
@github-actions
Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamaskbotv2 metamaskbotv2 Bot added the team-mobile-platform Mobile Platform team label Apr 21, 2026
@tommasini tommasini marked this pull request as ready for review April 22, 2026 10:11
@tommasini tommasini requested a review from a team as a code owner April 22, 2026 10:11
@github-actions github-actions Bot added the risk:low AI analysis: low risk label Apr 22, 2026
Comment thread .github/actions/check-force-builds/action.yml
@github-actions github-actions Bot added risk:medium AI analysis: medium risk and removed risk:low AI analysis: low risk labels Apr 22, 2026
Comment thread .github/workflows/ci.yml
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 22, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.23%. Comparing base (e1a97df) to head (b0c3bb5).
⚠️ Report is 23 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #29148      +/-   ##
==========================================
+ Coverage   75.40%   82.23%   +6.83%     
==========================================
  Files        5096     5107      +11     
  Lines      134310   134963     +653     
  Branches    30148    30355     +207     
==========================================
+ Hits       101275   110986    +9711     
+ Misses      25916    16409    -9507     
- Partials     7119     7568     +449     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions Bot added size-L and removed size-M labels Apr 22, 2026
Comment thread .github/workflows/ci.yml
Comment thread .github/actions/find-reusable-build/action.yml
@tommasini tommasini changed the title ci: reuse native e2e builds across PRs via build-source-hash + artifact lookup ci: reuse native e2e builds across PRs via build-source-hash + artifact lookup cp-7.74.0 Apr 22, 2026
@tommasini tommasini changed the title ci: reuse native e2e builds across PRs via build-source-hash + artifact lookup cp-7.74.0 ci: reuse native e2e builds across PRs via build-source-hash + artifact lookup Apr 22, 2026
@github-actions github-actions Bot added risk:high AI analysis: high risk and removed risk:medium AI analysis: medium risk labels Apr 22, 2026
@github-actions
Copy link
Copy Markdown
Contributor

AI PR Analysis

🚫 Merge safe: false | 🟠 Risk: high

Merge decision: AI analysis did not complete — manual review required before merging.

AI analysis did not complete. Manual review recommended.

View run

@github-actions
Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeAccounts, SmokeConfirmations
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: medium
  • AI Confidence: 78%
click to see 🤖 AI reasoning details

E2E Test Selection:
This PR introduces CI/infrastructure changes only — no application code, no test code, and no framework code is modified. The changes are:

  1. fingerprint.config.js: Narrows fingerprint tracking from entire .github/workflows/ and .github/scripts/ directories to only specific workflow files. This prevents unnecessary fingerprint invalidation on CI workflow edits.

  2. New GitHub Actions (3 new composite actions):

    • check-force-builds: Detects force-builds label/commit tag to bypass caching
    • find-reusable-build: Cross-PR artifact reuse by matching fingerprints across workflow runs
    • post-build-source-hash: Computes and posts fingerprint as a commit status
  3. build-android-e2e.yml / build-ios-e2e.yml: Integrates the new actions — adds source-fingerprint input, force-builds override, and cross-PR artifact download steps.

  4. ci.yml: Adds post-build-source-hash job, wires fingerprint to build jobs, adds !cancelled() guards.

Why run any tests? The build pipeline changes affect how E2E build artifacts (APKs, iOS .app) are produced and potentially reused from prior runs. Running a representative set of E2E tests validates that:

  • The new fingerprint-based caching/reuse mechanism produces correct, functional builds
  • The source-fingerprint propagation through the workflow chain works correctly
  • The force-builds override and cross-PR artifact download steps don't break the build flow

Why not run all tests? No app code changed, so there's no risk of regressions in specific feature areas. The risk is purely in the build pipeline producing valid artifacts.

Tag selection rationale: Selected SmokeAccounts and SmokeConfirmations as representative smoke tests covering core wallet functionality (account management) and transaction flows (confirmations). These are fundamental tests that would catch any build artifact corruption or misconfiguration. This is a minimal but meaningful validation of the new build pipeline.

Performance Test Selection:
No application code, UI components, controllers, or performance-sensitive paths were modified. All changes are purely CI/infrastructure (GitHub Actions workflows, build caching logic, fingerprint configuration). Performance test infrastructure (tests/performance/) was not touched. No performance impact expected.

View GitHub Actions results

Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 6dc1273. Configure here.

Comment thread .github/workflows/ci.yml
${{
!cancelled() &&
needs.needs_e2e_build.result == 'success' &&
needs.smart-e2e-selection.result == 'success' &&
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing post-build-source-hash result check allows silent failures

Medium Severity

The build-android-apks and build-ios-apps jobs use !cancelled() plus explicit result == 'success' checks for needs_e2e_build and smart-e2e-selection, but the comment on build-ios-apps says "a failure/skip of post-build-source-hash must NOT block the E2E build — it only disables cross-run cache reuse." In practice the source-fingerprint output silently becomes empty on post-build-source-hash failure, which disables all fingerprint-based caching (both GHA cache tiers and cross-run lookup), not just cross-run reuse. Every build on every PR degrades to a fresh ~20 min compile if the post-build-source-hash job breaks — with no visible error on the build jobs themselves to alert anyone that caching is fully disabled.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 6dc1273. Configure here.

@sonarqubecloud
Copy link
Copy Markdown

@github-actions
Copy link
Copy Markdown
Contributor

E2E Fixture Validation — Schema is up to date
12 value mismatches detected (expected — fixture represents an existing user).
View details

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:high AI analysis: high risk size-L team-mobile-platform Mobile Platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants