Skip to content

Push OTA Update (EXP Build) #79

Push OTA Update (EXP Build)

Push OTA Update (EXP Build) #79

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