Автоматизация наполнения Changelog через CI

—

от автора

В этой статье я постараюсь рассказать, как на моей работе я реализовал автоматическую генерацию Changelog из коммитов и создание тегов на их основе.

Предисловие

По мере роста количества микро-сервисов в нашей команде, какие-то общие куски кода мы стали выносить в отдельные репозитории (далее такие репозитории буду называть библиотеками), которые подключаются к проектам через composer.

Когда количество микро-сервисов было мало, для отслеживания истории изменений нам хватало истории коммитов. Со временем нашими библиотеками стали пользоваться и другие команды. Стали часто появляться вопросы, вида: «Подскажите, какую версию библиотеки нам нужно подключить, чтобы появился такой-то функционал?».

Стало очевидно, что история коммитов уже не отвечает запросам, и нужно искать более дружелюбное решение. Таким решением стало ведение файла Changelog в библиотеках, который по началу мы заполняли руками и присваивали руками теги с версиями.

Пожив так какое-то время у меня появилось желание как-то этот процесс автоматизировать. И спустя какое-то время на глаза попалась информация о генераторах changelog’а и соглашении о правилах оформления коммитов https://www.conventionalcommits.org/.

Реализация

Генератором, который попался мне на глаза, был проект https://github.com/marcocesarato/php-conventional-changelog. Так как наши проекты так же пишутся на PHP, генератор показался интересным и захотелось его опробовать в деле.

Шаг 1

Первым шагом стало введение нового требования к оформлению коммитов внутри команды, чтобы они соответствовали соглашению выше и генератор мог с ними работать.

Шаг 2

Добавляем в проект задачу для CI (в моем случае это Gitlab CI).

generate-changelog:     image: php:7.4-cli # у нас используется свой образ, поэтому пишу условно     before_script:         - git config --global user.email "$GITLAB_USER_EMAIL" # email и имя пользователя, от чьего имени будет создаваться коммит         - git config --global user.name "$GITLAB_USER_NAME"         - git fetch --tags -f         - composer install --no-interaction --no-scripts         - composer require marcocesarato/php-conventional-changelog # у нас используется свой форк с доработками         script:         - bin/changelog-generator --commit --no-verify # у нас скрипты устанавливаются в папку bin         - git push -o ci.skip --tags https://root:$ACCESS_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git HEAD:$CI_COMMIT_REF_NAME     stage: changelog     # делаем автозапуск задачи только для мастер ветки.     # Так как мы не пушим напрямую в мастер, а используем merge request, то задача выполняется после слияния MR     # так же запрещаем задачу, если проставляем тег и для коммитов с chore (значит, что команда уже была выполнена)     only:         - master     except:         refs:             - tags         variables:             - $CI_COMMIT_MESSAGE =~ /chore/ 

У нас в команде используется feature-branch подход и требование, чтобы в merge request был только один коммит. Поэтому в нашем случае один коммит = новая версия библиотеки.

Идея скрипта следующая:

  • мы подключаем к проекту генератор и запускаем его с нужными флагами

  • затем генератор:

    • определяет текущий (он же последний) коммит и на основании заголовка коммита определяет, какую версию по семверу нужно присвоить

    • добавляет изменения в CHANGELOG.md

    • создает новый коммит с измененным CHANGELOG.md. Отмечу, что в нашей версии в коммит попадает только файл CHANGELOG’а

    • присваивает тег с полученной версией коммиту

  • пушим новый коммит обратно в репозиторий проекта

Шаг 3

Для того чтобы CI мог запушить изменения в репозиторий, мы создали специального технического пользователя, и добавили в проекты переменную ACCESS_TOKEN , с токеном доступа этого пользователя.

Шаг 4

Какое-то время мы работали с таким подходом. Но в голове крутилась мысль, что использовать composer require так себе идея и перфекционизм требует решения по-лучше.

Хотелось чтобы генератор либо присутствовал все время в образе либо его можно было скачать и запустить.

По некоторым причинам, я выбрал второй путь. Для этого я поместил генератор в phar-архив и загрузил в Gitlab Packages. И получился следующий вариант скрипта CI

generate-changelog:     image: php:7.4-cli     before_script:         - git config --global user.email "$GITLAB_USER_EMAIL"         - git config --global user.name "$GITLAB_USER_NAME"         - git fetch --tags -f         # скачиваем генератор из Packages         - 'curl --header "PRIVATE-TOKEN: ${PACKAGE_TOKEN}" "${CI_API_V4_URL}/projects/615/packages/generic/changelog-generator/latest/changelog-generator.phar" --output changelog-generator.phar'         - chown 755 changelog-generator.phar     script:         - php ./changelog-generator.phar --commit --no-verify         - git push -o ci.skip --tags https://root:$ACCESS_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git HEAD:$CI_COMMIT_REF_NAME     stage: changelog     only:         - master     except:         refs:             - tags         variables:             - $CI_COMMIT_MESSAGE =~ /chore/ 

Проблемы

В какой-то момент из-за изменения прав пользователя у нас получилась ситуация с бесконечным созданием pipelines и запуском задачи с генератором. Точное решение уже не помню, одним из путей решения ситуации стало добавление в скрипт секций except и only

Результат

Я постарался изложить идею автоматизации, так как у разных проектов могут быть свои особенности.


ссылка на оригинал статьи https://habr.com/ru/articles/585422/