mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-28 22:55:41 +00:00
Replace deprecated altool (removed in Xcode 14) with xcodebuild -exportArchive using App Store Connect API authentication. Changes: - upload_testflight.sh: Use xcodebuild with destination=upload and API key authentication instead of altool - ios_testflight.yml: Pass xcarchive path and use new API key secrets Required new GitHub secrets: - APP_STORE_CONNECT_API_KEY_ID - APP_STORE_CONNECT_API_ISSUER_ID - APP_STORE_CONNECT_API_KEY (contents of .p8 file) Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
239 lines
8.5 KiB
YAML
239 lines
8.5 KiB
YAML
name: iOS TestFlight
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
skip_upload:
|
|
description: 'Skip TestFlight upload (build and archive only)'
|
|
required: false
|
|
default: 'false'
|
|
type: boolean
|
|
|
|
permissions:
|
|
contents: read
|
|
actions: write
|
|
|
|
env:
|
|
# Runner-specific build directory to allow parallel builds on multiple runners
|
|
EAGLE0_BUILD_DIR: /tmp/eagle0-${{ github.run_id }}
|
|
# Runner-specific keychain to avoid conflicts when multiple runners sign simultaneously
|
|
KEYCHAIN_NAME: ios-build-${{ github.run_id }}.keychain
|
|
|
|
jobs:
|
|
build-unity:
|
|
runs-on: [self-hosted, macOS, unity-mac]
|
|
outputs:
|
|
xcode_project_path: ${{ steps.build.outputs.xcode_project_path }}
|
|
|
|
steps:
|
|
- name: Prune stale PR refs
|
|
run: |
|
|
# Self-hosted runners persist .git between runs. When a PR is updated,
|
|
# old local refs (refs/remotes/pull/*/merge) may point to commits whose
|
|
# objects were never fetched or have been pruned. Remove these stale refs
|
|
# before checkout to prevent "missing object" errors.
|
|
if [ -d ".git" ]; then
|
|
echo "Pruning stale PR refs..."
|
|
git for-each-ref --format='%(refname)' refs/remotes/pull/ 2>/dev/null | \
|
|
xargs -r git update-ref -d 2>/dev/null || true
|
|
fi
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
lfs: false # Fetch LFS after checkout to avoid stale ref issues
|
|
clean: true
|
|
fetch-depth: 0
|
|
|
|
- name: Fetch LFS files
|
|
run: |
|
|
git lfs install
|
|
git lfs pull
|
|
|
|
- name: Ensure Unity version installed
|
|
run: ./ci/github_actions/ensure_unity_installed.sh ios
|
|
|
|
- name: Restore Library/
|
|
env:
|
|
UNITY_CACHE_PLATFORM: ios
|
|
run: ./ci/github_actions/restore_library.sh
|
|
|
|
- name: Build iOS Unity Project
|
|
id: build
|
|
run: |
|
|
./ci/github_actions/build_unity_ios.sh "$EAGLE0_BUILD_DIR/eagle0iOS"
|
|
echo "xcode_project_path=$EAGLE0_BUILD_DIR/eagle0iOS" >> $GITHUB_OUTPUT
|
|
|
|
- name: Persist Library/
|
|
if: success()
|
|
env:
|
|
UNITY_CACHE_PLATFORM: ios
|
|
run: ./ci/github_actions/persist_library.sh
|
|
|
|
- name: Upload Addressables to CDN
|
|
if: success()
|
|
env:
|
|
ACCESS_KEY_ID: ${{ secrets.ACCESS_KEY_ID }}
|
|
SECRET_KEY: ${{ secrets.SECRET_KEY }}
|
|
run: ./ci/github_actions/upload_addressables.sh iOS
|
|
|
|
- name: Zip Xcode project for artifact
|
|
run: |
|
|
cd $EAGLE0_BUILD_DIR
|
|
# Use tar for speed - Xcode projects have many small files
|
|
tar -czf eagle0iOS.tar.gz eagle0iOS
|
|
|
|
- name: Upload Xcode project
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: xcode-project-${{ github.run_id }}
|
|
path: ${{ env.EAGLE0_BUILD_DIR }}/eagle0iOS.tar.gz
|
|
retention-days: 1
|
|
|
|
- name: Archive Build Log
|
|
if: success() || failure()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: editor_ios.log
|
|
path: ${{ env.EAGLE0_BUILD_DIR }}/editor_ios.log
|
|
retention-days: 5
|
|
- name: Cleanup build directory
|
|
if: always()
|
|
run: rm -rf "${{ env.EAGLE0_BUILD_DIR }}"
|
|
|
|
archive-and-upload:
|
|
needs: build-unity
|
|
runs-on: [self-hosted, macOS, unity-mac]
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
sparse-checkout: |
|
|
ci
|
|
scripts
|
|
|
|
- name: Clean download directory
|
|
run: rm -rf $EAGLE0_BUILD_DIR/eagle0iOS
|
|
|
|
- name: Download Xcode project
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: xcode-project-${{ github.run_id }}
|
|
path: ${{ env.EAGLE0_BUILD_DIR }}
|
|
|
|
- name: Extract Xcode project
|
|
run: |
|
|
cd $EAGLE0_BUILD_DIR
|
|
tar -xzf eagle0iOS.tar.gz
|
|
rm eagle0iOS.tar.gz
|
|
ls -la eagle0iOS/
|
|
|
|
- name: Install Signing Certificate
|
|
env:
|
|
IOS_CERTIFICATE: ${{ secrets.IOS_CERTIFICATE }}
|
|
IOS_CERTIFICATE_PWD: ${{ secrets.IOS_CERTIFICATE_PWD }}
|
|
run: |
|
|
# Generate random keychain password
|
|
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
|
|
echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> $GITHUB_ENV
|
|
|
|
# Decode certificate
|
|
echo "$IOS_CERTIFICATE" | base64 --decode > certificate.p12
|
|
|
|
# Delete any existing keychain from previous runs
|
|
security delete-keychain "$KEYCHAIN_NAME" 2>/dev/null || true
|
|
|
|
# Create temporary keychain
|
|
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME"
|
|
security default-keychain -s "$KEYCHAIN_NAME"
|
|
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME"
|
|
security set-keychain-settings -t 3600 -u "$KEYCHAIN_NAME"
|
|
|
|
# Import certificate
|
|
security import certificate.p12 -k "$KEYCHAIN_NAME" -P "$IOS_CERTIFICATE_PWD" -T /usr/bin/codesign -T /usr/bin/security
|
|
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME"
|
|
|
|
# Add keychain to search list
|
|
security list-keychains -d user -s "$KEYCHAIN_NAME" login.keychain
|
|
|
|
rm certificate.p12
|
|
|
|
- name: Install Provisioning Profile
|
|
env:
|
|
IOS_PROVISIONING_PROFILE: ${{ secrets.IOS_PROVISIONING_PROFILE }}
|
|
run: |
|
|
# Decode provisioning profile
|
|
echo "$IOS_PROVISIONING_PROFILE" | base64 --decode > profile.mobileprovision
|
|
|
|
# Extract UUID from provisioning profile
|
|
PROFILE_UUID=$(/usr/libexec/PlistBuddy -c "Print :UUID" /dev/stdin <<< $(security cms -D -i profile.mobileprovision))
|
|
echo "PROFILE_UUID=$PROFILE_UUID" >> $GITHUB_ENV
|
|
|
|
# Install to standard location
|
|
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
|
|
cp profile.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/$PROFILE_UUID.mobileprovision
|
|
|
|
rm profile.mobileprovision
|
|
echo "Installed provisioning profile: $PROFILE_UUID"
|
|
|
|
- name: Archive and Export IPA
|
|
env:
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
run: |
|
|
chmod +x ./ci/github_actions/archive_ios.sh
|
|
./ci/github_actions/archive_ios.sh "$EAGLE0_BUILD_DIR/eagle0iOS" "$EAGLE0_BUILD_DIR/archive" "$APPLE_TEAM_ID" "$PROFILE_UUID"
|
|
|
|
- name: Upload to TestFlight
|
|
if: ${{ github.event.inputs.skip_upload != 'true' }}
|
|
env:
|
|
# App Store Connect API Key (replaces deprecated altool with Apple ID)
|
|
# Create at: https://appstoreconnect.apple.com/access/api
|
|
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
|
|
APP_STORE_CONNECT_API_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_ISSUER_ID }}
|
|
APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
run: |
|
|
# Write API key to file (xcodebuild needs a file path)
|
|
API_KEY_PATH=$(mktemp)
|
|
echo "$APP_STORE_CONNECT_API_KEY" > "$API_KEY_PATH"
|
|
export APP_STORE_CONNECT_API_KEY_PATH="$API_KEY_PATH"
|
|
|
|
chmod +x ./ci/github_actions/upload_testflight.sh
|
|
./ci/github_actions/upload_testflight.sh "$EAGLE0_BUILD_DIR/archive/eagle0.xcarchive" "$APPLE_TEAM_ID" "$PROFILE_UUID"
|
|
|
|
# Cleanup
|
|
rm -f "$API_KEY_PATH"
|
|
|
|
- name: Upload IPA artifact
|
|
# Only keep artifact if we skipped TestFlight upload (for debugging)
|
|
if: success() && github.event.inputs.skip_upload == 'true'
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: eagle0-ios-${{ github.run_id }}
|
|
path: ${{ env.EAGLE0_BUILD_DIR }}/archive/eagle0.ipa
|
|
retention-days: 1
|
|
|
|
- name: Cleanup Keychain
|
|
if: always()
|
|
run: |
|
|
security delete-keychain "$KEYCHAIN_NAME" 2>/dev/null || true
|
|
- name: Cleanup build directory
|
|
if: always()
|
|
run: rm -rf "${{ env.EAGLE0_BUILD_DIR }}"
|
|
|
|
cleanup:
|
|
needs: [build-unity, archive-and-upload]
|
|
if: always()
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Delete intermediate artifacts
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
artifact_name="xcode-project-${{ github.run_id }}"
|
|
echo "Deleting artifact: $artifact_name"
|
|
artifact_id=$(gh api "repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts" \
|
|
-q ".artifacts[] | select(.name == \"$artifact_name\") | .id")
|
|
if [ -n "$artifact_id" ]; then
|
|
gh api -X DELETE "repos/${{ github.repository }}/actions/artifacts/$artifact_id" || true
|
|
fi
|