3535jobs :
3636 build-ios-apps :
3737 name : Build iOS E2E Apps
38- runs-on : ${{ inputs.runner_provider == 'namespace' && 'namespace-profile-metamask-ios-build' || (startsWith(github.base_ref, 'release/') && fromJSON('["ghcr.io/cirruslabs/macos-runner:tahoe-xl"]') || fromJSON('["ghcr.io/cirruslabs/macos-runner:tahoe-xl", "low-priority"]')) }}
38+ runs-on : ${{ inputs.runner_provider == 'namespace' && 'namespace-profile-metamask-ios-build' || inputs.runner_provider == 'bitrise' && (vars.BITRISE_BUILD_MACHINE_TYPE != '' && fromJSON(format('["bitrise_pool_name:bitrise-metamask-ios-build","{0}"]', vars.BITRISE_BUILD_MACHINE_TYPE)) || 'bitrise_pool_name:bitrise-metamask-ios-build') || (startsWith(github.base_ref, 'release/') && fromJSON('["ghcr.io/cirruslabs/macos-runner:tahoe-xl"]') || fromJSON('["ghcr.io/cirruslabs/macos-runner:tahoe-xl", "low-priority"]')) }}
3939 outputs :
4040 artifacts-url : ${{ steps.set-artifacts-url.outputs.artifacts-url }}
4141 app-uploaded : ${{ steps.upload-app-namespace.outcome == 'success' || steps.upload-app.outcome == 'success' }}
4242 sourcemap-uploaded : ${{ steps.upload-sourcemap-namespace.outcome == 'success' || steps.upload-sourcemap.outcome == 'success' }}
4343 env :
44+ IOS_APP_CACHE_VERSION : 2
4445 XCODE_CACHE_VERSION : 1
4546 RCT_NO_LAUNCH_PACKAGER : 1
4647 XCODE_BUILD_SETTINGS : ' COMPILER_INDEX_STORE_ENABLE=NO'
8283 - name : Checkout repo
8384 uses : actions/checkout@v6
8485 if : ${{ inputs.runner_provider != 'namespace' }}
86+ with :
87+ # BITRISE-SHADOW: preserve prewarmed node_modules / Pods (INFRA-3679)
88+ clean : ${{ inputs.runner_provider != 'bitrise' }}
89+
90+ # Bitrise Build Hub VMs use Vagrant (user=vagrant, HOME=/Users/vagrant).
91+ # GitHub Actions tooling expects /Users/runner — symlink for compatibility (INFRA-3591 POC).
92+ - name : Fix Vagrant environment paths (Bitrise runners)
93+ if : ${{ inputs.runner_provider == 'bitrise' }}
94+ run : |
95+ if [ -L /Users/runner ]; then
96+ current_target="$(readlink /Users/runner)"
97+ if [ "$current_target" = "/Users/vagrant" ]; then
98+ echo "Symlink already correct: /Users/runner -> /Users/vagrant"
99+ else
100+ echo "Replacing incorrect symlink /Users/runner -> $current_target"
101+ sudo rm /Users/runner
102+ sudo ln -s /Users/vagrant /Users/runner
103+ echo "Recreated symlink: /Users/runner -> /Users/vagrant"
104+ fi
105+ elif [ -e /Users/runner ]; then
106+ echo "Error: /Users/runner exists but is not a symlink"
107+ ls -ld /Users/runner
108+ exit 1
109+ else
110+ sudo ln -s /Users/vagrant /Users/runner
111+ echo "Created symlink /Users/runner -> /Users/vagrant"
112+ fi
113+ mkdir -p "$HOME/hostedtoolcache" "$HOME/tmp"
114+ echo "RUNNER_TOOL_CACHE=$HOME/hostedtoolcache" >> "$GITHUB_ENV"
115+ echo "RUNNER_TEMP=$HOME/tmp" >> "$GITHUB_ENV"
116+ shell : bash
85117
86118 - name : Configure Namespace cache
87119 if : ${{ inputs.runner_provider == 'namespace' }}
@@ -114,7 +146,8 @@ jobs:
114146 - name : Find reusable build from prior run
115147 id : find-reusable-build
116148 # Match Android: skip cross-run GitHub artifact reuse on Namespace until backend parity is proven.
117- if : ${{ inputs.runner_provider != 'namespace' && steps.force-builds.outputs.force != 'true' && inputs.source-fingerprint != '' }}
149+ # BITRISE-SHADOW: skip GitHub artifact reuse; Bitrise uses actions/cache app fingerprint cache (INFRA-3591).
150+ if : ${{ inputs.runner_provider != 'namespace' && inputs.runner_provider != 'bitrise' && steps.force-builds.outputs.force != 'true' && inputs.source-fingerprint != '' }}
118151 uses : ./.github/actions/find-reusable-build
119152 with :
120153 fingerprint : ${{ inputs.source-fingerprint }}
@@ -202,7 +235,10 @@ jobs:
202235 - name : Compute native-build gate
203236 id : gate
204237 run : |
205- if [[ "${{ steps.find-reusable-build.outputs.found }}" == "true" \
238+ if [[ "${{ inputs.runner_provider }}" == "bitrise" && "${{ vars.BITRISE_FORCE_NATIVE_BUILD }}" == "true" ]]; then
239+ echo "needs-native-build=true" >> "$GITHUB_OUTPUT"
240+ echo "BITRISE_FORCE_NATIVE_BUILD=true — skipping GitHub artifact reuse to exercise Bitrise RN Build Cache."
241+ elif [[ "${{ steps.find-reusable-build.outputs.found }}" == "true" \
206242 && "${{ steps.validate-reusable-metadata.outputs.valid }}" == "true" \
207243 && "${{ steps.download-reusable-app.outcome }}" == "success" ]]; then
208244 echo "needs-native-build=false" >> "$GITHUB_OUTPUT"
@@ -272,9 +308,11 @@ jobs:
272308 # Heavy native setup — only runs on a full native-build path.
273309 # -------------------------------------------------------------------------
274310
311+ # Bitrise skips cirruslabs DerivedData caches below; RN Build Cache replaces them (INFRA-3591).
312+
275313 - name : Restore Xcode derived data from branch cache
276314 id : xcode-restore-cache
277- if : ${{ inputs.runner_provider != 'namespace' && steps.gate.outputs.needs-native-build == 'true' }}
315+ if : ${{ inputs.runner_provider != 'namespace' && inputs.runner_provider != 'bitrise' && steps.gate.outputs.needs-native-build == 'true' }}
278316 # This action automatically updates the cache at the end of the workflow
279317 uses : cirruslabs/cache@bba69c6578b863ad0398ad40567bd2ef70290fe0 # v4
280318 with :
@@ -284,7 +322,7 @@ jobs:
284322 key : ${{ runner.os }}-xcode-${{ github.ref_name }}-${{ env.XCODE_CACHE_VERSION }}-${{ hashFiles('ios/**/*.{h,m,mm,swift}', 'ios/**/Podfile.lock', 'yarn.lock') }}
285323
286324 - name : Restore Xcode derived data from main cache
287- if : ${{ inputs.runner_provider != 'namespace' && steps.gate.outputs.needs-native-build == 'true' && steps.xcode-restore-cache.outputs.cache-hit != 'true' && github.ref_name != 'main' }}
325+ if : ${{ inputs.runner_provider != 'namespace' && inputs.runner_provider != 'bitrise' && steps.gate.outputs.needs-native-build == 'true' && steps.xcode-restore-cache.outputs.cache-hit != 'true' && github.ref_name != 'main' }}
288326 id : xcode-restore-cache-main
289327 uses : cirruslabs/cache/restore@bba69c6578b863ad0398ad40567bd2ef70290fe0 # v4
290328 with :
@@ -333,7 +371,7 @@ jobs:
333371 run : find ios -name "*.plist" -exec xattr -c {} \;
334372
335373 - name : Restore .metamask folder
336- if : ${{ inputs.runner_provider != 'namespace' && steps.gate.outputs.needs-native-build == 'true' }}
374+ if : ${{ inputs.runner_provider != 'namespace' && inputs.runner_provider != 'bitrise' && steps.gate.outputs.needs-native-build == 'true' }}
337375 id : restore-metamask
338376 uses : actions/cache@v4
339377 with :
@@ -356,7 +394,7 @@ jobs:
356394 if : ${{ steps.gate.outputs.needs-native-build != 'true' }}
357395 uses : actions/setup-node@v6
358396 with :
359- node-version : ' 20.18 .0'
397+ node-version : ' 24.16 .0'
360398
361399 - name : Enable corepack (reuse-hit path)
362400 if : ${{ steps.gate.outputs.needs-native-build != 'true' }}
@@ -366,7 +404,7 @@ jobs:
366404 shell : bash
367405
368406 - name : Restore yarn cache (reuse-hit path)
369- if : ${{ steps.gate.outputs.needs-native-build != 'true' }}
407+ if : ${{ inputs.runner_provider != 'bitrise' && steps.gate.outputs.needs-native-build != 'true' }}
370408 uses : actions/cache@v4
371409 with :
372410 path : |
@@ -386,7 +424,7 @@ jobs:
386424 YARN_ENABLE_GLOBAL_CACHE : ' true'
387425
388426 - name : Restore .metamask folder (reuse-hit path)
389- if : ${{ inputs.runner_provider != 'namespace' && steps.gate.outputs.needs-native-build != 'true' }}
427+ if : ${{ inputs.runner_provider != 'namespace' && inputs.runner_provider != 'bitrise' && steps.gate.outputs.needs-native-build != 'true' }}
390428 id : restore-metamask-lean
391429 uses : actions/cache@v4
392430 with :
@@ -404,9 +442,77 @@ jobs:
404442 echo "📦 Setting up project (lightweight, skips Xcode build)..."
405443 yarn setup:github-ci --no-build-ios --no-build-android
406444
445+ - name : Activate Bitrise Build Cache for React Native
446+ if : ${{ inputs.runner_provider == 'bitrise' && steps.gate.outputs.needs-native-build == 'true' }}
447+ env :
448+ BITRISE_BUILD_CACHE_AUTH_TOKEN : ${{ secrets.BITRISE_BUILD_CACHE_AUTH_TOKEN }}
449+ BITRISE_BUILD_CACHE_WORKSPACE_ID : ${{ vars.BITRISE_BUILD_CACHE_WORKSPACE_ID }}
450+ run : |
451+ #!/usr/bin/env bash
452+ set -euxo pipefail
453+ curl --retry 5 -sSfL 'https://raw.githubusercontent.com/bitrise-io/bitrise-build-cache-cli/main/install/installer.sh' | sh -s -- -b /tmp/bin -d
454+ /tmp/bin/bitrise-build-cache activate react-native
455+ echo "/tmp/bin" >> "$GITHUB_PATH"
456+ shell : bash
457+
458+ - name : Generate current fingerprint
459+ if : ${{ inputs.runner_provider == 'bitrise' && steps.gate.outputs.needs-native-build == 'true' }}
460+ id : generate-fingerprint
461+ run : |
462+ if [[ -n "${{ inputs.source-fingerprint }}" ]]; then
463+ FINGERPRINT="${{ inputs.source-fingerprint }}"
464+ else
465+ FINGERPRINT=$(yarn fingerprint:generate)
466+ fi
467+ echo "fingerprint=$FINGERPRINT" >> "$GITHUB_OUTPUT"
468+ echo "Current fingerprint: ${FINGERPRINT}"
469+
470+ - name : Restore iOS app matching fingerprint from branch cache
471+ if : ${{ inputs.runner_provider == 'bitrise' && steps.gate.outputs.needs-native-build == 'true' }}
472+ id : cache-restore
473+ uses : actions/cache@v4
474+ with :
475+ path : |
476+ ios/build/Build/Products/Release-iphonesimulator/MetaMask.app
477+ key : bitrise-ios-app-${{ inputs.build_type }}-${{ github.ref_name }}-v${{ env.IOS_APP_CACHE_VERSION }}-${{ steps.generate-fingerprint.outputs.fingerprint }}
478+
479+ - name : Restore iOS app matching fingerprint from main cache
480+ if : ${{ inputs.runner_provider == 'bitrise' && steps.gate.outputs.needs-native-build == 'true' && steps.cache-restore.outputs.cache-hit != 'true' && github.ref_name != 'main' }}
481+ id : cache-restore-main
482+ uses : actions/cache/restore@v4
483+ with :
484+ path : |
485+ ios/build/Build/Products/Release-iphonesimulator/MetaMask.app
486+ key : bitrise-ios-app-${{ inputs.build_type }}-main-v${{ env.IOS_APP_CACHE_VERSION }}-${{ steps.generate-fingerprint.outputs.fingerprint }}
487+
488+ - name : Build iOS E2E App (Bitrise RN cache)
489+ if : ${{ inputs.runner_provider == 'bitrise' && steps.gate.outputs.needs-native-build == 'true' }}
490+ run : |
491+ echo "Building iOS E2E App on Bitrise runner..."
492+ bitrise-build-cache react-native run yarn build:ios:${{ inputs.build_type }}:e2e
493+ shell : bash
494+ env :
495+ PLATFORM : ios
496+ METAMASK_ENVIRONMENT : ${{ inputs.metamask_environment }}
497+ METAMASK_BUILD_TYPE : ${{ inputs.build_type }}
498+ HAS_TEST_OVERRIDES : true
499+ IS_SIM_BUILD : ' true'
500+ IGNORE_BOXLOGS_DEVELOPMENT : true
501+ GITHUB_CI : ' true'
502+ CI : ' true'
503+ NODE_OPTIONS : ' --max-old-space-size=8192'
504+ SEGMENT_WRITE_KEY_QA : ${{ secrets.SEGMENT_WRITE_KEY_QA }}
505+ SEGMENT_PROXY_URL_QA : ${{ secrets.SEGMENT_PROXY_URL_QA }}
506+ SEGMENT_DELETE_API_SOURCE_ID_QA : ${{ secrets.SEGMENT_DELETE_API_SOURCE_ID_QA }}
507+ SEGMENT_REGULATIONS_ENDPOINT_QA : ${{ secrets.SEGMENT_REGULATIONS_ENDPOINT_QA }}
508+ MM_SENTRY_DSN_TEST : ${{ secrets.MM_SENTRY_DSN_TEST }}
509+ MM_SENTRY_AUTH_TOKEN : ${{ secrets.MM_SENTRY_AUTH_TOKEN }}
510+ GOOGLE_SERVICES_B64_IOS : ${{ secrets.GOOGLE_SERVICES_B64_IOS }}
511+ GOOGLE_SERVICES_B64_ANDROID : ${{ secrets.GOOGLE_SERVICES_B64_ANDROID }}
512+
407513 # Build the iOS E2E app for simulator
408514 - name : Build iOS E2E App
409- if : ${{ steps.gate.outputs.needs-native-build == 'true' }}
515+ if : ${{ inputs.runner_provider != 'bitrise' && steps.gate.outputs.needs-native-build == 'true' }}
410516 run : |
411517 echo "🏗 Building iOS E2E App..."
412518 export NODE_OPTIONS="--max-old-space-size=8192"
0 commit comments