Subscribe RSS

Spydemon's personal blog

  • Clef GPG

Les hooks git

5 mai 2015 Posté par Spydemon sous Programmation, Sysadmin
Pas de commentaire

Git est un système de versionnage bien pratique pour plusieurs raisons. Les plus communes sont probablement la souplesse avec laquelle il est possible de cloner et repartager n’importe quel dépôt, sa notion de branches très fonctionnelle grâce aux commandes avancées que la solution propose (commits interactifs, rebase, stash et bien-sûr : merge), ou simplement le fait qu’il s’agisse d’une des technologies les plus populaires, donc la plus supportée. Une raison secondaire, mais potentiellement aussi puissante réside dans son système de hooks (« crochets », en français) autorisant le couplage avec des applications externes.

Concrètement, ce procédé nous permet d’automatiser des tâches annexes au versionnage, mais dépendant de celui-ci. Par exemple, un outil de revue de code susceptible de rejeter un commit s’il ne respecte pas certains standards, ou encore de procéder à un déploiement quand une branche évolue.

D’un point de vue technique, cela fonctionne comme le patron de conception « observeur ». C’est-à-dire que nous avons Git qui émet des signaux à certains stades de l’avancement de son exécution. À nous de nous y greffer pour lancer des tâches annexes.

Avant de lister les crochets disponibles, il reste à comprendre la différence d’usage entre ceux sur le serveur, et les autres côtés client. Ces premiers sont les seuls par lesquels le passage est imposé, car l’utilisateur aura toujours la possibilité de modifier ou de désactiver les hooks à son niveau. De plus, ils ne sont pas transférés en clonant le dépôt, ce qui rend leurs partages plus fastidieux. Ces derniers sont donc à réserver aux cas ou le développeur veut, localement, procéder à un couplage. C’est au serveur qu’on devra mettre en place les procédures automatisées de déploiement ou de revue de code propre à l’intégralité du projet.

Une fois cette distinction faite, nous pouvons à présent passer dans le listing des crochets disponibles :

Côté client :
  • Pre-commit : revue automatique du code à commiter.
  • Prepare-commit-msg : génération du message de commit.
  • Commit-msg : validation du message de commit.
  • Post-commit : notifications.
  • Applypatch-msg : validation du message du patch.
  • Pre-applypatch : validation du contenu d’un patch.
  • Post-applypatch : notification de l’application d’un patch.
  • Pre-rebase : avant d’effectuer un rebase.
  • Post-checkout : après avoir changé de branche.
  • Post-merge : après avoir mergé.
  • Côté serveur :

    • Pre-receive : valide ou non la poussée : vérification de la qualité du code, que l’utilisateur ne modifie pas de fichiers interdits, etc.
    • Post-receive : notification par emails, au logiciel d’intégration continue, ou encore mise à jour du bug tracker, etc.
    • Update : équivalent au crochet post-receive, mais avec une segmentation par branche.

    Ceux-ci sont présents dans le répertoire .git/hooks de votre dépôt de travail, et directement dans hooks pour un dépôt bare. Ils consistent simplement en une série de fichiers shell ayant le même intitulé que le hook qu’il représente. Par défaut, des exemples sont fournis. Il suffit de retirer le .sample au nom pour les activer.

    Voyons à présent comment implémenter ces choses.

    Hook côté client

    Pour nos tests, nous allons concevoir un petit script vérifiant que nous effectuons bien un retour à la ligne entre l’accolade ouvrante d’une classe ou d’une fonction, et sa signature.

    Voici le code à commiter :

    <?php
    function helloWord () {
    	echo ”Hello word !” ;
    }
    

    La création de cette révision devrait donc être empêchée. Comment procéder à ce contrôle ? La première étape consiste à définir au niveau de quel hook se greffer. Vous avez trouvé ? Il s’agit du pre-commit, car c’est le contenu même que nous voulons mettre à l’épreuve. Il nous reste plus qu’à écrire le script de test :

    #! /bin/sh
    set −e
    modif=‘git diff −−cached ‘
    
    printf %s ”$modif ” | while IFS= read −r line; do
    	if [[ $line =~ ˆ\+.∗(function | class).∗\{ ]] ; then
    		echo ” !reject : $line ”
    		echo ” !reject : jump a line for the brace! ”
    		exit 1
    	fi
    done
    
    exit 0
    

    La première chose à constater dans ce script se situe dans les codes de retour : 0 est l’unique valeur signalant à Git de continuer l’exécution. Les autres stopperont directement la création du commit. Nous avons le même comportement pour tous les hooks préfixés par « pre ».

    Il nous reste plus qu’à tester :

    $ git add test.php
    $ git status -s
    M test.php
    $ git commit -m "My new function."
    !reject: +function helloWord() {
    !reject: jump a line for the brace!
    $ git status -s
    M test.php
    $ git commit -m "My new function." --no-verify
    [master 2d29740] My new function.
    1 file changed, 1 insertion(+),
    1 deletion(-)
    $ git status -s
    $
    

    Nous apercevons le rejet par Git ainsi que l’affichage des retours de la commande echo présent dans notre script shell. L’exécution semble donc adéquate. 🙂 On notera aussi qu’il reste bien facile de passer au travers du filet via l’option –no-verify, ce qui confirme bien que le seul objectif ici est d’aider le développeur, et non de le restreindre. Ce comportement nous permet de réaliser très rapidement des hooks comme celui ci-dessus, qui sera fonctionnel presque partout, mais qui risquera quand même de poser problème dans quelques rares cas, par exemple le jour ou l’on voudra publier un one-liner, ou une fonction anonyme en Javascript. Dans ces circonstances, il nous suffira de le sauter plutôt que de perdre des heures pour le rendre compatible avec la subtilité du moment.

    Hook côté serveur

    Essayons à présent de vérifier le retour à la ligne avant l’accolade ouvrante au niveau du serveur. Une version incomplète ressemblerait à cela :

    #! /bin/sh
    set −e
    validation () {
    	newcontent=‘git show $2 ‘
    	printf %s ”$newcontent” | while IFS= read −r line; do
    		if [[ $line =~ ˆ\+.∗(function | class).∗\{ ]]; then
    			echo ”!reject: $line ”
    			echo ”!reject: jump a line for the brace!”
    			exit 1
    		fi
    	done
    }
    while read oldrev newrev refname ; do
    	validation $oldrev $newrev $refname
    done
    exit 0
    

    C’est un peu plus complexe, car ce crochet possède plus de données à traiter que précédemment. Je vous invite à consulter la documentation disponible sur Internet pour comprendre le fonctionnement en détail, mais sachez que cet exemple est incomplet : il ne vérifie que les plus jeunes enfants des branches poussées. En effet, si plusieurs révisions sont envoyées, seule la dernière sera effectivement testée. Nous nous contenterons de ça pour ce cas d’école.

    Avec le même fichier PHP que précédemment, voilà la « conversation » avec Git qui en retourne :

    $ git commit -m "My commit." --no-verify
    [master ee73c01] My commit.
    1 file changed, 1 insertion(+), 2 deletions(-)
    $ git push
    Décompte des objets: 3, fait.
    Delta compression using up to 4 threads.
    Compression des objets: 100% (3/3), fait.
    ́
    Ecriture des objets: 100% (3/3), 349 bytes | 0 bytes/s, fait.
    Total 3 (delta 0), reused 0 (delta 0)
    remote: !reject: +function helloWord() {
    remote: !reject: jump a line for the brace!
    To /tmp/tests/bare
    ! [remote rejected] master -> master (pre-receive hook declined)
    error: impossible de pousser des références vers ’/tmp/tests/bare’
    

    Il nous sera impossible de forcer l’acceptation de ce commit par le serveur.

    Cette petite introduction sur les hooks Git est à présent terminée. J’espère qu’elle vous inspirera pour vos flux de travaux, en les rendants plus solides et plus simples à gérer !


    Crédit image :

    • Le chemin en couverture par WiciaQ

    Publication originale :

    Cet article a été publié initialement sur le blog Netapsys.
    Logo Netapsys

    Tags: git, hooks

Laisser un commentaire Annuler la réponse

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*

*

Code Anti-spam
Rafraîchir

*

Click to cancel reply
« Contact+ : retrouver les désagréments du Minitel à l’heure d’Internet, par Orange.
Reprenez le contrôle grâce au carton ! »
Catégories
  • DIY (4)
  • Electronique (3)
  • Expatriations (15)
    • 1. Squat Grenoble 2010 (8)
    • 2. Camping Haspelschiedt 2010 (5)
  • Informations (1)
  • LTDI (4)
  • Pensés abstraites (8)
  • Périples (7)
  • Programmation (22)
    • Embarqué (2)
    • Maintenance (1)
    • Sysadmin (7)
    • Théorie (6)
  • VIA (3)
Étiquettes
amplificateur ampoule ancien AOP Atmel bac backup blog C++ carton convertion crous Danemark DBus denmark dut début développeur facebook France GIO GTK Horsens infixe lampe led Linux lucie M1280 opérationnel orientation photo podcast postbac postfixe profil présentation Raspberry Pi réseaux sondage sécurité tension VIA voyage économie
Archives
  • août 2018 (1)
  • juin 2018 (1)
  • novembre 2017 (1)
  • juillet 2017 (1)
  • juin 2017 (1)
  • avril 2017 (1)
  • janvier 2017 (1)
  • juillet 2016 (1)
  • juin 2016 (1)
  • avril 2016 (1)
  • novembre 2015 (2)
  • mai 2015 (2)
  • avril 2015 (1)
  • février 2015 (1)
  • décembre 2014 (1)
  • décembre 2013 (1)
  • novembre 2013 (2)
  • septembre 2013 (2)
  • juin 2013 (1)
  • mai 2013 (1)
  • avril 2013 (1)
  • janvier 2013 (1)
  • novembre 2012 (1)
  • août 2012 (1)
  • juillet 2012 (2)
  • mai 2012 (2)
  • avril 2012 (2)
  • mars 2012 (1)
  • février 2012 (1)
  • janvier 2012 (2)
  • décembre 2011 (4)
  • novembre 2011 (1)
  • octobre 2011 (1)
  • juin 2011 (1)
  • mai 2011 (1)
  • décembre 2010 (1)
  • août 2010 (2)
  • juillet 2010 (4)
  • mai 2010 (9)
  • mars 2010 (3)
Blogs d'amis
  • Choix Libres
  • Johnn'y Space
  • Shades of blue
  • Soulou's blog
Articles récents
  • L’histoire de la création de Linux
  • Comment juger de la qualité de la connectivité d’un site Web ?
  • Une introduction aux graphiques avec R
  • Réalisation d’une (grosse) armoire en carton
  • Comprendre AppArmor
Commentaires récents
  • Raclet dans Bookeen et leur foutage de gueule
  • Gregory dans Bookeen et leur foutage de gueule
  • chataigne dans Bookeen et leur foutage de gueule
  • Alain Riou dans Bookeen et leur foutage de gueule
  • Rodrigues dans Bookeen et leur foutage de gueule
Spydemon's personal blog powered by WordPress and The Clear Line Theme

Compression Plugin created by Jake Ruston's Wordpress Plugins - Powered by Protection Racket and Kanye West.