Continuous Integration (CI) — це практика розробки, за якої кожен учасник команди інтегрує свої зміни в загальний репозиторій мінімум раз на день, а кожна інтеграція перевіряється автоматичною збіркою та тестами. CI виявляє конфлікти коду та регресійні помилки на ранніх етапах, скорочуючи вартість їх виправлення. За даними Puppet State of DevOps Report, 2025, команди з CI виправляють баги в 4 рази швидше команд без автоматизації.
Головне
Continuous Integration (CI) — це методологія розробки, яка автоматизує процес інтеграції коду від кількох учасників у єдину кодову базу. Термін був введений Мартіном Фаулером на початку 2000-х як набір практик, що запобігають «пеклу інтеграції» — ситуації, коли розробники тижнями працюють ізольовано, а при злитті змін виникає безліч конфліктів, які потребують днів ручного вирішення.
Без CI розробник завершує фічу, намагається злити свої зміни з main-гілкою та виявляє, що колеги змінили ті самі файли. Вирішення конфліктів займає години та часто ламає робочий код. CI вирішує цю проблему примусовою інтеграцією кілька разів на день: чим частіше інтеграція, тим менше конфліктів і простіше їх вирішення. Практика показує, що при щоденній інтеграції вирішення конфлікту займає хвилини, а при щотижневій — години.
За даними IBM Systems Sciences Institute, вартість виправлення бага на етапі написання коду становить $25, на етапі тестування — $100, на етапі продакшну — $2 500. CI зсуває виявлення дефектів максимально вліво (shift left), виявляючи помилки на етапі коміту, коли їх виправлення практично безкоштовне. Команди з CI витрачають на налагодження в середньому 15% часу проти 35% у команд без CI.
Мартін Фаулер визначив ключові практики CI, які залишаються актуальними незалежно від стеку технологій. Дотримання цих принципів гарантує, що CI приносить користь, а не стає бюрократичним навантаженням. Мобільна розробка накладає додаткові вимоги, але ядро залишається незмінним.
Весь код проекту зберігається в одному репозиторії з єдиною системою контролю версій (Git). Єдине джерело правди виключає ситуацію, коли фіча розробляється у форку та не синхронізується з основною кодовою базою тижнями. У мобільних проектах це означає, що Android, iOS та backend-частини можуть знаходитися в одному репозиторії (монорепозиторій) або в окремих репозиторіях із загальною схемою версіонування.
Збірка проекту повинна виконуватися однією командою. Для Android це ./gradlew assembleDebug, для iOS — xcodebuild або fastlane build. Скрипт збірки перевіряє відтворюваність: збірка на CI-сервері повинна давати той самий результат, що й на машині розробника. Будь-які відмінності в середовищі усуваються контейнеризацією або IaC (Infrastructure as Code).
Після збірки виконуються всі рівні тестів: модульні, інтеграційні та UI. Якщо тести падають — коміт вважається невалідним. Підтримка зеленого статусу — загальна відповідальність команди. У мобільних проектах часто розділяють fast-тести (виконуються до 5 хвилин на кожен коміт) і slow-тести (UI-тести на реальних пристроях, запускаються рідше).
// Приклад юніт-тесту з CI-дружнім звітом
class LoginViewModelTest {
private val repository = mock<AuthRepository>()
private val viewModel = LoginViewModel(repository)
@Test
fun loginWithValidCredentials_success() {
val email = "test@example.com"
val password = "ValidPass123"
whenever(repository.login(email, password))
.thenReturn(Result.success(User("token-xyz")))
val result = viewModel.login(email, password)
assertEquals(LoginState.Success, result)
verify(repository).login(email, password)
}
}
Результати CI публічні для всієї команди: кожен бачить, чий коміт зламав збірку. Прозорість створює культуру відповідальності: розробники перевіряють свої зміни перед push-ем та фіксять зламану збірку поза чергою. CI-сервер надсилає сповіщення в Slack або Telegram при зміні статусу збірки.
Повноцінна CI-система складається з кількох компонентів, які взаємодіють один з одним. Кожен компонент відповідає за свою частину конвеєра: від запуску до звіту. Розуміння архітектури CI допомагає діагностувати проблеми та оптимізувати продуктивність.
Центральний компонент, який керує чергою збірок, розподілом ресурсів та публікацією результатів. CI-сервер може бути хмарним (GitHub Actions, GitLab CI, CircleCI) або self-hosted (Jenkins, TeamCity). Сервер відстежує зміни в репозиторії через webhook або polling та запускає пайплайн при кожному push-і або pull request.
Раннери — це віртуальні або фізичні машини, які виконують завдання збірки. У хмарних CI раннери надаються провайдером і оплачуються за часом використання. Self-hosted раннери встановлюються на власній інфраструктурі та потребують обслуговування. Для iOS-збірок необхідні macOS-раннери, для Android — Linux або Windows.
Після збірки CI-система зберігає артефакти (APK, IPA, звіти тестів) у сховищі — вони доступні для завантаження та деплою. Кешування залежностей (Gradle cache, CocoaPods cache) між запусками прискорює наступні збірки в 3–5 разів.
| Компонент | Призначення | Приклад |
|---|---|---|
| CI-сервер | Оркестрація збірок | Jenkins, GitHub Actions |
| Раннер | Виконання завдань | macOS-раннер для iOS |
| Репозиторій | Зберігання коду | GitHub, GitLab |
| Artifact storage | Зберігання артефактів | AWS S3, Artifactory |
| Notification | Сповіщення команди | Slack, Telegram, email |
Мобільна розробка висуває особливі вимоги до CI, відмінні від веб- або backend-проектів. Тривала збірка (3–15 хвилин для Android, 5–20 хвилин для iOS), кілька типів артефактів (APK, AAB, IPA), необхідність підписання та обфускації — все це потребує індивідуального налаштування CI-пайплайна.
Типовий CI для Android включає: лінтинг (ktlint, detekt) та статичний аналіз, юніт-тести з JUnit та MockK, збірку debug та release APK/AAB, інструментаційні тести на емуляторі всередині CI та публікацію артефактів. Gradle-кеш прискорює повторні збірки — без нього кожна збірка завантажує залежності заново, втрачаючи 3–5 хвилин.
iOS CI потребує macOS-раннера для компіляції Swift/Objective-C коду. Пайплайн включає: встановлення CocoaPods або SPM залежностей, SwiftLint для перевірки стилю, юніт-тести з XCTest, збірку IPA, підписання сертифікатами через Fastlane match та завантаження в TestFlight. Self-hosted раннер на Mac mini або Mac в дата-центрі — альтернатива хмарним macOS-раннерам.
Flutter та React Native компілюються в нативні білди для обох платформ. CI повинен підтримувати два раннери: Linux для Android-збірки та macOS для iOS-збірки. Оптимальна стратегія — роздільний пайплайн: Android-збірка на Linux-раннері, iOS-збірка на macOS-раннері, після чого обидва артефакти об’єднуються в єдиний реліз.
Вибір CI-інструменту залежить від розміру команди, необхідної продуктивності, бюджету та стеку технологій. Нижче наведено порівняння популярних рішень з акцентом на мобільну розробку. Self-hosted рішення дають контроль, але потребують адміністрування, хмарні — зручність, але обмежують конфігурацію.
Безкоштовний для публічних репозиторіїв (2000 хвилин/міс). GitHub Actions пропонує екосистему готових actions для Android (gradle/actions) та iOS (apple-actions). Мінус — macOS-раннери доступні тільки на платних тарифах. Ідеальний для Open Source та невеликих команд, які вже використовують GitHub.
Self-hosted CI-сервер з відкритим вихідним кодом. Jenkins налаштовується через Groovy Pipeline, підтримує сотні плагінів та працює на будь-якому залізі. Потребує DevOps-інженера для встановлення та підтримки. Популярний в enterprise-сегменті, де критичний контроль над інфраструктурою.
Вбудований CI/CD в GitLab з відкритою runner-архітектурою. GitLab CI дозволяє використовувати власні раннери (включаючи macOS) на безкоштовному тарифі. YAML-конфігурація потужніша за GitHub Actions, але складніша в освоєнні. Підходить для команд, які використовують GitLab як єдину платформу DevOps.
Хмарний CI з акцентом на швидкість. CircleCI підтримує Docker, macOS та Android образи, автоматично кешує залежності. Ціноутворення покредитне — дорожче GitHub Actions для невеликих команд, але швидше за рахунок оптимізованих раннерів. Рекомендується для продакшн-проектів з вимогою до швидкості.
Розглянемо налаштування CI для Android-проекту з використанням GitHub Actions. Пайплайн виконує статичний аналіз, збірку та тестування при кожному push-і та pull request в main-гілку. Мінімальна конфігурація займає 15 хвилин та не потребує зовнішніх сервісів.
name: Android CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: 17
distribution: temurin
- run: ./gradlew ktlintCheck detekt
unit-tests:
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: 17
distribution: temurin
- uses: gradle/actions/setup-gradle@v4
- run: ./gradlew testDebugUnitTest
- uses: actions/upload-artifact@v4
with:
name: test-results
path: app/build/reports/tests/
Пайплайн складається з двох паралельних джоб: lint (виконує статичний аналіз) та unit-tests (залежить від lint — якщо лінтинг не пройшов, тести не запускаються). Джоба unit-tests завантажує звіт про тести як артефакт — команда може переглянути його в GitHub Actions UI, не завантажуючи файли локально.
Щоб уникнути падіння CI через тривіальні помилки, налаштуйте pre-push hook в Git або Gradle task, який запускає ті самі перевірки локально. Наприклад: ./gradlew ktlintCheck detekt testDebugUnitTest. Якщо local checks займають більше 3 хвилин — розділіть їх на швидкі (лінтер) та повільні (тести), запускаючи швидкі перед кожним комітом, а повільні — тільки перед push-ем.
Часті запитання
CI фокусується на інтеграції та верифікації коду (збірка + тести), а CD додає автоматизацію деплою. CI перевіряє, що код коректний; CD гарантує, що цей коректний код може бути доставлений користувачам. CI — передумова для CD, але CD без CI не працює.
Мінімальна частота — раз на день на розробника. Ідеальна практика — push в репозиторій при кожній завершеній логічній одиниці роботи (кожні 1–4 години). Чим частіше інтеграція, тим менше конфліктів і простіше їх вирішення. Якщо між інтеграціями проходить більше 2 днів — ви не використовуєте CI.
Для Android оптимальний GitHub Actions (безкоштовний, простий у налаштуванні) або GitLab CI (власні раннери). Для iOS — CircleCI (найкраща підтримка macOS) або Bitrise (спеціалізований CI для мобільних проектів). Для крос-платформенних — GitLab CI з двома раннерами (Linux + macOS).
Так, але із застереженнями. UI-тести повільні (10–30 хвилин) та нестабільні (flaky). Оптимальна стратегія: запускати швидкі (юніт + інтеграційні) на кожен push, а UI-тести — на pull request, вночі або перед релізом. Використовуйте Device Farm або емулятори в CI для UI-тестів.
Метрики ефективного CI: час збірки менше 15 хвилин, відсоток зелених збірок більше 85%, середній час відновлення після падіння менше 30 хвилин. Якщо збірка часто падає — CI не допомагає, а заважає. Перегляньте тести: прибирайте flaky тести, оптимізуйте залежності, скорочуйте час збірки.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також