SVN hook

Contrôle automatiquement des soumissions

Auteur

Noel Perez

Les projets étant toujours plus gros et complexe il est très compliqué d'en suivre la qualité d'autant plus quand l'équipe se constitue de collaborateur avec peu de recule. Aujourd'hui nous nous appuyons beaucoup sur les compilations automatisées associées au lancement de tests automatiques et d'outil tel que SONAR. Ce process peut durer plusieurs heures dans certains cas et une toute petite erreur peut entraîner un gros retard avec l'obligation de relancer le process du début. Avec SVN il existe une possibilité de garantir que certains commits ne seront pas accepter en testant des points importants ou en obligeant le passage en relecture auprès d'un responsable du projet. Il s'agit dans cet article de mieux voir tout l'intérêt des Hooks de SVN dans ce cadre.

- Titre : SVN hook

- Auteur : Noel Perez

- Parution : 27 août 2014

- Mise à jour : 1 septembre 2014

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2014 Noel PEREZ. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Généralité

- II. Architecture SVN

- III. Principe des HOOKs

- III-A. Soumission de fichier

- III-B. Verrouillage de fichier

- III-C. Déverrouillage de fichier

- III-D. changement des propriétés d'une révision

- IV. Mise en place des HOOKs

- V. Hook en puissance

- V-A. Limitation des accès

- V-B. Interdire la modification d'une classe

- VI. Conclusion

- VII. Annexe

I - Généralité

Subversion est avec GIT un des outils de gestions de versions les plus connus et usités. Il permet de partager entre toute une équipe les codes d'une application en gérant la concurrence et les différentes versions d'une même application. Je partirai du principe que vous avez déjà utilisé une solution de gestion de versions. Je ne reviendrai donc pas sur le rôle de SVN par contre il sera intéressant pour la suite de mieux comprendre le fonctionnement côté serveur.

En effet certains considèrent l'aspect client-serveur de SVN comme un handicap et lui préfère GIT. Cependant cette architecture à un très gros avantage : elle permet aux responsables de projet ( architecte / CP / responsable qualité ) d'avoir un point de contrôle sur ce que fait l'équipe de développeurs. Ceci peut s'avérer cruciale avec une équipe composée de junior ou de personnes n'étant pas conscientes de l'importance de la qualité.

Ainsi nous allons voir comment automatiser des contrôles et alertes au niveau du commit et non plus des compilations automatisées qui peuvent intervenir avec un certain décalage. C'est en ce sens que les hooks ont été intégrés. Malheureusement par méconnaissance ils sont rarement mis en place.

Avant de nous lancer revenons sur l'architecture de SVN.

II - Architecture SVN

Comme évoqué précédemment Subversion repose sur un serveur centraliser, un protocole et des clients intégrer ou non aux éditeurs de code. Le clients se charge des mise à jour de code en récupérant les dernières versions auprès du serveur et envoi dans le cadre des commits les différences avec les codes présents sur le serveur.

SVN s'assure alors à travers des numéros de commit, qu'il attribue de manière séquentiel, que toute modifications déclarée sur une classe s'est faite sur la dernière version connue par le serveur. Dans le cas contraire il demande au client de se mettre à jour avant de recommiter. Ainsi le conflit est toujours géré sur le client.

Ci dessous voici le process que suit la demande de commit :

Comme ont peut le voir à chaque étape le serveur peut être amener à renvoyer un code d'erreur avec le message ce qui bloquera le commit. C'est au niveau de chacun de ces moments comme nous le verrons qu'un hook peut être mis en place.

Dans le cadre de cet article, les tests ont été fait sur une version 1.8.1 de subversion.

III - Principe des HOOKs

Les hooks sont une extension de svn permettant d'interagir avec ce dernier afin de confirmer ou non les commits, les verrouillage ou déverrouillage sur un fichiers . Il s'agit d'appels prévus dans les différents process que gère SVN. Ces appels se font vers des exécutables ou scripts qui sont normalisés en terme de nom et associer à un dépôt. Le plus courant reste l'utilisation de script.

Remarque : les appels fait par SVN se font en réinitialisant les variables d'environnement.

Ainsi si vous êtes sous UNIX et que vous souhaitez contrôler le dépôt 'projet 1' vous trouverez les hooks dans le répertoire '$svn-repos/projet1/hooks'. Par défaut vous trouverez 9 fichiers qui représentent tout les hooks possibles et sont écris pour Unix. Ces hooks sont inactif avec l'extension .tmpl. Il vous suffit si le serveur est sous unix de les renommer avec l'extension .sh et les rendre exécutable avec un 'chmod' pour les activer.

Sous WINDOWS le répertoire se trouvera dans '%SVN_home%\Repositories\projet1\hooks'. Comme nous le verrons plus tard, il faudra cependant entièrement recréer les scripts, le plus simple étant de le faire par fichier batch ou powershell.

L'ensemble des hooks disponibles permettent de suivre 4 processus :

1. s

2. verrouillage d'un fichier

3. déverrouillage d'un fichier

4. changement des propriétés d'une révision

Intéressons nous à chacun d'eux plu en détail.

III-A - Soumission de fichier

Processus le plus courant, aussi appelé commit, il permet de suivre la soumission d'une nouvelle révision.

start-commit.bat

Paramètres :

1. emplacement du dépôt

2. auteur

3. info annexe

4. id de transaction

Objectif :

Notification du début d'une propagation, permet de bloquer au plus tôt le commit.

Remarque : Par contre comme on le voit dans les paramètres ( extrait d'un test ) on a une numéro de transaction contrairement à ce qu'indique la documentation officielle. Une transaction est donc déjà ouverte puisque j'ai pu interroger svn sur la transaction indiqué.

pre-commit.bat

Paramètres :

1. emplacement du dépôt

2. id de transaction

Objectif :

Ici on en profitera le plus souvent pour bloquer le commit en fonction de la liste des fichiers déclarés. On reviendra plus précisément dessus aux chapitres IV et V.

post-commit.bat

Paramètres :

1. emplacement du dépôt

2. id de révision

3. id de transaction

Objectif :

Attention le post commit ne permet pas d'empêcher le commit mais peut néanmoins renvoyer une erreur.Les modifications sont déjà validé dans SVN au moment de l'execution. L'objectif est ici est plus l'intégration avec d'autres outils pour lancer une compilation par exemple ou une notification par mail au CP.

III-B - Verrouillage de fichier

Il est rare qu'il soit nécessaire de locker des classes par contre cela peut s'avérer utile sur des fichiers binaires seuls fichiers que SVN ne sait pas gérer par différentiel.

Il peut être utile pour éviter les erreurs de refuser les lock sur les fichiers de code et texte qui eux sont pleinement gérer par SVN.
Il peut aussi être intéressant d'envoyer un mail à l'ensemble de l'équipe pour notifier du lock.

Remarque : Attention le lock se fait par fichier. En effet même si votre client permet de sélectionner plusieurs fichiers il emmétra en réalité une demande de lock par fichier.

Paramètres :

1. emplacement du dépôt

2. emplacement du fichier dans le dépôt

3. auteur

4. message saisie par l'utilisateur

5. 0 - je n'ai pas trouvé sa signification

Objectif :

Vérifier les droits d'accès et possible alerte à l'équipe.

post-lock.bat

Paramétrés :

1. emplacement du dépôt

2. auteur

Objectif :

notification de verrouillage.

Remarque : attention le post-lock ne renvoi pas le message d'erreur pour affichage et le lock est déjà complété. Mais une erreur étant noté par le client on obtient un état incohérent puisque le client affiche le fichier comme non locké et ne permet pas de le déverrouiller. Il est donc préférable sur ce script de ne jamais renvoyer d'erreur.

III-C - Déverrouillage de fichier

Il n'existe pas à mon sens pour le moment d'utilité au hook sur le déverrouillage sauf dans un cadre de log ou pour avertir par mail à l'équipe de la libération de la ressource.

pre-unlock.bat

Paramètres :

1. emplacement du dépôt

2. emplacement du fichier dans le dépôt

3. auteur

4. token du lock de la forme opaquelocktoken:d28186f1-f209-4a42-ba26-9e3cee4afeba

5. 0 - je n'ai pas trouvé sa signification

Objectif :

Vérifier les droits d'accès et possible alerte à l'équipe. De plus contrairement au pre-lock le message d'erreur n'est pas renvoyé pour affichage. Il est préférable sur ce script de ne jamais renvoyer d'erreur.

post-unlock.bat

Paramètres :

1. emplacement u dépôt

2. auteur

Objectif :

notification de déverrouillage.

Remarque : attention le post-unlock ne renvoi pas le message d'erreur pour affichage et le unlock est déjà complété. Mais une erreur étant noté par le client on obtient un état incohérent puisque le client affiche le fichier comme locké et ne permet pas de le verrouiller. Il est donc préférable sur ce script de ne jamais renvoyer d'erreur.

III-D - changement des propriétés d'une révision

Processus rare, peu utile sauf sur de grosses erreurs où le plus souvent s'est l'administrateur qui doit intervenir. Il s'agira donc plus de bloquer les accès au simple utilisateur et réserver cela à des administrateurs/CP/architecte.

pre-revprop-change.bat

Parametres :

1. emplacement du dépôt

2. id de la revision

3. auteur de la modification

4. propriété modifiée ex svn:log |svn :author

5. description de la modification : A (ajout), D (suppression) ou M (modification)

Objectif :

bloquer les modifications sur les versions deployées.

post-revprop-change.bat

Parametres :

1. emplacement du dépôt

2. id de la revision

3. auteur de la modification

4. propriété modifiée ex svn:log|svn:author

5. description de la modification : A (ajout), D (suppression) ou M (modification)

Objectif :

Je cherche encore, j'exagère il peut servir à notifier la modification à l'équipe.

IV - Mise en place des HOOKs

Intéressons nous au script nommé pre-commit.tmpl, celui-ci est appelé avant que le code ne soit ajouté au dépôt ( s'il est renommé en .sh sous UNIX ). Ainsi avec le script suivant nous allons pouvoir contrôler que le développeur ayant commité à ajouter une explication au commit.

1. 1. #!/bin/sh

2. 2.

3. 3. # PRE-COMMIT HOOK

4. 4. ...

5. 5.

6. 6. REPOS="$1"

7. 7. TXN="$2"

8. 8.

9. 9. # Make sure that the log message contains some text.

10. 10. SVNLOOK=/usr/local/bin/svnlook

11. 11. $SVNLOOK log -t "$TXN" "$REPOS" | \

12. 12.    grep "[a-zA-Z0-9]" > /dev/null || exit 1

13. 13.

14. 14. # Check that the author of this commit has the rights to perform

15. 15. # the commit on the files and directories being modified.

16. 16. commit-access-control.pl "$REPOS" "$TXN" commit-access-control.cfg || exit 1

17. 17.

18. 18. # All checks passed, so allow the commit.

19. 19. Exit 0

Nous voyons que nous recevons en ligne 6 le dépôt sur lequel le commit à lieu. Ligne 7, il s'agit du numéro de transaction associé au commit.

Grâce à ces infos nous allons pouvoir interroger SVN pour connaître le log associé au commit et contrôler qu'il ne soit pas vide ( ligne 11 & 12 ). Si c'est le cas on met fin au script avec exit 1 ce qui entraînera un rollback de SVN et enverra au client un code d'erreur. En imprimant sur la console un texte explicatif, celui-ci sera transmis jusqu'au client ayant lancé le commit.

Ligne 16 on voit que l'on peut encore rajouter l'appel à d'autres scripts pour par exemple ici contrôler les accès.

----

Si SVN est installé sous WINDOWS, le script est à créer de toute pièce sous forme de fichier batch. L'exemple suivant reprend le script précédent mais acceptera tout texte de plus de 3 caractères :

1. 1. @ECHO ON

2. 2.

3. 3. set repos=%1

4. 4. set rev=%2

5. 5.

6. 6. svnlook log %repos% -t %rev% | findstr ... > nul

7. 7.

8. 8.  if %errorlevel% gtr 0 (goto err) else exit 0

9. 9.

10. 10.  :err

11. 11.  echo %repos% %rev%

12. 12.  echo --------------------------------------------------------------------------- 1>&2

13. 13.  echo pre-commit.bat 1>&2

14. 14.  echo parametres %1 -- %2 1>&2

15. 15.  echo commit bloqué car n'inclus pas de message. 1>&2

16. 16.  echo --------------------------------------------------------------------------- 1>&2

17. 17.

18. 18.  exit 1

Nous retrouvons ligne 3 & 4 les paramètres précédemment vu et en ligne 6 nous interrogeons le serveur pour obtenir le texte associé au commit et le testons pour voir s'il s'agit d'un texte d'au moins 3 caractères.

Ainsi si nous tentons de commiter sous Eclipse avec un commentaire vide comme sur l'exemple :

nous passons dans la rubrique err ou nous allons afficher les causes du refus du commit qui apparaîtra sur le client Eclipse :

On voit que l'on peut imaginer ainsi toute sorte de blocage le message permettant à l'utilisateur final de comprendre son erreur.

V - Hook en puissance

Comme nous l'avons vu, nous pouvons interroger en ligne de commande Subversion et ce sur toute information contenu dans SVN. Ainsi nous allons pouvoir conditionner l'acceptation du commit sur :

- le texte du commit ( vu plus haut )

- l'auteur

- le nom des fichiers avec le cadre de la modification ( ajout / suppression / modification )

- la modification faite sur un fichier

- les dates

- ?

On peut grâce à cela imaginer :

- de bloquer l'accès à une zone du projet pour des personnes,

- d'analyser les commit pour interdire l'opérateur ternaire, les appels au garbage collector, ...

- d'interdire l'ajout de classe n'ayant aucun commentaire,

- d'interdire de commiter certains fichiers ( ex psd, tiff, ? ) ce qui permet de garantir aussi la taille du projet.

Pour cela il faut donc bien maîtriser le mode d'interrogation de SVN en ligne de commandes et savoir en interpréter le résultat. Ceci dépasse largement le cadre de cet article cependant j'aimerai revenir sur 2 exemples plus concret qui vous permettrons de faire ensuite vos propres scripts plus facilement je l'espère.

V-A - Limitation des accès

Sur le script suivant on voit que l'on peut simplement demander par la commande ligne 6 à récupérer l'auteur d'une transaction ( transaction puisque nous sommes en pre-commit ).

Remarque : Si on décide de le faire en post-commit on remplacera le '-t' par un '-r' puisque nous rechercherons sur une révision.

Maintenant ce type de test ne devrait se faire que sur un start-commit ou pre-commit afin d'empêcher le commit si besoin.

On peut voir que le traitement d'erreur est lui similaire à ce que nous avons pu voir.

1. 1. @ECHO ON

2. 2.

3. 3. set repos=%1

4. 4. set rev=%2

5. 5.

6. 6. svnlook author -t %rev% %repos% | findstr NPE > nul

7. 7.

8. 8.  if %errorlevel% gtr 0 (goto err) else exit 0

9. 9.

10. 10.  :err

11. 11.  echo %repos% %rev%

12. 12.  echo --------------------------------------------------------------------------- 1>&2

13. 13.  echo pre-commit.bat 1>&2

14. 14.  echo parametres %1 -- %2  1>&2

15. 15.  echo commit bloqué car seul NPE peut commiter. 1>&2

16. 16.  echo --------------------------------------------------------------------------- 1>&2

17. 17.

18. 18.  exit 1

Comme vu cet exemple reste assez simple, contrairement au suivant.

V-B - Interdire la modification d'une classe

Dans cet exemple nous allons empêcher le commit sans commentaire et si un des fichiers correspond à une liste d'exclusions que nous posons dans le fichier 'e:\svn\Repositories\testSVN\hooks\exclu.txt'. Ce fichier contient simplement sur chaque ligne la fin d'un nom de fichier à exclure. Exemple de fichier :

1. 1. .class

2. 2. .psd

3. 3. Authentification.java

Sur l'exemple de fichier on empêchera ainsi tout commit avec un fichier class ou photoshop ainsi que la classe Authentification.java. Pour pouvoir commiter ce type de fichier le développeur devra donc demander à une personne habilitée à modifier la liste des exclusions le temps du commit.

Remarque : Nous pourrions envisager d'utiliser des expressions régulières.

Le script en lui même va s'avérer plus compliquer comme vous le voyez ci-dessous :

1. 1. @ECHO ON

2. 2.

3. 3. set repos=%1

4. 4. set rev=%2

5. 5.

6. 6. svnlook log %repos% -t %rev% | findstr ... > nul

7. 7.

8. 8. if %errorlevel% gtr 0 (goto err) else (goto test2)

9. 9.

10. 10. :err

11. 11. echo %repos% %rev%

12. 12. echo --------------------------------------------------------------------------- 1>&2

13. 13. echo pre-commit.bat 1>&2

14. 14. echo parametres %1 -- %2 -- %3 -- %4 -- %5  1>&2

15. 15. echo commit bloqué car n'inclus pas de message. 1>&2

16. 16. echo --------------------------------------------------------------------------- 1>&2

17. 17. exit 1

18. 18.

19. 19. :test2

20. 20.

21. 21. FOR /f "delims=" %%f in ( 'svnlook changed %repos% -t %rev%' ) do (

22. 22.     echo %%f | findstr /G:e:\svn\Repositories\testSVN\hooks\exclu.txt > nul

23. 23.     if %errorlevel% gtr 0 (echo 1 > nul) else (goto err2)

24. 24. )

25. 25. exit 1

26. 26.

27. 27. :err2

28. 28. echo %repos% %rev%

29. 29. echo --------------------------------------------------------------------------- 1>&2

30. 30. echo pre-commit.bat 1>&2

31. 31. echo parametres %1 -- %2 -- %3 -- %4 -- %5  1>&2

32. 32. echo commit bloqué car un fichier exclu est envoyé pour commit. %%entry 1>&2

33. 33. FOR /f "delims=" %%f in ( 'svnlook changed %repos% -t %rev%' ) do echo %%f | findstr /G:e:\svn\Repositories\testSVN\hooks\exclu.txt 1>&2

34. 34. echo --------------------------------------------------------------------------- 1>&2

35. 35. exit 1

Sur l'exemple on retrouve jusqu'à la ligne 17 le script testant le commentaire. En cas de succès de ce test on passe maintenant à la section 'test2' sinon on bloquera le commit et on renverra le message d'erreur précédant.

Au test2 on voit que l'on parcours l'ensemble des retours de la commande 'svnlook changed %repos% -t %rev%' ( ligne 21 ) qui va retourner la liste des fichiers ajoutés/modifiés/supprimés. Pour chaque ligne on va comparer avec la fin de chaque ligne avec les lignes contenues dans le fichier 'exclu.txt'. Si une ligne est retournée nous savons que nous devons bloquer le commit et afficher un message d'erreur. On renvoit donc vers la section errr2.

Dans la section err2, on affiche un message général suivi de la liste des fichiers à exclure du commit. ( ligne 33 )

Afin d'obtenir un système plus complet il sera intéressant de rajouter un super-compte qui permettra lui de commiter même des fichiers normalement exclus.

VI - Conclusion

Ainsi sous peu que l'on maîtrise correctement le scripting, les hooks peuvent nous permettre d'éviter beaucoup de problèmes sur les projets en terme de qualité voir de sécurité. De mon côté j'ai du bloqué sur un de mes projets le commit sur toute les classes impliquées dans l'authentification. Tout développeur modifiant cette partie devais alors obtenir mon accord avant de commiter sa modification. J'avais bien sur profiter de ce script pour m'assurer qu'un commentaire existait sur tout commit et que les fichiers des intégrateurs graphiques n'était pas commité dans des zones reprise à la génération des jar/war.

Il vous reste maintenant à faire vos propres règles.

VII - Annexe

livre : Gestion de version avec SubVersion