Skip to content

mobile: land handoff, logging, and CI updates #10

mobile: land handoff, logging, and CI updates

mobile: land handoff, logging, and CI updates #10

name: iOS TestFlight Release

Check failure on line 1 in .github/workflows/ios-testflight.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/ios-testflight.yml

Invalid workflow file

(Line: 33, Col: 26): Unrecognized named-value: 'runner'. Located at position 1 within expression: runner.temp
on:
workflow_dispatch:
inputs:
beta_group_names:
description: "Comma-separated TestFlight beta groups"
required: false
default: "Internal Testers,External Testers"
type: string
wait_for_processing:
description: "Wait for ASC processing before finishing"
required: false
default: true
type: boolean
permissions:
contents: read
jobs:
upload-testflight:
runs-on: macos-15
timeout-minutes: 90
environment: release
env:
HOMEBREW_NO_AUTO_UPDATE: "1"
SCCACHE_BUCKET: rust-cache
SCCACHE_ENDPOINT: ${{ secrets.SCCACHE_R2_ENDPOINT }}
SCCACHE_REGION: auto
SCCACHE_S3_USE_SSL: "true"
SCCACHE_S3_KEY_PREFIX: ci/ios
SCCACHE_LOG: info
SCCACHE_ERROR_LOG: ${{ runner.temp }}/sccache-ios.log
AWS_ACCESS_KEY_ID: ${{ secrets.SCCACHE_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.SCCACHE_R2_SECRET_ACCESS_KEY }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Validate required secrets
env:
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
ASC_PRIVATE_KEY_P8_B64: ${{ secrets.ASC_PRIVATE_KEY_P8_B64 }}
IOS_APP_STORE_APP_ID: ${{ secrets.IOS_APP_STORE_APP_ID }}
IOS_TEAM_ID: ${{ secrets.IOS_TEAM_ID }}
IOS_DIST_CERT_P12_B64: ${{ secrets.IOS_DIST_CERT_P12_B64 }}
IOS_DIST_CERT_PASSWORD: ${{ secrets.IOS_DIST_CERT_PASSWORD }}
IOS_APP_STORE_PROFILE_B64: ${{ secrets.IOS_APP_STORE_PROFILE_B64 }}
run: |
set -euo pipefail
required=(
ASC_KEY_ID
ASC_ISSUER_ID
ASC_PRIVATE_KEY_P8_B64
IOS_APP_STORE_APP_ID
IOS_TEAM_ID
IOS_DIST_CERT_P12_B64
IOS_DIST_CERT_PASSWORD
IOS_APP_STORE_PROFILE_B64
)
for name in "${required[@]}"; do
if [[ -z "${!name:-}" ]]; then
echo "Missing required secret: $name" >&2
exit 1
fi
done
- name: Install build dependencies
run: |
set -euo pipefail
brew install xcodegen jq asc meson ninja
xcodebuild -version
asc --version
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-apple-ios,aarch64-apple-ios-sim,x86_64-apple-ios
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.9
- name: Prime sccache
run: |
rm -f "$SCCACHE_ERROR_LOG"
sccache --stop-server || true
sccache --start-server
sccache --show-stats || true
- name: Decode App Store Connect API key
env:
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
ASC_PRIVATE_KEY_P8_B64: ${{ secrets.ASC_PRIVATE_KEY_P8_B64 }}
run: |
set -euo pipefail
ASC_KEY_PATH="$RUNNER_TEMP/AuthKey_${ASC_KEY_ID}.p8"
echo "$ASC_PRIVATE_KEY_P8_B64" | base64 --decode > "$ASC_KEY_PATH"
chmod 600 "$ASC_KEY_PATH"
echo "ASC_PRIVATE_KEY_PATH=$ASC_KEY_PATH" >> "$GITHUB_ENV"
- name: Install signing certificate and provisioning profile
env:
IOS_DIST_CERT_P12_B64: ${{ secrets.IOS_DIST_CERT_P12_B64 }}
IOS_DIST_CERT_PASSWORD: ${{ secrets.IOS_DIST_CERT_PASSWORD }}
IOS_APP_STORE_PROFILE_B64: ${{ secrets.IOS_APP_STORE_PROFILE_B64 }}
run: |
set -euo pipefail
CERT_PATH="$RUNNER_TEMP/dist-cert.p12"
PROFILE_PATH="$RUNNER_TEMP/app-store.mobileprovision"
KEYCHAIN_PATH="$RUNNER_TEMP/build.keychain-db"
KEYCHAIN_PASSWORD="$(openssl rand -base64 24)"
echo "$IOS_DIST_CERT_P12_B64" | base64 --decode > "$CERT_PATH"
echo "$IOS_APP_STORE_PROFILE_B64" | base64 --decode > "$PROFILE_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 list-keychains -d user -s "$KEYCHAIN_PATH"
security default-keychain -d user -s "$KEYCHAIN_PATH"
security import "$CERT_PATH" -k "$KEYCHAIN_PATH" -P "$IOS_DIST_CERT_PASSWORD" -T /usr/bin/codesign -T /usr/bin/security
security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles"
PROFILE_UUID="$(security cms -D -i "$PROFILE_PATH" | plutil -extract UUID raw -)"
PROFILE_NAME="$(security cms -D -i "$PROFILE_PATH" | plutil -extract Name raw -)"
cp "$PROFILE_PATH" "$HOME/Library/MobileDevice/Provisioning Profiles/$PROFILE_UUID.mobileprovision"
echo "PROVISIONING_PROFILE_SPECIFIER=$PROFILE_NAME" >> "$GITHUB_ENV"
- name: Resolve release inputs
run: |
set -euo pipefail
SCHEME="Litter"
APP_BUNDLE_ID="com.sigkitten.litter"
MARKETING_VERSION="1.0.1"
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
BETA_GROUP_NAMES="${{ inputs.beta_group_names }}"
if [[ "${{ inputs.wait_for_processing }}" == "true" ]]; then
WAIT_FOR_PROCESSING="1"
else
WAIT_FOR_PROCESSING="0"
fi
else
BETA_GROUP_NAMES="Internal Testers,External Testers"
WAIT_FOR_PROCESSING="1"
fi
echo "SCHEME=$SCHEME" >> "$GITHUB_ENV"
echo "APP_BUNDLE_ID=$APP_BUNDLE_ID" >> "$GITHUB_ENV"
echo "MARKETING_VERSION=$MARKETING_VERSION" >> "$GITHUB_ENV"
echo "BETA_GROUP_NAMES=$BETA_GROUP_NAMES" >> "$GITHUB_ENV"
echo "WAIT_FOR_PROCESSING=$WAIT_FOR_PROCESSING" >> "$GITHUB_ENV"
- name: Upload to TestFlight
env:
CARGO_BUILD_JOBS: "2"
RUSTC_WRAPPER: sccache
SCHEME: ${{ env.SCHEME }}
APP_BUNDLE_ID: ${{ env.APP_BUNDLE_ID }}
APP_STORE_APP_ID: ${{ secrets.IOS_APP_STORE_APP_ID }}
TEAM_ID: ${{ secrets.IOS_TEAM_ID }}
PROVISIONING_PROFILE_SPECIFIER: ${{ env.PROVISIONING_PROFILE_SPECIFIER }}
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
ASC_PRIVATE_KEY_PATH: ${{ env.ASC_PRIVATE_KEY_PATH }}
MARKETING_VERSION: ${{ env.MARKETING_VERSION }}
BETA_GROUP_NAMES: ${{ env.BETA_GROUP_NAMES }}
WAIT_FOR_PROCESSING: ${{ env.WAIT_FOR_PROCESSING }}
run: |
set -euo pipefail
trap 'status=$?; echo "==> sccache stats"; sccache --show-stats || true; if [ -f "$SCCACHE_ERROR_LOG" ]; then echo "==> sccache error log"; tail -200 "$SCCACHE_ERROR_LOG" || true; fi; exit $status' EXIT
make testflight