Основная цель любого проекта по разработке ПО – получить прибыль за счет автоматизации бизнес-процессов. Чем быстрее вы начнете выпускать новые версии, тем лучше для компании. Но как же научиться выпускать новые версии максимально быстро? Конечно же, все можно делать вручную. Например, подключить удаленный сервер через SSH, клонировать клонировать репозиторий с новым кодом, собрать его и запустить через командную строку. Да, такой способ работает, но он малоэффективен. Сегодня мы поговорим об автоматизации процесса разработки и выхода новых версий.
CI и CD – это два сокращения, которые означают Continuous Integration (Непрерывная интеграция) и Continuous Delivery (Непрерывное развертывание).
CI описывает процесс добавления изменений в репозиторий. Ниже схематически представлен простой пример коллективной разработки.
Одновременно может работать целая группа людей, но все изменения передаются в главную ветку master
поэтапно. Хотя даже в такой простой схеме возникает несколько вопросов.
master
, компилируется?Конечно же, все это можно проверить вручную. Но такой подход весьма хаотичен. Кроме того, по мере разрастания команды выполнять подобные проверки становится сложнее.
CI используется для автоматизации выше обозначенных пунктов.
Начнем с первого пункта. Как можно проверить, что новые изменения не сломают сборку? Для этого нам потребуется еще один блок в схеме.
Большинство CI-процессов можно описать по следующему алгоритму.
bugfix/wrong-sorting
) и сливает ее с основной веткой master
../gradlew build
.Данный процесс гарантирует, что код, попадающий в ветку master
, не сломает дальнейшие сборки.
Давайте немного усложним задачу. Предположим, нам захотелось установить минимальный охват тестового покрытия. Это означает, что в любой момент времени покрытие ветки master
должно быть не менее 50%. Плагин Jacoco идеально справляется с этой задачей. Вы просто настраиваете его так, чтобы при охвате тестового покрытия ниже допустимого, сборка уходила в ошибку.
Реализовать такой подход проще некуда. Но есть небольшая оговорка. Этот метод работает только при условии, что плагин настраивался на старте проекта.
Представим ситуацию: вы работаете над проектом, которому уже 5 лет. С момента первого коммита никто не проверял тестовое покрытие. Разработчики добавляли тесты в случайном порядке и без какой-либо организации. Но вот однажды вы решаете увеличить количество тестов. Вы настраиваете плагин Jacoco на минимальную планку в 60%. Спустя какое-то время разработчик открывает новый Pull Request. Затем разработчики вдруг понимают, что покрытие – всего лишь 30%. Так что для успешного закрытия задачи нужно покрыть не менее 30% кода продукта. Как вы можете догадаться, для проекта 5-летней давности – это практически неразрешимая проблема.
Но что, если будут проверяться только будущие изменения в коде, а не весь продукт? Если в Pull Request разработчик изменит 200 строк, то нужно будет охватить не менее 120 из них (при тестовом покрытии в 60%). Тогда не придется проходить по множеству модулей, которые не относятся к задаче. В принципе, проблема решаема. Но как применить все это к проекту? К счастью, есть решение.
Отчет Jacoco отправляется на сервер тестового покрытия.
Одно из самых популярных решений – SonarCloud.
Сервер хранит статистику по предыдущим вычислениям. Это очень удобно: вычислять тестовое покрытие не только всего кода, но и будущих изменений. Затем результат анализа отправляется на CI-сервер, который перенаправляет его на Git-сервер.
Такая рабочая модель позволяет применять культуру обязательного тестирования на любой стадии развития продукта, поскольку проверяется лишь часть изменений.
Если говорить о стиле оформления кода, то отличий практически нет. Можете попробовать плагин Checkstyle. Он автоматически отклоняет сборку, которая нарушает любое из заявленных требований. Например, в коде есть неиспользованный импорт. Кроме того, вы можете присмотреться к облачным сервисам, которые выполняют анализ кода и визуально отображают результаты в виде графиков (SonarCloud это тоже умеет).
CD описывает процесс автоматического развертывания новой версии продукта.
Давайте еще немного подкорректируем схему CI. Вот так конвейерный процесс CI/CD мог бы выглядеть в реальном проекте.
Первое отличие – теперь CI-сервер называется CI/CD-сервером. Дело в том, что зачастую оба процесса (CI и CD) выполняются одним и тем же диспетчером задач. Так что мы будем рассматривать именно этот случай.
Но так бывает не всегда. Например, задачи по интеграции могут делегироваться на GitLab CI, а задачи по доставке – отдаваться в Jenkins.
Правая часть схемы изображает CI. Мы обсудили ее выше. Слева показана CD. Задача по CD создает проект (или повторно использует артефакты, полученные на стадии CI) и развертывает его на конечном сервере.
Стоит отметить, что сервер в нашем случае – это понятие абстрактное. Например, развертывание может выполняться в кластер Kubernetes. Так что самих серверов может быть несколько.
Обычно после стадии развертывания на почту приходят сообщения о выполнении. Например, CD-сервер может уведомлять подписчиков об успешном развертывании/ошибках.
В любом случае, возникает важный вопрос. В какой момент мы должны запускать задачи по CD? Триггеры могут быть разными.
В первом пункте процесс выстроен так, что задачи по CI и CD всегда выполняются последовательно. Данный подход весьма популярен при разработке программ с исходным кодом. Библиотека Semantic Release помогает настроить проект для прозрачной интеграции данной модели.
Важно помнить о трактовке понятия deploy (развертывание). Это не всегда «что-то где-то запустить». Например, при разработке библиотеки, нет никакого запуска. В данном случае процесс развертывания означает выпуск новой версии библиотеки.
Второй пункт не зависит от процесса CI, ведь проект развертывается по определенному расписанию. Например, ежедневно в 01:00.
Третий пункт аналогичен первому, но с небольшими отличиями. Предположим, в репозитории у нас есть 2 основные ветки: develop
и master
. В develop
содержатся самые последние изменения, а в master
– только релизы версий. Если мы хотим развертывать только ветку master
, то не нужно вызывать CD-задачу по слиянию в develop
.
Последний пункт – это сочетание подходов. Например, ветку develop
можно развертывать по расписанию в среду разработки. А ветку master
– в реальную среду по каждому слиянию Pull Request.
На рынке доступно множество решений по автоматизации процессов CI/CD. Ниже представлено несколько продуктов.