#!/usr/bin/env bash # # release.sh — archive Workouts (iOS app with the embedded watch app) and upload # to TestFlight / App Store Connect. No third-party tooling: pure xcodebuild + the # App Store Connect API key. Credentials live in .env.release (gitignored); see # .env.release.example. # # What it does: # 1. Regenerates the Xcode project with XcodeGen. # 2. Stamps CFBundleVersion (CURRENT_PROJECT_VERSION) with the git commit count # for both the iOS app and the embedded watch app. # 3. xcodebuild archive (the watch app rides along in the same archive) # 4. xcodebuild -exportArchive with destination=upload -> App Store Connect. # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" cd "$ROOT" PROJECT="Workouts.xcodeproj" SCHEME="Workouts" BUILD_DIR="$ROOT/build" # ---- credentials ------------------------------------------------------------ ENV_FILE="$ROOT/.env.release" [ -f "$ENV_FILE" ] && { set -a; . "$ENV_FILE"; set +a; } : "${APPLE_TEAM_ID:?Set APPLE_TEAM_ID (copy .env.release.example -> .env.release)}" : "${ASC_KEY_ID:?Set ASC_KEY_ID in .env.release}" : "${ASC_ISSUER_ID:?Set ASC_ISSUER_ID in .env.release}" : "${ASC_KEY_PATH:?Set ASC_KEY_PATH in .env.release}" [ -f "$ASC_KEY_PATH" ] || { echo "❌ API key not found at: $ASC_KEY_PATH"; exit 1; } AUTH=( -authenticationKeyPath "$ASC_KEY_PATH" -authenticationKeyID "$ASC_KEY_ID" -authenticationKeyIssuerID "$ASC_ISSUER_ID" -allowProvisioningUpdates ) # ---- regenerate project ----------------------------------------------------- if command -v xcodegen >/dev/null 2>&1; then echo "🧩 Generating $PROJECT ..." xcodegen generate elif [ ! -d "$PROJECT" ]; then echo "❌ $PROJECT missing and xcodegen not installed."; exit 1 fi # ---- versioning ------------------------------------------------------------- BUILD_NUMBER="$(git rev-list HEAD --count)" MARKETING_VERSION="$(grep -m1 'MARKETING_VERSION:' project.yml | sed -E 's/.*"([^"]+)".*/\1/')" echo "📦 Version $MARKETING_VERSION (build $BUILD_NUMBER)" mkdir -p "$BUILD_DIR" ARCHIVE="$BUILD_DIR/Workouts.xcarchive" EXPORT="$BUILD_DIR/Workouts-export" rm -rf "$ARCHIVE" "$EXPORT" echo "🛠 Archiving (iOS app + embedded watch app) ..." xcodebuild archive \ -project "$PROJECT" \ -scheme "$SCHEME" \ -configuration Release \ -destination 'generic/platform=iOS' \ -archivePath "$ARCHIVE" \ CURRENT_PROJECT_VERSION="$BUILD_NUMBER" \ CODE_SIGN_STYLE=Automatic \ DEVELOPMENT_TEAM="$APPLE_TEAM_ID" \ "${AUTH[@]}" echo "🚀 Exporting + uploading to App Store Connect ..." xcodebuild -exportArchive \ -archivePath "$ARCHIVE" \ -exportPath "$EXPORT" \ -exportOptionsPlist "$SCRIPT_DIR/ExportOptions-iOS.plist" \ "${AUTH[@]}" echo "" echo "✅ Uploaded build $BUILD_NUMBER. Appears in App Store Connect > TestFlight after processing (~5–15 min)."