Files
orca/.github/workflows/mobile-ios-release.yml
T

192 lines
7.2 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Mobile iOS Release
# Release iOS independently so App Store review cannot block Android.
on:
push:
tags:
- 'mobile-ios-v*'
workflow_dispatch:
inputs:
bump_patch_version:
description: 'Use the first open iOS patch version after the checked-in version, skipping versions already closed on the App Store.'
required: false
default: false
type: boolean
release_version:
description: 'Optional exact iOS marketing version override, e.g. 0.0.15'
required: false
type: string
testflight_changelog:
description: 'Optional TestFlight external tester changelog'
required: false
type: string
permissions:
contents: read
jobs:
ios-build:
# Xcode 27.1's iOS SDK enables iPhone Duo resizing; Expo SDK 55 requires Swift 6 syntax.
runs-on: xcode-27
# Archive + upload is ~30–40m when healthy; 90m leaves margin for setup.
timeout-minutes: 90
env:
# Freeze Gemfile.lock in both jobs; installs ~25min apart must not resolve different fastlane versions.
BUNDLE_FROZEN: 'true'
outputs:
release_version: ${{ steps.release_metadata.outputs.version }}
build_number: ${{ steps.release_metadata.outputs.build_number }}
defaults:
run:
working-directory: mobile
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Select Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
# iOS 27.1 SDK: iPhone Duo resizing and reserved (fold/camera) regions.
xcode-version: '27.1'
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24
check-latest: true
- name: Setup pnpm
uses: pnpm/setup@v2
with:
install: false
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup Ruby and fastlane
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
bundler-cache: true
working-directory: mobile
- name: Resolve release version and build number
env:
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
ASC_API_KEY_P8: ${{ secrets.ASC_API_KEY_P8 }}
MOBILE_IOS_RELEASE_VERSION: ${{ github.event.inputs.release_version }}
MOBILE_IOS_BUMP_PATCH_VERSION: ${{ github.event.inputs.bump_patch_version }}
FASTLANE_SKIP_UPDATE_CHECK: '1'
FASTLANE_HIDE_CHANGELOG: '1'
run: bundle exec fastlane ios prepare_release_version version:"$MOBILE_IOS_RELEASE_VERSION" bump_patch:"$MOBILE_IOS_BUMP_PATCH_VERSION"
- name: Capture release metadata
id: release_metadata
run: node -e 'const fs = require("node:fs"); const { expo } = require("./app.json"); fs.appendFileSync(process.env.GITHUB_OUTPUT, `version=${expo.version}\nbuild_number=${expo.ios.buildNumber}\n`)'
- name: Expo prebuild
env:
ORCA_IOS_APS_ENVIRONMENT: production
run: npx expo prebuild --platform ios --no-install
- name: Install CocoaPods
working-directory: mobile/ios
run: bundle exec pod install
# Import exported distribution .p12 into ephemeral runner keychain: provisioning updates/API key cannot recreate its private key.
- name: Import distribution certificate
env:
IOS_DIST_CERT_P12: ${{ secrets.IOS_DIST_CERT_P12 }}
IOS_DIST_CERT_PASSWORD: ${{ secrets.IOS_DIST_CERT_PASSWORD }}
run: |
set -euo pipefail
KEYCHAIN_PATH="$RUNNER_TEMP/orca-signing.keychain-db"
# Random per-run keychain password; never persisted.
KEYCHAIN_PASSWORD="$(openssl rand -base64 24)"
CERT_PATH="$RUNNER_TEMP/orca-dist-cert.p12"
echo "$IOS_DIST_CERT_P12" | base64 --decode > "$CERT_PATH"
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security import "$CERT_PATH" -P "$IOS_DIST_CERT_PASSWORD" \
-A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
# Allow codesign/xcodebuild to use the key without an interactive prompt.
security set-key-partition-list -S apple-tool:,apple: \
-k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" >/dev/null
# Put our keychain in the search list so xcodebuild can find the identity.
security list-keychains -d user -s "$KEYCHAIN_PATH" login.keychain-db
rm -f "$CERT_PATH"
- name: Build and upload to TestFlight
env:
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
ASC_API_KEY_P8: ${{ secrets.ASC_API_KEY_P8 }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
# Keep fastlane non-interactive and quiet about analytics in CI.
FASTLANE_SKIP_UPDATE_CHECK: '1'
FASTLANE_HIDE_CHANGELOG: '1'
# Metro's release transform of the 3.6 MB Mermaid module needs >2 GB heap; the runner's default cap sits at that edge.
NODE_OPTIONS: --max-old-space-size=4096
run: bundle exec fastlane ios build_and_upload
- name: Upload .ipa artifact
if: always()
uses: actions/upload-artifact@v7
with:
name: orca-mobile-ipa
path: mobile/build/*.ipa
if-no-files-found: ignore
ios-distribute:
name: Distribute to external TestFlight testers
needs: ios-build
runs-on: ubuntu-latest
# Fastlane's processing wait fails after 20m; this outer bound leaves setup
# margin without allowing App Store Connect polling to hang for hours.
timeout-minutes: 30
env:
# Same fastlane as ios-build, or fail before touching App Store Connect.
BUNDLE_FROZEN: 'true'
defaults:
run:
working-directory: mobile
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Ruby and fastlane
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
bundler-cache: true
working-directory: mobile
- name: Wait for processing and distribute to peeps
env:
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
ASC_API_KEY_P8: ${{ secrets.ASC_API_KEY_P8 }}
TESTFLIGHT_CHANGELOG: ${{ github.event.inputs.testflight_changelog }}
MOBILE_IOS_RELEASE_VERSION: ${{ needs.ios-build.outputs.release_version }}
MOBILE_IOS_BUILD_NUMBER: ${{ needs.ios-build.outputs.build_number }}
FASTLANE_SKIP_UPDATE_CHECK: '1'
FASTLANE_HIDE_CHANGELOG: '1'
run: |
if ! bundle exec fastlane ios distribute_testflight \
version:"$MOBILE_IOS_RELEASE_VERSION" \
build_number:"$MOBILE_IOS_BUILD_NUMBER"; then
echo "::error::TestFlight $MOBILE_IOS_RELEASE_VERSION ($MOBILE_IOS_BUILD_NUMBER) was uploaded but not distributed to peeps. If App Store Connect is still processing it, rerun only this failed job after the build becomes Ready; otherwise inspect the Fastlane error above."
exit 1
fi