Section 17/181 menit

17. Real Use Cases

17. Real Use Cases

Use Case 1: Setup Project Baru yang Production-Ready dari Hari Pertama

Script bootstrap yang mengotomasi setup lengkap untuk project baru.

swift
#!/bin/bash
# setup-ios-project.sh
set -e

PROJECT_NAME="${1:-MyApp}"
BUNDLE_ID="${2:-com.mycompany.myapp}"
TEAM_ID="${3:-ABCDEF1234}"

echo "🚀 Setting up $PROJECT_NAME..."

# Install dependencies
brew install swiftlint swiftformat periphery pre-commit fastlane

# Init Xcode project (jika belum ada)
if [ ! -f "$PROJECT_NAME.xcodeproj/project.pbxproj" ]; then
    echo "Create project di Xcode dulu, lalu jalankan script ini."
    exit 1
fi

# Setup xcconfig
mkdir -p Configurations
cat > Configurations/Base.xcconfig << EOF
PRODUCT_BUNDLE_IDENTIFIER = $BUNDLE_ID
DEVELOPMENT_TEAM = $TEAM_ID
SWIFT_VERSION = 5.0
IPHONEOS_DEPLOYMENT_TARGET = 17.0
EOF

cat > Configurations/Debug.xcconfig << EOF
#include "Base.xcconfig"
SWIFT_OPTIMIZATION_LEVEL = -Onone
ENABLE_TESTABILITY = YES
GCC_PREPROCESSOR_DEFINITIONS = \$(inherited) DEBUG=1
BASE_URL = https://api-dev.myapp.com
EOF

cat > Configurations/Release.xcconfig << EOF
#include "Base.xcconfig"
SWIFT_OPTIMIZATION_LEVEL = -O
SWIFT_COMPILATION_MODE = wholemodule
STRIP_INSTALLED_PRODUCT = YES
BASE_URL = https://api.myapp.com
EOF

# Setup SwiftLint
cat > .swiftlint.yml << 'EOF'
opt_in_rules:
  - force_unwrapping
  - empty_string
  - first_where
  - sorted_first_last

disabled_rules:
  - trailing_whitespace

line_length:
  warning: 120
  error: 200
  ignores_comments: true

excluded:
  - Pods
  - .build
  - Packages
EOF

# Setup SwiftFormat
cat > .swiftformat << 'EOF'
--indent 4
--allman false
--wraparguments before-first
--maxwidth 120
--self init-only
--commas always
--semicolons never
--emptybraces no-space
--linebreaks lf
--enable isEmpty
--enable sortedImports
--enable unusedArguments
--exclude Pods,.build,Packages
EOF

# Setup Makefile
cat > Makefile << 'MAKEOF'
.PHONY: setup lint format test clean ci

setup:
	brew install swiftlint swiftformat pre-commit
	pre-commit install

lint:
	swiftlint --strict

format:
	swiftformat .

lint-ci:
	swiftlint --strict && swiftformat . --lint

test:
	xcodebuild test \
		-project *.xcodeproj \
		-scheme $(shell ls *.xcodeproj | head -1 | sed 's/.xcodeproj//') \
		-destination "platform=iOS Simulator,name=iPhone 15 Pro" \
		-quiet

clean:
	rm -rf build/ DerivedData/

ci: lint-ci test
	@echo "✓ CI passed"
MAKEOF

# Setup pre-commit
cat > .pre-commit-config.yaml << 'EOF'
repos:
  - repo: local
    hooks:
      - id: swiftlint
        name: SwiftLint
        entry: swiftlint
        language: system
        types: [swift]
      - id: swiftformat
        name: SwiftFormat
        entry: swiftformat
        args: [--lint]
        language: system
        types: [swift]
EOF

pre-commit install

# Setup Fastlane
fastlane init <<< "2"  # Option 2: automate App Store distribution

# Setup Periphery
periphery setup

# Git ignore additions
cat >> .gitignore << 'EOF'

# Fastlane
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots/**/*.png
fastlane/test_output
fastlane/*.cer
fastlane/*.p12

# Build artifacts
build/
*.xcarchive
*.ipa
*.dSYM.zip
EOF

echo ""
echo "✅ $PROJECT_NAME setup complete!"
echo ""
echo "Next steps:"
echo "  1. Set xcconfig di Xcode Build Settings"
echo "  2. Configure Fastlane Match: fastlane match init"
echo "  3. Setup Xcode Cloud di Xcode → Product → Xcode Cloud"
echo "  4. Add BASE_URL ke Info.plist: BASE_URL = \$(BASE_URL)"

Use Case 2: CI Pipeline di GitHub Actions (Alternatif Xcode Cloud)

swift
# .github/workflows/ios-ci.yml

name: iOS CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  lint:
    name: Code Quality
    runs-on: macos-15
    steps:
      - uses: actions/checkout@v4
      
      - name: Install SwiftLint
        run: brew install swiftlint swiftformat
        
      - name: SwiftLint
        run: swiftlint --strict
        
      - name: SwiftFormat
        run: swiftformat . --lint

  test:
    name: Unit Tests
    runs-on: macos-15
    needs: lint
    steps:
      - uses: actions/checkout@v4
      
      - name: Select Xcode
        run: sudo xcode-select -s /Applications/Xcode_16.3.app
        
      - name: Cache SPM
        uses: actions/cache@v4
        with:
          path: .build
          key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}
          
      - name: Run Tests
        run: |
          xcodebuild test \
            -project MyApp.xcodeproj \
            -scheme MyApp \
            -destination "platform=iOS Simulator,name=iPhone 16 Pro,OS=18.4" \
            -resultBundlePath TestResults.xcresult \
            | xcpretty --report junit --output test-results.xml
            
      - name: Upload Test Results
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: test-results
          path: test-results.xml

  build:
    name: Build Archive
    runs-on: macos-15
    needs: test
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.3'
          bundler-cache: true
          
      - name: Install Fastlane
        run: bundle install
        
      - name: Import Certificates
        env:
          CERTIFICATES_P12: ${{ secrets.CERTIFICATES_P12 }}
          CERTIFICATES_PASSWORD: ${{ secrets.CERTIFICATES_PASSWORD }}
          PROVISIONING_PROFILE: ${{ secrets.PROVISIONING_PROFILE }}
        run: |
          echo "$CERTIFICATES_P12" | base64 --decode > cert.p12
          security import cert.p12 -P "$CERTIFICATES_PASSWORD" \
            -k ~/Library/Keychains/login.keychain-db -T /usr/bin/codesign
            
      - name: Build & Upload to TestFlight
        env:
          APP_STORE_CONNECT_API_KEY: ${{ secrets.ASC_API_KEY }}
        run: bundle exec fastlane beta
        
      - name: Upload dSYMs
        run: ./Scripts/upload_dsyms.sh build/MyApp.xcarchive

Use Case 3: Otomasi Deteksi Performa Regression

Script yang dijalankan nightly untuk mendeteksi penurunan performa build.

swift
#!/bin/bash
# scripts/check_build_performance.sh
set -e

PROJECT="MyApp.xcodeproj"
SCHEME="MyApp"
THRESHOLD_SECONDS=180  # Alert jika build > 3 menit
LOG_FILE="/tmp/build_timing.log"

echo "Building $SCHEME..."
START=$(date +%s)

xcodebuild build \
  -project "$PROJECT" \
  -scheme "$SCHEME" \
  -configuration Debug \
  -destination "platform=iOS Simulator,name=iPhone 15 Pro" \
  -derivedDataPath /tmp/BuildTimingDerivedData \
  clean build \
  2>&1 | tee "$LOG_FILE" | grep -E "error:|warning:|Build complete"

END=$(date +%s)
DURATION=$((END - START))
echo "Build time: ${DURATION}s"

# Simpan ke history
echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) $DURATION" >> build_times.log

# Alert jika melebihi threshold
if [ $DURATION -gt $THRESHOLD_SECONDS ]; then
    # Cari fungsi dengan compile time paling lama
    grep "expression took" "$LOG_FILE" | sort -t= -k2 -rn | head -10
    
    echo "⚠️ Build time ${DURATION}s melebihi threshold ${THRESHOLD_SECONDS}s!"
    
    # Kirim notifikasi (Slack, email, dll)
    if [ -n "$SLACK_WEBHOOK" ]; then
        curl -X POST "$SLACK_WEBHOOK" \
          -H "Content-Type: application/json" \
          -d "{\"text\": \"⚠️ Build time regression: ${DURATION}s (threshold: ${THRESHOLD_SECONDS}s)\"}"
    fi
    exit 1
fi

echo "✓ Build time ${DURATION}s OK (threshold: ${THRESHOLD_SECONDS}s)"