- Что такое CI (непрерывная интеграция)
- Процессы CI
- Контроль тестового покрытия
- Что такое CD (непрерывная доставка)
- Инструменты CI/CD
В конечном счете, цель всякого ИТ-проекта — автоматизация бизнес-процессов.
И чем быстрее получится релиз новой версии, тем выгоднее компании.
Как ускорить релиз? Все можно делать вручную, при желании достаточно быстро. Например, подключиться к удаленному серверу через SSH, клонировать репозиторий с новым кодом, сделать билд, запустить его из командной строки. Это все еще работает, но это плохой подход.
Сегодня обсудим автоматизацию релизов и самого процесса разработки, при помощи общепринятого сейчас подхода — CI/CD.
CI означает Continuous Integration (Непрерывная Интеграция) кода; CD — (Continuous Delivery) Непрерывная Доставка кода.
Что такое CI (непрерывная интеграция)
Непрерывная интеграция — это процесс, заключающийся в практически непрерывном потоке — потоке внесения изменений в код репозитория. Посмотрим на простую схему, это условный пример работы CI.

Выделенная на задачу группа людей одновременно вносит правки в код. В конечном счете все изменения вливаются в основную, master-ветку.
Даже в такой простой модели могут возникнуть вопросы:
- Как гарантировать, что код, отправленный в master-ветку, точно скомпилируется?
- У нас принято, чтобы разработчики писали тесты своего кода. Как гарантировать, что покрытие не снизилось в результате постоянных изменений?
- Все участники команды должны придерживаться одного стиля написания кода. Как контролировать возможные отклонения от гайдлайнов?
Конечно, все описанные выше требования могут контролироваться вручную. Но такой подход “рыхлый” и весьма затратный по времени. И становится вообще нереальным, когда команда состоит из многих десятков и сотен человек.
CI-подход придумали, чтобы автоматизировать описанный выше контроль.
Начнем с первого пункта в списке. Как проверим, что новые правки изменения не сломают билд? Для этого вводим еще один блок в нашу схему.

CI-процессы, или по крайней мере бОльшая часть, работают по такому алгоритму:
- При открытии каждого Pull Request, Git-сервер отправляет уведомление CI-серверу.
- CI-сервер клонирует репозиторий, проверяет исходную ветку (например bugfix/wrong-sorting), и сливает код с кодом master-ветке.
- Тогда запускается билд-скрипт (сценарий сборки). Например ./gradlew build.
- Если эта команда возвращает код ответа “0”, то билд успешно выполнен. (Другой ответ означает ошибку).
- CI-сервер направляет уведомление об успешном билде на Git-сервере.
- Если билд был успешен, то Pull Request разрешается слить с существующим кодом. (Если не успешен, то, соответственно, не разрешается).
Такой процесс гарантирует, что любой код, отправляемый в master-ветку, не сломает следующие билды.
Контроль тестового покрытия
Теперь усложняем задачу. Представим, что надо удерживать некое минимальное покрытие кода тестами. Например, в любой момент покрытие кода master-ветки не должно опускаться ниже 50%. Такую проблему иногда помогает решать, например, плагин Jacoco, просто настраиваешь его на “непропуск” билда, если покрытие упало ниже какого-то уровня.
Но здесь есть ограничение. Такой плагин может работать только если плагин был поставлен и настроен на старте проекта.
Представим, что работаем на проекте с пятилетней историей. Тогда несколько разработчиков просто писали код и отправляли его, проверки покрытия не было. Тестировщики тестировали код рандомно, без какой-либо системности. Но в один день руководство решило увеличить количество тестов, и покрытие. Поставлен плагин Jacoco, и настроен на минимальное покрытие 60%. Потом какой-то разработчик открывает новый Pull Request, при этом оказывается, тестовое покрытие лишь 30%. В такой ситуации, чтобы успешно “закрыть задачу”, надо обязательно покрыть тестированием как минимум еще 30% всей кодовой базы. Это практически невыполнимая задача, для проекта начатого 5 лет назад.
А что, если будем проверять (валидировать) только новый, приходящий код, а не весь проект? Если разработчик изменил 200 строк за один свой Pull Request, тестировщикам надо покрыть как минимум 120 строк (если целевое покрытие мы ставили 60%). И нам совсем необязательно трогать код во всех модулях, не касающихся текущей задачи. Надо подходить как-то избирательно, и есть способы как это сделать изящнее: тот же SonarCloud.

Сервер собирает статистику оценок покрытия; оценивает покрытие с учетом приходящих дополнений, и всего кода. Затем анализ отправляется на CI-сервер, который переправляет его на Git-сервер.
Этот процесс позволяет привить команде, скажем так, “культуру обязательного тестирования” на любой стадии продукта, потому что проверяются только новые правки.
С точки зрения стиля кода, процессы примерно такие же. Можно посмотреть на плагин Checkstyle. Он автоматически “фейлит” билд, нарушающий прописанное требование; например, не пропускает билд, если в коде есть неиспользованный импорт библиотек. Потом, можно пробовать облачные сервисы анализа кода, которые удобно выводят результат графически (так же выводит и SonarCloud).
Что такое CD (непрерывная доставка)
А вот термин Непрерывная доставка описывает процесс автоматического деплоя (развертывания, или еще называют автодеплоя) новых версий продукта.
Давайте теперь внесем еще изменения в схему CI выше. Так процесс CI/CD выглядит в более-менее крупном реальном проекте.

“CI-сервер” теперь у нас будет называться “CI/CD-сервер”. Это потому что наши задачи в рамках подходов CI и CD — теперь выполняются одним таск-менеджером. Рассмотрим такой комбинированный подход.
Впрочем бывают исключения; например, команды могут делегировать CI-задачи в GitLab CI, а CD-задачи в Jenkins.
Итак, в правой части схемы у нас CI, который мы обсудили выше. Слева у нас CD. CD-задача у нас это билд проекта (или отработка артефактов, возникших на CI-этапе), и деплой ее на сервер.
Надо отметить, что “сервер” выше — это абстракция. Например, деплой может быть делегирован такой вещи как кластер Kubernetes. То есть, строго говоря, может быть и несколько серверов.
После завершения этапа деплоя, обычно отправляются email-уведомления. CD-сервер уведомляет подписчиков об успешном (или нет) деплое.
И вот здесь возникает важный вопрос: когда начинать CD-таски? Триггеры на это могут быть разные:
- Деплой после каждого Pull Request на слияние (merge) кода.
- Деплой по расписанию.
- Деплой после каждого слияния по Pull Request-у в какую-то ветку.
- Или комбинация этих опций.
Первый пункт определяет процессы так, что CI и CD таски всегда идут последовательно, один за другим. Этот подход более популярен в опенсорсной разработке. При этом используют библиотеки типа Semantic Release.
Важно чётче понимать понятие развертывания (деплоя). Оно необязательно означает, что “что-то где-то запускается”. Если вы пишете какую-то библиотеку, там нет “запуска”. В таком случае “деплой” означает “выпуск новой версии библиотеки”.
Второй пункт у нас “независим” от CI-процесса, поскольку проект деплоится по расписанию. Например каждый день в час ночи.
Третий пункт похож на первый. Хотя есть разница. Представим, что есть две главные ветки в репозитории: develop и master. В ветке develop у нас самые релевантные изменения. А в master — только релизы. Если нам нужно деплоить только master-ветку, нам нет необходимости запускать CD-задачу на слияние в develop.
Последний пункт — это комбинированный подход. Например, develop-ветка может деплоиться по расписанию, в dev-окружение. А master деплоится в продакшен по каждому Pull Request-у на слияние.
Инструменты CI/CD
На рынке — десятки решений автоматизации CI/CD. Самые важные, которыми желательно владеть
- Jenkins. Один из самых важных CI/CD-инструментов, может быть самый важный. Популярен потому что бесплатный и опенсорсный, то есть за него не надо платить. Jenkins позволяет прописывать билд-пайплайны на языке Groovy. С одной стороны, это дает больше гибкости. А с другой, отличается высоким порогом вхождения.
- GitHub Actions. Инструменты для CI/CD интегрированы в GitHub и GitHub Enterprise. В отличие от Jenkins, GitHub Actions это “декларативные” билды с YAML-конфигурацией. Помимо того, решение имеет множество интеграций с разными полезными-удобными инструментами контроля качества кода (Quality Assurance Systems — тот же SonarQube). Поэтому билд-скрипт можно написать буквально в несколько строк кода.
- GitLab CI. довольно похож на GitHub Actions. Но есть и отличительные особенности. Например Gitlab CI может указывать на отдельные тесты, вызывающие падение билда.
- Travis CI. Облачное решение. Много возможностей, не требующих сложной настройки. Например, шифрование данных, которые надо размещать в публичном репозитории. Кроме того, бонус — Travis CI можно применять в публичных опенсорсных проектах на GitHub, GitLab и BitBucket абсолютно бесплатно.
***
Возможно также будет интересно:
Chrome Developer Tools для тестировщика