diff --git a/Scripts/ExportOptions-macOS.plist b/Scripts/ExportOptions-macOS.plist new file mode 100644 index 0000000..5527d0e --- /dev/null +++ b/Scripts/ExportOptions-macOS.plist @@ -0,0 +1,23 @@ + + + + + + method + app-store-connect + teamID + C32Z8JNLG6 + + destination + upload + signingStyle + automatic + uploadSymbols + + stripSwiftSymbols + + manageAppVersionAndBuildNumber + + + diff --git a/Scripts/release.sh b/Scripts/release.sh index f5e522a..ac68ab2 100755 --- a/Scripts/release.sh +++ b/Scripts/release.sh @@ -1,16 +1,19 @@ #!/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. +# release.sh — archive Workouts and upload to TestFlight / App Store Connect. # -# What it does: +# Usage: Scripts/release.sh [ios|mac|all] (default: ios) +# +# 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, per platform: # 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. +# 2. xcodebuild archive (the watch app rides along in the iOS archive). +# CFBundleVersion is stamped by the update_build_info.sh post-build phase, +# platform-partitioned: iOS/watchOS even (commits*2), macOS odd (commits*2+1) +# — both platforms share one ASC build-number space. +# 3. xcodebuild -exportArchive with destination=upload -> App Store Connect. # set -euo pipefail @@ -19,8 +22,8 @@ ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" cd "$ROOT" PROJECT="Workouts.xcodeproj" -SCHEME="Workouts" BUILD_DIR="$ROOT/build" +PLATFORM="${1:-ios}" # ---- credentials ------------------------------------------------------------ ENV_FILE="$ROOT/.env.release" @@ -49,38 +52,70 @@ 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)" +echo "📦 Version $MARKETING_VERSION — iOS build $((BUILD_NUMBER * 2)), macOS build $((BUILD_NUMBER * 2 + 1))" 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[@]}" +# ---- per-platform archive + upload ------------------------------------------ +# args: +archive_and_upload() { + local scheme="$1" destination="$2" export_plist="$3" + local archive_path="$BUILD_DIR/$scheme.xcarchive" + local export_path="$BUILD_DIR/$scheme-export" -echo "🚀 Exporting + uploading to App Store Connect ..." -xcodebuild -exportArchive \ - -archivePath "$ARCHIVE" \ - -exportPath "$EXPORT" \ - -exportOptionsPlist "$SCRIPT_DIR/ExportOptions-iOS.plist" \ - "${AUTH[@]}" + echo "" + echo "──────── $scheme ────────" + + rm -rf "$archive_path" "$export_path" + + echo "🛠 Archiving $scheme ..." + xcodebuild archive \ + -project "$PROJECT" \ + -scheme "$scheme" \ + -configuration Release \ + -destination "$destination" \ + -archivePath "$archive_path" \ + CODE_SIGN_STYLE=Automatic \ + DEVELOPMENT_TEAM="$APPLE_TEAM_ID" \ + "${AUTH[@]}" + + echo "🚀 Exporting + uploading $scheme to App Store Connect ..." + xcodebuild -exportArchive \ + -archivePath "$archive_path" \ + -exportPath "$export_path" \ + -exportOptionsPlist "$export_plist" \ + "${AUTH[@]}" + + case "$scheme" in + *Mac) local plat_build=$((BUILD_NUMBER * 2 + 1)) ;; + *) local plat_build=$((BUILD_NUMBER * 2)) ;; + esac + echo "✅ $scheme uploaded (build $plat_build)." +} + +do_ios() { + archive_and_upload "Workouts" "generic/platform=iOS" \ + "$SCRIPT_DIR/ExportOptions-iOS.plist" +} + +do_mac() { + archive_and_upload "Workouts Mac" "generic/platform=macOS" \ + "$SCRIPT_DIR/ExportOptions-macOS.plist" +} + +case "$PLATFORM" in + ios) do_ios ;; + mac|macos) do_mac ;; + all) do_ios; do_mac ;; + *) echo "Usage: Scripts/release.sh [ios|mac|all]"; exit 1 ;; +esac echo "" -echo "✅ Uploaded build $BUILD_NUMBER. Appears in App Store Connect > TestFlight after processing (~5–15 min)." +echo "🎉 Done. Builds appear in App Store Connect > TestFlight after processing (~5–15 min)." echo "" echo "➡️ Push metadata, then stage/submit for review with the canonical scripts" echo " (apps sit as siblings of indie-skills under ~/Documents/indie; --bundle" -echo " and --version are required flags — there are no per-app defaults):" +echo " and --version are required flags; pass --platform macos for the Mac listing):" echo "" echo " set -a; source .env.release; set +a; swift ../indie-skills/skills/appstore-publish/scripts/asc-metadata.swift --bundle dev.rzen.indie.Workouts --version $MARKETING_VERSION --dry-run" echo " set -a; source .env.release; set +a; swift ../indie-skills/skills/appstore-publish/scripts/asc-metadata.swift --bundle dev.rzen.indie.Workouts --version $MARKETING_VERSION"