Ilmselt on kõik, kes kasutavad Git'i, vähemalt korra kuulnud terminit Git hook. Aga mul isiklikult ei ole varasemalt olnud vajadust neid uurida. Mingites projektides olen küll näid näinud kasutusel, aga ma ei olnud neid kunagi loonud ega süveninud nende sisusse. Tuleb aga välja, et Git hook'id on tegelikult väga kasulikud tööriistad, mis võimaldavad automatiseerid Git'i tööprotsessi osasid. See tähendab, et saab luua skripte, mis käivituvad kindlate tegevuste tegemisel, näiteks enne või pärast commit'i või push'i.
Git hook'i kasutamine
Ise kasutasin Git hook'e selleks, et automatiseeride Kotlini Ktlint'i kasutamine. Kui lokaalselt jätta see käivitamata võivad vormistusvead jääda märkamata ja see teeb katki tarkvara kokkuehitamise protsessi. Võimalik on muidugi kasutada ka näiteks IntelliJ'i enda vahendeid, et automatiseerid vormistuse kontroll, aga see ei oleks universaalne lahendus, mis töötab igas arendaja arvutis samamoodi. Seega Git hook on ideaalne võimalus, kuidas vormistuse vead automaatselt parandada enne commit'i. Näide Ktlint'i kasutamisest pre-commit hook'ina:
#!/bin/bash
# Stash the current index to be used in the event of failure
git stash -q --keep-index
echo "Running Ktlint before git commit is committed"
./gradlew ktlintFormat
RESULT=$?
git stash pop -q
# return 1 exit code if running checks fails
[ $RESULT -ne 0 ] && exit 1
######## KTLINT-GRADLE HOOK START ########
CHANGED_FILES="$(git --no-pager diff --name-status --no-color --cached | awk '$1 != "D" && $2 ~ /\.kts|\.kt/ { print $2}')"
if [ -z "$CHANGED_FILES" ]; then
echo "No Kotlin staged files."
exit 0
fi;
echo "Running ktlint over these files:"
echo "$CHANGED_FILES"
./gradlew --quiet ktlintFormat -PinternalKtlintGitFilter="$CHANGED_FILES"
echo "Completed ktlint run."
echo "$CHANGED_FILES" | while read -r file; do
if [ -f $file ]; then
git add $file
fi
done
echo "Completed ktlint hook."
######## KTLINT-GRADLE HOOK END ########
Git hook'i loomine
Tähelepanu võiks pöörata asjaolule, et Git hook'e ei tohiks kesksesse reporitooriumisse otse lisada. Kuna .git kaust on lokaalne kataloog, siis tuleks olulised hook'id paigaldada kõigile arendajatele automaatselt. Gradle'i abil on see väga lihtne teha. Näiteks:
tasks.register('installGitHook', Copy) {
def lintingConfigScript = new File(rootProject.rootDir, '.git/hooks/pre-commit')
if (!lintingConfigScript.exists()) {
from new File(rootProject.rootDir, '.githooks/pre-commit')
into { new File(rootProject.rootDir, '.git/hooks') }
fileMode 0777
}
}
tasks.compileKotlin.dependsOn('installGitHook')