Section 9/171 menit

9. Custom Build Scripts (ci_scripts)

9. Custom Build Scripts (ci_scripts)

Tiga Script Hooks

swift
ci_scripts/
├── ci_post_clone.sh      — setelah git clone, sebelum apapun
├── ci_pre_xcodebuild.sh  — sebelum setiap action (build/test/archive)
└── ci_post_xcodebuild.sh — setelah setiap action

Script harus:

  • Executable: chmod +x ci_scripts/*.sh
  • Shebang line di baris pertama
  • Return exit code 0 untuk sukses, non-zero untuk gagal

ci_post_clone.sh — Setup Dependencies

swift
#!/bin/zsh
# ci_scripts/ci_post_clone.sh
# Dijalankan SEKALI setelah clone — cocok untuk install dependencies

set -e  # exit on error

echo "=== ci_post_clone.sh ==="
echo "Branch: $CI_BRANCH"
echo "Action: $CI_XCODEBUILD_ACTION"

# Install CocoaPods jika project menggunakan Pods
if [ -f "$CI_PRIMARY_REPOSITORY_PATH/Podfile" ]; then
    echo "Installing CocoaPods..."
    cd "$CI_PRIMARY_REPOSITORY_PATH"
    
    # Gunakan bundler jika ada Gemfile
    if [ -f "Gemfile" ]; then
        bundle install
        bundle exec pod install
    else
        pod install
    fi
fi

# Decode secrets berdasarkan environment
if [[ "$CI_BRANCH" == "main" || -n "$CI_TAG" ]]; then
    echo "Production environment detected"
    echo "$PROD_GOOGLE_SERVICE_INFO" | base64 --decode \
        > "$CI_PRIMARY_REPOSITORY_PATH/MyApp/GoogleService-Info.plist"
else
    echo "Staging environment detected"
    echo "$STAGING_GOOGLE_SERVICE_INFO" | base64 --decode \
        > "$CI_PRIMARY_REPOSITORY_PATH/MyApp/GoogleService-Info.plist"
fi

echo "=== ci_post_clone.sh selesai ==="

ci_pre_xcodebuild.sh — Pre-Build Setup

swift
#!/bin/zsh
# ci_scripts/ci_pre_xcodebuild.sh
# Dijalankan SETIAP KALI sebelum action (build, test, atau archive)

set -e

echo "=== ci_pre_xcodebuild.sh ==="
echo "Action: $CI_XCODEBUILD_ACTION"

# Bump build number hanya saat archive
if [[ "$CI_XCODEBUILD_ACTION" == "archive" ]]; then
    echo "Bumping build number to $CI_BUILD_NUMBER"
    
    # Update CFBundleVersion di semua Info.plist
    find "$CI_PRIMARY_REPOSITORY_PATH" -name "Info.plist" \
        -not -path "*/Pods/*" \
        -not -path "*/build/*" | while read -r plist; do
        /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $CI_BUILD_NUMBER" "$plist" 2>/dev/null || true
    done
    
    # Update xcconfig jika menggunakan CURRENT_PROJECT_VERSION
    if [ -f "$CI_PRIMARY_REPOSITORY_PATH/Configuration/Version.xcconfig" ]; then
        sed -i '' "s/CURRENT_PROJECT_VERSION = .*/CURRENT_PROJECT_VERSION = $CI_BUILD_NUMBER/" \
            "$CI_PRIMARY_REPOSITORY_PATH/Configuration/Version.xcconfig"
    fi
fi

# Generate version info file untuk in-app display
cat > "$CI_PRIMARY_REPOSITORY_PATH/Sources/Generated/BuildInfo.swift" << EOF
// Auto-generated oleh ci_pre_xcodebuild.sh — jangan edit manual
enum BuildInfo {
    static let buildNumber = "$CI_BUILD_NUMBER"
    static let commitHash = "$CI_COMMIT"
    static let branch = "$CI_BRANCH"
    static let buildDate = "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
}
EOF

echo "=== ci_pre_xcodebuild.sh selesai ==="

ci_post_xcodebuild.sh — Post-Build Actions

swift
#!/bin/zsh
# ci_scripts/ci_post_xcodebuild.sh
# Dijalankan setelah action selesai — cocok untuk upload artifact atau notifikasi custom

set -e

echo "=== ci_post_xcodebuild.sh ==="
echo "Action: $CI_XCODEBUILD_ACTION"

# Upload ke Sentry setelah archive untuk source map / dSYM
if [[ "$CI_XCODEBUILD_ACTION" == "archive" && -n "$SENTRY_AUTH_TOKEN" ]]; then
    echo "Uploading dSYMs to Sentry..."
    
    # Download Sentry CLI
    curl -sL https://sentry.io/get-cli/ | bash
    
    # Upload dSYMs dari archive
    DSYM_PATH="$CI_ARCHIVE_PATH/dSYMs"
    if [ -d "$DSYM_PATH" ]; then
        sentry-cli --auth-token "$SENTRY_AUTH_TOKEN" \
            upload-dif \
            --org "$SENTRY_ORG" \
            --project "$SENTRY_PROJECT" \
            "$DSYM_PATH"
    fi
fi

# Parse test results dan kirim custom metric
if [[ "$CI_XCODEBUILD_ACTION" == "test" && -n "$CI_RESULT_BUNDLE_PATH" ]]; then
    echo "Parsing test results..."
    
    # Xcresulttool untuk mengekstrak summary
    SUMMARY=$(xcrun xcresulttool get \
        --format json \
        --path "$CI_RESULT_BUNDLE_PATH" 2>/dev/null || echo "{}")
    
    echo "Test result bundle: $CI_RESULT_BUNDLE_PATH"
fi

echo "=== ci_post_xcodebuild.sh selesai ==="

Mengelola Swift Package Dependencies

Untuk project yang menggunakan Swift Package Manager, Xcode Cloud otomatis resolve packages. Namun untuk project besar, pertimbangkan:

swift
#!/bin/zsh
# ci_scripts/ci_post_clone.sh (SPM cache strategy)

set -e

# Untuk mempercepat build, bisa menggunakan local SPM mirror
# atau pre-download packages ke lokasi yang di-cache

# Resolve packages secara eksplisit (opsional — Xcode melakukan ini otomatis)
cd "$CI_PRIMARY_REPOSITORY_PATH"
xcodebuild -resolvePackageDependencies \
    -project "MyApp.xcodeproj" \
    -scheme "MyApp" || true

echo "SPM packages resolved"