Push OTA Update (EXP Build) #78
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Push OTA Update (EXP Build) | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| pr_number: | |
| description: 'Pull request number to publish' | |
| required: true | |
| type: string | |
| base_branch: | |
| description: 'Base branch ref to compare fingerprints against (e.g., main)' | |
| required: true | |
| type: string | |
| message: | |
| description: 'EAS update message' | |
| required: true | |
| type: string | |
| permissions: | |
| contents: read | |
| id-token: write | |
| env: | |
| TARGET_PR_NUMBER: ${{ inputs.pr_number }} | |
| BASE_BRANCH_REF: ${{ inputs.base_branch }} | |
| UPDATE_MESSAGE: ${{ inputs.message }} | |
| jobs: | |
| fingerprint-comparison: | |
| name: Compare Expo Fingerprints | |
| runs-on: ubuntu-latest | |
| outputs: | |
| branch_fingerprint: ${{ steps.branch_fingerprint.outputs.fingerprint }} | |
| main_fingerprint: ${{ steps.main_fingerprint.outputs.fingerprint }} | |
| fingerprints_equal: ${{ steps.compare.outputs.equal }} | |
| steps: | |
| - name: Checkout target PR branch | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: refs/pull/${{ env.TARGET_PR_NUMBER }}/head | |
| fetch-depth: 0 | |
| - name: Checkout base branch snapshot | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ env.BASE_BRANCH_REF }} | |
| path: main | |
| fetch-depth: 0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'yarn' | |
| - name: Install dependencies (workflow branch) | |
| run: | | |
| echo "📦 Installing dependencies for current branch..." | |
| yarn install --immutable | |
| - name: Generate fingerprint (workflow branch) | |
| id: branch_fingerprint | |
| run: | | |
| echo "🧬 Generating fingerprint for current branch..." | |
| FINGERPRINT=$(yarn fingerprint:generate) | |
| echo "fingerprint=$FINGERPRINT" >> "$GITHUB_OUTPUT" | |
| echo "Target PR fingerprint: $FINGERPRINT" | |
| echo "Writing detailed fingerprint file to fingerprint-pr.json" | |
| npx @expo/fingerprint ./ > fingerprint-pr.json | |
| - name: Install dependencies (base branch) | |
| working-directory: main | |
| run: | | |
| echo "📦 Installing dependencies for base branch snapshot (${BASE_BRANCH_REF})..." | |
| yarn install --immutable | |
| - name: Generate fingerprint (base branch) | |
| id: main_fingerprint | |
| working-directory: main | |
| run: | | |
| echo "🧬 Generating fingerprint for base branch (${BASE_BRANCH_REF})..." | |
| FINGERPRINT=$(yarn fingerprint:generate) | |
| echo "fingerprint=$FINGERPRINT" >> "$GITHUB_OUTPUT" | |
| echo "Base branch fingerprint: $FINGERPRINT" | |
| echo "Writing detailed fingerprint file to ../fingerprint-base.json" | |
| npx @expo/fingerprint ./ > ../fingerprint-base.json | |
| - name: Compare fingerprints | |
| id: compare | |
| env: | |
| BRANCH_FP: ${{ steps.branch_fingerprint.outputs.fingerprint }} | |
| MAIN_FP: ${{ steps.main_fingerprint.outputs.fingerprint }} | |
| run: | | |
| if [ -z "$BRANCH_FP" ] || [ -z "$MAIN_FP" ]; then | |
| echo "❌ Fingerprint generation failed." >&2 | |
| exit 1 | |
| fi | |
| echo "Target PR fingerprint: $BRANCH_FP" | |
| echo "Base branch fingerprint: $MAIN_FP" | |
| if [ "$BRANCH_FP" = "$MAIN_FP" ]; then | |
| echo "✅ Fingerprints match. No native changes detected." | |
| echo "equal=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "⚠️ Fingerprints differ. Native changes detected." | |
| echo "equal=false" >> "$GITHUB_OUTPUT" | |
| if [ -f fingerprint-base.json ] && [ -f fingerprint-pr.json ]; then | |
| echo "Fingerprint differences:" | |
| npx @expo/fingerprint ./ fingerprint-base.json fingerprint-pr.json || true | |
| else | |
| echo "Detailed fingerprint files not found; skipping diff." | |
| fi | |
| fi | |
| - name: Record fingerprint summary | |
| env: | |
| BRANCH_FP: ${{ steps.branch_fingerprint.outputs.fingerprint }} | |
| MAIN_FP: ${{ steps.main_fingerprint.outputs.fingerprint }} | |
| MATCHES: ${{ steps.compare.outputs.equal }} | |
| TARGET_PR_NUMBER: ${{ env.TARGET_PR_NUMBER }} | |
| BASE_BRANCH_REF: ${{ env.BASE_BRANCH_REF }} | |
| run: | | |
| { | |
| echo "### Expo Fingerprint Comparison" | |
| echo "" | |
| echo "- Target PR (#$TARGET_PR_NUMBER) fingerprint: \`$BRANCH_FP\`" | |
| echo "- Base branch (\`$BASE_BRANCH_REF\`) fingerprint: \`$MAIN_FP\`" | |
| echo "- Match: \`$MATCHES\`" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| approval: | |
| name: Require OTA Update Approval | |
| needs: fingerprint-comparison | |
| if: ${{ needs.fingerprint-comparison.outputs.fingerprints_equal == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Await approval from mobile platform team | |
| uses: op5dev/require-team-approval@dfd7b8b9a88bf82a955c103f7e19642b0411aecd | |
| with: | |
| team: mobile-platform | |
| pr-number: ${{ env.TARGET_PR_NUMBER }} | |
| token: ${{ secrets.METAMASK_MOBILE_ORG_READ_TOKEN }} | |
| push-update: | |
| name: Push EAS Update | |
| runs-on: ubuntu-latest | |
| environment: build-exp | |
| needs: | |
| - fingerprint-comparison | |
| - approval | |
| if: ${{ needs.fingerprint-comparison.outputs.fingerprints_equal == 'true' }} | |
| env: | |
| EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }} | |
| EXPO_PROJECT_ID: ${{ secrets.EXPO_PROJECT_ID }} | |
| EXPO_CHANNEL: ${{ vars.EXPO_CHANNEL }} | |
| GIT_BRANCH: ${{ github.ref_name }} | |
| BRIDGE_USE_DEV_APIS: 'true' | |
| RAMP_INTERNAL_BUILD: 'true' | |
| SEEDLESS_ONBOARDING_ENABLED: 'true' | |
| MM_NOTIFICATIONS_UI_ENABLED: 'true' | |
| MM_SECURITY_ALERTS_API_ENABLED: 'true' | |
| MM_REMOVE_GLOBAL_NETWORK_SELECTOR: 'true' | |
| FEATURES_ANNOUNCEMENTS_ACCESS_TOKEN: ${{ secrets.FEATURES_ANNOUNCEMENTS_ACCESS_TOKEN }} | |
| FEATURES_ANNOUNCEMENTS_SPACE_ID: ${{ secrets.FEATURES_ANNOUNCEMENTS_SPACE_ID }} | |
| SEGMENT_WRITE_KEY_QA: ${{ secrets.SEGMENT_WRITE_KEY_QA }} | |
| SEGMENT_PROXY_URL_QA: ${{ secrets.SEGMENT_PROXY_URL_QA }} | |
| SEGMENT_DELETE_API_SOURCE_ID_QA: ${{ secrets.SEGMENT_DELETE_API_SOURCE_ID_QA }} | |
| SEGMENT_REGULATIONS_ENDPOINT_QA: ${{ secrets.SEGMENT_REGULATIONS_ENDPOINT_QA }} | |
| MM_SENTRY_DSN: ${{ secrets.MM_SENTRY_DSN }} #need to add to secrets | |
| MM_SENTRY_AUTH_TOKEN: ${{ secrets.MM_SENTRY_AUTH_TOKEN }} | |
| MAIN_IOS_GOOGLE_CLIENT_ID_UAT: ${{ secrets.MAIN_IOS_GOOGLE_CLIENT_ID_UAT }} | |
| MAIN_IOS_GOOGLE_REDIRECT_URI_UAT: ${{ secrets.MAIN_IOS_GOOGLE_REDIRECT_URI_UAT }} | |
| MAIN_ANDROID_APPLE_CLIENT_ID_UAT: ${{ secrets.MAIN_ANDROID_APPLE_CLIENT_ID_UAT }} | |
| MAIN_ANDROID_GOOGLE_CLIENT_ID_UAT: ${{ secrets.MAIN_ANDROID_GOOGLE_CLIENT_ID_UAT }} | |
| MAIN_ANDROID_GOOGLE_SERVER_CLIENT_ID_UAT: ${{ secrets.MAIN_ANDROID_GOOGLE_SERVER_CLIENT_ID_UAT }} | |
| GOOGLE_SERVICES_B64_IOS: ${{ secrets.GOOGLE_SERVICES_B64_IOS }} | |
| GOOGLE_SERVICES_B64_ANDROID: ${{ secrets.GOOGLE_SERVICES_B64_ANDROID }} | |
| MM_INFURA_PROJECT_ID: ${{ secrets.MM_INFURA_PROJECT_ID }} | |
| MM_BRANCH_KEY_LIVE: ${{ secrets.MM_BRANCH_KEY_LIVE }} #need to add to secrets | |
| MM_CARD_BAANX_API_CLIENT_KEY_UAT: ${{ secrets.MM_CARD_BAANX_API_CLIENT_KEY_UAT }} #need to add to secrets | |
| WALLET_CONNECT_PROJECT_ID: ${{ secrets.WALLET_CONNECT_PROJECT_ID }} #need to add to secrets | |
| MM_FOX_CODE: ${{ secrets.MM_FOX_CODE_TEST }} #need to add to secrets | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: refs/pull/${{ env.TARGET_PR_NUMBER }}/head | |
| fetch-depth: 0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'yarn' | |
| - name: Install dependencies | |
| run: | | |
| echo "📦 Installing dependencies..." | |
| yarn install --immutable | |
| - name: Setup project | |
| run: | | |
| echo "🔧 Running setup for GitHub CI..." | |
| yarn setup:github-ci | |
| - name: Display configuration | |
| run: | | |
| TARGET_RUNTIME_VERSION=$(node -p "require('./package.json').version") | |
| TARGET_PROJECT_ID=$(node -p "require('./ota.config.js').PROJECT_ID") | |
| echo "🔧 Configuration:" | |
| echo " Channel: ${EXPO_CHANNEL:-<not set>}" | |
| echo " Channel (vars.EXPO_CHANNEL): ${{ vars.EXPO_CHANNEL }}" | |
| echo " Message: ${UPDATE_MESSAGE:-<not set>}" | |
| echo " Runtime Version (target): ${TARGET_RUNTIME_VERSION}" | |
| # Fingerprint comparison temporarily disabled | |
| echo "" | |
| echo "📱 Project Info:" | |
| echo " Project ID (target branch): ${TARGET_PROJECT_ID}" | |
| echo " EXPO_PROJECT_ID (from secrets): $EXPO_PROJECT_ID" | |
| echo " EXPO_TOKEN (from secrets): $EXPO_TOKEN" | |
| - name: Build & Push EAS Update via build.sh | |
| env: | |
| EXPO_KEY_PRIV: ${{ secrets.EXPO_KEY_PRIV }} | |
| # Skip linting during Metro transform in CI (linting already done separately) | |
| SKIP_TRANSFORM_LINT: 'true' | |
| # Increase Node heap to avoid OOM during Expo export in CI | |
| NODE_OPTIONS: '--max_old_space_size=8192' | |
| # Disable LavaMoat sandbox to prevent duplicate bundle executions in CI | |
| EXPO_NO_LAVAMOAT: '1' | |
| run: | | |
| yarn run build:expo-update:main:exp | |
| - name: Update summary | |
| if: success() | |
| run: | | |
| { | |
| echo "### ✅ EAS Update Published Successfully" | |
| echo | |
| echo "**Channel:** \`${EXPO_CHANNEL:-<not set>}\`" | |
| echo "**Message:** ${UPDATE_MESSAGE:-<not set>}" | |
| echo | |
| echo "Users on the \`${EXPO_CHANNEL:-<not set>}\` channel will receive this update on their next app launch." | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Update summary on failure | |
| if: failure() | |
| run: | | |
| { | |
| echo "### ❌ EAS Update Failed" | |
| echo | |
| echo "Check the logs above for error details." | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| fingerprint-mismatch: | |
| name: Fingerprint Mismatch Guard | |
| needs: fingerprint-comparison | |
| if: ${{ needs.fingerprint-comparison.outputs.fingerprints_equal != 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Fail on native changes | |
| run: | | |
| echo "::error title=Fingerprint mismatch::Current branch fingerprint differs from main. Native changes detected; aborting workflow." | |
| echo "Current fingerprint: ${{ needs.fingerprint-comparison.outputs.branch_fingerprint }}" | |
| echo "Main fingerprint: ${{ needs.fingerprint-comparison.outputs.main_fingerprint }}" | |
| exit 1 |