ci(ios): use fastlane pilot upload instead of distribute #16
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: iOS Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| concurrency: | |
| group: ios-release-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| release: | |
| name: Build & Upload to TestFlight | |
| runs-on: nscloud-macos-tahoe-arm64-6x14 | |
| timeout-minutes: 60 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Select Xcode 26.2 | |
| run: | | |
| sudo xcode-select -s /Applications/Xcode_26.2.app | |
| xcodebuild -version | |
| - uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: 23 | |
| - uses: gradle/actions/setup-gradle@v4 | |
| - name: Import signing certificate | |
| env: | |
| APPLE_CERTIFICATE_BASE64: ${{ secrets.APPLE_CERTIFICATE_BASE64 }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| run: | | |
| CERTIFICATE_PATH="$RUNNER_TEMP/certificate.p12" | |
| KEYCHAIN_PATH="$RUNNER_TEMP/signing.keychain-db" | |
| KEYCHAIN_PASSWORD="$(openssl rand -base64 32)" | |
| echo -n "$APPLE_CERTIFICATE_BASE64" | base64 --decode -o "$CERTIFICATE_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 "$CERTIFICATE_PATH" \ | |
| -P "$APPLE_CERTIFICATE_PASSWORD" \ | |
| -A \ | |
| -t cert \ | |
| -f pkcs12 \ | |
| -k "$KEYCHAIN_PATH" | |
| security set-key-partition-list \ | |
| -S apple-tool:,apple: \ | |
| -k "$KEYCHAIN_PASSWORD" \ | |
| "$KEYCHAIN_PATH" | |
| security list-keychains -d user -s "$KEYCHAIN_PATH" login.keychain-db | |
| - name: Import provisioning profile | |
| env: | |
| APPLE_PROVISIONING_PROFILE_BASE64: ${{ secrets.APPLE_PROVISIONING_PROFILE_BASE64 }} | |
| run: | | |
| PROFILE_PATH="$RUNNER_TEMP/profile.mobileprovision" | |
| echo -n "$APPLE_PROVISIONING_PROFILE_BASE64" | base64 --decode -o "$PROFILE_PATH" | |
| mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles | |
| PROFILE_UUID=$(/usr/libexec/PlistBuddy -c "Print UUID" /dev/stdin <<< \ | |
| "$(security cms -D -i "$PROFILE_PATH")") | |
| cp "$PROFILE_PATH" ~/Library/MobileDevice/Provisioning\ Profiles/"$PROFILE_UUID".mobileprovision | |
| echo "PROVISIONING_PROFILE_UUID=$PROFILE_UUID" >> "$GITHUB_ENV" | |
| - name: Set up App Store Connect API key | |
| env: | |
| APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} | |
| APP_STORE_CONNECT_API_KEY_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_BASE64 }} | |
| run: | | |
| mkdir -p ~/.private_keys | |
| echo -n "$APP_STORE_CONNECT_API_KEY_BASE64" | base64 --decode \ | |
| -o ~/.private_keys/AuthKey_"$APP_STORE_CONNECT_API_KEY_ID".p8 | |
| - name: Extract version from tag | |
| run: | | |
| TAG="${GITHUB_REF#refs/tags/v}" | |
| echo "MARKETING_VERSION=$TAG" >> "$GITHUB_ENV" | |
| echo "CURRENT_PROJECT_VERSION=$GITHUB_RUN_NUMBER" >> "$GITHUB_ENV" | |
| echo "Building version $TAG ($GITHUB_RUN_NUMBER)" | |
| - name: Build archive | |
| run: | | |
| xcodebuild archive \ | |
| -project app/ios/FareBot.xcodeproj \ | |
| -scheme FareBot \ | |
| -configuration Release \ | |
| -destination 'generic/platform=iOS' \ | |
| -archivePath "$RUNNER_TEMP/FareBot.xcarchive" \ | |
| MARKETING_VERSION="$MARKETING_VERSION" \ | |
| CURRENT_PROJECT_VERSION="$CURRENT_PROJECT_VERSION" \ | |
| CODE_SIGN_STYLE=Manual \ | |
| CODE_SIGN_IDENTITY="Apple Distribution" \ | |
| DEVELOPMENT_TEAM=ZJ9GEQ36AH \ | |
| PROVISIONING_PROFILE_SPECIFIER="$PROVISIONING_PROFILE_UUID" | |
| - name: Export IPA | |
| run: | | |
| EXPORT_PLIST="$RUNNER_TEMP/ExportOptions.plist" | |
| cat > "$EXPORT_PLIST" <<-PLIST | |
| <?xml version="1.0" encoding="UTF-8"?> | |
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
| <plist version="1.0"> | |
| <dict> | |
| <key>method</key> | |
| <string>app-store-connect</string> | |
| <key>teamID</key> | |
| <string>ZJ9GEQ36AH</string> | |
| <key>signingStyle</key> | |
| <string>manual</string> | |
| <key>signingCertificate</key> | |
| <string>Apple Distribution</string> | |
| <key>provisioningProfiles</key> | |
| <dict> | |
| <key>com.codebutler.farebot</key> | |
| <string>$PROVISIONING_PROFILE_UUID</string> | |
| </dict> | |
| <key>uploadSymbols</key> | |
| <true/> | |
| <key>destination</key> | |
| <string>export</string> | |
| </dict> | |
| </plist> | |
| PLIST | |
| xcodebuild -exportArchive \ | |
| -archivePath "$RUNNER_TEMP/FareBot.xcarchive" \ | |
| -exportPath "$RUNNER_TEMP/export" \ | |
| -exportOptionsPlist "$EXPORT_PLIST" | |
| - name: Install fastlane | |
| run: brew install fastlane | |
| - name: Upload & distribute to TestFlight | |
| env: | |
| APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} | |
| APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} | |
| run: | | |
| API_KEY_JSON="$RUNNER_TEMP/api_key.json" | |
| P8_CONTENTS=$(cat ~/.private_keys/AuthKey_"$APP_STORE_CONNECT_API_KEY_ID".p8) | |
| jq -n \ | |
| --arg key_id "$APP_STORE_CONNECT_API_KEY_ID" \ | |
| --arg issuer_id "$APP_STORE_CONNECT_ISSUER_ID" \ | |
| --arg key "$P8_CONTENTS" \ | |
| '{key_id: $key_id, issuer_id: $issuer_id, key: $key, in_house: false}' \ | |
| > "$API_KEY_JSON" | |
| IPA_PATH=$(find "$RUNNER_TEMP/export" -name '*.ipa' -print -quit) | |
| echo "IPA: $IPA_PATH" | |
| [ -f "$IPA_PATH" ] || { echo "No IPA found"; ls -la "$RUNNER_TEMP/export"; exit 1; } | |
| fastlane pilot upload \ | |
| --ipa "$IPA_PATH" \ | |
| --api_key_path "$API_KEY_JSON" \ | |
| --app_platform ios \ | |
| --distribute_external true \ | |
| --notify_external_testers true \ | |
| --skip_waiting_for_build_processing false \ | |
| --changelog "Build $MARKETING_VERSION ($CURRENT_PROJECT_VERSION)" | |
| - name: Cleanup keychain | |
| if: always() | |
| run: | | |
| KEYCHAIN_PATH="$RUNNER_TEMP/signing.keychain-db" | |
| if [ -f "$KEYCHAIN_PATH" ]; then | |
| security delete-keychain "$KEYCHAIN_PATH" | |
| fi |