Версионирование. Автоматизация. А может всё вместе?

Всё уже придумано, просто настрой под себя и пользуйся.

Всем привет, я Дмитрий Валеев — DevOps инженер в команде разработки фреймворка для тестирования устройств на заводах Аквариус. И это моя первая маленькая статья на Хабр :)

В любом проекте настаёт день «икс», когда вы понимаете, что необходимо внедрять какое-либо версионирование. Вот и в нашем случае настал такой момент. Вариант с хэш-коммитами казался просто хаосом и нужно было привести вид компонент в порядок

Введение

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

В этой статье описан очень простой подход к автоматизации присвоения версий и написания патч-ноутов для проектов. Семантическое версионирование, а также соглашение о коммитах с открытой спецификацией и документаций поможет не придумывать новые стандарты.

Сразу обозначу, в качестве VCS (Version Control System) выбран «GitLab». Поэтому почти всё описанное взаимодействие в статье будет происходить с данным инструментом.

Структура версий

Структура версии

Структура версии

  • 1 — Major версия

    Мажорная версия изменяется только в случае обратно несовместимых изменений

  • 2 — Minor версия

    Минорная версия изменяется только в случае добавления нового функционала БЕЗ обратно несовместимых изменений

  • 3 — Патч версия

    Патч версия изменяется в случае выпуска каких-либо исправлений, незначительных улучшений

  • dev — Название prerelease/разрабатываемых состояний проекта

  • 4 — Номер билда/коммита для пререлиз состояний версии

    »-dev. 4» используется в любых видах пререлиз веток (Например: alpha; beta; dev; rc…).

Спецификация по написанию коммитов

Спецификации по написанию коммитов — это предмет договоренности внутри вашей команды. Она может быть изменена любым удобным способом. Однако, существует так называемая договоренность о коммитах (conventional commits), рекомендую ознакомиться с ней, хотя бы как с базовым примером того, как это может выглядеть.

Перейдём к краткому описанию правил коммитов:

fix: something

fix (PROJECT-999): fix something

feat: something

feat (ui): Add something

feat!: something

BREAKING CHANGE: something

«BREAKING CHANGE» находится именно в сноске коммит месседжа. Восклицательный знак в данном случае предупреждает о наличии «BREAKING CHANGE» в сноске коммита. Так выглядит в гитлабе:

Коммит в гитлабе

Коммит в гитлабе

Можно использовать и другие типы коммитов. Все, кроме вышеописанных, не влияют на изменение версии релиза (здесь описаны лишь некоторые):

  • ci: Изменения в наших конфигурационных файлах и скриптах CI.

  • docs: Изменения документации.

  • refactor: Рефакторинг кода, не затрагивающий баг-фиксы и не добавляющий функциональность.

  • style: Изменения, которые не влияют на смысл кода (пробелы, форматирование, отсутствие точек с запятой и т.д.).

  • test: Добавление недостающих или исправление существующих тестов.

Рекомендую ознакомиться с одним из таких соглашений по ссылкам: на английском и на русском.

Инструмент «Semantic-release»

Напишем своё или возьмём уже готовое?

Рекомендую обратить внимание на инструмент semantic-release. Это решение на базе проекта с открытым кодом, написанное на node.js,  позволяющее без особых проблем писать CHANGELOG, создавать теги или релизы, вносить любые автоматизированные изменения в репозиторий от имени бота с выпуском новой версии. И всё это без участия человека.

Решение также помогает поддерживать legacy. Например:

  • Заморозили старую версию 1.X.X, но вносим в неё необходимые фиксы и патчи в legacy ветке.

  • Ведем версию 2.X.X в master ветке.

  • Для обеих версий доступны dev ветки/каналы для разработки.

Ещё один плюс данного инструмента — наличие в арсенале разнообразных плагинов. Например: changelog, docker, exec и.т.д., которые открывают возможность создавать GitLab/GitHub Release вместе с тегом, автоматизировать ваши собственные изменения при выпуске версии и многое другое.

Как работает semantic-release

При каждом коммите инструмент анализирует его содержимое и существующие версии. На основе этого анализа принимается решение — выпускать новую версию или нет. (См. спецификацию по написанию коммитов)

Каждая новая версия автоматически создаёт тег.

Теги в репозитории

Теги в репозитории

Теги в репозитории

Теги в репозитории

А так выглядят коммиты самого бота с выпуском тега:

Полный коммит бота

Полный коммит бота

Как изменяются версии пре-релиз веток (на примере «dev»)

При внесении изменений в dev-ветку версия изменяется в зависимости от целевого коммита.
То есть, если мы ведем dev ветку с версии 1.0.0, у нас есть 2 коммита «feat» и 3 «fix» в любом порядке, то текущая версия в dev будет 1.1.0-dev. 5. Неважно, сколько новых фич или фиксов было добавлено в dev, изменение версии отражает, что было добавлено хотя бы одно улучшение. Оно же показывает, какого рода были самые критичные изменения. Для наглядности картинка ниже:

49695265b29430fe7ad4f0008e1064f3.png

Как добавить semantic-release к себе в проект

Не буду переписывать инструкцию, а просто оставлю ссылку на удобную документацию от разработчиков и покажу один из вариантов настройки:

1. Соберем контейнер для раннера и положим туда semantic-release с нужными плагинами
Как пример базовой сборки:

FROM node:18.14.2-alpine3.17

COPY certs/. /etc/ssl/certs/.

RUN apk --no-cache add curl; \
    apk --no-cache add git; \
    apk --no-cache add ca-certificates && \
    update-ca-certificates -v

RUN npm config set prefix /usr/local; \
    npm install -g @semantic-release/gitlab@v10.0.1; \
    npm install -g @semantic-release/exec; \
    npm install -g @semantic-release/git; \
    npm install -g @semantic-release/changelog; \
    npm install -g semantic-release

ENTRYPOINT [""]

CMD [""]

2. Создадим бота в GitLab и токен для него с правами api, write_repository. Это нужно для того, чтобы бот мог коммитить в репозиторий автоматические изменения.

3. Передадим токен через ci/cd variables. Можете добавить сразу в группу репозиториев.

Токен в ci/cd variables

Токен в ci/cd variables

4. Напишем базовую джобу

a. Если не используете ci templates:

stages:
  - semantic-release

release-job:
  image: *your_registry*/semantic_release:latest
  stage: semantic-release
  only:
    refs:
      # Release branch
      - master
      # Pre-release branch
      - dev
  script:
    - npx semantic-release
  tags:
    - *your_tag*

b. Если пользуетесь ci templates:

.release-job:
  stage: semantic-release
  image: *your_registry*/semantic_release:latest
  only:
    refs:
      # Release branch
      - master
      # Pre-release branch
      - dev
  script:
    - npx semantic-release
  tags:
    - *your_tag*
  artifacts:
    reports:
      dotenv: release_version.env

.gitlab-ci.yml в проекте:

include:
  project: path/to/your/templates
  file: path/to/your/template.yml

stages:
    - semantic-release

semantic-release:pypi:
  extends: .release-job
  stage: semantic-release

5. Добавим в репозиторий .releaserc.json

{
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    ["@semantic-release/exec",{
      "prepareCmd": "if [ -f .release.override ]; then echo \"Detected .release.override\" && VERSION=${nextRelease.version} && source .release.override; else sed -i \"s/__version__ *= *.*/__version__ = \\\"${nextRelease.version}\\\"/\" ./setup.py; fi",
      "publishCmd": "echo NEW_VERSION=${nextRelease.version} >> release_version.env"
    }],
    ["@semantic-release/changelog",{
      "changelogFile": "CHANGELOG.md"
    }],
    ["@semantic-release/git", {
      "assets": ["CHANGELOG.md", "setup.py"],
      "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
      }
    ]
  ],
  "branches": [
    "master",
    {"name": "dev", "prerelease": true}
  ],
  "tagFormat": "v${version}"
}

Здесь, например, мы можем внести любое автоматическое изменение в prepareCmd, а в assets указать файлы, которые будут участвовать в коммите бота. На выходе мы будем иметь коммит и тег от бота, с уже измененными файлами.

Автоматизация CHANGELOG (-а)

Вернемся к данному коммиту:

fix (PROJECT-999): fix something

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

CHANGELOG

CHANGELOG

Опять же, changelog пишется автоматически, если мы оставляем в assets «CHANGELOG.md», а также устанавливаем и добавляем необходимый плагин (см. настройку semantic-release пункт 5).

Самый простой сценарий использования

  1. Коммит разработчика в формате semver.

  2. Автоматическое вычисление версии с помощью semantic-release.

  3. Автоматическое изменение файла setup.py и CHANGELOG.md.

  4. Сборка и последующая доставка пакета.

  5. Коммит/выпуск тега (релиза) с уже измененной версией.

В заключении

Семантическое версионирование вполне вяжется с подходом к разработке gitflow. Мы можем вести все пререлиз ветки с версиями.

Большинство наших репозиториев и компонент версионируется именно в таком формате, на них также завязаны job (-ы) по сборкам и публикации/деплою. Всё это избавляет нас от большого объема  ручной работы и прививает в команде единый стандарт написания коммитов.

В действительности такая автоматизация настраивается очень быстро и не требует трудоемких операций. Попробуйте:)

© Habrahabr.ru