web-dev-qa-db-fra.com

Comment mettre à jour la version des modules enfants dans Maven?

Comment mettre à jour la version des modules enfants? Il y a beaucoup de questions Stackoverflow comme celle-ci, mais je n'ai pas réussi à en trouver une qui corresponde exactement à ce scénario ... j'adorerais s'il s'agissait d'un doublon.

Considérez le projet suivant.

parent
  --mod1
  --mod2

Au début d'un cycle de publication de dev, je dois mettre à jour le parent et les modules avec la même version. Si la version du parent et des modules est restée la même tout au long de la publication, je voudrais simplement omettre la balise <version> des modules et exécuter versions:set -DnewVersion=1.1.1 pour lancer le cycle de développement. Mais il s'avère que les modules ne terminent pas tous le cycle avec la même version. Comme les bogues et les correctifs se matérialisent, seuls les modules avec les bogues sont mis à jour. Par exemple, le parent et mod2 pourraient être à la version 1.1.1-RC1, mais mod1 pourrait être à 1.1.1-RC2. 

En tant que tel, je dois:
1) Incluez une balise <version> dans les modules pour suivre indépendamment la version de chaque module.

2) Si mod2 nécessite mod1 en tant que dépendance, je dois m'assurer que mod2 fait référence à la dernière version de mod1.

Cela conduit aux deux questions suivantes. 

1) Au début du cycle, comment définir la même version du parent et des modules dans une commande maven? J'ai essayé version:set -DnewVersion=1.1.1, mais cela ne fait que mettre à jour la version du parent pour tous les POM, mais pas la version du module. J'ai aussi essayé -N versions:update-child-modules, mais je pense que je l'utilise mal car il ne fait rien, il indique simplement que tous les modules sont ignorés.

2) Ceci est un peu plus difficile et correspond au point 2 ci-dessus. Comment mettre à jour la version de mod1 et la référence de mod2 à la version de mod1 en une seule étape? Je sais le faire en 2 étapes:

pom parent:

<properties>
    <!-- update this manually if mod1's version no longer matches parent -->
    <mod1.version>${project.version}</mod1.version>
</properties>

pom mod2:

    <dependency>
        <groupId>com.xxx</groupId>
        <artifactId>mod1</artifactId>
        <version>${mod1.version}</version>
    </dependency>

Lorsque mod1 passe à 1.1.1-RC2, je mets à jour le POM parent et le POM mod1 en conséquence. Ce sont deux étapes. Quoi qu'il en soit, le transformer en une seule étape?

Mon exemple était petit, mais dans la vie réelle, il existe de nombreux modules, ce qui fait gagner un temps précieux. De plus, je suis curieux.

17
Jose Martinez

Question 1)

Le meilleur moyen de gérer le cycle de vie des applications et des versions consiste à utiliser le plug-in de version.

Comme vous le savez peut-être, la philosophie Maven est la convention sur la configuration. La convention Maven consiste à utiliser des versions de capture instantanée (celles se terminant par -SNAPSHOT) lors du développement et à affecter une version autre que de capture instantanée uniquement pour les versions.

Supposons que vous développiez la version 1.1.1. En cours de développement, vous utilisez simplement 1.1.1-SNAPSHOT. Maven se chargera des mises à jour de l'instantané. Si vous utilisez un référentiel d'artefacts, vous pouvez utiliser -U pour vous assurer de toujours disposer de la dernière version des instantanés.

Lorsque la version est prête, le plug-in de version génère et déploie la version 1.1.1 et met à jour les POM avec la nouvelle version de développement, telle que 1.1.2-SNAPSHOT.

En ce qui concerne les projets multimodules, il existe deux scénarios: les modules sont liés mais indépendants (par exemple, plusieurs applications Web) ou ce sont les modules d’une seule grande application ou bibliothèque et ils partagent des versions. Vous semblez intéressé par ce dernier.

Dans ce cas, la meilleure solution consiste simplement à hériter du même module parent (peut-être aussi root), y compris de sa version. Vous référencez le groupe parent: artefact: version et vous ne spécifiez pas de version pour les enfants. Généralement, vous héritez également d'un groupe afin que votre enfant puisse ressembler à:

<parent>
   <groupId>com.mycompany.myproject</groupId>
   <artifactId>myproject-parent</artifactId>
   <version>1.1.1-SNAPSHOT</version>
   <relativePath>../myproject-parent</relativePath>
</parent>
<artifactId>myproject-module1</artifactId>

Maintenant, il vous suffit de vous occuper des enfants pointant vers la bonne version du parent à l'aide du plug-in de version.

Pour l'aider à connaître les enfants, vous devez également faire de votre pom parent un pom racine en incluant la section des modules, comme indiqué plus loin.

Question 2) Je déclare généralement les propriétés dans le parent avec toutes les versions de tous les artefacts pouvant être référencés. Si plusieurs modules partagent une version, il vous suffit d'une propriété. Le parent peut ressembler à:

<groupId>com.mycompany.myproject</groupId>
<artifactId>myproject-parent</artifactId>
<version>1.1.1-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
   <myproject.version>1.1.1-SNAPSHOT</myproject.version>
</properties>

.......

<modules>
   <module>../myproject-module1</module>
   ...
</modules>

Les enfants peuvent référencer d’autres modules en utilisant

<version>${myproject.version}</version>

C'est une très mauvaise pratique de déclarer des dépendances à l'aide de LATEST. Disons que vous faites cela pour la version 1.1.1. Vous travaillez maintenant avec la version 1.1.2-SNAPSHOT et vous avez probablement des artefacts avec cette version installés dans votre référentiel local.

Maintenant, disons pour une raison quelconque que vous avez besoin de reconstruire la version 1.1.1, par exemple à cause d'un bogue dans la production. Votre construction utilisera la nouvelle version. Si vous avez de la chance, cela cassera la construction. Si vous êtes malchanceux, la production risque même de passer inaperçue.

Enfin, certaines personnes préfèrent utiliser les valeurs de propriété pour déclarer les versions enfants. Ceci est fortement déconseillé et sera signalé comme un avertissement par Maven. Personnellement, je ne le fais jamais. Les raisons sont également liées à la reproductibilité des versions et au fait que maven suppose qu'une version validée ne changera jamais. Avoir une version de module pouvant être modifiée à l'extérieur n'est pas vraiment une bonne idée.

MODIFIER:

Cas où les versions de module ne sont pas alignées.

En fait, les deux scénarios peuvent être mélangés ... Vous pouvez avoir, par exemple:

Parent

--- Composant1

--- Composant2

--- Composant3

------ Comp3Module1

------ Como3Module2

------ Comp3Module3

Les versions parent et trois composants sont différentes et les trois modules de composant 3 partagent la même version, comme expliqué précédemment.

Question 1) Dans ce cas, la version de chaque module est spécifiée de manière dépendante . Comme indiqué précédemment, il est déconseillé d'utiliser une propriété pour spécifier la version du module, raison pour laquelle je ne peux que recommander de spécifier littéralement les versions ..__ Comme déjà dit, pour gérer les versions, le meilleur moyen consiste à utiliser le plug-in de version et à l'intégrer au système de contrôle de version, tel que SVN . D'autres réponses donnent des détails sur son utilisation, aussi je ne développerai pas plus loin, à moins que demandé.

Question 2) L’approche recommandée est la même que celle expliquée dans le cas du partage de la même version, mais vous avez besoin de plusieurs propriétés.

<properties>
   <myproject.group>com.mycompany.myproject</myproject.group>
   <component1.version>1.1.1-RC1</component1.version>
   <component2.version>1.1.1-RC2</component2.version>
   <component3.version>2.0.0</component3.version>
<properties>

Vous pouvez ensuite utiliser la gestion des dépendances pour centraliser la gestion des versions dans le parent.

Par exemple, dans parent pom,

<dependencyManagement>
   <dependencies>
      <dependency>
         <groupId>${myproject.group}</groupId>
         <artifactId>component1</artifactId>
         <version>${component1.version}</version>
      </dependency>
      <dependency>
        <groupId>${myproject.group}</groupId>
         <artifactId>component2</artifactId>
         <version>${component2.version}</version>
         <type>war</type>
      </dependency>
      <dependency>
         <groupId>${myproject.group}</groupId>
         <artifactId>comp3module1</artifactId>
         <version>${component3.version}</version>
        <type>ejb</type>
      </dependency>
      <dependency>
         <groupId>${myproject.group}</groupId>
         <artifactId>comp3module1</artifactId>
         <version>${component3.version}</version>
        <type>ejb-client</type>
      </dependency>
      <dependency>
         <groupId>${myproject.group}</groupId>
         <artifactId>comp3module2</artifactId>
         <version>${component3.version}</version>
        <type>war</version>
      </dependency>
   </dependencies>
</dependencyManagement>

Maintenant, pour référencer n'importe quel module à partir de n'importe quel autre module, c'est aussi simple que:

<dependency>
   <groupId>${myproject.group}</groupId>
   <artifactId>component1</artifactId>
</dependency>
<dependency>
   <groupId>${myproject.group}</groupId>
   <artifactId>comp3module1</artifactId>
   <type>ejb-client</type>
</dependency>

Les versions sont automatiquement gérées depuis le parent. Vous n'avez pas besoin de les maintenir dans les dépendances des enfants, qui deviennent également moins verbeuses.

5
Juan

Ok c'est ce que je suis venu avec. Ceci est basé sur cet libération continue d'artefacts maven article.

Parent POM:

<properties>
    <!-- versions of modules -->
    <main.version>1.0</main.version>
    <revision>SNAPSHOT</revision> <!-- default revision -->
    <Module1.revision>${revision}</Module1.revision>
    <Module2.revision>${revision}</Module2.revision>
    <Module3.revision>${revision}</Module3.revision>
    <Module4.revision>${revision}</Module4.revision>
    <Module5.revision>${revision}</Module5.revision>
    <Module1.version>${main.version}-${Module1.revision}</Module1.version>
    <Module2.version>${main.version}-${Module2.revision}</Module2.version>
    <Module3.version>${main.version}-${Module3.revision}</Module3.version>
    <Module4.version>${main.version}-${Module4.revision}</Module4.version>
    <Module5.version>${main.version}-${Module5.revision}</Module5.version>
</properties>

Exemple de POM enfant avec dépendance entre projets:

    <groupId>com.xyz</groupId>
    <artifactId>Module4</artifactId>
    <packaging>jar</packaging>
    <version>${Module4.version}</version>

    <parent>
        <groupId>com.xyz</groupId>
        <artifactId>ParentProject</artifactId>
        <version>1.0</version>
    </parent>   

    <dependencies>
        <dependency>
            <groupId>com.xyz</groupId>
            <artifactId>Module1</artifactId>
            <version>${Module1.version}</version>
        </dependency>
        <dependency>
            <groupId>com.xyz</groupId>
            <artifactId>Module2</artifactId>
            <version>${Module2.version}</version>
        </dependency>
        <dependency>
            <groupId>com.xyz</groupId>
            <artifactId>Module3</artifactId>
            <version>${Module3.version}</version>
            <type>jar</type>
        </dependency>
    <dependencies>

1) Au début du cycle, comment définir la même version du parent et des modules dans une commande maven?

Vous n'avez plus besoin de. Le POM parent peut rester à la même version, ne changeant que si le POM parent change. Dans ce cas, vous pouvez utiliser mvn version:set -DnewVersion=1.1.1. Mais vous n’avez pas besoin de cette approche.

Au lieu de cela, vous pouvez définir dynamiquement la version à l'aide de la propriété main.version. Par exemple. mvn clean deploy -Dmain.version=1.1.1 De plus, pour forcer le passage dynamique du numéro de version, vous pouvez omettre la propriété par défaut main.version que j'ai incluse dans mon POM parent ci-dessus.

2) Comment mettre à jour la version de mod1 et la référence de mod2 à la version de mod1 en une seule étape?

Cela se résume essentiellement à la gestion des révisions. Si je ne définit pas la propriété revision dans la commande mvn, tous les modules utiliseront SNAPSHOT comme révision. Si je définis la propriété revision sur RC1, tous les modules recevront cette révision. De plus, si je règle revision sur RC1 mais Module4.revision sur RC2, Module4 obtient RC2 et tous les autres modules obtiennent RC1. Cela répond à la demande des clients d’avoir des révisions dynamiques module par module.

Voici quelques exemples: 

  • mvn clean deploy -Dmain.version=1.1.1 Définit tous les modules sur la version 1.1.1-SNAPSHOT
  • mvn clean deploy -Dmain.version=1.1.1 -Drevision=RC1 Définit tous les modules sur la version 1.1.1-RC1.
  • mvn clean deploy -Dmain.version=1.1.1 -Drevision=RC1 -DModule4.revision=RC2 Définit tous les modules sur la version 1.1.1-RC1 à l'exception de Module4 qui est défini sur la version 1.1.1-RC2.

Il convient de mentionner une mise en garde. Si vous incrémentez la version d'un module dépendant, par exemple Module1, vers RC2, vous devez également incrémenter la version de tous les modules qui l'utilisent. Par exemple, Module4 ne doit pas être incrémenté également pour RC2 (ou la version suivante). C’est quelque chose dont le client a été informé et c’est aussi pourquoi je préférerais que tous les modules aient la même version. Mais j'aime vraiment la dynamique. Essentiellement, la version est maintenant définie via une ligne de commande, aucune mise à jour des fichiers POM n’est requise.

1
Jose Martinez

1) J'ai aussi essayé la version: définie dans le passé, mais je ne l'ai jamais fait fonctionner correctement. Il est supposé suivre le même processus que la publication: préparer, mais ce n'est pas le cas. Donc, ce que vous pouvez essayer, c'est mvn release:prepare -DautoVersionSubmodules -DdryRun. Cela est supposé faire toutes les mises à jour sans rien vérifier dans le repo et sans faire de tags.

2) Je pense que le projet ClearTK a déjà suivi une stratégie similaire à la vôtre: ils ont maintenu un projet multi-module, chaque module ayant son propre cycle de publication. Pour rester au courant de la situation, ils ont mis en place un plugin personnalisé maven pour les avertir des incohérences de version de dépendance. 

https://github.com/ClearTK/cleartk/tree/master/consistent-versions-plugin

Bien qu'un tel plug-in ne produise pas les mises à jour que vous demandez, il doit au moins vous avertir lorsque des mises à jour sont nécessaires. Pour vraiment résoudre votre problème, vous pouvez envisager de suivre le même itinéraire que ClearTK et d’implémenter votre propre plug-in Maven (ou de faire ce que ClearTK a finalement fait: basculer vers un cycle de version synchronisé;))

1
rec

1) Comme @rec l'a dit, le plugin Maven Release ferait l'affaire

$ mvn release:prepare -DautoVersionSubmodules=true
$ mvn release:perform

2) Vous pouvez définir une dépendance de mod2 à mod1 comme:

<dependency>
    <groupId>com.xxx</groupId>
    <artifactId>mod1</artifactId>
    <version>LATEST</version>
</dependency>

Plus d'informations: Comment dire à Maven d'utiliser la dernière version d'une dépendance?

J'ai testé les deux solutions et ça marche! J'espère que ça vous aide :)

0
Andrés