Intégration continue et pré-commit hooks avec Husky
La qualité du code se construit bien avant l’ouverture d’une pull request. Une faute de formatage, une variable inutilisée ou un test oublié peut sembler anodine sur un poste local, puis ralentir toute l’équipe une fois le changement intégré à la branche principale. Les contrôles automatisés réduisent ce risque en intervenant au moment où le développeur écrit et valide son code.
Les pré-commit hooks sont des scripts exécutés juste avant la création d’un commit Git. Ils peuvent lancer un formateur, un linter, des tests ciblés ou une vérification de types. Husky simplifie leur installation dans un projet JavaScript ou TypeScript et rend ces règles visibles dans le dépôt, au lieu de les laisser dépendre de la configuration personnelle de chaque machine.
Cette approche s’inscrit dans une chaîne d’intégration continue plus large. Les contrôles locaux offrent un retour immédiat, tandis que le serveur de CI vérifie l’ensemble du projet dans un environnement reproductible. Ces deux niveaux se complètent : le premier évite les erreurs triviales, le second protège la branche partagée.
Pour un projet Node.js, React ou TypeScript, la mise en place peut rester progressive. Il est préférable de commencer par quelques règles rapides et fiables, puis d’ajouter les tests, l’analyse statique et les contrôles de sécurité lorsque l’équipe maîtrise le flux de travail.
Comprendre la place des contrôles locaux
Un hook Git agit comme un point de contrôle avant une opération précise. Le hook pre-commit intervient avant la création du commit, tandis que commit-msg peut valider le format du message et pre-push lancer une suite de tests plus coûteuse. Cette granularité permet de choisir le bon moment pour chaque vérification.
L’objectif n’est pas de transformer chaque commit en pipeline interminable. Un contrôle exécuté en quelques secondes peut vérifier les fichiers modifiés avec ESLint et Prettier. Les tests d’intégration, les audits de dépendances et la compilation complète restent généralement adaptés au serveur d’intégration continue.
Cette séparation accélère le cycle de développement. Le développeur reçoit une erreur près de sa source, corrige le problème avant de le publier et évite une exécution inutile sur le runner CI. Les règles doivent toutefois rester identiques entre le poste local et le pipeline, afin qu’un commit accepté localement ne soit pas systématiquement rejeté à distance.
Installer Husky Dans Un Projet Node.js
Husky s’ajoute comme dépendance de développement. Après l’installation, un script de préparation initialise les hooks lorsque les dépendances sont installées :
npm install --save-dev husky
npm pkg set scripts.prepare="husky"
npm run prepare
Selon la version utilisée, la commande d’initialisation peut différer légèrement. Le principe reste le même : le dépôt contient une configuration versionnée et chaque membre de l’équipe bénéficie des mêmes règles après un npm install.
Pour éviter de traiter tout le projet à chaque validation, lint-staged cible uniquement les fichiers placés dans l’index Git. Une configuration typique peut associer les fichiers JavaScript et TypeScript à ESLint, puis appliquer Prettier aux sources, aux fichiers JSON et à la documentation. Si une commande échoue, le commit est interrompu et les modifications restent disponibles pour correction.
Construire Un Hook Rapide Et Prévisible
Un hook efficace doit être déterministe, lisible et suffisamment court pour ne pas inciter les développeurs à le contourner. Une chaîne courante commence par le formatage, poursuit avec le linting, puis exécute les tests unitaires liés aux fichiers modifiés. TypeScript peut intervenir avec tsc --noEmit lorsque la vérification complète reste acceptable en local.
Il faut distinguer les erreurs bloquantes des simples avertissements. Une règle ESLint qui signale une variable non utilisée peut arrêter le commit, alors qu’un outil de détection de complexité peut d’abord produire un rapport. Cette hiérarchie évite de rendre le mécanisme trop sévère dès son adoption.
Les hooks ne remplacent pas les revues de code. Ils garantissent des invariants mécaniques — style, syntaxe, types ou tests — tandis que la revue examine l’architecture, la lisibilité et les conséquences métier. Dans un service qui exploite PostgreSQL, par exemple, la qualité d’une requête ou d’un index mérite une analyse humaine en complément des vérifications automatisées, comme le montre ce guide sur un moteur de recherche full-text.
Relier Les Hooks À L’intégration Continue
Le pipeline CI doit repartir d’un environnement propre : installation verrouillée avec npm ci, exécution du lint, contrôle des types, tests et production du paquet. Il ne faut pas supposer qu’un hook local a été exécuté, car Git permet de désactiver les hooks et les robots CI travaillent souvent dans un clone fraîchement créé.
| Contrôle | Moment d’exécution | Périmètre conseillé | Objectif |
|---|---|---|---|
| Formatage | Pré-commit | Fichiers modifiés | Uniformiser le style |
| Linting | Pré-commit et CI | Fichiers modifiés puis dépôt entier | Détecter les erreurs de code |
| Tests unitaires | Pré-commit ciblé et CI | Modules concernés puis projet complet | Vérifier le comportement |
| Compilation et types | CI, parfois localement | Projet entier | Garantir un artefact cohérent |
| Audit de sécurité | CI planifiée ou à chaque fusion | Dépendances et configuration | Réduire le risque logiciel |
La branche principale peut exiger le passage au vert avant toute fusion. Une règle de protection GitHub ou GitLab bloque alors les changements qui échouent aux tests, même si un développeur a contourné le pré-commit. La CI devient la source d’autorité, tandis que Husky reste un accélérateur de feedback.
Le même raisonnement s’applique à l’observabilité. Une chaîne de livraison robuste doit produire des journaux exploitables et suivre les erreurs après déploiement ; la mise en place de logs unifiés avec Loki, Promtail et Grafana illustre cette continuité entre qualité du code et fonctionnement en production.
Gérer Les Exceptions Sans Affaiblir La Règle
Un hook peut échouer pour une raison légitime : migration massive de formatage, génération de code ou intervention urgente. Le contournement doit rester exceptionnel et traçable. La commande git commit --no-verify existe, mais elle ne doit pas devenir une habitude ni remplacer la correction de la configuration.
Les fichiers générés doivent généralement être exclus du linting, tandis que les fichiers sources restent contrôlés. Un monorepo peut également définir des règles propres à chaque paquet, avec une configuration commune pour les conventions partagées. Les développeurs doivent savoir quelle commande relancer manuellement pour diagnostiquer un échec.
Il est utile d’afficher des messages précis et de limiter les outils redondants. Deux linters qui signalent la même erreur créent de la confusion. La documentation du dépôt doit expliquer l’installation, les scripts disponibles et la procédure de mise à jour des hooks, particulièrement pour les nouveaux contributeurs.
Étendre La Qualité Aux Tests Et À La Sécurité
Après le style et le linting, l’équipe peut intégrer des tests unitaires ciblés, une vérification des types et un contrôle des dépendances. Les tests rapides s’exécutent avant le commit, tandis que les scénarios d’intégration sont réservés à la CI. Cette organisation évite de ralentir chaque modification tout en conservant une couverture fiable avant fusion.
Les contrôles de sécurité doivent être adaptés au risque. Une analyse des secrets, une vérification des paquets vulnérables et une analyse statique peuvent être déclenchées dans le pipeline. Pour les applications qui appellent des services distants, la robustesse du code d’exécution mérite aussi une attention dédiée : l’implémentation du pattern Circuit Breaker avec Polly et HttpClient fournit un exemple transposable dans la réflexion sur les défaillances réseau.
La qualité se mesure à plusieurs niveaux. Un test qui échoue rapidement est utile, mais un test instable qui bloque fréquemment les fusions dégrade la confiance dans la CI. Les équipes doivent donc surveiller la durée des jobs, le taux d’échec non lié au code et le temps moyen de correction.
Faire Évoluer Les Règles Avec L’équipe
Une configuration de hooks doit suivre la réalité du projet. Quand le nombre de fichiers augmente, il devient pertinent de paralléliser certaines tâches, de mettre en cache les dépendances et de réserver les vérifications lourdes à la CI. Dans un monorepo, les outils de détection des paquets affectés peuvent réduire fortement le temps d’exécution.
Les règles gagnent à être introduites par étapes : formatage automatique, linting des fichiers modifiés, tests unitaires ciblés, puis validation complète dans le pipeline. Chaque ajout doit être accompagné d’une explication et d’un résultat observable. Cette progression facilite l’adoption et permet de corriger les faux positifs avant qu’ils ne deviennent une source de frustration.
L’analyse de code peut également soutenir les décisions techniques. Dans un projet de machine learning ou de scoring, comprendre l’influence des variables est essentiel ; une ressource sur la valeur de Shapley rappelle que les résultats automatisés doivent rester interprétables. La même exigence vaut pour les règles de qualité : chaque blocage doit avoir une raison compréhensible.
Adoptez une première version dès maintenant : installez Husky, activez un pré-commit avec ESLint et Prettier, puis ajoutez ce même contrôle au pipeline CI. Mesurez sa durée, documentez les commandes et faites évoluer les règles avec les besoins du projet. Cette discipline transforme progressivement la qualité du code en réflexe quotidien, sans attendre la phase de revue ou le déploiement.