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: 🤖 Android Build | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| profile: | |
| type: choice | |
| default: preview | |
| options: | |
| - preview | |
| - production | |
| description: 'EAS build profile' | |
| pull_request: | |
| branches: | |
| - main | |
| - test | |
| - staging | |
| - 'feat-*' | |
| push: | |
| branches: | |
| - main | |
| - test | |
| - staging | |
| - 'feat-*' | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: native-android-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| detect: | |
| name: Detect Android impact | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| outputs: | |
| impacted: ${{ steps.detect.outputs.surface-native-android }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - uses: ./.github/actions/setup | |
| - id: detect | |
| run: tsx scripts/ci/detect-surfaces.ts --surface native-android --format github | |
| fingerprint: | |
| name: Fingerprint diff (android) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| outputs: | |
| requires_release: ${{ steps.fp.outputs.requires_release }} | |
| head_hash: ${{ steps.fp.outputs.head_hash }} | |
| base_hash: ${{ steps.fp.outputs.base_hash }} | |
| fallback_reason: ${{ steps.fp.outputs.fallback_reason }} | |
| head_sources: ${{ steps.fp.outputs.head_sources }} | |
| base_sources: ${{ steps.fp.outputs.base_sources }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - uses: ./.github/actions/setup | |
| - id: fp | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| tsx scripts/ci/native-fingerprint.ts --platform android --output fingerprint-android.json | tee fingerprint-android.log | |
| require_release=$(jq -r '.requiresStoreRelease' fingerprint-android.json) | |
| head_hash=$(jq -r '.headHash' fingerprint-android.json) | |
| base_hash=$(jq -r '.baseHash // ""' fingerprint-android.json) | |
| fallback_reason=$(jq -r '.fallbackReason // ""' fingerprint-android.json) | |
| head_sources=$(jq -r 'if .headFingerprint then (.headFingerprint.sources | length) else 0 end' fingerprint-android.json) | |
| base_sources=$(jq -r 'if .baseFingerprint then (.baseFingerprint.sources | length) else 0 end' fingerprint-android.json) | |
| { | |
| echo "requires_release=${require_release}" | |
| echo "head_hash=${head_hash}" | |
| echo "base_hash=${base_hash}" | |
| echo "fallback_reason=${fallback_reason}" | |
| echo "head_sources=${head_sources}" | |
| echo "base_sources=${base_sources}" | |
| } >> "$GITHUB_OUTPUT" | |
| - uses: actions/upload-artifact@v5 | |
| with: | |
| name: android-fingerprint | |
| path: fingerprint-android.json | |
| retention-days: 7 | |
| classify: | |
| name: Determine native build need | |
| runs-on: ubuntu-latest | |
| needs: [detect, fingerprint] | |
| outputs: | |
| build_native: ${{ steps.compute.outputs.build_native }} | |
| steps: | |
| - id: compute | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| build_native=false | |
| if [[ "${{ needs.detect.outputs.impacted }}" == 'true' ]]; then | |
| build_native=true | |
| fi | |
| if [[ "${{ needs.fingerprint.outputs.requires_release }}" == 'true' ]]; then | |
| build_native=true | |
| fi | |
| if [[ "${{ github.event_name }}" == 'workflow_dispatch' ]]; then | |
| build_native=true | |
| fi | |
| echo "build_native=${build_native}" >> "$GITHUB_OUTPUT" | |
| printf 'build_native=%s\n' "$build_native" | |
| build: | |
| name: Build Android artifact | |
| runs-on: ubuntu-latest | |
| needs: [classify] | |
| if: needs.classify.outputs.build_native == 'true' && github.secret_source != 'None' | |
| timeout-minutes: 90 | |
| env: | |
| EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - uses: ./.github/actions/setup | |
| - id: profile | |
| shell: bash | |
| run: | | |
| if [[ "${{ github.event_name }}" == 'workflow_dispatch' ]]; then | |
| PROFILE="${{ github.event.inputs.profile }}" | |
| elif [[ "${{ github.ref_name }}" == 'main' ]]; then | |
| PROFILE="production" | |
| else | |
| PROFILE="preview" | |
| fi | |
| echo "profile=$PROFILE" >> "$GITHUB_OUTPUT" | |
| echo "EAS_ANDROID_PROFILE=$PROFILE" >> "$GITHUB_ENV" | |
| - uses: expo/expo-github-action@v8 | |
| with: | |
| eas-version: latest | |
| token: ${{ secrets.EXPO_TOKEN }} | |
| - name: 🏗️ Run Android stage | |
| run: tsx scripts/run-ci-stage.ts --stage native-android --platform linux | |
| - name: 📦 Package artifact | |
| id: package | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mkdir -p artifacts | |
| PROFILE="${{ steps.profile.outputs.profile }}" | |
| CANDIDATES=("dist/native/android-${PROFILE}.aab" "dist/native/android-${PROFILE}.apk") | |
| ARTIFACT_PATH="" | |
| for file in "${CANDIDATES[@]}"; do | |
| if [[ -f "$file" ]]; then | |
| ARTIFACT_PATH="$file" | |
| break | |
| fi | |
| done | |
| if [[ -z "$ARTIFACT_PATH" ]]; then | |
| echo "No Android artifact found under dist/native" >&2 | |
| exit 1 | |
| fi | |
| tar -czf "artifacts/native-android-${PROFILE}.tar.gz" "$ARTIFACT_PATH" | |
| echo "artifact-name=native-android-${PROFILE}" >> "$GITHUB_OUTPUT" | |
| echo "artifact-path=artifacts/native-android-${PROFILE}.tar.gz" >> "$GITHUB_OUTPUT" | |
| - uses: actions/upload-artifact@v5 | |
| with: | |
| name: ${{ steps.package.outputs.artifact-name }} | |
| path: ${{ steps.package.outputs.artifact-path }} | |
| if-no-files-found: error | |
| retention-days: 7 | |
| skip: | |
| name: Nothing to build | |
| needs: classify | |
| if: needs.classify.outputs.build_native != 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - run: echo "No Android-related Nx projects changed. Skipping builds." |