Ответ
Современный CI/CD для iOS часто строится на связке Fastlane и облачного CI-сервиса (например, GitHub Actions или Bitrise).
Основные этапы пайплайна:
- Триггер: Событие в системе контроля версий (push в ветку, pull request).
- Сборка зависимостей:
bundle install(для Fastlane) иpod install/xcodebuild -resolvePackageDependencies. - Тестирование:
# Fastlane lane run_tests( scheme: "MyApp", devices: ["iPhone 15"], output_directory: "./test_results" ) - Сборка артефакта:
# Сборка .ipa или .xcarchive build_app( scheme: "MyApp", export_method: "app-store", output_directory: "./build" ) - Распространение:
- Внутреннее тестирование: Загрузка в TestFlight (
upload_to_testflight) или Firebase App Distribution. - Бета-тестирование: Загрузка в сервисы вроде TestFlight для внешних тестеров.
- Продакшен: Автоматическая отправка в App Store Connect (
upload_to_app_store).
- Внутреннее тестирование: Загрузка в TestFlight (
Пример конфигурации GitHub Actions:
name: CI
on: [push]
jobs:
build-and-test:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Install Bundler Dependencies
run: bundle install
- name: Run Tests
run: bundle exec fastlane tests
- name: Build and Upload to TestFlight
if: github.ref == 'refs/heads/main'
run: bundle exec fastlane beta
Ключевые практики: Кеширование производных данных (DerivedData), инкрементальные сборки, параллельное выполнение тестов.
Ответ 18+ 🔞
Ну что за жизнь, блядь! Сидишь тут, втыкаешь в этот ваш CI/CD для iOS, а там, сука, одни заклинания: Fastlane, GitHub Actions, Bitrise... Ёперный театр, в рот меня чих-пых! Это ж надо было так всё усложнить, чтобы просто приложение собрать!
Смотри, как оно, блядь, обычно работает, этот твой "современный пайплайн", ага:
-
Триггер, блядь. Толкнул код в ветку — и понеслась. Или там пулл-реквест создал — всё, система уже проснулась и чешет репу.
-
Зависимости тянуть. Ну, это святое.
bundle install, чтобы Fastlane не взбрыкнул, иpod installилиxcodebuild -resolvePackageDependencies, чтобы все библиотеки на местах были. Без этого нихуя не соберётся, проверено. -
Тесты гонять. Ну тут всё понятно, надо убедиться, что твой гениальный код не развалил всё к хуям собачьим. В Fastlane это выглядит как-то так:
# Fastlane lane run_tests( scheme: "MyApp", devices: ["iPhone 15"], output_directory: "./test_results" )Сидит себе, тыкает в интерфейс на симуляторе, а ты в это время кофе пьёшь. Красота.
-
Собрать артефакт. Ну то есть само приложение,
.ipaили архив. Тоже магия простая:# Сборка .ipa или .xcarchive build_app( scheme: "MyApp", export_method: "app-store", output_directory: "./build" )Главное —
export_methodне перепутать, а то вместо тестовой сборки в продакшен попрёшь, и потом волнение ебать. -
И наконец, раскидать плоды трудов. Куда душа пожелает:
- Для своих — в TestFlight (
upload_to_testflight) или в Firebase App Distribution. Чтобы коллеги покликали и сказали "чё за хуйня?". - Для бета-тестеров — опять же в TestFlight, но уже для внешних. Пусть народ ловит баги за тебя.
- И наконец, в продакшен — прямиком в App Store Connect (
upload_to_app_store). Тут уже страшно, блядь. Нажал кнопку — и жди вердикта от яблочных богов.
- Для своих — в TestFlight (
А теперь, внимание, сюрприз! Вот тебе пример, как это всё в GitHub Actions выглядит, эта кухня под капотом:
name: CI
on: [push]
jobs:
build-and-test:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Install Bundler Dependencies
run: bundle install
- name: Run Tests
run: bundle exec fastlane tests
- name: Build and Upload to TestFlight
if: github.ref == 'refs/heads/main'
run: bundle exec fastlane beta
Видишь эту строчку if: github.ref == 'refs/heads/main'? Это, блядь, мудрость! Чтобы не палить каждую сборку с левой ветки в TestFlight, а только с главной. А то терпения ноль ебать у тестеров будет.
И запомни главные мантры умных людей: кеширование (чтобы каждый раз не ждать по часу), инкрементальные сборки (чтобы не пересобирать то, что не менялось) и параллельные тесты (чтобы не дохуя времени убивать). Без этого — просто дичь, а не CI/CD, ёпта.