web-dev-qa-db-fra.com

Jenkins construit-il un produit composé de nombreux projets Maven? (avec le plugin Jenkins Pipeline?)

Nous avons un produit composé de nombreux projets Maven qui dépendent les uns des autres. Tous ces projets Maven sont réunis en un seul projet qui fournit le produit final.

Les projets Maven partagent le même cycle de vie. En d'autres termes, ils ne sont pas gérés par des équipes distinctes de personnes disposant de <dependency> modifications pour récupérer les nouvelles versions d'autres projets. Au contraire, lorsque quelqu'un change quelque chose dans l'un des projets, le résultat doit aller directement dans le produit final sans modifications supplémentaires.

Nous utilisons Jenkins comme outil d'intégration continue.

Les principaux souhaits que nous avons sont les suivants:

  • Pas besoin de copier toutes les dépendances inter-projets dans la configuration Jenkins: celles-ci devraient être en un seul endroit, idéalement le pom.xml des dossiers.
  • Évitez les builds inutiles: lors d'un changement de SCM, ne construisez que les projets potentiellement affectés.
  • Dans le cas de dépendances au diamant (C dépend à la fois de B1 et B2, qui dépendent tous deux de A), si le plus bas (A) est modifié, alors le le produit final (C) doit toujours utiliser la version de A qui a également été utilisée pour construire/tester B1 et B2.

Question: Quelle est la meilleure approche pour le faire avec Jenkins?

Nous pensons actuellement à utiliser un seul travail en utilisant le plugin Jenkins Pipeline, qui analyse les dépendances Maven et les modifications SCM, décide de ce qui doit être construit et dans quel ordre, puis construit réellement les projets.

Pour répondre à vos besoins, vous pouvez vous fier à de nombreuses fonctionnalités par défaut d'une version multi-module maven et à une configuration supplémentaire expliquée ci-dessous.

De votre question:

Pas besoin de copier toutes les dépendances inter-projets dans la configuration Jenkins: celles-ci devraient être en un seul endroit, idéalement le pom.xml des dossiers.

En utilisant un agrégateur/pom multi-module vous pouvez avoir un seul point d'entrée (un fichier pom.xml) pour une construction maven qui construirait alors tous les modules définis:

Un projet avec modules est appelé projet multimodule ou agrégateur. Les modules sont des projets répertoriés par ce POM et sont exécutés en tant que groupe. Un projet empaqueté pom peut agréger la construction d'un ensemble de projets en les répertoriant comme modules, qui sont des répertoires relatifs à ces projets.

C'est un pom.xml fichier comme suit:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sample</groupId>
    <artifactId>project</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <modules>
        <module>module-1</module>
        <module>module-2</module>
        <module>module-n</module>
    </modules>
</project>

Est un exemple minimal: définir une liste de modules (autres projets maven) qui seront construits à partir de ce projet maven (un projet vide dont le seul but est de construire d'autres projets maven). Notez le pom packaging requis pour avoir des modules, cela indique à maven que ce projet ne fournit qu'un pom (pas d'autres artefacts).

Vous pourriez donc avoir un projet agrégateur Maven racine qui définirait les autres projets maven comme ses modules et aurait un seul travail Jenkins pour construire ce point d'entrée.


De plus, à partir de votre question:

Évitez les builds inutiles: lors d'un changement de SCM, ne construisez que les projets potentiellement affectés.

Pour répondre à cette exigence, vous pouvez utiliser le incremental-build-plugin :

Parce qu'il recherche des modifications sur les modules d'un projet unique, le plug-in incrémental Maven le prend en compte uniquement sur les projets multi-modules. Si une modification sur un module est détectée, le répertoire de sortie est supprimé.

Ce plugin vérifiera si l'un des fichiers pom, ressources, sources, sources de test, ressources de test changerait dans un module et si le cas supprimait son répertoire de sortie. En tant que tel, gagner du temps de construction pour un module concerné et en chaîne pour l'ensemble du projet multi-module (notre propre construction, dans ce cas).

Pour activer ce mécanisme, vous pouvez configurer dans le pom d'agrégateur ci-dessus, les éléments suivants:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sample</groupId>
    <artifactId>project</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>module-1</module>
        <module>module-2</module>
        <module>module-n</module>
    </modules>

    <properties>
        <skip.incremental>true</skip.incremental>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>net.Java.maven-incremental-build</groupId>
                <artifactId>incremental-build-plugin</artifactId>
                <version>1.6</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>incremental-build</goal>
                        </goals>
                        <configuration>
                            <noIncrementalBuild>${skip.incremental}</noIncrementalBuild>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Ci-dessus, nous avons simplement ajouté le incremental-build-plugin à la génération d'agrégateur et à une propriété, skip.incremental, qui ignorera l'exécution du plug-in pour la première génération, l'agrégateur vide, tout en l'activant dans les modules comme suit:

<project>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.sample</groupId>
        <artifactId>project</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>simple-module</artifactId>

    <properties>
        <skip.incremental>false</skip.incremental>
    </properties>
</project>

Remarque: dans le pom ci-dessus d'un exemple de module, nous pointons le fichier pom d'agrégateur en tant que parent, donc en utilisant héritage maven en combinaison avec l'agrégation (une utilisation classique) et en tant que tel ayant un multi-module build plus une gouvernance de build commune fournie par le parent commun pour tous les modules déclarés (dans ce cas, la gouvernance de build commune fournit le incremental-build-plugin configuration). De plus, chaque module reconfigure le skip.incremental propriété pour ne pas ignorer le plugin susmentionné. C'est une astuce: maintenant, le plugin ne sera exécuté que dans les modules, pas dans sa racine (ce qui n'aurait pas de sens et dans ce cas, en réalité, cela déclencherait une erreur).

Évidemment, dans le travail Jenkins connexe, dans sa section Gestion du code source, nous n'avons pas à configurer une nouvelle extraction dans le cadre de chaque build, sinon aucune modification ne serait détectable (et à chaque fois, il partirait de zéro, ce qui est une bonne pratique pour les versions en cours).

De plus, votre commande maven ne devrait pas invoquer le cycle de vie clean, ce qui supprimerait également le target à chaque build et ne rendrait donc aucun changement détectable.


De plus, à partir de votre question:

En cas de `` dépendances au diamant '' (C dépend à la fois de B1 et B2, qui dépendent tous deux de A), si le plus bas (A) est modifié, le produit final (C) doit toujours utiliser la version de A qui a également été utilisée. pour construire/tester B1 et B2.

Maven prendra soin de cette exigence dans le cadre d'une construction multi-modules et de son mécanisme réacteur :

Le mécanisme de Maven qui gère les projets multi-modules est appelé réacteur. Cette partie du noyau Maven fait ce qui suit:

  • Collecte tous les modules disponibles à construire
  • Trie les projets dans le bon ordre de construction
  • Construit les projets sélectionnés dans l'ordre

Par défaut, le réacteur va donc également créer un ordre de construction et toujours construire un module avant son module dépendant/consommateur. Cela signifie également que le dernier module construit sera en fait le module responsable de la construction de l'artefact final, le produit livrable dépendant d'une partie ou de tous les autres modules (par exemple, un module responsable de la livraison d'un fichier war sera sera probablement le dernier à construire dans un projet webapp multi-modules).


Lectures complémentaires concernant Maven et ignorer les actions lorsque quelque chose est inchangé:

  • Le maven-jar-plugin fournit le forceCreation qui par défaut est déjà activé

    Exiger que le plugin jar crée un nouveau JAR même si aucun des contenus ne semble avoir changé. Par défaut, ce plugin cherche à voir si le pot de sortie existe et si les entrées n'ont pas changé. Si ces conditions sont remplies, le plugin ignore la création du bocal.

  • Le maven-compiler-plugin fournit le useIncrementalCompilation , bien que ne fonctionne pas correctement pour le moment.
  • Le maven-war-plugin fournit l'option recompressZippedFiles qui pourrait également être utilisée pour accélérer les builds et éviter de refaire quelque chose (pour passer à false dans ce cas) :

    Indique si les archives Zip (jar, Zip, etc.) ajoutées à la guerre doivent à nouveau être compressées. Une nouvelle compression peut réduire la taille de l'archive, mais augmente considérablement le temps d'exécution.
    Par défaut : true


Mise à jour

Les projets Maven partagent le même cycle de vie.

Cette exigence imposerait également l'utilisation d'un projet d'agrégateur/multi-module, mais peut également s'appliquer à différents projets liés via des dépendances.

ils ne sont pas gérés par des équipes distinctes de personnes avec des changements explicites pour récupérer les nouvelles versions d'autres projets.

Ce point impose également l'utilisation d'un projet multi-module. Dans un projet multi-modules, vous pouvez avoir différentes versions entre les modules, mais la pratique courante et la directive sont de partager la même version, définie par le projet parent (l'agrégateur) et en cascade sur ses modules. À ce titre, sa centralisation et sa gouvernance éviteront les désalignements et les erreurs.

lorsque quelqu'un change quelque chose dans l'un des projets, le résultat doit aller directement dans le produit final sans modifications supplémentaires.

Encore une fois, cela serait géré automatiquement par un projet multi-modules. La même chose se produirait avec différents projets utilisant chacun versions SNAPSHOT , alors pas besoin de changer la version de dépendance dans son projet consommateur (celui responsable de la construction du produit final). Cependant, bien que les versions SNAPSHOT soient vraiment utiles (et recommandées) pendant le développement, elles ne devraient certainement pas être utilisées lors de la livraison du produit final car la reproductibilité de la construction serait en danger (c'est-à-dire que vous ne pourrez peut-être pas recréer la même version plus tard. car il s'appuyait sur des versions INSTANTANÉES, donc pas des versions figées). Par conséquent, SNAPSHOT n'est pas une solution miracle et ne doit être utilisé que pendant certaines phases du SDLC du produit, et non comme une solution finalisée et congelée.


Mise à jour 2
Cela vaut également la peine d'examiner le nouveau Maven Incremental Module Builder pour Maven 3.3.1 + et Java 7 .

Plus de détails sur:

24
A_Di-Matteo