iOS TestFlight Deploy #50
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: iOS TestFlight Deploy | |
| permissions: | |
| contents: read | |
| on: | |
| push: | |
| branches: [main, feature/audio-v2-cutover] | |
| paths: ['app/**'] | |
| workflow_dispatch: | |
| inputs: | |
| build_id: | |
| description: 'Existing EAS build ID to submit, or status to inspect TestFlight' | |
| required: false | |
| type: string | |
| jobs: | |
| build-and-submit: | |
| runs-on: macos-26 | |
| timeout-minutes: 120 | |
| defaults: | |
| run: | |
| working-directory: ./app | |
| steps: | |
| - name: Setup repo | |
| uses: actions/checkout@v4 | |
| - name: Setup node | |
| uses: actions/setup-node@v4.0.2 | |
| with: | |
| # eas-cli 23 requires Node >=22; pin the runner toolchain accordingly. | |
| node-version: 22.x | |
| cache: 'npm' | |
| cache-dependency-path: ./app/package-lock.json | |
| - name: Select Xcode version | |
| run: sudo xcode-select -s /Applications/Xcode_26.2.app/Contents/Developer | |
| - name: Setup Expo | |
| uses: expo/expo-github-action@v8 | |
| with: | |
| expo-version: latest | |
| eas-version: latest | |
| token: ${{ secrets.EXPO_TOKEN }} | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Verify mobile app | |
| run: | | |
| npm run test:wearable-activation | |
| npm run typecheck | |
| npm run test:durable-audio-spool | |
| npm run test:phone-audio-diagnostics | |
| npm run test:push-notifications | |
| npm run check:theme | |
| npx --no-install expo-modules-autolinking verify --platform ios --verbose | |
| swift test --package-path modules/chronicle-duplex-audio/ios | |
| - name: Write and validate ASC API key | |
| env: | |
| ASC_API_KEY_P8: ${{ secrets.ASC_API_KEY_P8 }} | |
| run: | | |
| set -euo pipefail | |
| if [ -z "$ASC_API_KEY_P8" ]; then | |
| echo "ASC_API_KEY_P8 is not configured" | |
| exit 1 | |
| fi | |
| printf '%s\n' "$ASC_API_KEY_P8" > asc-api-key.p8 | |
| chmod 600 asc-api-key.p8 | |
| openssl pkey -in asc-api-key.p8 -noout -check | |
| # Read the key/issuer ids from eas.json rather than repeating them, so the | |
| # build and submit steps can never disagree about which key they mean. | |
| node -e ' | |
| const ios = require("./eas.json").submit.testflight.ios; | |
| const out = require("fs"); | |
| out.appendFileSync(process.env.GITHUB_ENV, | |
| `EXPO_ASC_KEY_ID=${ios.ascApiKeyId}\nEXPO_ASC_ISSUER_ID=${ios.ascApiKeyIssuerId}\n`); | |
| ' | |
| - name: Build App Store IPA locally | |
| if: inputs.build_id == '' | |
| # EAS still supplies the managed signing credentials, but compilation runs | |
| # on this macOS runner so it does not consume the monthly EAS build quota. | |
| env: | |
| EXPO_ASC_API_KEY_PATH: ${{ github.workspace }}/app/asc-api-key.p8 | |
| EXPO_APPLE_TEAM_ID: '39Z45MQX8Z' | |
| run: >- | |
| eas build | |
| --platform ios | |
| --profile testflight | |
| --local | |
| --non-interactive | |
| --output "${{ runner.temp }}/chronicle.ipa" | |
| - name: Submit local IPA to TestFlight | |
| if: inputs.build_id == '' | |
| run: >- | |
| eas submit | |
| --platform ios | |
| --profile testflight | |
| --path "${{ runner.temp }}/chronicle.ipa" | |
| --non-interactive | |
| --wait | |
| - name: Submit existing build to TestFlight | |
| if: inputs.build_id != '' && inputs.build_id != 'status' | |
| env: | |
| EAS_BUILD_ID: ${{ inputs.build_id }} | |
| run: >- | |
| eas build:submit | |
| --platform ios | |
| --profile testflight | |
| --id "$EAS_BUILD_ID" | |
| --non-interactive | |
| --wait | |
| - name: Check TestFlight status | |
| if: inputs.build_id == 'status' | |
| run: >- | |
| eas submit:status | |
| --platform ios | |
| --profile testflight | |
| --json | |
| --non-interactive |