Автоматическая генерация лога изменений проекта с помощью GitLab

Kate

Administrator
Команда форума
В этой небольшой статье поговорим о том, что такое лог изменений проекта, зачем он нужен и как можно автоматизировать его генерацию с помощью GitLab.

Что такое changelog и для чего он нужен?​

Лог изменений проекта (changelog) - это документ, в котором обычно содержится упорядоченный список версий проекта с датами их выхода, а также перечень всех изменений для каждой из версий.

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

Как вести лог изменений?​

Как минимум, хороший лог изменений должен придерживаться следующих принципов:​

  • Для каждой версии должен быть отдельный раздел.
  • Группировать изменения по категориям (Feature, Bug fix, Changed и т.п).
  • Самые новые версии должны располагаться в начале документа.
  • Иметь возможность навигации по файлу.
Файл с логом можно вести вручную, но мало какой разработчик будет с энтузиазмом это делать, а если вы поддерживаете одновременно несколько версий продукта, то это превращается в очень нудное занятие. Другим вариантом будет автоматизация этого процесса.

Одним из способов генерации лога изменений (который мы и будем использовать), будет генерация лога из списка коммитов, но поскольку частенько их пишут как попало, то в первую очередь нужно, чтобы команда разработки, при написании коммитов придерживалась определенного стиля. Этот стиль будет зависеть от того, что вы хотите видеть в логе изменений, можно воспользоваться чем-то готовым или написать что-то свое.

Как генерировать?​

Для генерации воспользуемся функциональностью GitLab API, с его помощью будет формироваться файл (CHANGELOG.md) с логом изменений, основанный на заголовках коммитов. Добавляются только те коммиты, которые включают в себя определенную метку (Git trailers). GitLab использует эти метки для того, чтобы сгруппировать изменения по категориям.

Для генерации нужно выполнить POST запрос:

%gitlab-host%/api/v4/projects/%id%/repository/changelog

  • gitlab-host - это адрес на котором расположен сервер GitLab с вашим репозиторием.
  • id - это project id вашего репозитория, который можно посмотреть в настройках на вкладке "General".
Также нужно передать токен доступа для api, который можно получить в настройках на вкладке "Access Tokens". (или в настройках вашего профиля, на вкладке "Access Tokens".) И как минимум, обязательный атрибут "version" - версия, для которой генерируется лог изменений. Список всех атрибутов.

Результатом выполнения запроса, будет новый раздел в файлеCHANGELOG.md в выбранном репозитории. По умолчанию, диапазон коммитов начинается с последнего тега, идущего до версии, указанной в атрибуте "version" и заканчивается веткой по умолчанию в проекте, в этой же ветке и обновится файл с логом изменений.

Для того, чтобы GitLab мог автоматически находить последний тег, нужно чтобы и версия, и имя тега были оформлены в соответствии с семантикой версионирования.

Если мы хотим именовать как-то по-другому или использовать другой диапазон коммитов, то на помощь приходят атрибуты:

  • from - название ветки, последний коммит которой станет началом диапазона. Сам коммит не будет включен в список.
  • to - название ветки, последний коммит которой станет концом диапазона. Сам коммит будет включен в список.
  • branch - название ветки, в которой будет обновлен/создан файл CHANGELOG.md.
Например, выполним несколько запросов с исходными данными:

  • Project id - 111
  • Gitlab-host - https://gitlab.com/
  • API access token - token
  • Имя последнего тега - 0.9.0
  • Имя ветки по умолчанию - main
curl --header "PRIVATE-TOKEN: token" --data "version=1.0.0" "https://gitlab.com/api/v4/projects/111/repository/changelog"
Результатом выполнения будет новый раздел в ветке main, с подзаголовком 1.0.0 и диапазоном включенных коммитов 0.9.0..main.

curl --header "PRIVATE-TOKEN: token" --data "version=1.0.0&from=release_0.9.0&to=develop&branch=develop" "https://gitlab.com/api/v4/projects/111/repository/changelog"
Результатом выполнения будет новый раздел в ветке develop, с подзаголовком 1.0.0 и диапазоном включенных коммитов release_0.9.0..develop.

Как кастомизировать?​

Для кастомизации используется конфигурационный файл в формате YAML. Файл должен располагаться в корне репозитория по пути: .gitlab/changelog_config.yml

Чтобы GitLab начал распознавать файл конфигурации, он должен быть расположен в ветке по умолчанию.
Для редактирования доступны следующие переменные:

  • date_format - формат даты, который будет использоваться в заголовке нового раздела лога изменений
  • template - формат данных, который будет использоваться для отображения каждой категории лога изменений
  • categories - псевдоним, который будет использоваться как имя категории, вместо тех, которые мы используем, как метки коммитов (git trailers)
Для примера, структура наших коммитов будет выглядеть так:

<Тип>(номер задачи): Заголовок

- Подробное описание (если оно требуется)

[git trailers]

Используя стандартные настройки, сгенерированный файл будет выглядеть так:

## 1.0.0 (2021-08-31)

### bug (2 changes)

- [bug(#12445): Исправлено зависание приложения, при нажатии кнопки "Выход"](Nethius/example@commit-sha1)([merge request](Nethius/example!4))
- [bug(#12347): Исправлено отображение кнопок "Добавить", "Удалить"](Nethius/example@commit-sha1)

### performance (2 changes)

- [refactoring(#12349): Повышена скорость сборки приложения](Nethius/example@commit-sha1)
- [refactoring(#12348): Повышена скорость загрузки приложения](Nethius/example@commit-sha1)

### feature (2 changes)

- [feature(#12346): Добавлена поддержка файлов формата .md .yml](Nethius/example@commit-sha1)
- [feature(#12345): Реализована форма авторизации](Nethius/example@commit-sha1)
Теперь попробуем поменять заголовки категорий и добавить для каждой записи автора коммита.

В примере выше мы используем стандартный git trailer - Changelog и используемые для него значения: feature, bug, performance, которые и стали названиями категорий.

Чтобы изменить названия категорий, нужно добавить в файл конфигурации changelog_config.yml следующие строки:

categories:
feature: Features
bug: Bug fixes
performance: Performance improvements
Для генерации данных в категориях, используются шаблоны. Для примера выше, шаблон выглядит так:

template: |
{% if categories %}
{% each categories %}
### {{ title }} ({% if single_change %}1 change{% else %}{{ count }} changes{% end %})

{% each entries %}
- [{{ title }}]({{ commit.reference }})\
{% if merge_request %} ([merge request]({{ merge_request.reference }})){% end %}

{% end %}

{% end %}
{% else %}
No changes.
{% end %}
Здесь мы в основном цикле проходим по всем категориям, отображаем название и количество записей в категории. В вложенном цикле совершаем обход всех записей и выписываем заголовок коммита и ссылку на него, если есть ссылка на МР, то добавляем её.

  • {% ... %} - используется для условий (if/else) и циклов (each). Каждое выражение, должно закрываться с помощью {% end %}
  • {{ ... }} - используется для отображения данных доступных в шаблоне
Для отображения автора коммита, изменим текст шаблона, добавив в вложенный цикл строку by {{ author.reference }} после вывода ссылки на коммит.

После всех изменений, файл changelog_config.yml будет выглядеть следующим образом:

---
categories:
feature: Features
bug: Bug fixes
performance: Performance improvements
template: |
{% if categories %}
{% each categories %}
### {{ title }} ({% if single_change %}1 change{% else %}{{ count }} changes{% end %})

{% each entries %}
- [{{ title }}]({{ commit.reference }}) by {{ author.reference }}\
{% if merge_request %} ([merge request]({{ merge_request.reference }})){% end %}

{% end %}

{% end %}
{% else %}
No changes.
{% end %}
А сгенерированный файл CHANGELOG.md так:

## 1.0.0 (2021-08-31)

### Bug fixes (2 changes)

- [bug(#12445): Исправлено зависание приложения, при нажатии кнопки "Выход"](Nethius/example@commit-sha1) by @Nethius ([merge request](Nethius/example!4))
- [bug(#12347): Исправлено отображение кнопок "Добавить", "Удалить"](Nethius/example@commit-sha1) by @Nethius

### Performance improvements (2 changes)

- [refactoring(#12349): Повышена скорость сборки приложения](Nethius/example@commit-sha1) by @Nethius
- [refactoring(#12348): Повышена скорость загрузки приложения](Nethius/example@commit-sha1) by @Nethius

### Features (2 changes)

- [feature(#12346): Добавлена поддержка файлов формата .md .yml](Nethius/example@commit-sha1) by @Nethius
- [feature(#12345): Реализована форма авторизации](Nethius/example@commit-sha1) by @Nethius

Как автоматизировать?​

Для начала настроить GitLab CI/CD. После того, как этот этап пройден, добавить в файл .gitlab-ci.yml новый stage (или изменить уже существующий) для обновления лога изменений. В нем мы должны получить имена веток для атрибутов from и to и после этого выполнить POST запрос для генерации файла CHANGELOG.md.

Например, пусть наша выборка коммитов начинается с последнего тега и заканчивается текущей версией релиза. Версию лога изменений, допустим, будем брать из файлов проекта, stage будет запускаться только для ветки релиз.

update-changelog:
stage: update_changelog
script:
- latestVersion=$(git describe --tags --abbrev=0)
- currentVersion=$(grep -oP '(?<=VERSION ")([^"]*)' version.h)
- |
curl --header "PRIVATE-TOKEN: token" --data "version=$currentVersion&from=$latestVersion&to=release&branch=release" "https://gitlab.com/api/v4/projects/111/repository/changelog"
only:
- release
Теперь каждый раз при сборке релиза, будет добавляться новый раздел с версией currentVersion в файл CHANGELOG.md.

Важно, что если раздел с текущей версией уже существует, то дополняться новыми коммитами он не будет.

Итог​

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

 
Сверху