Maven One Phase by Ci Stage
Avez-vous déjà essayé de lancer des phases Maven dans des stages/jobs différents d’une CI ? Si la réponse est oui, vous êtes surement tombé sur un problème un peu embêtant faisant que Maven relance les phases exécutées dans les jobs précédents malgré la présence des fichiers produit par la phase précédente. Voyons comment corriger cela !
Contexte
Imaginons que vous souhaitez lancer les phases de compile, test et package de Maven dans trois jobs séparés. C’est un cas légitime dans le cadre, par exemple d’un monorepo avec plusieurs modules dans différents langages.
Dans ce genre de cas et pour plus de lisibilité, j’aime bien avoir un découpage fin de mon pipeline. Un stage Build exécute l’ensemble des stages de build, un stage de test exécute l’ensemble des jobs de test, ….
L’optimisation de ce genre de pipeline est un autre sujet qu’on traitera dans un autre article. Avec Maven, lors du stage de test, celui-ci va relancer l’intégration de la phase de compile. Même si vous restaurez l’ensemble du dossier target contenant le résultat de la phase de compile dans le job de test avant de le lancer, Maven ne voudra rien savoir. Cela annule complétement l’intérêt de séparer les phases par jobs.
Pourquoi Maven agit ainsi ?
Le plugin maven-compiler-plugin utilise deux critères pour savoir s’il doit recompiler :
- La liste des fichiers déjà traités dans une phase précédente (sources compilées lors de la phase de test, tests compilés lors de la phase de package)
- Le timestamp des sources par rapport au .class produit
Ces deux critères peuvent poser problèmes lors de l’utilisation de maven dans une CI avec des agents docker.
Changement de chemin des fichiers déjà traités
Si votre CI, monte les sources de votre projet dans un conteneur docker avant l’exécution du job, il se peut que le chemin dans le conteneur ne soit pas le même que dans le conteneur de la phase précédente. J’ai eu ce cas dernièrement avec TFS. Le conteneur de Build qui lançait mvn compile avait les sources du projet montées sous le chemin /__w/<n>/s. n étant un numéro attribué par chaque agent de la CI. Le conteneur de Test avait donc un chemin /__w/<n>/s avec un n différent.
Maven qui compare les chemins absolus enregistrés dans target/maven-status/maven-compiler-plugin/**/inputFiles.lst avec les sources présentes dans /target, ne vas pas les trouver et va donc lancer une nouvelle compilation.
Pour résoudre ce problème, il faut modifier les chemins des sources dans les fichiers inputFiles.lst
|
|
Changement du timestamp
Le second mécanisme voit Maven recompiler l’ensemble des .class si leur timestamp est plus ancien que les sources. Ceci est le cas lorsque vous restaurez les .class précédemment compilés directement dans le dossier du projet monté dans votre conteneur. Pour résoudre ce problème, il suffit de faire un touch sur les fichiers pour réinitialiser le timestamp des fichiers.
Conclusion
Ce problème m’a bien pris la tête et je suis content d’avoir une solution. Ce n’est surement pas la plus propre des solutions, mais elle a le mérite de fonctionner. Je peux ainsi avoir une CI avec des jobs clairement séparés.