Section 14/151 menit

14. Real Use Cases

14. Real Use Cases

Use Case 1: Setup CI Lengkap untuk Project Hybrid (GitHub Actions)

Project nyata: app dengan Firebase (CocoaPods) + Alamofire, Kingfisher (SPM).

swift
# .github/workflows/ci.yml

name: iOS CI  Hybrid Project

on:
  push:
    branches: [main, 'release/*']
  pull_request:
    branches: [main]

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true  # Batalkan run lama jika ada push baru

jobs:
  test:
    name: Build & Test
    runs-on: macos-15
    timeout-minutes: 30
    
    env:
      XCODE_VERSION: '16.3'
      DERIVED_DATA: ${{ github.workspace }}/DerivedData
      
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 1  # Shallow clone untuk kecepatan
      
      - name: Select Xcode ${{ env.XCODE_VERSION }}
        run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app
      
      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.3'
          bundler-cache: true
          
      # ── COCOAPODS CACHE ─────────────────────────────────────────
      - name: Restore CocoaPods Specs Cache
        id: specs-cache
        uses: actions/cache/restore@v4
        with:
          path: ~/.cocoapods/repos/trunk
          key: cocoapods-trunk-v1-${{ hashFiles('Podfile.lock') }}
          restore-keys: cocoapods-trunk-v1-
      
      - name: Restore Pods Cache
        id: pods-cache
        uses: actions/cache/restore@v4
        with:
          path: Pods
          key: pods-v1-${{ runner.os }}-xcode${{ env.XCODE_VERSION }}-${{ hashFiles('Podfile.lock') }}
          restore-keys: pods-v1-${{ runner.os }}-xcode${{ env.XCODE_VERSION }}-
      
      - name: Install CocoaPods
        if: steps.pods-cache.outputs.cache-hit != 'true'
        run: |
          bundle exec pod install --no-repo-update
          echo "✓ Pods installed"
      
      - name: Save Pods Cache
        if: steps.pods-cache.outputs.cache-hit != 'true'
        uses: actions/cache/save@v4
        with:
          path: Pods
          key: pods-v1-${{ runner.os }}-xcode${{ env.XCODE_VERSION }}-${{ hashFiles('Podfile.lock') }}
      
      # ── SPM CACHE ────────────────────────────────────────────────
      - name: Restore SPM Cache
        id: spm-cache
        uses: actions/cache/restore@v4
        with:
          path: ${{ env.DERIVED_DATA }}/SourcePackages
          key: spm-v1-${{ runner.os }}-xcode${{ env.XCODE_VERSION }}-${{ hashFiles('MyApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }}
          restore-keys: spm-v1-${{ runner.os }}-xcode${{ env.XCODE_VERSION }}-
      
      - name: Resolve SPM Packages
        run: |
          xcodebuild -resolvePackageDependencies \
            -workspace MyApp.xcworkspace \
            -scheme MyApp \
            -derivedDataPath "$DERIVED_DATA" \
            | grep -E "Fetching|Cloning|Resolved" || true
      
      - name: Save SPM Cache
        if: steps.spm-cache.outputs.cache-hit != 'true'
        uses: actions/cache/save@v4
        with:
          path: ${{ env.DERIVED_DATA }}/SourcePackages
          key: spm-v1-${{ runner.os }}-xcode${{ env.XCODE_VERSION }}-${{ hashFiles('MyApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }}
      
      # ── BUILD & TEST ─────────────────────────────────────────────
      - name: Build for Testing
        run: |
          xcodebuild build-for-testing \
            -workspace MyApp.xcworkspace \
            -scheme MyApp \
            -destination "platform=iOS Simulator,name=iPhone 16 Pro,OS=18.4" \
            -derivedDataPath "$DERIVED_DATA" \
            | xcpretty
      
      - name: Run Tests
        run: |
          xcodebuild test-without-building \
            -workspace MyApp.xcworkspace \
            -scheme MyApp \
            -destination "platform=iOS Simulator,name=iPhone 16 Pro,OS=18.4" \
            -derivedDataPath "$DERIVED_DATA" \
            -resultBundlePath TestResults.xcresult \
            | xcpretty --report junit --output test-report.xml
      
      - name: Upload Test Results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-results-${{ github.run_number }}
          path: |
            test-report.xml
            TestResults.xcresult

  # Job terpisah untuk cache warming (opsional, untuk branch utama)
  warm-cache:
    name: Warm Dependency Cache
    runs-on: macos-15
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    needs: test  # Jalankan setelah test sukses
    
    steps:
      - uses: actions/checkout@v4
      - name: Pre-warm cache untuk developer baru
        run: echo "Cache sudah di-warm oleh job test di atas"

Use Case 2: Script Audit Dependency — CocoaPods vs SPM Overlap Check

swift
#!/bin/bash
# scripts/check-dependency-overlap.sh
# Cek apakah ada library yang sama di CocoaPods dan SPM

set -e

echo "=== Checking for dependency overlaps ==="

# Extract pod names dari Podfile.lock
PODS=$(grep "  - " Podfile.lock | grep -v "//" | awk '{print $2}' | cut -d'(' -f1 | tr '[:upper:]' '[:lower:]')

# Extract SPM package names dari Package.resolved
SPM_PACKAGES=$(cat "MyApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved" \
  | python3 -c "
import json, sys
data = json.load(sys.stdin)
for pin in data.get('pins', []):
    print(pin['identity'].lower())
")

# Cari overlap
OVERLAPS=()
while IFS= read -r pod; do
    if echo "$SPM_PACKAGES" | grep -qi "^${pod}$"; then
        OVERLAPS+=("$pod")
    fi
done <<< "$PODS"

if [ ${#OVERLAPS[@]} -gt 0 ]; then
    echo "⚠️  OVERLAP DETECTED — These packages appear in BOTH CocoaPods and SPM:"
    for overlap in "${OVERLAPS[@]}"; do
        echo "   - $overlap"
    done
    echo ""
    echo "This may cause duplicate symbols! Remove from one dependency manager."
    exit 1
else
    echo "✓ No overlaps found between CocoaPods and SPM"
fi

Use Case 3: Makefile untuk Hybrid Project Development

swift
# Makefile

.PHONY: install update clean ci

# Setup semua dependencies (pertama kali atau setelah clone)
install:
	@echo "Installing CocoaPods..."
	bundle exec pod install --no-repo-update
	@echo "Resolving SPM packages..."
	xcodebuild -resolvePackageDependencies \
		-workspace MyApp.xcworkspace \
		-scheme MyApp
	@echo "✓ All dependencies installed"

# Update semua (hati-hati!)
update-pods:
	bundle exec pod update
	
update-spm:
	# Buka Xcode → File → Packages → Update to Latest Package Versions
	@echo "Update SPM via Xcode: File → Packages → Update to Latest Package Versions"

# Check overlaps
check-deps:
	./scripts/check-dependency-overlap.sh

# Clean semua artifacts
clean:
	rm -rf DerivedData/
	rm -rf build/
	xcodebuild clean -workspace MyApp.xcworkspace -scheme MyApp

# Full CI simulation lokal
ci: check-deps
	xcodebuild test \
		-workspace MyApp.xcworkspace \
		-scheme MyApp \
		-destination "platform=iOS Simulator,name=iPhone 16 Pro" \
		| xcpretty

# Report cache sizes
cache-sizes:
	@echo "=== Dependency Cache Sizes ==="
	@du -sh Pods/ 2>/dev/null && echo "(CocoaPods)" || echo "Pods/: not found"
	@du -sh ~/Library/Developer/Xcode/DerivedData/*/SourcePackages 2>/dev/null \
		| tail -1 && echo "(SPM)" || echo "SPM SourcePackages: not found"