#!/usr/bin/env bash # Build, sign, and upload a TestFlight release of the iPhone app (LChat), then # hand the uploaded build to ios/asc-testflight.mjs, which does the App Store # Connect side: wait out processing, declare export compliance, seed "What to # Test", and place the build with the tester groups. # # The Mac's counterpart is ios/release-mac.sh (Developer ID + Sparkle). Mint # both from the same version/build so the two apps stay in step — they are one # product (CLAUDE.md § Conventions). # # Usage: ios/release-ios.sh [--external] # ios/release-ios.sh 0.9.0 1 # internal testers only # ios/release-ios.sh 0.9.0 1 --external # …and submit for external review # # Required env: # LCHAT_ASC_KEY_PATH / LCHAT_ASC_KEY_ID / LCHAT_ASC_ISSUER_ID # The App Store Connect API key (see the operator runbook). The key must # have Admin role — an App Manager key can't mint the cloud distribution # certificate and dies with "Cloud signing permission error". # Optional env: # LCHAT_RELEASE_NOTES_MD Path to the release notes; becomes the build's # "What to Test" text for testers. # LCHAT_ASC_APP_ID Default 6787060127 (the Eleven Messenger app record). # # ALWAYS pass the -authenticationKey* flags (they're built in below): without # them xcodebuild scans Xcode's stored ASC accounts, and one dead account # session aborts the whole export with "Error Downloading App Information". set -euo pipefail VERSION="${1:?usage: release-ios.sh [--external]}" BUILD="${2:?usage: release-ios.sh [--external]}" EXTERNAL="${3:-}" : "${LCHAT_ASC_KEY_PATH:?LCHAT_ASC_KEY_PATH is required (ASC API key .p8 path)}" : "${LCHAT_ASC_KEY_ID:?LCHAT_ASC_KEY_ID is required}" : "${LCHAT_ASC_ISSUER_ID:?LCHAT_ASC_ISSUER_ID is required}" TEAM_ID="J5NDF5PCD8" REPO="$(cd "$(dirname "$0")/.." && pwd)" IOS="$REPO/ios" TMP="$(mktemp -d)" trap 'rm -rf "$TMP"' EXIT ASC_AUTH=(-authenticationKeyPath "$LCHAT_ASC_KEY_PATH" -authenticationKeyID "$LCHAT_ASC_KEY_ID" -authenticationKeyIssuerID "$LCHAT_ASC_ISSUER_ID") echo "Building Eleven $VERSION ($BUILD) — App Store Connect / TestFlight" cd "$IOS" xcodegen generate xcodebuild archive \ -project LChat.xcodeproj -scheme LChat -destination 'generic/platform=iOS' \ -archivePath "$TMP/LChat.xcarchive" -allowProvisioningUpdates \ CODE_SIGN_STYLE=Automatic MARKETING_VERSION="$VERSION" CURRENT_PROJECT_VERSION="$BUILD" # -exportOptionsPlist has no CLI flag form, so template a throwaway one. # manageAppVersionAndBuildNumber is deliberately FALSE: it would override the # numbers we just archived with whatever ASC thinks comes next, and the whole # point is that the Mac and the iPhone carry the same version. cat > "$TMP/export-options.plist" < method app-store-connect destination upload teamID $TEAM_ID signingStyle automatic uploadSymbols manageAppVersionAndBuildNumber PLIST xcodebuild -exportArchive -archivePath "$TMP/LChat.xcarchive" -exportPath "$TMP/export" \ -exportOptionsPlist "$TMP/export-options.plist" -allowProvisioningUpdates "${ASC_AUTH[@]}" echo "Uploaded. Handing over to App Store Connect…" exec node "$IOS/asc-testflight.mjs" "$VERSION" "$BUILD" $EXTERNAL