mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
* Bump mobile app.json to 0.0.42 * fix(mobile-ios): stop TestFlight CI from waiting on ASC processing 0.0.42 builds 1–2 uploaded successfully then hung for hours polling processing with no Ready build and no Apple email. Exit after upload and cap the job at 90m so the next cut does not repeat that hang. * fix(mobile-ios): fully skip Pilot wait (no changelog) Pilot only returns immediately after upload when changelog is nil; passing notes re-enters the ASC build-list poll.
138 lines
5.3 KiB
YAML
138 lines
5.3 KiB
YAML
name: Mobile iOS Release
|
||
|
||
# Why a separate workflow from Android: iOS releases go through App Store
|
||
# review, which can take days. Decoupling the triggers lets an Android release
|
||
# ship immediately without waiting on iOS, and vice versa.
|
||
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
|
||
|
||
jobs:
|
||
ios-build:
|
||
# GitHub-hosted macOS runner: required for Xcode. Expo SDK 55's
|
||
# expo-modules-core declares swift_version 6.0 and uses Swift 6 syntax
|
||
# (@MainActor isolation). Xcode 16.x (macos-15) can't even parse it
|
||
# ("unknown attribute 'MainActor'"), so we need Xcode 26.x → macos-26.
|
||
runs-on: macos-26
|
||
# Archive + upload is ~30–40m when healthy; 90m leaves margin without
|
||
# sitting multi-hour on ASC processing polls (see Fastfile pilot wait).
|
||
timeout-minutes: 90
|
||
|
||
defaults:
|
||
run:
|
||
working-directory: mobile
|
||
|
||
steps:
|
||
- name: Checkout
|
||
uses: actions/checkout@v6
|
||
|
||
- name: Select Xcode
|
||
uses: maxim-lobanov/setup-xcode@v1
|
||
with:
|
||
# Xcode 26.x ships the Swift 6.x toolchain Expo SDK 55 requires.
|
||
xcode-version: '26.5'
|
||
|
||
- name: Setup Node.js
|
||
uses: actions/setup-node@v6
|
||
with:
|
||
node-version: 24
|
||
|
||
- name: Setup pnpm
|
||
uses: pnpm/action-setup@v6
|
||
with:
|
||
run_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: Expo prebuild
|
||
run: npx expo prebuild --platform ios --no-install
|
||
|
||
- name: Install CocoaPods
|
||
run: npx pod-install ios
|
||
|
||
# Why: `-allowProvisioningUpdates` + the App Store Connect API key can
|
||
# create/refresh provisioning profiles, but it cannot recreate the
|
||
# distribution certificate's PRIVATE KEY across runs. So we import a
|
||
# pre-exported distribution .p12 (created once via Apple Developer) into a
|
||
# throwaway keychain. The keychain is ephemeral to the runner and torn
|
||
# down with the VM; nothing secret is written to the repo.
|
||
- 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 }}
|
||
TESTFLIGHT_CHANGELOG: ${{ github.event.inputs.testflight_changelog }}
|
||
# Keep fastlane non-interactive and quiet about analytics in CI.
|
||
FASTLANE_SKIP_UPDATE_CHECK: '1'
|
||
FASTLANE_HIDE_CHANGELOG: '1'
|
||
run: bundle exec fastlane ios release
|
||
|
||
- 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
|