Поднялся вопрос стандартизации коммитов в команде. До этого были такие правила, мы пишем номер задачи и через тире описание того, что было сделано кратко. Номер задачи берется из номера issue. Например: #1 - реализован функционал сборки прода. Но, это надоело и стало как-то неудобно, когда у нас есть четкое деление задач на фиксы, фичи и так далее.

Нашли Conventional Commits и попробовали его на тестовом репозитории, понравилось. Решили внедрить это в команду, но столкнулись с тем, что люди не всегда делают коммиты правильно, а значит нужна какая-то валидация.

В нашей команде принято по максимуму IDE и его возможности. То есть, коммиты мы делаем не через консоль, а через встроенные утилиты. Поэтому, сразу пошли искать плагины, которые есть в PHPStorm и нашли вот эти 2 важных плагина: Conventional Commit и Git Commit Template. После их установки видим новые кнопки в окне коммита:

Первая - это от плагина Git Commit Template, а остальные от Conventional Commits. Если рассмотреть каждую из низ, то открываются следующие окна:

Окно создания коммита в Git Commit Template
Окно создания коммита в Git Commit Template
Окно создания коммита в Conventional Commits
Окно создания коммита в Conventional Commits

Они очень походи, выбирайте сами то, что вам больше нравится. Результат обоих окно будет коммитом в нужном формате. Но, после создания коммита вы можете его руками изменить, что опять же может привести к нарушению стиля и правил коммитов. Здесь уже мы решили через npm поставить специальный хук, который будет перед созданием коммита проверять его.

Для решения задачи валидации нужно установить пакет @commitlint/cli и husky. Первый проверяет коммиты, а второй реализует клиентские хуки для git. Но тут мы столкнулись с проблемой проверки, так как у нас node стоит через nvm и PHPStorm отказывается это принимать, хотя в конфигах самого PHPStorm ссылки корректные. Возможно, тут кто-то еще не знает про это, но это уже не важно, так как мы решили данную проблему через скрипты npm.

В секцию scripts package.json нужно добавить установку самого husky и добавление хука на commit-msg в git:

{
  "scripts": {
    ...
    "prepare": "husky install && npx husky add .husky/commit-msg  'npx --no -- commitlint --edit ${1}'"
  }
}

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

Долго читая документацию и разбирая скрипты, я понял, что в скрипте (создается после выполнения скрипт в prepare) .husky/_/husky.sh есть код:

  if [ -f ~/.huskyrc ]; then
    debug "sourcing ~/.huskyrc"
    . ~/.huskyrc
  fi

Он проверяет наличие файла .huskyrc в домашнем разделе пользователя UNIX систем. Если он есть, то смотрит то, что там написано. Как раз в этом файле можно явно указать где лежит node в системе.

Для автоматизации процесса для UNIX системы мы обновили секцию prepare и добавили туда создание этого файла в домашнюю директорию пользователя:

{
  "scripts": {
    ...
    "prepare": "husky install && npx husky add .husky/commit-msg  'npx --no -- commitlint --edit ${1}' && echo \"export PATH=\\\"$(dirname $(which node)):\\$PATH\\\"\" > ~/.huskyrc\n"
  },
}

Соответственно, создался файл с содержимым (версия ноды может быть другой у вас):

export PATH="/home/ТУТ_ПОЛЬЗОВАТЕЛЬ_UNIX/.nvm/versions/node/v14.20.1/bin:$PATH"

После чего тестируем. Создаем кривой коммит сами: git commit -m "error" - получаем ответ:

Вывод ошибки коммита в терминале
Вывод ошибки коммита в терминале
Вывод ошибки коммита в PHPStorm через средства IDE
Вывод ошибки коммита в PHPStorm через средства IDE

Теперь, все работает, но хотелось бы немного ограничить разработчиков и "заставить" писать коммиты по правилам. Помните, мы подключали commitlint/cli? Так вот эта штука регламентирует правила. Подробнее про правила можно прочитать тут.

Чтобы правила заработали, создаем в корне проекта файл .commitlintrc.js с содержимым:

module.exports = {
    rules: {
        // Тело коммита должно начинаться с пустой строки
        'body-leading-blank': [2, 'always'],
        
        // Нижний колонтитул коммита должен начинаться с пустой строки
        'footer-leading-blank': [2, 'always'],
        
        // Максимальная длина заголовка 72 символа
        'header-max-length': [2, 'always', 72],
        
        // Область всегда только в нижнем регистре
        'scope-case': [2, 'always', 'lower-case'],

        // Описание не может быть пустым
        'subject-empty': [2, 'never'],
        // Описание не должно заканчиваться '.'
        'subject-full-stop': [2, 'never', '.'],

        // Тип всегда только в нижнем регистре
        'type-case': [2, 'always', 'lower-case'],
        // Тип не может быть пустым
        'type-empty': [2, 'never'],
        // Перечислим все возможные варианты коммитов
        'type-enum': [
            2,
            'always',
            [
                'build',
                'ci',
                'docs',
                'feat',
                'fix',
                'perf',
                'refactor',
                'revert',
                'style',
                'test',
            ],
        ],
    },
};

После чего делаем будут дополнительные правила проверки каждой секции. Секции можно посмотреть на сайте Conventional Commits в разделе Summary.

Подытожим. С помощью этих плагинов и подходов удалось стандартизировать коммиты, сделать проверку правильности коммитов, решить вопрос с NVM установкой, автоматизировать реализацию данных компонентов.

Комментарии (6)


  1. UMenyaNeudobnieVoprosiki
    21.12.2022 16:51
    +5

    И после всех этих манипуляций и страданий в истории изменений в IDE, а ещё лучше через git shortlog --no-merges HEAD --not ${prev_release} вам показывает что? Я просто когда вижу все эти конвеншнл [fix] #1234 fix for prev fix вместо нормального человекочитаемого текста - всегда хочу спросить у автора, а делал то ты что?

    Стараюсь писать нормальный тайтл с номером задачи в конце и этого более чем хватает. В тушку могу пояснений написать. Оно отлично читается и в IDE (даже если все боковые расхлопушки максимально узкие), и как выхлоп для release notes, и в git log --oneline, а номер задачи отлично превращается в ссылку на гитлабе или, например, в GitExtensions, которая поведёт напрямую в трекер одним кликом.

    А можно добавить в алиас немного магии

    report = "!me=$(git config user.email); git log --all --author-date-order --since=1 --reverse --no-merges --pretty=time --date=format:'%Y-%m-%d %H:%M:%S' --author=\"$me\""

    и git report будет вам помогать даже время трекать по таскам


    1. mepihin Автор
      22.12.2022 13:11

      Соглашусь с вами. Лично мне данный (о чем я говорит) "шаблон" коммитов нравится и кажется достаточно информативным. Вместо scope, как описано в правилах, можно писать номер задачи:

      fix(#1): реализация базового функционала чего-то
      
      Реализовано то-то и то-то в таких-то местах


  1. pOmelchenko
    21.12.2022 21:29

    Я правильно понимаю, что оно коммитит все изменения, а не только то что я хочу (выбрать файл, выбрать строки)?


    1. mepihin Автор
      22.12.2022 13:06

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


  1. ggo
    22.12.2022 10:00

    Но, это надоело и стало как-то неудобно, когда у нас есть четкое деление задач на фиксы, фичи и так далее.

    А зачем вам деление на фиксы, фичи и так далее? Вот вы видите эти коммиты раздельно, и что?

    вопрос с подкавыркой ;)


    1. mepihin Автор
      22.12.2022 13:08

      Ну да, еще с какой подкавыркой. В общем случае, захотелось как-то стандартизировать решение это. А деление на типы коммитов поможет определить кто, что и сколько делал. С другой стороны, можно поставить тэги на задачу, мол БАГ/ФИЧА и так далее, но тут я даже не знаю. Лично мне было бы круто видеть в истории гита не только то, что за задача была, а что именно человек делал, чтобы не лезть в хаб/лаб.