Организация хранения кода в GitLab и интеграция код ревью в GitFlow
Не так давно на одном из проектов нашей компании было принято решение наконец отказаться от использования Subversion для хранения и версионирования кода в пользу Git.
Основными целями перехода были следующие:
- Повышение прозрачности процесса разработки.
- Внедрение обязательной процедуры код ревью до выноса обновлений на тестовые среды.
- Внедрение непрерывной интеграции для сборки обновлений после код ревью и установки их на тестовые среды.
Обязательным условием для достижения поставленных целей было использование GitLab (этот сервер Git уже использовался у заказчика и там даже уже жил код, относящийся к фронтовой части решения) и Jira (также уже использовалась у заказчика).
В качестве целевой модели разработки было предложено использовать Git Flow, добавив в неё процедуру код ревью. Данная модель разработки де факто стала стандартом в разработке программного обеспечения с открытым исходным кодом и используется большинством гигантов индустрии. Именно поэтому её поддержка встроена во многие популярные средства работы с Git. На тему его использования написано большое количество материалов, приведу наиболее удачные из них для первоначального ознакомления: раз и два.
Сама по себе эта модель предлагает лишь общие принципы ведения кода, оставляя за рамками процессы, сопутствующие его написанию. Поэтому реализация всего остального, в том числе код ревью, зависит от конкретного сервера Git. В этом плане наиболее удобен GitHub: он изначально строился как платформа для совместной работы большого количества независимых разработчиков и позволяет ограничивать права на отправку коммитов (Push) в репозитории с возможностью создания запросов на отправку кода. Помимо этого, GitLab предлагает свой рабочий процесс для ведения кода под названием GitLab Flow, заточенный под использование GitLab CI. Поэтому в GitLab функционал по созданию запросов на отправку кода не реализован и для проведения ревью кода изменений предлагается использовать запросы на слияние веток. Для сборки и установки артефактов на проекте уже использовался Jenkins, позволяющий гибко создавать и настраивать задачи сборки и развёртывания, и на GitLab CI было решено не переходить, попутно отбросив идею использования GitLab Flow.
Также отмечу, что для проекта были настроены интеграции в Jira и Git. В Jira в плагине Git был добавлен для отслеживания репозиторий, созданный для хранения исходного кода, а в GitLab у данного репозитория была настроена интеграция с Jira в разделе «Интеграции» репозитория.
Для решения данной задачи был разработан рабочий процесс для работы с кодом, по своей структуре схожий с Git Flow, но позволяющий производить ревью кода при каждом выносе изменений в основные ветки процесса (develop, release-n и master) средствами GitLab. Далее будет описан получившийся процесс, а также смежные с ним этапы непрерывной интеграции и доставки ПО на стреды. В скобках приведены соответствующие команды для выполнения.
Репозиторий, созданный для хранения исходного кода, выкачивается в локальный репозиторий (git clone) и в нём инициализируется Git Flow (git flow init) — помимо ветки master (для создания тегов с целью хранения стабильных релизов) создаётся ветка develop (основная ветка разработки, в которую интегрируются ветки функций, релизов и исправлений), задаются маски для веток функций, релизов и исправлений, а также совершается переход в ветку develop.
Далее в рабочую копию переносится актуальная ветка исходного кода из Subversion, производится коммит кода (git add -A + git commit -m «Commit message») в ветку develop локального репозитория и его загрузка в удалённый репозиторий (git push origin develop). После этого можно начинать разрабатывать новый функционал, используя Git для версионирования кода.
При разработке загружается актуальная версия ветки develop и из неё создаются ветки для разработки новых функций (git flow feature start MYFEATURE) в соответствии с кодами задач Jira, в рамках которых ведётся разработка.
Автоматически производится переход в созданную ветку (git checkout MYFEATURE), запланированный функционал разрабатывается и изменения коммитятся в локальную ветку MYFEATURE (git commit -m «Commit message»). Заметим, что для корректной интеграции Git и Jira в сообщениях коммитов следует указывать код задачи в Jira, к которой это исправление относится. Тогда данные коммиты будут отображаться в соответствующих им задачах, а также в разделе «Коммиты Git» проекта, с помощью которого однозначно можно установить, что вошло в тот или иной релиз.
Когда функционал выбранной задачи разработан и готов к выносу на среду тестирования, производится загрузка созданных коммитов в удалённую ветку с аналогичным названием (git push -u origin MYFEATURE) и на тимлида разработки или исполняющего его обязанности заводится запрос на слияние загруженной ветки с веткой develop.
Для запроса на слияние разработчик разрешает конфликты слияния (в случае их наличия) и тимлид разработки (или и.о.) производит code review, в ходе которого возможно создание дополнительных коммитов (git commit -m «Commit message») с исправлениями замечаний, полученных в ходе ревью кода, в ветке с новым функционалом и их отправка в центральный репозиторий (git push -u origin MYFEATURE). После успешного завершения ревью тимлид разработки (или и.о.) подтверждает слияние веток. Здесь не лишним является установка флага удаления ветки после слияния — в противном случае количество веток может быстро разрастись до неприличных масштабов.
Чтобы обеспечить непрерывную интеграцию в репозитории GitLab, в разделе «Интеграции» настраивается Web Hook, который осуществляет вызов в Jenkins задачи для сборки и установки нового функционала на тестовую среду. Jenkins с помощью плагина для работы с Git выкачивает исходный код, получает из него название задачи и с помощью API Jira запрашивает список компонентов, которые были изменены и должны быть собраны, запускает процесс сборки, осуществляет прогон Unit тестов и при их удачном прохождении загружает созданные артефакты в Sonatype Nexus и устанавливает их на тестовую среду. Если же на одном из этапов произошёл сбой или Unit тесты завершаются неудачей, то с помощью плагина для Telegram команда разработки оповещается об исходе сборки. Если же установка прошла успешно, то команда QA оповещается о готовности задачи к тестированию.
Если появляются дефекты, то производится загрузка актуальной версии ветки develop и от коммита слияния ветки MYFEATURE с веткой develop создаётся ветка hotfix-MYFEATURE (git checkout [BASECOMMIT] -b hotfix-MYFEATURE).
При создании автоматически производится checkout в созданную ветку, вносятся исправления и изменения коммитятся в локальную ветку hotfix-MYFEATURE (git commit hotfix-MYFEATURE -m «Commit message»). Когда исправление закончено и готово к выносу на среду тестирования, производится их пуш в удалённую ветку с аналогичным названием (git push -u origin hotfix-MYFEATURE) и создаётся запрос на слияние с веткой develop.
Для запроса на слияние разработчик разрешает конфликты слияния (в случае наличия) и производится code review, в ходе которого возможно создание дополнительных коммитов с исправлениями полученных замечаний. После успешного завершения ревью производится слияние веток. Сразу после переноса исправления в ветку develop также срабатывает Web Hook для вызова задачи в Jenkins для сборки, прогона Unit тестов, загрузки созданных артефактов в Sonatype Nexus и установки исправления на тестовую среду. Для исправлений работает аналогичный механизм оповещений.
Если все дефекты исправлены, то производится загрузка актуальной версии ветки develop и от коммита слияния ветки hotfix-MYFEATURE с веткой develop создаётся ветка release-m.n (git flow release start RELEASENAME [BASECOMMIT]).
Создание релизной ветки также инициализирует запуск Web Hook для вызова задачи в Jenkins, которая выкачивает исходный код из Git, получает из него название релизной ветки и с помощью API Jira запрашивает список компонентов, которые были изменены в рамках задач релиза, выкачивает актуальные версии из Sonatype Nexus и устанавливает их на среду регрессионного тестирования. Вслед за установкой релиза на среду регрессионного тестирования запускаются скрипты подготовки среды к тестированию (перезапуск приложений, очистка БД и пр.) и производится прогон регрессионных автотестов для проверки работы основного функционала системы, по результатам которого формируется отчёт с помощью плагина Allure Reports для Jenkins. После установки команда QA оповещается в Telegram о результатах прогона автотестов и готовности релиза к ручному регрессионному тестированию.
Если в ходе регрессионного тестирования появляются дефекты, то производится загрузка актуальной версии ветки release-m.n и от последнего коммита создаётся ветка hotfix/BUGNAME по имени дефекта в Jira (git checkout -b hotfix/BUGNAME [BASECOMMIT]).
Автоматически производится checkout в созданную ветку, вносятся необходимые исправления и изменения коммитятся в локальную ветку hotfix/BUGNAME (git commit hotfix/BUGNAME -m «Commit message»). Когда исправление закончено и готово к выносу на среду регрессионного тестирования, производится их пуш в удалённую ветку с аналогичным названием (git push -u origin hotfix/BUGNAME) и создаётся запрос на слияние с веткой release-m.n.
Для запроса на слияние разработчик разрешает конфликты слияния (в случае наличия) и производится code review, в ходе которого возможно создание дополнительных коммитов с исправлениями замечаний, полученных в ходе ревью кода. Эти коммиты также производятся в локальную ветку hotfix/BUGNAME (git commit hotfix/BUGNAME -m «Commit message») и производится их пуш в удалённую ветку с аналогичным названием (git push -u origin hotfix/BUGNAME). После успешного завершения ревью производится слияние веток. Слияние инициализирует запуск Web Hook для вызова задачи в Jenkins, аналогичной предыдущей, но отличающейся тем, что она выкачивает код из Git, получает из него название дефекта, с помощью API Jira запрашивает список компонентов, которые были изменены в рамках исправления, собирает эти компоненты, загружает в Sonatype Nexus и устанавливает их на среду регрессионного тестирования. Далее по аналогии производится подготовка среды к автотестированию, прогон регрессионных автотестов и нотификация о его результатах.
Когда все дефекты исправлены, производится установка релиза на продуктивную среду. Для этого производится слияние ветки release-m.n с ветками develop и master, а также создаётся релизный тег.
При его создании инициализирует запуск Web Hook для вызова задачи в Jenkins, которая выкачивает исходный код из Git, получает из него номер релиза и с помощью API Jira запрашивает список задач, которые вошли в релиз и компонентов, которые были изменены в рамках этих задач, после чего выкачивает актуальные версии артефактов из Sonatype Nexus и устанавливает их на продуктивную среду.
С хотфиксами для прода было решено использовать процесс, аналогичный релизному — в противном случае теряются стадии тестирования выносимых изменений.
При внедерении процесса также было проведено обучение для сотрудников, не имеющих практики работы с Git и GitLab, для которого была разработана соответствующая программа обучения. С её помощью вы сами сможете проводить обучение по использованию Source Tree и Intellij IDEA для работы с Git, а также GitLab для проведения ревью кода. В следующем посте приведу её, дополнив иллюстрациями.