Husky: Форматирование, линтинг и тестирование при коммите или пуше

Источник: «Husky: How to automatically format, lint and test before you commit or push»
Когда команда работает над проектом, поддержание кодовой базы в соответствии со стандартами кодирования может оказаться непростой задачей. Возможно, кто-то из членов команды присылает код, не соответствующий установленному стилю кодирования, или вы делаете коммит, исправляющий один компонент, но непреднамеренно ломающий другой. Что можно сделать, чтобы снизить эти риски?

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

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

Поэтому сегодня мы рассмотрим Husky, инструмент, автоматически выполняющий любое количество команд при коммите или пуше. Теперь не нужно беспокоиться, что вы забыли отформатировать, проверить или протестировать код перед загрузкой в репозиторий — Husky делает это каждый раз, при запуске git commit или git push. Давайте приступим.

Подготовка сцены

Предположим, мы работаем над проектом Laravel, содержащим код на PHP и JavaScript. Не волнуйтесь, эти инструкции будут работать, даже если вы не работаете именно с этим технологическим стеком.

Для PHP используем:

И для JavaScript:

Husky в действии

Husky — это современное решение для управления Git хуками, пользовательскими скриптами, которые можно задать для запуска при наступлении определённых событий в Git. Созданный typicode (разработчиком json-server и jsonplaceholder) и насчитывающий более 10 миллионов еженедельных загрузок на npm, этот инструмент позволяет автоматизировать выполнение команд при таких событиях Git, как коммиты или пуши.

Для начала установите Husky в качестве зависимости для разработки:

npm install --save-dev husky

После установки инициализируйте Husky, выполнив следующую команду:

npx husky init

Обратите внимание, что для успешного выполнения этой команды потребуется сначала инициализировать Git-репозиторий.

Эта простая команда выполняет две важные задачи:

Файл pre-commit — это bash-скрипт, выполняющийся перед каждым коммитом; по умолчанию он содержит всего одну строку:

npm test

Можно изменить этот файл, чтобы включить в него дополнительные команды. Давайте адаптируем его для запуска команд, необходимых для данного проекта. Измените файл pre-commit следующим образом:

npm run format
npm run lint
npm run test
./vendor/bin/duster fix
php artisan test

Теперь при выполнении коммита с использованием:

git add -A && git commit -m "My commit message"

Husky автоматически выполнит указанные команды, прежде чем разрешить выполнение коммита.

Представим, например, что есть неопределённый метод в файле JavaScript. Husky выполнит первую команду, npm run format, без проблем. Затем перейдёт ко второй команде, npm run lint, где столкнётся с ошибкой:

/dev/laravel-app/resources/js/bootstrap.js
4:1 error 'translate' is not defined no-undef

1 problem (1 error, 0 warnings)

husky - pre-commit script failed (code 1)

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

После завершения настройки Husky добавьте папку .husky в репозиторий, чтобы созданный нами хук pre-commit выполнялся до того, как кто-то сделает коммит в кодовую базу.

Можно создать ещё один хук, создав несколько файлов в каталоге .husky. Имя файла должно быть правильным именем Git-хука; например, pre-push.

Как обрабатывать только staged файлы

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

В PHP

В Duster можно использовать флаг --dirty, указывающий инструменту запускать линтеры или фиксеры только для staged файлов.

В нашем примере команда будет выглядеть так:

./vendor/bin/duster fix --dirty

Можно приступать к редактированию файла .husky/pre-commit:

 npm run format
npm run lint
npm run test
-./vendor/bin/duster fix
+./vendor/bin/duster fix --dirty
php artisan test

И мы закончили! Теперь перейдём к JavaScript.

В JavaScript

lint-staged — это инструмент, позволяющий выборочно выполнять проверки только тех файлов, которые мы отредактировали и передали для коммита, что значительно ускоряет выполнение проверки.

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

npm install --save-dev lint-staged

Добавьте этот скрипт в файл package.json:

{
"scripts": {
// другие скрипты
"lint-staged": "lint-staged"
}
}

Теперь обновим хук pre-commit в Husky. Откройте .husky/pre-commit и замените несколько команд npm на ту, что только что добавили:

-npm run format
-npm run lint
-npm run test
+npm run lint-staged
./vendor/bin/duster fix --dirty
php artisan test

Наконец, создадим файл конфигурации с именем .lintstagedrc.json в корне проекта. В этом файле указывается, какие команды запускать на основе расширений файлов. Точный набор команд может меняться в зависимости от установки, но в данном примере он будет таким:

{
"*.css": [
"prettier --write"
],
"*.{js,vue}": [
"prettier --write",
"eslint --ignore-path .gitignore --fix",
"vitest related --run --environment=jsdom"
]
}

Мы поручаем lint-staged выполнить следующие задания:

Когда передаются CSS-файлы, то:

Когда передаются файлы JavaScript, то:

Так, если у нас есть только три файла, lint-staged проверит только эти три, пропуская остальную часть кодовой базы. Таким образом, мы экономим время, концентрируясь только на том, что является новым или изменённым.

$ git add -A && git commit -am "Add a cool feature"

> demo-husky@0.0.0 lint-staged
> lint-staged

✔ Preparing lint-staged...
✔ Running tasks for staged files...
✔ Applying modifications from tasks...
✔ Cleaning up temporary files...
[main b57de91] Test lint-staged
2 files changed, 4 insertions(+), 7 deletions(-)

Мы запускаем весь набор тестов каждый раз, когда изменяем код JavaScript, потому что изменения могут иметь неожиданные побочные эффекты для других частей приложения. Однако если были отредактированы только CSS-файлы, можно смело считать, что тестирование JavaScript можно пропустить.

А если мы не добавили JavaScript или CSS файлы, то ни одна из этих проверок не будет запущена. Например, если мы добавим app/Models/User.php, Husky запустит Duster и Pest, но ни одну из команд, включённых в lint-staged (Prettier, ESLint и Vitest).

В завершение

Вот и всё! Мы рассказали о том, как форматировать, проверять и тестировать фронтенд и бэкенд код.

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

Да, поначалу может быть неприятно, когда коммит останавливается из-за ошибки. Но отдача значительно превосходит этот первоначальный дискомфорт. И вот вам маленький секрет: если вы хотите обойти Хаски, добавьте --no-verify в конце команды коммита. Но никому не говорите, что я вам рассказал!

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

Надеюсь, вы сможете применить один или два совета из этого руководства. Если вы хотите видеть больше подобных материалов, дайте нам знать. До следующего раза!

Дополнительные материалы

Предыдущая Статья

Исследование переноса текста и слов

Следующая Статья

PHP 8.4: OpenSSL: минимальная требуемая версия увеличена до 1.1.1