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

21c45bb46a4455a296126d21242747f7

В этой небольшой статье поговорим о том, что такое лог изменений проекта, зачем он нужен и как можно автоматизировать его генерацию с помощью 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.

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

Итог

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

Спасибо за чтение!

Теги: GitLab CI, GitLab, Changelog, DevOps

Хабы: Git

© Habrahabr.ru