K čemu je nástroj pre-commit dobrý
Jednou z užitečných funkcionalit Gitu jsou zásuvné moduly (hooks), které mohou při určitých událostech provádět námi definované akce. Například před vytvořením revize (commit) mohou automaticky spouštět nástroje pro kontrolu, opravu a formátování kódu. Je tak mnohem snazší včas odchytávat některé chyby a dodržovat konvence daného projektu, neboli – slovy Pavla Herouta – udržovat „štábní kulturu“. Šetříme tak čas a úsilí jak sobě tak i lidem, kteří provádějí revizi našeho kódu (code review).
Problém ale nastane ve chvíli, kdy chceme svoje zásuvné moduly sdílet mezi projekty s různou strukturou. Nebo chceme volat program vyžadující instalaci jazyka, který v našem projektu nepoužíváme. Proto vznikl nástroj pre-commit, který umožňuje spravovat celou řadu zásuvných modulů Gitu (tedy nejen modul pre-commit, třebaže se v tomto článku budeme věnovat výhradně jemu) jednoduše a nezávisle na projektu a použitém jazyce.
Vezměme praktický příklad: Před vytvořením revize (commit) chceme automaticky zkontrolovat syntax, zbavit se nadbytečných bílých znaků, předejít úniku soukromých klíčů a opravit konce souborů. Náš projekt je napsaný v jazyce Python a soubory připravené k revizi chceme nejprve opravit a zformátovat pomocí nástrojů isort a black, a poté zkontrolovat pomocí flake8. Toto vše tedy nadefinujeme v souboru .pre-commit-config.yaml, nainstalujeme balíček pre-commit a (vyjma konfiguračních detailů) se už o nic dalšího zpravidla nemusíme starat.
Instalace
pre-commit lze nainstalovat z pypi.org:
$ python3 -m pip install --user pre-commit
Další možnosti (zipapp, homebrew, conda) jsou popsány v dokumentaci.
Konfigurace
Pro snadné vyzkoušení si naklonujeme repozitář s demonstračními příklady:
$ git clone https://github.com/peberanek/pre-commit-examples
Máme zde soubor example.py s několika vadami ve zdrojovém kódu, a soubor .pre-commit-config.yaml, který nám definuje akce popsané v posledním odstavci předchozí kapitoly:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-yaml # syntax check
- id: trailing-whitespace
- id: detect-private-key
- id: end-of-file-fixer
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
args: ["--profile", "black"]
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
- repo: https://github.com/pycqa/flake8
rev: 6.0.0
hooks:
- id: flake8
args: ["--max-line-length", "100"]
První akce – neboli plugin nástroje pre-commit – začíná odkazem na repozitář ( repo) a označením revize nebo tagu ( rev), které chceme nainstalovat. Následuje výčet zásuvných modulů ( hooks pro daný plugin), které chceme volat. V našem případě provádět kontrolu syntaxe souborů ve formátu YAML, zbavovat se přebytečných bílých znaků a tak dále.
Jak můžeme vidět u pluginu isort, použitým nástrojům můžeme předávat i argumenty ( args) jako při volání z příkazové řádky, což se hodí kdybychom chtěli načítat nějaký externí konfigurační soubor, například:
- repo: https://github.com/PyCQA/bandit
rev: 1.7.5
hooks:
- id: bandit
args: ["-c", "pyproject.toml"]
additional_dependencies: ["bandit[toml]"]
Spuštění
Jakmile máme základní konfiguraci hotovou, nainstalujeme pre-commit do našeho gitovského repozitáře:
$ pre-commit install
Nyní se nám při každém vytváření revize ( git commit) zavolají vybrané pluginy automaticky. Pokud si chceme funkčnost ověřit bez nutnosti vytvářet novou revizi, jde to udělat následovně:
$ pre-commit run --all-files
--all-files pracuje pre-commit pouze se soubory připravenými k revizi (stage).Jak můžeme vidět na obrázku, pre-commit odhalil několik problémů.isort ablack automaticky opravily řazení importů a formátování. Zapomenutý soukromý klíč (který se v reálu v repozitáři vůbec nesmí objevit) a nepoužitý modulsys odstraníme manuálně. Jakmile jsou problémy opravené, při tvorbě další revize (git commit -a ) již všechny kontroly projdou.
Jednotlivé pluginy a jejich zásuvné moduly lze volat i samostatně, například pouzeblack (voláme pomocí hodnoty klíčeid z konfigurace výše):
$ pre-commit run black
Shrnutí a další odkazy
V článku jsme si ukázali jednoduché nastavení a použití správce gitovských zásuvných modulů nazvaného pre-commit. Ten nám může usnadnit automatizaci některých rutinních akcí a ve svém důsledku tak i pomoct k více konzistentnímu a kvalitnějšímu kódu.
V případě, že vás nástroj zaujal, mohl by vás zajímat přehled použití a správa z příkazové řádky, využití v rámci Průběžné integrace (CI) nebo tvorba vlastních zásuvných modulů pro pluginy.
(Autorem obrázků je Petr Beránek.)

