Aller au contenu principal

Git Hooks — Automatiser le contrôle qualité

Module 05 45 min

Objectifs de la section

  • Comprendre ce que sont les hooks Git et comment ils fonctionnent
  • Créer des hooks pre-commit, commit-msg et pre-push
  • Partager les hooks avec l'équipe via des outils
  • Utiliser husky pour les projets JavaScript/Node.js

Qu'est-ce qu'un hook Git ?

Les hooks Git sont des scripts qui s'exécutent automatiquement lors d'événements Git (commit, push, merge...). Ils permettent d'automatiser :

  • La vérification du format des messages de commit
  • Le linting et le formatage du code
  • L'exécution des tests avant un push
  • La validation des changements

Où sont les hooks ?

# Les hooks sont dans .git/hooks/
ls .git/hooks/
# applypatch-msg.sample
# commit-msg.sample
# pre-commit.sample
# pre-push.sample
# ...

# Activer un hook : supprimer l'extension .sample
cp .git/hooks/pre-commit.sample .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit

Les hooks les plus utiles

1. pre-commit — Avant le commit

S'exécute avant l'enregistrement du commit. Si le script retourne un code d'erreur, le commit est annulé.

#!/bin/bash
# .git/hooks/pre-commit

echo "Exécution des vérifications pre-commit..."

# Vérification 1 : Pas de fichiers .env commités
if git diff --cached --name-only | grep -E "\.env$|\.env\.local$"; then
echo "ERREUR : Fichier .env détecté ! Ne commitez jamais les fichiers d'environnement."
exit 1
fi

# Vérification 2 : Linting Python (si pylint est installé)
if command -v pylint &> /dev/null; then
FICHIERS_PY=$(git diff --cached --name-only --diff-filter=ACM | grep "\.py$")
if [ -n "$FICHIERS_PY" ]; then
pylint $FICHIERS_PY
if [ $? -ne 0 ]; then
echo "ERREUR : Le linting a échoué. Corrigez les erreurs avant de commiter."
exit 1
fi
fi
fi

# Vérification 3 : Tests Python
if command -v pytest &> /dev/null; then
pytest tests/ --tb=short -q
if [ $? -ne 0 ]; then
echo "ERREUR : Des tests ont échoué. Corrigez-les avant de commiter."
exit 1
fi
fi

echo "Toutes les vérifications pre-commit ont réussi ✅"
exit 0

2. commit-msg — Valider le message de commit

#!/bin/bash
# .git/hooks/commit-msg

FICHIER_MSG_COMMIT="$1"
MESSAGE=$(cat "$FICHIER_MSG_COMMIT")

# Vérifier le format Conventional Commits
# Pattern : type(portée optionnelle): description
PATTERN="^(feat|fix|docs|style|refactor|test|chore|perf|ci|revert)(\(.+\))?: .{1,72}"

if ! echo "$MESSAGE" | grep -qE "$PATTERN"; then
echo "ERREUR : Message de commit invalide !"
echo ""
echo "Format requis : type(portée): description"
echo "Types valides : feat, fix, docs, style, refactor, test, chore, perf, ci, revert"
echo ""
echo "Exemples :"
echo " feat(auth): ajouter le formulaire de connexion"
echo " fix(api): corriger la validation email"
echo " docs: mettre à jour le README"
echo ""
echo "Votre message : $MESSAGE"
exit 1
fi

# Vérifier la longueur du sujet (max 72 caractères)
SUJET=$(echo "$MESSAGE" | head -1)
if [ ${#SUJET} -gt 72 ]; then
echo "ERREUR : Le sujet du commit est trop long (${#SUJET}/72 caractères)"
exit 1
fi

echo "Message de commit valide ✅"
exit 0

3. pre-push — Avant le push

#!/bin/bash
# .git/hooks/pre-push

echo "Exécution des vérifications pre-push..."

# Exécuter la suite de tests complète
pytest tests/ -v
if [ $? -ne 0 ]; then
echo "ERREUR : Des tests ont échoué. Corrigez avant de pousser."
exit 1
fi

# Vérifier la couverture de code
pytest tests/ --cov=src --cov-report=term-missing --cov-fail-under=70
if [ $? -ne 0 ]; then
echo "AVERTISSEMENT : La couverture de code est inférieure à 70%"
exit 1
fi

echo "Toutes les vérifications pre-push ont réussi ✅"
exit 0

Partager les hooks avec l'équipe

Problème : Le dossier .git/hooks/ n'est pas versionné, donc les hooks ne se partagent pas automatiquement.

Solution : Stocker les hooks dans un dossier versionné et les lier.

# Créer un dossier pour les hooks dans le dépôt
mkdir -p .githooks

# Copier vos hooks
cp .git/hooks/pre-commit .githooks/pre-commit
cp .git/hooks/commit-msg .githooks/commit-msg

# Configurer Git pour utiliser ce dossier
git config core.hooksPath .githooks

# Rendre les hooks exécutables
chmod +x .githooks/*

# Commiter les hooks
git add .githooks/
git commit -m "chore: ajouter les hooks Git de l'équipe"

Ajoutez dans votre README.md :

## Configuration du projet

Après avoir cloné le dépôt, configurez les hooks :
```bash
git config core.hooksPath .githooks
chmod +x .githooks/*

---

## Husky — Hooks pour projets Node.js

Pour les projets JavaScript/Node.js, **Husky** gère les hooks automatiquement :

```bash
# Installer Husky
npm install --save-dev husky

# Initialiser Husky
npx husky init

# Créer le hook pre-commit
echo "npm test" > .husky/pre-commit

# Créer le hook commit-msg (avec commitlint)
npm install --save-dev @commitlint/cli @commitlint/config-conventional
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg

Désactiver temporairement les hooks

# Désactiver un hook pour un commit spécifique (cas d'urgence)
git commit --no-verify -m "fix: correction urgente en prod"
git push --no-verify

# Désactiver tous les hooks globalement
git config --global core.hooksPath /dev/null
# (à ne faire qu'en cas d'urgence absolue !)

Résumé

HookQuand s'exécuteCas d'utilisation
pre-commitAvant chaque commitLinting, tests, vérification de secrets
commit-msgAprès la saisie du messageValider le format du message
pre-pushAvant chaque pushTests complets, couverture
post-mergeAprès un mergeInstaller les nouvelles dépendances
prepare-commit-msgAvant l'éditeurPré-remplir le message

Prochaines étapes