Sauvez vos commits grâce à husky et git-precommit-checks
Par Maxime Bréhin • Publié le 6 sept. 2021

Au-delà de la mise en forme du code et du respect des bonnes pratiques, on souhaite que nos commits ne contiennent pas n’importe quoi. Pour les fichiers non versionnables, on a déjà le fichier .gitignore. Mais qu’en est-il pour les fichiers qu’on souhaite versionner ? Comment empêcher l’ajout de contenus indésirables ?

C’est là qu’intervient git-precommit-checks et son exécution automatique au moment du commit grâce à husky, dont nous avons couvert la mise en place dans un précédent article.

Vous préférez une vidéo ?

Si vous êtes du genre à préférer regarder que lire pour apprendre, on a pensé à vous :

Comment ça marche ?

git-precommit-checks est un module npm à installer sur vos projets et à exécuter en pre-commit. Il analyse uniquement les ajouts et modifications des fichiers ajoutés en vue du commit (stagés suite à un git add …). Il nous permet soit de stopper le commit en cas de détection d’un contenu non souhaité, soit d’afficher une alerte sur la sortie standard, si on considère que certains contenus sont « tolérables » mais méritent d’être signalés.

Contrairement à un outil d’analyse statique (linter), il n’est pas limité à un langage source. C’est à nous de lui décrire les textes recherchés, éventuellement les motifs de fichiers concernés, et le message à afficher.

Mise en place

Pour l’installation, rien de bien difficile :

# Installation
npm install --save-dev git-precommit-checks
# Configuration en pre-commit via husky
npx husky add .husky/pre-commit "npx --no-install git-precommit-checks"

Là, sur le papier tout est bon, sauf qu’on n’a renseigné aucune règle d’analyse. C’est le moment de vous poser avec votre cahier et votre crayon et de noter les choses qui vous semblent pertinentes pour votre projet.

Quand vous êtes prêt·e, vous pourrez créer la configuration dans le fichier git-precommit-checks.config.js (en pratique vous pouvez la renseigner sous d’autres formats, mais le JS est souvent plus lisible).

Voici un exemple pour vous inspirer :

module.exports = {
  display: {
    // Utilise les notifs système pour nous signler qu’un
    // problème est détecté.
    notifications: true,
    // Affiche les chemins des fichiers et numéros de lignes
    // ainsi que les contenus défaillants. Pratique pour ouvrir
    // via un "Ctrl + clic" le fichier au bon emplacement
    // directement dans l'éditeur.
    offendingContent: true,
    // Si jamais on souhaite obtenir l’affiche dans le
    // terminal du détail des règles en place.
    rulesSummary: false,
    // Si on veut afficher des statistiques simplifiées
    // (exemple : "1 error, 1 warning").
    shortStats: true,
    // Pour afficher le détail de chaque action executée,
    // les fichiers analysés, le résumé des opérations.
    verbose: false,
  },
  rules: [
    // Règles globales, appliquées sur tous les contenus ajoutés
    {
      // On renseigne le message qui doit nous être affiché en cas de problème.
      message: 'Aurais-tu oublié de terminer certaines tâches ?',
      // Ici on indique qu’on veut juste une alerte, sans stopper le commit.
      // Par défaut c’est renseigné à "false".
      nonBlocking: true,
      // On passe sous forme de texte ou d’expression rationnelle
      // les contenus à rechercher.
      regex: /(?:FIXME|TODO)/,
    },
    {
      message: 'Tu as des marqueurs de conflits qui traînent',
      regex: /^[<>|=]{4,}/m,
    },
    {
      message:
        'Arrêt du commit : tu as renseigné des choses qui ne doivent pas être commitées !',
      regex: /do not commit/i,
    },
    // Ensuite on peut spécifier des fichiers ou motifs particuliers
    // pour appliquer nos règles, ça se fait avec la propriété "filter".
    {
      // Là encore on peut utiliser une expression rationnelle
      filter: /\.js$/,
      message: '🤔 Hum ! N’as-tu pas oublié de retirer du "console.log(…)" ?',
      nonBlocking: true,
      regex: /^\s*console\.log/,
    },
    // Spécifique à Ruby/Rails
    {
      filter: /_spec\.rb$/,
      message: 'Tu as laissé traîner un "focus" dans tes tests RSpec',
      regex: /(?:focus: true|:focus => true)/,
    },
    {
      filter: /\.rb$/,
      message:
        'Ça sent l’oubli après un debug manuel : regarde ce `binding.pry` qui traîne',
      regex: /^[^#]*\bbinding\.pry/,
    },
  ],
}

Voyons voir ce que ça donne une fois en place :

Pour aller plus loin 🐱‍🏍

L’automatisation autour du commit est précieuse pour nous permettre de nous concentrer sur notre travail sans craindre pour autant de faire des erreurs ou d’oublier des choses. La vérification des contenus n’est pas la seule chose utile à mettre en place, libre à vous de compléter avec d’autres assistances :

Découvrez nos cours vidéo ! 🖥

Nos cours vidéo sont un complément idéal et bon marché à nos articles techniques et formations présentielles. Autour de Git, de JavaScript et d’autres sujets, retrouvez des contenus de très grande qualité à des prix abordables, spécialement conçus pour lever vos plus gros points de blocage.