Désormais ancrées dans le quotidien des développeurs, les plateformes d’intégration continue permettent de détecter rapidement tout problème de compilation, de tests en erreur ou même d’ajout de défauts remontés par SonarQube. L’objectif fixé par le team leader est de ne pas faire échouer le build et, si c’est malheureusement le cas, tout arrêter pour le réparer. Sur certains projets, le gage donné au développeur ayant cassé le build est de ramener les viennoiseries le lendemain.
Pour être certain de ne pas faire chauffer sa carte de paiement, une bonne pratique consiste à exécuter une ligne de commande maven (ou gradle) avant chaque commit dans le gestionnaire de code source. Cependant, sur certains changements que l’on juge mineur, il peut être tentant de passer outre. Aujourd’hui, les PC ou les Mac multi-coeurs avec SSD permettent de lancer un build sans freezer le poste de développement. C’est donc davantage par excès de confiance qu’à cause du temps d’attente qu’il arrive de casser Jenkins, Bamboo ou bien encore TeamCity.
Pour contrer tout oubli, il est possible de systématiser l’exécution du build Maven avant de commiter. Les outils de gestion de configuration SVN et Git offrent un mécanisme de hook. Lors de la phase de pre-commit, on va demander au SCM d’exécuter un script de hook chargé de vérifier le code source. En cas d’erreur, le commit est refusé.
Ecrire de tels scripts n’est pas compliqué sous Linux car beaucoup d’exemples existent. Par contre, sous Windows, c’est plus rare. L’objet de cet article est donc de vous donner des exemples de scripts de hook de pre-commit et de vous expliquer comment les configurer dans Tortoise SVN et Git.
Hook SVN
Deux types de hook existent dans Subversion : des hooks clients et des hooks serveurs.
Pour ne pas transformer le serveur SVN en serveur d’intégration continue, ce sont les hooks clients qui vont ici nous intéresser.
Le script appelé par le hook n’est rien d’autre qu’un .bat.
L’exemple de script pre-commit.bat ci-dessous est localisé dans le même répertoire que le POM reactor du projet. Un pré-requis est que Maven et Java sont dans le PATH de Windows.
@echo on call mvn clean –f myapp-parent\pom.xml > target\pre-commit.log if not exist target mkdir target call mvn install sonar:sonar -Dsonar.analysis.mode=preview -Dsonar.issuesReport.html.enable=true -Dsonar.buildbreaker.skip=false –f myapp-parent\pom.xml > target\pre-commit.log echo Maven error code: %ERROR_CODE% cmd /C exit /B %ERROR_CODE%
Afin de pouvoir être consultée en cas d’échec du build, la sortie console est redirigée dans un fichier de logs. Le code d’erreur de maven est retourné à SVN qui sait l’interpréter. Tout code différent de 0 fait échouer le commit.
Exécuté dans à la racine de l’arborescence, le paramètre –f myapp-parent\pom.xml permet de spécifier à maven où se trouve le POM parent (structure de type flat module). Nul besoin d’ajouter ce paramètre lorsque le POM parent se situe à la racine du projet.
TortoiseSVN permet de configurer un hook client à 2 niveaux :
- De manière globale pour tous les repos SVN du poste de dév. Chaque développeur doit individuellement configurer TortoiseSVN. Cette configuration peut être problématique lorsqu’un développeur est amené à travailler sur plusieurs repos et que le script de hook n’est pas assez générique. Le script précédent devra être généralisé pour fonctionner avec l’ensemble des projets.
- De manière unitaire pour chaque repo SVN. A l’instar d’une propriété svn:ignore, TortoiseSVN ajoute récursivement une propriété tsn:precommithook au niveau du repository SVN. Tous les développeurs bénéficient alors de ce hook.
Etapes de configuration du mode global :
- Depuis n’importe quel répertoire, sélectionner le menu contextuel TortoiseSVN > Settings
- Se rendre dans le menu Hook Scripts
- Renseigner les champs suivants :
- Hook type : pre-commit
- Woking copy path : chemin vers le pom parent de l’application
- Command line to execute : pre-commit.bat
Etapes de configuration du mode local :
- Sélectionner le répertoire racine du projet SVN
- Ouvrir le menu contextuel et sélectionner le menu TortoiseSVN > Properties
- Cliquer sur le bouton New > Local Hooks (création d’une property tsvn:precommithook)
- Choisir les paramètres suivants :
- Hook Type : Start Commit Hook
- Command Line to Execute : %REPOROOT+%/myproject-parent/pre-commit.bat
- Cocher les options suivantes :
- Wait for the script to finish
- Always execute the script
- Apply property recursively
- Commiter ces modifications de manière récursive sur l’ensemble des sous répertoires du projet SVN
Remarque : les hooks clients sont une fonctionnalité propre à TortoiseSVN. De ce fait, le client en ligne de commande svn.exe ou bien encore le plugin Subversive d’Eclipse ne reconnaissent pas la propriété tsvn:precommithook.
Hook Git
Git appartenant à la catégorie des DVCS, il n’existe pas de hook server. La configuration s’effectue donc au niveau du repository Git local. Les scripts de hook sont à positionner dans le sous-répertoire .git\hooks. Par défaut, ce répertoire contient des exemples post-fixés par l’extension .sample. Le nom des scripts est conventionné et correspond au nom de la phase à laquelle il est exécuté. Ainsi, le script de hook exécuté avant le commit se nomme pre-commit.
Sous Windows, Msysgit est le client Git le plus populaire. Basé sur les utilitaires Msys, le script ne doitpas être écrit en script batch comme c’est le cas avec SVN, mais en bash Linux.
Voici un exemple de sript shell pre-commit :
#!/bin/sh echo "Executing pre-commit" # Set Java and Maven: export JAVA_HOME="C:/dev/jdk/1.7.0_45" export MAVEN_OPTS="-Xmx1024m -XX:MaxPermSize=256m" export MAVEN_HOME="C:/dev/maven/apache-maven-3.2.3" echo "Running Maven clean install for errors and Sonar for testing if the project fails its quality gate." # Retrieving current working directory CWD=`pwd` MAIN_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # Go to main project dir cd $MAIN_DIR/../../myapp-parent # Running Maven clean install and Sonar $MAVEN_HOME/bin/mvn clean install -U sonar:sonar -Dsonar.analysis.mode=preview -Dsonar.issuesReport.html.enable=true -Dsonar.buildbreaker.skip=false if [ $? -ne 0 ]; then echo "Error while compiling or testing the code" # Go back to current working dir cd $CWD exit 1 fi # Go back to current working dir cd $CWD exit 0
La commande cd $MAIN_DIR/../../myapp-parent permet de positionner dans le répertoire contenant le POM parent. Ce chemin est à adapter selon la structure du projet.
Conclusion
Que ce soit avec Git ou avec TortoiseSVN, il est possible de systématiser l’appel à commande mvn clean install (ou à tout autre script) avant de commiter. Cette bonne pratique fait en sorte que le code historisé dans le gestionnaire de code source est toujours stable. L’intérêt de maintenir un serveur d’intégration continue peut donc se poser. Dès 2009, David Gageot montrait d’ailleurs qu’il était possible de monter une intégration continue sans serveur. Pour autant, les serveurs d’intégration continue tels que Jenkins ont aujourd’hui davantage de responsabilités que par le passé : exécution des tests d’intégration, des tests Selenium et des tests de montée en charge, packaging, déploiement d’applications sur les différents environnements … Leurs jours ne sont donc pas comptés !