La mise en place des hooks de Git et le partage de ceux-ci avec l’ensemble de l’équipe d’un projet peut parfois s’avérer compliqué. Nous avons vu brièvement dans un précédent article que l’utilisation de librairie husky pouvait grandement nous faciliter cette mise en place. C’est ce que nous allons voir aujourd’hui.
Mise à jour : Cet article est une mise à jour de l’article initiale suite à la sortie de la version 7 de husky qui change la mise en place des différents hooks.
Un hook c’est quoi ?
Avant de s’attaquer à la librairie husky, voyons voir ce qu’est un hook. Un hook est simplement un script qui s’exécute automatiquement lorsqu’un événement particulier se produit dans un dépôt Git. On distingue deux types de hooks, ceux s’exécutant côté client et ceux s’exécutant côté serveur.
Côté client
Les hooks côté client s’exécutent uniquement sur les machines des utilisateurs et ne sont pas partagés avec les membres de l’équipe d’un projet, nous reviendrons sur ce point lorsque nous parlerons de la librairie husky.
On distingue trois catégories de hooks côté client :
- Les hooks concernant les commits;
- Les hooks concernant l’application de correctifs;
- Les hooks concernant les autres opérations.
Les hooks concernant les commits
Les hooks concernant les commits permettent d’effectuer certaines actions telles que la vérification des tests unitaires, le pré-remplissage d’un message de commit, la vérification du respect des conventions de nommage des messages de commit comme nous l’avons vu dans le précédent article ou même l’envoie de notification aux autres membres de l’équipe avec par exemple les changements effectués par le commit.
Les principaux hooks concernant les commits sont les suivants :
pre-commit
: Ce hook se déclenche en premier avant même de saisir le message du commit;prepare-commit-msg
: Ce hook se déclenche avant que l’éditeur de message ne soit lancé;commit-msg
: Ce hook se déclenche juste après l’édition du message du commit, mais avant la création de celui-ci;post-commit
: Ce hook se déclenche après la création du commit.
Les hooks concernant l’application de correctifs
Cette catégorie de hooks concerne les correctifs envoyés par email. Voici les principaux hooks concernant cette catégorie :
applypatch-msg
: Ce hook se déclenche avant l’application du correctif;pre-applypatch
: Ce hook se déclenche après l’application du correctif, mais avant la création du commit associé;post-applypatch
: Ce hook se déclenche une fois le correctif appliqué et le commit associé crée.
Les hooks concernant les autres opérations
Il existe également d’autres hooks qui ne rentrent pas dans les deux premières catégories. Voici les principaux :
pre-rebase
: Ce hook se déclenche avant l’exécution de la commandegit rebase
;post-checkout
: Ce hook se déclenche après l’exécution de la commandegit checkout
ougit clone
;post-merge
: Ce hook se déclenche après l’exécution réussie de la commandegit merge
;pre-push
: Ce hook se déclenche avant l’exécution de la commandegit push
.
Côté serveur
Ces hooks contrairement à ceux vus précédemment sont uniquement exécutés par le serveur qui héberge le dépôt Git.
Les principaux hooks serveur sont les suivants :
pre-receive
: Ce hook se déclenche lorsqu’une personne effectue la commandegit push
. Il s’exécute juste avant la réception des objets et des références;update
: Ce hook est similaire au hookpre-receive
, mais contrairement à celui-ci qui s’exécute une seule fois quelque soit le nombre de branches concernées par la modification,update
s’exécute pour chacune des branches devant être modifiées;post-receive
: Ce hook se déclenche une fois l’ensemble des objets et références ont été mis à jour.
Pour les plus curieux d’entre vous, la liste complète des hooks est disponible sur la documentation officielle de git : https://git-scm.com/docs/githooks.
Comment mettre en place les hooks ?
Après avoir vu ce qu’était un hook, voyons comment mettre en place ceux-ci.
Pour ajouter un hook côté client, il suffit de se rendre dans le dossier caché .git
de votre projet puis le sous-dossier .hooks
et de créer un script ayant le même nom que le hook que vous souhaitez ajouter.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | +---.git +---hooks | applypatch-msg.sample | commit-msg.sample | fsmonitor-watchman.sample | post-update.sample | pre-applypatch.sample | pre-commit.sample | pre-merge-commit.sample | pre-push.sample | pre-rebase.sample | pre-receive.sample | prepare-commit-msg.sample | update.sample |
Git fournit, pour chaque dépôt, des scripts d’exemples possédant l’extension .sample
. N’hésitez surtout pas à aller voir leur contenu. Pour les activer, retirer simplement l’extension .sample
.
L’un des soucis avec les hooks côté client et le partage de ceux-ci avec les autres membres de l’équipe. En effet, ceux-ci ne sont pas versionnés avec votre code et sont uniquement disponibles sur les machines des utilisateurs.
Pour résoudre ce problème, nous allons utiliser la librairie husky.
Note : Il existe bien entendu d’autres solutions. Par exemple l’utilisation d’un dossier partagé avec les membres de l’équipe contenant vos hooks configurables via l’option core.hooksPath.
Husky à la rescousse
Husky est une librairie permettant de faciliter la création et le partage des hooks au sein d’un projet. Commençons par l’installer :
1 | npm install husky --save-dev |
Puis activons les hooks avec la commande suivante :
1 | npx husky install |
Cela créera un dossier.husky
qui contiendra vos différents hooks.
Pour s’assurer que les hooks soient bien activés après l’installation des paquets, lancer la commande suivante :
1 | npm set-script prepare "husky install" |
Celle-ci va simplement ajouter un script prepare
dans le fichier package.json
:
1 2 3 4 5 | { "scripts": { "prepare": "husky install" } } |
Pour ajouter des hooks avec husky, il suffit ensuite d’utiliser la commande suivante :
1 2 | // Créer un hook "pre-commit" npx husky add .husky/pre-commit "CMD" |
Exemples d’utilisation
Voyons voir maintenant quelques exemples d’utilisations.
Respecter une convention d’écriture des messages de commit
Nous avons vu, dans le précédent article sur Git, une convention de nommage concernant les messages de commit. Nous avons également vu comment mettre en place un hook avec husky permettant de vérifier le respect de cette convention, je vous invite donc à aller lire cet article.
Respecter une convention de nommage de nos branches
Nous avons uniquement mis en place une vérification des messages de commit dans le précédent article. Il est possible également de vérifier le nommage de nos branches avant d’envoyer celles-ci sur le dépôt distant. Pour cela installons la librairie validate-branch-name
:
1 | npm install validate-branch-name --save-dev |
Configurons ensuite le modèle pour nos noms de branche. Nous pouvons soit configurer celui-ci via le fichier package.json
:
1 2 3 4 5 6 | { "validate-branch-name": { "pattern":"^(master|develop){1}$|^(feature|bugfix|hotfix|chore|experiment)\/([\w-]+?)(\/\d+)?$", "errorMsg":"Branch name format : <type>/<name>/<issue_ID>" } } |
Soit en créant un fichier .validate-branch-namerc :
1 2 3 4 | { "pattern":"^(master|develop){1}$|^(feature|bugfix|hotfix|chore|experiment)\/([\w-]+?)(\/\d+)?$", "errorMsg":"Branch name format : <type>/<name>/<issue_ID>" } |
L’expression régulière s’assure juste que le nom des branches respecte le format <type>/<name>/<issue_ID>
comme vu dans le précédent article.
Je sais que vous maîtrisez les expressions régulières, il est donc inutile de vous expliquer en détail (#troll). Si jamais vous ne comprenez pas et j’en doute fortement, il y a le site regex101 qui peut vous aider.
Il nous reste plus qu’à créer le hook via la commande suivante :
1 | npx husky add .husky/pre-push "npx validate-branch-name" |
Formater son code et vérifier les erreurs avant un commit
Afin d’éviter de vous faire engueuler en envoyant du code qui de toute façon va être rejeté par votre outil d’intégration continue, car celui-ci ne respecte pas les conventions de codage ou comporte des erreurs de syntaxe, il est peut être intéressant de faire une vérification avant chaque commit.
Nous allons donc utiliser prettier
et eslint
pour cet exemple, mais vous pouvez également utiliser standard
. Tout dépend des règles de formatage que vous utilisez c’est pourquoi nous n’allons pas rentrer dans les détails concernant la configuration de ces outils, qui pourrait faire l’objet d’un article à eux seuls, mais plutôt nous concentrer sur la mise en place du hook.
Pour vérifier uniquement les fichiers indexés plutôt que l’intégralité de notre projet, nous allons utiliser la librairie lint-staged
. Installons celle-ci :
1 | npm install lint-staged --save-dev |
Passons ensuite à la configuration de lint-staged
et ajoutons nos commandes permettant de vérifier et formater notre code. Nous pouvons soit directement ajouter la configuration dans le fichier package.json
:
1 2 3 4 5 6 7 8 9 10 | { "lint-staged": { "*.(js|html|css)": [ "prettier --write" ], "*.js": [ "eslint --fix" ] } } |
Soit passer par un fichier .lintstagedrc
:
1 2 3 4 5 6 7 8 | { "*.(js|html|css)":[ "prettier --write" ], "*.js":[ "eslint --fix" ] } |
La première commande prettier --write
formate les fichiers dont l’extension se termine par js
, html
, ou css.
La seconde commande quant à elle corrige les erreurs eslint
des fichiers dont l’extension se termine par js
.
Mettons en place le hook qui va lancer ses deux commandes lors d’un git commit
, pour cela lançons la commande suivante :
1 | npx husky add .husky/pre-commit "npx lint-staged" |
Vérifier les tests avant d’envoyer ses modifications
Il peut être également intéressant de vérifier que les tests passent avant d’autoriser l’envoi de votre code sur votre dépôt distant. Mettons en place cette vérification avec husky via la commande suivante :
1 | npx husky add .husky/pre-push "npm run test" |
Eh oui ! C’est tout, si les tests échouent, il est impossible d’envoyer du code sur votre dépôt distant.
D’autres exemples
Il existe tout un tas d’autres cas d’utilisation des hooks :
- Vérification des tâches non terminées (via les commentaires TODO, FIXME, etc.);
- Vérifications de sécurité (présence de mots de passe ou de clés d’API par exemple);
- Envoi de notifications;
- Des trucs totalement inutiles, mais fun comme prendre une photo via la webcam à chaque commit (lolcommit);
- etc.
Contourner les hooks
Il est possible de contourner l’utilisation des hooks via l’option --no-verify
de la plupart des commandes Git, n’hésitez pas à aller lire la documentation de chacune des commandes pour en savoir plus.
Pour finir…
Les hooks de Git sont un outil très puissant, mais souvent peu connu des développeurs. Ils permettent par exemple de s’assurer de la qualité de son code avant l’envoi sur le dépôt distant. Leur mise en place et leur partage deviennent un jeu d’enfant avec l’utilisation de la librairie husky
, on aurait donc tort de s’en priver.
Je suis lead developer dans une boîte spécialisée dans l’univers du streaming/gaming, et en parallèle, je m’éclate en tant que freelance. Passionné par l’écosystème JavaScript, je suis un inconditionnel de Node.js depuis 2011. J’adore échanger sur les nouvelles tendances et partager mon expérience avec les autres développeurs.
Si vous avez envie de papoter, n’hésitez pas à me retrouver sur Twitter, m’envoyer un petit email ou même laisser un commentaire.