CI/CD для Swift проектов: настройка GitHub Actions

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в CI/CD для Swift проектов

Современная разработка мобильных и десктопных приложений на Swift требует не только качественного кода, но и надежного процесса интеграции и доставки. CI/CD (Continuous Integration / Continuous Deployment) — это практика, которая позволяет автоматизировать сборку, тестирование и развертывание приложений. Для Swift проектов, особенно под iOS и macOS, GitHub Actions является одним из самых удобных и популярных инструментов.

В этой статье мы разберем, как настроить полноценный CI/CD пайплайн для Swift проектов с использованием GitHub Actions. Вы узнаете, как автоматизировать сборку, запускать юнит-тесты и даже отправлять приложение в TestFlight или на Mac App Store.

Почему GitHub Actions для Swift?

GitHub Actions предоставляет встроенные возможности для работы с экосистемой Apple. В отличие от сторонних сервисов, он полностью интегрирован с репозиторием и не требует дополнительной настройки плагинов. Основные преимущества:

  • Бесплатные минуты для публичных репозиториев (до 2000 минут в месяц)
  • Готовые экшены для Xcode, SwiftLint, CocoaPods и SPM
  • Поддержка macOS раннеров с предустановленным Xcode
  • Гибкая настройка через YAML-файлы

Базовая настройка CI для Swift проекта

Начнем с простого пайплайна, который будет собирать проект и запускать тесты при каждом пуше в ветку main или при создании Pull Request.

Создайте файл .github/workflows/swift-ci.yml в корне репозитория:

name: Swift CI

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

jobs:
  build-and-test:
    runs-on: macos-latest
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Select Xcode version
      run: sudo xcode-select -s /Applications/Xcode_15.2.app
    
    - name: Build
      run: xcodebuild build -scheme MyApp -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 15,OS=17.2' | xcpretty
    
    - name: Run tests
      run: xcodebuild test -scheme MyApp -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 15,OS=17.2' | xcpretty

Этот workflow выполняет два основных шага: сборку проекта и запуск тестов. Обратите внимание на использование xcpretty — утилиты, которая форматирует вывод Xcodebuild в читаемый вид.

Дополнительная проверка качества кода

Добавим статический анализ с помощью SwiftLint. Это поможет поддерживать единый стиль кода в команде:

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: SwiftLint
      uses: norio-nomura/action-swiftlint@3.2.1
      with:
        args: --strict

Теперь при каждом коммите будет проверяться соответствие кода правилам SwiftLint. Если найдутся нарушения, workflow завершится с ошибкой.

Продвинутый CI/CD: тестирование и деплой

После базовой настройки можно перейти к более сложным сценариям. Рассмотрим пайплайн, который включает:

  • Сборку для нескольких симуляторов
  • Тестирование с покрытием кода
  • Автоматическую публикацию в TestFlight (для iOS) или Mac App Store

Сборка и тестирование с покрытием

Для сбора данных о покрытии тестами используйте флаг -enableCodeCoverage YES:

jobs:
  test-coverage:
    runs-on: macos-latest
    steps:
    - uses: actions/checkout@v4
    
    - name: Test with coverage
      run: |
        xcodebuild test \
          -scheme MyApp \
          -sdk iphonesimulator \
          -destination 'platform=iOS Simulator,name=iPhone 15,OS=17.2' \
          -enableCodeCoverage YES \
          -derivedDataPath Build/DerivedData | xcpretty
    
    - name: Upload coverage to Codecov
      uses: codecov/codecov-action@v3
      with:
        token: ${{ secrets.CODECOV_TOKEN }}
        directory: Build/DerivedData/Build/ProfileData

Автоматический деплой в TestFlight

Для публикации в TestFlight потребуется настроить App Store Connect API и сохранить ключи в секретах GitHub:

jobs:
  deploy-testflight:
    runs-on: macos-latest
    if: github.ref == 'refs/heads/release'
    steps:
    - uses: actions/checkout@v4
    
    - name: Install provisioning profiles
      run: |
        echo "${{ secrets.APPSTORE_CONNECT_KEY }}" > /tmp/AuthKey.p8
        xcodebuild -exportArchive \
          -archivePath Build/MyApp.xcarchive \
          -exportPath Build/export \
          -exportOptionsPlist ExportOptions.plist
    
    - name: Upload to TestFlight
      env:
        APP_STORE_CONNECT_USERNAME: ${{ secrets.APPSTORE_USERNAME }}
        APP_STORE_CONNECT_PASSWORD: ${{ secrets.APPSTORE_PASSWORD }}
      run: |
        xcrun altool --upload-app \
          -f Build/export/MyApp.ipa \
          -u "$APP_STORE_CONNECT_USERNAME" \
          -p "$APP_STORE_CONNECT_PASSWORD" \
          --type ios

Важно: Никогда не храните пароли и ключи в коде. Используйте GitHub Secrets (Settings → Secrets and variables → Actions).

Оптимизация и лучшие практики

Чтобы CI/CD работал быстро и надежно, следуйте этим рекомендациям:

  • Кэширование зависимостей: сохраняйте SPM-пакеты и Pods между запусками
  • Параллельные джобы: разделите линтинг, тестирование и сборку на разные jobs
  • Матрица тестирования: запускайте тесты на нескольких версиях iOS/macOS одновременно

Пример кэширования SPM

steps:
- uses: actions/cache@v3
  with:
    path: .build
    key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}
    restore-keys: |
      ${{ runner.os }}-spm-

- name: Resolve SPM packages
  run: xcodebuild -resolvePackageDependencies -scheme MyApp

Матрица для тестирования на разных устройствах

jobs:
  matrix-test:
    strategy:
      matrix:
        device: ['iPhone 15', 'iPad Pro (12.9-inch) (6th generation)']
        os: ['17.2', '16.4']                

Блоги

Рекомендаций по книгам