Что такое pre hook
Вступление
Для начала пару слов, о том что такое в целом хуки (hooks) и для чего они могут быть нужны. Git «из коробки» предоставляет инструмент, который умеет запускать ваши скрипты при наступлении какого-либо события (к примеру пуш на сервер и т.п.)
Установка
Установим необходимые зависимости:
Выскажу свое мнение по поводу flake-8 и линтеров в целом. Если у вас уже большой проект с кучей legacy кода, то можете линтеры смело удалять. Затраты которые будут потрачены на «приведение к идеалу», начальство не оценит. Линтеры ставим для новых (и небольших) проектов. Повторюсь, это лично мое мнение, никому его не навязываю.
Интеграция в среду
Заходим в корневой каталог среды разработки и выполняем следующие команды
Тесты
Помимо проверки и форматирования кода мы будем выполнять тесты на этапе создания коммита. Для этого мы будем использовать pytest (https://docs.pytest.org/en/latest/) и настроим его для наших нужд.
В корневом каталоге нашей среды создадим файл pytest.ini
Далее создадим папку tests и поместим туда следующие файлы
test_example_without_db.py, test_example_with_db.py
Для удобства настроим тесты таким образом, чтобы можно было использовать текущую базу данных (к примеру копию базы данных с боевого сервера), а не создавать каждый раз новую.
Простой тест test_example_without_db.py
В простых тестах мы можем подключить например webbot и обходить узлы нашей системы, чтобы автоматизировать ручной труд тестировщика.
Тест с использованием базы данных test_example_with_db.py
Пример довольно искусственный и создан исключительно для данной заметки, но тем не менее он позволяет нам обратиться к текущей базе данных, и провести сложные тесты, которые выходят за рамки ручного тестирования.
Чтобы подключить тесты нам потребуется shell script в корневом каталоге среды, который мы назовем tests.sh:
Его содержание весьма очевидное, но вы можете заметить что активация виртуального окружения явным образом прописана в коде. Это может быть неудобно, если ваша команда ведет разработку на разных рабочих станциях (к примеру кто развернул среду на локальной машине, а кто-то разрабатывает на сервере).
Создаем коммит
Теперь осталось создать коммит и посмотреть как это работает
Коммит теперь создается в «два этапа». На первом этапе хуки выполняют форматирование кода, поэтому после их работы нам нужно просто «повторить» команды.
Запуск Git-хуков при помощи pre-commit
Умение работать с системой контроля версий Git — базовый навык для выживания разработчика (на любом языке программирования) в современных реалиях. Система контроля версий — это этакая машина времени для вашего проекта: всегда можно вернуться на любое прошлое состояние проекта, понять когда, как, что и кем менялось.
Интересный факт: согласно Google Trends, во всём мире Git фактически вытеснил другие системы контроля версий. Только в Китае почему-то до сих пор популярен Subversion (46% рынка). К чему бы это?
Git имеет крайне полезную фичу — возможность исполнять произвольный код на многих этапах работы через так называемые хуки. Вот примеры доступных хуков:
Полный список хуков можно посмотреть в документации.
Как это работает? Рассмотрим, например, схему работы хука pre-commit :
Фишка в том, что хуки могут прерывать операции, за которые они отвечают, если что-то идёт не так. Это идеальное место, чтобы запускать какие-нибудь проверки качества кода, например, линтеры, форматтеры или тесты (если они работают быстро, конечно), или проверять сообщение коммита на соответствие конвенциям или на грамматические ошибки.
Пишем Git-хук на bash
Давайте для понимания напишем простой скрипт, который будет использоваться в качестве хука.
В этом примере я использую Linux. Если вы пользуетесь Windows, то большинство описанный вещей будут работать без изменений через Git Bash, который устанавливается вместе с Git for Windows. Возможно, вам только придётся поменять путь до вашего bash в шебанге, как описано в конце этой статьи. Если же вы соберётесь писать в хуках что-то сложное и требующее интеграции с ОС, то, возможно, стоит вместо bash использовать PowerShell.
Создадим пустой репозиторий:
Git уже заботливо создал для нас шаблоны для написания хуков, которые лежат в специальной служебной директории:
Давайте не будем этого делать, а взамен напишем простой скрипт, который будет запускать все нужные нам линтеры и форматтеры:
Попытаемся его закоммитить:
На этот раз всё срабатывает успешно.
У такого ручного способа есть несколько недостатков:
Используем готовый инструмент — pre-commit
Как обычно, для всего уже есть решения. Представляю вашему вниманию pre-commit — умный инструмент для управления Git-хуками.
Установка
Настройка
И допилим примерно до такого состояния:
Теперь включим pre-commit в текущем репозитории.
Рекомендую добавить эту команду в документацию для разработчиков. Это всё, что нужно будет сделать вашим коллегам, чтобы хуки заработали и у них тоже.
Можно убедиться, что pre-commit заменил наш старый хук на свой:
Проверим, что конфигурационный файл валиден, а заодно и что всё нынешнее содержимое репозитория удовлетворяет описанными правилам:
При первом запуске pre-commit скачает и закэширует все файлы, необходимые для выполнения проверок. Для проверок, которые написаны на Python, будут созданы изолированные виртуальные окружения, так что они никак не будут зависеть от виртуального окружения проекта. Первый раз из-за скачивания зависимостей эта команда может выполняться секунд 30 (в зависимости от скорости интернета), но перезапустите её ещё раз и она завершится за секунду.
Возможно, pre-commit найдёт проблемы или даже исправит некоторые файлы.
Если проверка отработала без ошибок, то конфиг нужно добавить в Git:
Плагины/зависимости для проверок
Использование
Теперь можно вообще забыть про существование pre-commit и просто пользоваться Git как обычно, а pre-commit будет выполнять все описанные проверки, изредка беспокоя вас прерванными операциями, если будут найдены какие-нибудь проблемы. Давайте снова попробуем закоммитить тот сломанный файл с пробелами и кавычками:
Альтернативы pre-commit
Мне проще всего использовать инструменты, написанные на знакомом мне языке, но вообще pre-commit далеко не уникальный инструмент и имеет множество альтернатив. Если вы пишете не на Python, то может быть вам будут ближе другие инструменты, хотя все они имеют примерно схожий функционал:
Возможно, вы также найдете для себя что-то полезное на странице “Awesome Git hooks”.
Заключение
Я всегда стараюсь использовать Git-хуки для запуска всех быстрых проверок. Это не дает мне забывать о проверках, и позволяет быстрее получать обратную связь.
Представьте ситуацию, когда сидишь и ждёшь результатов проверок от CI, которые могут быть достаточно долгими (на проекте, где я сейчас работаю, тесты выполняются 8-10 минут), видишь красный крестик, идёшь посмотреть, что же там сломалось, а там всё почти отлично — тесты прошли, но только flake8 нашёл лишний пробел. Чинишь лишний пробел и снова ждёшь 10 минут, чтобы получить свою зелёную галочку. Дак вот хуки спасают от таких ситуаций, потому что все тривиальные проблемы обнаруживаются за несколько секунд локально на моей машине и никогда не попадают в историю Git.
Настоятельно рекомендую пользоваться Git-хуками. Это позволит вам не тратить время на ерунду, и в итоге быть более эффективным и довольным разработчиком.
Примеры из поста можно найти здесь.
Если понравилась статья, то подпишитесь на уведомления о новых постах в блоге, чтобы ничего не пропустить!
Держите свой код в чистоте с помощью Black & Pylint, Git Hooks и Pre-commit
Кодирование может быть очень сложной задачей, особенно при работе над проектом с разными разработчиками. Каждый член команды использует свой собственный способ кодирования, что приводит к очень разнородным сценариям.
Вот почему важно иметь аналогичный формататор кода и линтер кода, чтобы сделать ваши коммиты git более чистыми. Это может быть выполнено либо между этапами постановки и фиксации, либо во время цепочки CI / CD.
В этой статье мы увидим, как это сделать на этапе перед фиксацией с помощью хуков git.
Оглавление
Резюме выглядит следующим образом:
Black
Его можно установить с помощью следующей командной строки:
Вы можете запустить black в любом файле Python, набрав:
Black можно слегка настроить с помощью файла pyproject.toml, который следует поместить в корень вашего проекта. Ниже пример этого файла:
Например, мы можем выбрать длину строк кодов, а также установить расширения, файлы которых не должны форматироваться.
Pylint
Pylint можно установить с помощью следующей командной строки:
Чтобы оценить качество написания кода для данного скрипта, вы можете запустить:
Вы можете проверить эту страницу для получения более подробной информации о конфигурации.
Предварительные коммиты в виде хуков Git
В этой статье мы сосредоточимся на клиентских, рабочий процесс которых можно описать следующим графиком:
Настройка предварительных коммитов
Чтобы добавить действие перед фиксацией в ваш репозиторий:
2. Добавьте в файл команды bash. В нашем случае:
Первая строка применяет форматировщик black, а вторая строка применяет linting к каждому файлу python вашего проекта. Вы можете скачать файл lint.py по этой ссылке:
NB: по умолчанию установлено пороговое значение 7. Если оценка pylint ниже этого числа, фиксация завершится ошибкой, и вам придется очистить свой скрипт перед повторной фиксацией.
3. Сделайте его исполняемым, выполнив следующую команду bash:
После этого каждой фиксации вашего проекта будет предшествовать форматирование Black и linting pylint.
В качестве иллюстрации рассмотрим следующее приложение:
При фиксации нового изменения мы получаем следующие результаты:
Совместное использование linter и formatter
Теперь, когда вы настроили black в качестве средства форматирования и pylint в качестве linter, вы определенно хотите, чтобы ваша команда имела такую же конфигурацию.
Для этого вы можете использовать следующий файл bash, который будет помещен в корень вашего проекта и запущен каждым членом вашей команды после клонирования репозитория:
Заключение
Автоматизация разработки и развертывания с помощью хуков Git
Контроль версий стал неотъемлемой частью разработки современного программного обеспечения. Помимо прочих преимуществ, он позволяет безопасно отслеживать изменения в коде и включать реверсии проектов, проверять целостность и совместно использовать код с другими разработчиками. Система управления версиями git широко используется в разработке благодаря своей децентрализованной архитектуре и скорости.
Набор инструментов git предлагает множество хороших функций, но одной из самых полезных его характеристик является гибкость. Благодаря системе хуков (или перехватчиков) git позволяет разработчикам и администраторам расширять функциональность с помощью скриптов, которые git будет вызывать на основе разных событий и действий.
Данный мануал расскажет вам, что такое хуки git, и научит реализовать код, который поможет автоматизировать задачи в среде разработки.
Примечание: Данный мануал протестирован на сервере Ubuntu 14.04, но на других дистрибутивах он должен работать аналогичным образом.
Требования
Что такое хуки Git?
Хуки Git – довольно простая концепция. При разработке программного обеспечения по совместному проекту, поддержке стандартов стилей или при развертывании программного обеспечения (все это типичные ситуации при работе с git) есть часто повторяемые задачи.
Хуки Git работают на основе событий. Когда вы запускаете определенные команды git, программное обеспечение проверяет каталог hooks в репозитории git и ищет в нем соответствующий скрипт.
Некоторые скрипты запускаются до начала выполнения задачи, чтобы обеспечить соответствие кода стандартам, проверить его работоспособность или настроить среду. Другие скрипты запускаются после события, чтобы развернуть код, восстановить права доступа и собственности (git не очень хорошо их отслеживает) и так далее.
С помощью этой функции можно обеспечить соблюдение политик, обеспечить согласованность и управление средой, а также выполнить задачи развертывания.
Книга Pro Git описывает разные хуки по категориям:
Эти классификации полезны для получения общего представления о событиях, для которых вы можете использовать тот или иной хук. Но чтобы понять, как работают эти элементы, лучше всего поэкспериментировать и продумать решения, которые вы пытаетесь реализовать.
Некоторые хуки также принимают параметры. Это означает, что когда git вызывает скрипт хука, он передает некоторые релевантные данные, которые скрипт может затем использовать для выполнения задач. В этой таблице описаны доступные хуки:
Название хука
Вызывается
Описание
Параметры (число и описание)
- » для каждого ref.
- ». Поскольку он вызывается после обновления, он не может прервать процесс.
- ».
Настройка репозитория
Для начала нужно создать новый, пустой репозиторий в домашнем каталоге (здесь он называется proj).
/proj
git init
Initialized empty Git repository in /home/demo/proj/.git/
Теперь вы находитесь в пустом рабочем каталоге, который контролирует git. Перейдите в репозиторий, который хранится в скрытом файле.git в этом каталоге:
В нем вы увидите ряд файлов и каталогов. Найдите каталог hooks:
Во-первых, обратите внимание, что каждый из этих файлов отмечен как исполняемый. Поскольку эти скрипты вызываются просто по имени, они должны быть исполняемыми, а их первая строка должна быть ссылкой на магическое число с шебангом для вызова правильного интерпретатора скриптов. Чаще всего это скриптовые языки, такие как bash, perl, python и т. д.
Вернитесь в рабочий каталог:
Развертывание на локальный веб-сервер с помощью хука post-commit
В первом примере будет использоваться хук post-commit, который может развернуть код на локальном сервере после каждого коммита. Этот хук не стоит использовать для производственной среды, но он позволяет вам просмотреть важные, но плохо задокументированные элементы, о которых вы должны знать.
Для начала установите веб-сервер Apache:
sudo apt-get update
sudo apt-get install apache2
Чтобы скрипт изменил корневой каталог веб-сайта /var/www/html (это document root по умолчанию в Ubuntu 14.04, при необходимости измените его), нужно иметь права на запись. Измените права собственности на каталог:
Теперь создайте файл index.html:
/proj
nano index.html
В файл нужно добавить простой HTML.
Here is a title!
Добавьте новый файл, чтобы git мог отслеживать файл:
Прежде чем добавить что-либо в этот файл, нужно немного узнать о том, как git устанавливает среду при запуске хуков.
Кратко о переменных среды и хуках git
Прежде чем начать работу со скриптом, нужно понять, какие переменные среды git задает при вызове хуков. Чтобы заставить скрипт работать, в конечном итоге нужно будет отключить переменную среды, которую git задает при вызове хука post-commit.
Это очень важный момент, если вы хотите написать надежные git-хуки. Git устанавливает различные переменные среды в зависимости от вызова. Это означает, что среда, из которой git извлекает информацию, будет отличаться в зависимости от хука.
Первая проблема заключается в том, что это может сделать среду сценариев очень непредсказуемой, если вы не знаете, какие переменные устанавливаются автоматически. Вторая проблема заключается в том, что установленные переменные почти полностью отсутствуют в документации git.
К счастью, Марк Лонгэйр разработал метод тестирования каждой из переменных, которые git устанавливает при запуске хуков. Этот метод включает в себя следующие строки в различных скриптах хуков git:
Примечание: Версия может отличаться.
Ниже приведены результаты тестов этой версии git (включая рабочий каталог, который git просматривает при запуске каждого хука). Локальным рабочим каталогом для тестирования /home/demo/test_hooks, а пустым удаленным каталогом был /home/demo/origin/test_hooks.git.
Эти переменные влияют на то, как git видит свою среду. Мы будем использовать приведенную выше информацию о переменных, чтобы убедиться, что скрипт учитывает окружающую его среду.
Работа над скриптом
Теперь, когда у вас есть представление о среде, можно начать писать скрипт.
Поскольку git-хуки являются стандартными скриптами, нужно сказать git, какой интерпретатор использовать:
После этого можно использовать git для распаковки последней версии репозитория после коммита в каталоге веб-сервера. Чтобы сделать это, нужно сделать корневой каталог Apache рабочим каталогом. Также нужно установить каталог git в репозитории.
Нужно убедиться в том, что каждая такая транзакция прошла успешно, даже если содержимое рабочего каталога конфликтует:
Этот путь связан с рабочим каталогом, в этом случае с /var/www/html. Поскольку git index не существует в этом месте, скрипт выдаст ошибку, если оставить все как есть. Чтобы избежать этой ситуации, можно вручную отключить эту переменную. Добавьте в сценарий такую строку:
Вот почему ошибки хуков git иногда трудно диагностировать. Вы должны знать, как git создает среду, в которой работает.
Сохраните и закройте файл.
Сделайте файл исполняемым:
Теперь, наконец, можно зафиксировать в коммите изменения, которые вы сделали в нашем репозитории git. Убедитесь, что вы вернулись в правильный каталог, а затем зафиксируете изменения:
Если вы теперь посетите доменное имя или IP-адрес своего сервера в браузере, вы увидите созданный файл index.html:
http://server_domain_or_IP
Here is a title!
Please deploy me!
Как видите, после фиксации последние изменения были автоматически перенесены в корневой каталог веб-сервера. Теперь можно внести дополнительные изменения, чтобы убедиться, что это работает для каждого коммита:
Снова откройте браузер. Теперь вы увидите:
Here is a title!
Please deploy me!
Here is a change.
Как вы можете видеть, такой скрипт может облегчить локальное тестирование изменений. Тем не менее, коммиты почти никогда не публикуются сразу в производственной среде. Гораздо безопаснее загружать их туда после проверки.
Развертывание на отдельном сервере производства с помощью хуков
В этом примере мы продемонстрируем лучший способ обновления производственного сервера. Сделать это можно с помощью модели push-to-deploy, которая будет обновлять веб-сервер после каждой загрузки в пустой репозиторий git.
Используйте тот же сервер, который вы раньше использовали раньше в качестве машины разработки. Вы сможете увидеть все изменения после каждого коммита.
На производственной машине создайте еще один веб-сервер, простой репозиторий git, в который будут вноситься изменения, и git-хук, который будет выполняться всякий раз, когда будет получен push-сигнал.
Этот раздел можно выполнить как обычный пользователь с привилегиями sudo.
Настойка хука post-receive
На сервере производства установите веб-сервер.
sudo apt-get update
sudo apt-get install apache2
Передайте права на document root текущему пользователю:
Установите git на эту машину:
sudo apt-get install git
Теперь в домашнем каталоге пользователя можно создать каталог для хранения репозитория. Затем нужно перейти в этот каталог и инициализировать открытый репозиторий. В пустом репозитории не будет рабочего каталога, и он лучше подходит для обслуживания серверов, с которыми вы не будете работать напрямую:
Теперь нужно создать еще один хук git. На этот раз нужен хук post-receive, который запускается на сервере, получающем git push. Откройте этот файл в редакторе:
Опять же, начать нужно с определения типа скрипта. После этого можно добавить ту же команду проверки, которую вы использовали в файле post-commit, нужно только обновить пути:
Поскольку это пустой репозиторий, параметр –git-dir должен указывать на каталог верхнего уровня этого репозитория.
Также нужно добавить в скрипт дополнительную логику. Если вы случайно загрузите на этот сервер ветку test-feature, ее развертывать не нужно. Этот сервер должен собирать только ветку master.
Возможно, вы заметили в таблице для post-receive, что git передает хэш коммита старой ревизии, хэш коммита новой ревизии и ссылку, которая вставляется в скрипт как стандартный ввод. Это можно использовать, чтобы проверить, является ли ref главной веткой или нет.
Сначала нужно прочитать стандартный ввод. Для каждой загруженной ссылки в качестве стандартного ввода в сценарий будут загружаться три фрагмента информации (старая ревизия, новая ревизия, ссылка), разделенные пробелом. Эти данные можно прочитать с помощью цикла while:
Итак, теперь у вас есть три переменных, основанных на загруженных данных. Для загрузки ветки master объект ref будет содержать данные типа refs/heads/master. Проверьте, поддерживает ли этот формат объект ref, который получает сервер, с помощью if:
Для серверных хуков git может передавать сообщения обратно клиенту. Все, что отправляется в стандартный вывод, будет перенаправлено клиенту. Это дает возможность явно уведомить пользователя о том, какое решение было принято.
Теперь нужно добавить текст, описывающий текущую ситуацию и предпринятые действия. Добавьте блок else, чтобы уведомить пользователя о том, что данные в не master ветку добавлены успешно, даже если действие не приведет к развертыванию:
Сохраните и закройте файл.
Сделайте скрипт исполняемым:
chmod +x hooks/post-receive
Настройка удаленного сервера на клиентской машине
Вернитесь на клиентский сервер (разработки) и откройте этот каталог:
Добавьте в файл удаленный сервер как production. Вам нужно знать имя пользователя, которое вы использовали на сервере производства, а также его IP-адрес или доменное имя. Вам также необходимо знать местоположение репозитория по отношению к домашнему каталогу пользователя. Команда будет иметь примерно такой вид:
git remote add production demo@server_domain_or_IP:proj
Загрузите текущую ветку master на сервер производства:
git push production master
Если у вас не настроены SSH-ключи, вам может потребоваться ввести пароль пользователя вашего сервера производства. Вы должны увидеть примерно такой вывод:
Как видите, в выводе команды находится текст хука post-receive. Если вы посетите доменное имя или IP-адрес производственного сервера в веб-браузере, вы увидите текущую версию проекта:
Here is a title!
Please deploy me!
Here is a change.
Похоже, хук успешно загрузил код в производство.
Теперь давайте протестируем новый код. Вернитесь к машине разработки, а затем создайте новую ветку для хранения изменений. Таким образом, вы сможете убедиться, что все готово к работе, прежде чем начать развертывание в производство.
Создайте новую ветку test_feature и проверьте ее:
Сейчас вы работаете в ветке test_feature. Теперь внесите изменения, которые, возможно, будут загружены в производство. Зафиксируйте их в этой ветке.
New Feature Here
Теперь откройте IP или домен машины производства в браузере. Вы увидите:
Here is a title!
Please deploy me!
Here is a change.
New Feature Here
Это связано с тем, что машина разработки по-прежнему развертывает код при каждом коммите. Этот рабочий процесс отлично подходит для тестирования изменений до их перемещения в производство.
Вы можете выгрузить ветку test_feature на удаленный сервер:
git push production test_feature
Вы увидите новое сообщение от хука post-receive:
Если вы снова запустите сервер производства в браузере, вы увидите, что ничего не изменилось. Это ожидаемое поведение, поскольку загруженное изменение не было в ветке master.
Теперь, когда вы протестировали изменения на машине разработки, вы можете включить эту функцию в основную ветку. Мы можем проверить ветку master и объединить ее с веткой test_feature на машине разработки:
git checkout master
git merge test_feature
Вы добавили новую функцию в главную ветку. Загрузите изменения на производственный сервер, чтобы развернуть новую функцию.
git push production master
В браузере введите домен или IP-адрес сервера производства, и вы увидите:
Here is a title!
Please deploy me!
Here is a change.
New Feature Here
Используя этот рабочий процесс, вы получите машину разработки, которая сразу же развертывает все зафиксированные изменения. Машина производства будет обновляться всякий раз, когда вы будете обновлять ветку master.