Maven parent pom vs modules pom

284

Il semble y avoir plusieurs façons de structurer les poms parent dans une construction multiprojet et je me demande si quelqu'un a des réflexions sur les avantages / inconvénients de chaque manière.

La méthode la plus simple pour avoir un pom parent serait de le mettre à la racine d'un projet, c'est-à-dire

myproject/
  myproject-core/
  myproject-api/
  myproject-app/
  pom.xml

où le pom.xml est à la fois le projet parent et décrit les modules -core -api et -app

La méthode suivante consiste à séparer le parent dans son propre sous-répertoire comme dans

myproject/
  mypoject-parent/
    pom.xml
  myproject-core/
  myproject-api/
  myproject-app/

Où le pom parent contient toujours les modules mais ils sont relatifs, par exemple ../myproject-core

Enfin, il y a l'option où la définition du module et le parent sont séparés comme dans

myproject/
  mypoject-parent/
    pom.xml
  myproject-core/
  myproject-api/
  myproject-app/
  pom.xml

Où le pom parent contient une configuration "partagée" (dependencyManagement, propriétés, etc.) et où myproject / pom.xml contient la liste des modules.

L'intention est d'être évolutive à une construction à grande échelle, donc devrait être évolutive à un grand nombre de projets et d'artefacts.

Quelques questions bonus:

  • Où est le meilleur endroit pour définir les différentes configurations partagées comme dans le contrôle de code source, les répertoires de déploiement, les plugins communs, etc. (je suppose que le parent mais j'ai souvent été mordu par cela et ils se sont retrouvés dans chaque projet plutôt que un commun).
  • Comment le plug-in Maven, Hudson et Nexus traitent-ils la façon dont vous configurez vos multi-projets (peut-être une question géante, c'est plus si quelqu'un a été rattrapé par la façon dont une construction multi-projets a été configurée)?

Edit: Chacun des sous-projets a son propre pom.xml, je l'ai laissé de côté pour le garder concis.

Jamie McCrindle
la source
Les modules ont-ils chacun leur propre pom? Mon projet a un pom parent, mais les modules ont également chacun un pom. (peut-être une quatrième façon de décrire ce que vous décrivez)
harschware
Ah, oui, je vais éditer et mettre à jour. Chacun des sous-modules a également son propre pompon.
Jamie McCrindle
3
Tout comme une mise à jour, je peux voir un avantage de la deuxième option est qu'elle est plus facile à gérer dans Eclipse où le root pom.xml dans le premier et le troisième exemple serait difficile à inclure si les sous-modules sont des projets séparés dans Eclipse.
Jamie McCrindle

Réponses:

166

À mon avis, pour répondre à cette question, vous devez penser en termes de cycle de vie du projet et de contrôle de version. En d'autres termes, le pom parent a-t-il son propre cycle de vie, c'est-à-dire qu'il peut être libéré séparément des autres modules ou non?

Si la réponse est oui (et c'est le cas de la plupart des projets qui ont été mentionnés dans la question ou dans les commentaires), alors le parent pom a besoin de son propre module d'un VCS et d'un point de vue Maven et vous finirez avec quelque chose comme ça au niveau VCS:

root
|-- parent-pom
|   |-- branches
|   |-- tags
|   `-- trunk
|       `-- pom.xml
`-- projectA
    |-- branches
    |-- tags
    `-- trunk
        |-- module1
        |   `-- pom.xml
        |-- moduleN
        |   `-- pom.xml
        `-- pom.xml

Cela rend la vérification un peu douloureuse et une façon courante de gérer cela est d'utiliser svn:externals. Par exemple, ajoutez un trunksrépertoire:

root
|-- parent-pom
|   |-- branches
|   |-- tags
|   `-- trunk
|       `-- pom.xml
|-- projectA
|   |-- branches
|   |-- tags
|   `-- trunk
|       |-- module1
|       |   `-- pom.xml
|       |-- moduleN
|       |   `-- pom.xml
|       `-- pom.xml
`-- trunks

Avec la définition externe suivante:

parent-pom http://host/svn/parent-pom/trunk
projectA http://host/svn/projectA/trunk

Une extraction trunksentraînerait alors la structure locale suivante (modèle # 2):

root/
  parent-pom/
    pom.xml
  projectA/

En option, vous pouvez même ajouter un pom.xmldans le trunksrépertoire:

root
|-- parent-pom
|   |-- branches
|   |-- tags
|   `-- trunk
|       `-- pom.xml
|-- projectA
|   |-- branches
|   |-- tags
|   `-- trunk
|       |-- module1
|       |   `-- pom.xml
|       |-- moduleN
|       |   `-- pom.xml
|       `-- pom.xml
`-- trunks
    `-- pom.xml

C'est pom.xmlune sorte de "faux" pom: il n'est jamais sorti, il ne contient pas de vraie version puisque ce fichier n'est jamais sorti, il ne contient qu'une liste de modules. Avec ce fichier, une extraction entraînerait cette structure (modèle # 3):

root/
  parent-pom/
    pom.xml
  projectA/
  pom.xml

Ce "hack" permet de lancer une construction de réacteur depuis la racine après un checkout et de rendre les choses encore plus pratiques. En fait, c'est comme ça que j'aime configurer des projets maven et un référentiel VCS pour les grands builds : ça marche, ça évolue bien, ça donne toute la flexibilité dont vous pourriez avoir besoin.

Si la réponse est non (retour à la question initiale), alors je pense que vous pouvez vivre avec le modèle # 1 (faire la chose la plus simple qui pourrait éventuellement fonctionner).

Maintenant, sur les questions bonus:

  • Où est le meilleur endroit pour définir les différentes configurations partagées comme dans le contrôle de code source, les répertoires de déploiement, les plugins communs, etc. (je suppose que le parent mais j'ai souvent été mordu par cela et ils se sont retrouvés dans chaque projet plutôt que un commun).

Honnêtement, je ne sais pas comment ne pas donner de réponse générale ici (comme "utiliser le niveau auquel vous pensez qu'il est logique de mutualiser les choses"). Et de toute façon, les pompons enfants peuvent toujours remplacer les paramètres hérités.

  • Comment le plug-in Maven, Hudson et Nexus traitent-ils la façon dont vous configurez vos multi-projets (peut-être une question géante, c'est plus si quelqu'un a été rattrapé par la façon dont une construction multi-projets a été configurée)?

La configuration que j'utilise fonctionne bien, rien de particulier à mentionner.

En fait, je me demande comment le plug-in maven-release traite le modèle # 1 (en particulier avec la <parent>section car vous ne pouvez pas avoir de dépendances SNAPSHOT au moment de la sortie). Cela ressemble à un problème de poulet ou d'oeuf mais je ne me souviens juste pas si cela fonctionne et était trop paresseux pour le tester.

Pascal Thivent
la source
C'est très bien car je peux voir comment ça évolue. Le svn: externals répond à ma préoccupation quant à sa lourdeur.
Jamie McCrindle
@jamie Content que vous trouviez cela utile.
Pascal Thivent
1
Pourriez-vous nous expliquer comment faire fonctionner le "hack"? J'ai le projet trunks et je m'attends à ce que vous cibliez l'option -pl avec "lancement d'une construction de réacteur" mais cela présente un problème lors de la publication d'une version sur la structure car cette option ne passe pas non plus d'une construction au niveau racine puis-je le placer dans l'option <arguments /> du release-Plugin. Par conséquent , la libération: effectuer failes parce qu'il essaie de travailler sur les pom-racine ...
Jan
Le hack svn: externals est le hack svn le plus utile que j'ai vu depuis longtemps. Très utile avec les projets qui ont une branche par projet dans le même référentiel.
omerkudat
1
Salut Pascal, Comment gérerais-tu la version # si les projets mentionnés dans la section des modules n'utilisaient pas parent-pom comme <parent> mais un-autre-projet-parent-pom? Quelles versions obtiendrons-nous pour un artefact de tels projets (version # de l'artefact dans la section <parent> de ces projets OU version # du projet qui répertorie ces projets en tant que modules)? stackoverflow.com/questions/25918593/…
AKS
34

D'après mon expérience et les meilleures pratiques Maven, il existe deux types de "poms parent"

  • pom parent "entreprise" - ce pom contient les informations et la configuration spécifiques à votre entreprise qui héritent de chaque pom et n'ont pas besoin d'être copiées. Ces informations sont:

    • référentiels
    • sections de gestion de la distribution
    • configurations de plugins courantes (comme les versions source et cible de maven-compiler-plugin)
    • organisation, développeurs, etc.

    La préparation de ce pom parent doit être effectuée avec prudence, car tous les poms de votre entreprise en hériteront, donc ce pom doit être mature et stable (la publication d'une version de pom parent ne devrait pas affecter la publication de tous vos projets d'entreprise!)

  • le deuxième type de pom parent est un parent multimodule. Je préfère votre première solution - il s'agit d'une convention maven par défaut pour les projets multi-modules, représente très souvent la structure de code VCS

L'intention est d'être évolutive à une construction à grande échelle, donc devrait être évolutive à un grand nombre de projets et d'artefacts.

Les projets multiples ont une structure d'arbres - vous n'êtes donc pas limité à un seul niveau de pom parent. Essayez de trouver une structure de projet adaptée à vos besoins - un exemple classique est de savoir comment distribuer des projets mutimodules

distibution/
documentation/
myproject/
  myproject-core/
  myproject-api/
  myproject-app/
  pom.xml
pom.xml

Quelques questions bonus:

  • Où est le meilleur endroit pour définir les différentes configurations partagées comme dans le contrôle de code source, les répertoires de déploiement, les plugins communs, etc. (je suppose que le parent mais j'ai souvent été mordu par cela et ils se sont retrouvés dans chaque projet plutôt que un commun).

Cette configuration doit être judicieusement divisée en un pom parent «entreprise» et un ou plusieurs pom parents. Les choses liées à tout ce que vous projetez vont au parent «entreprise» et celles liées au projet en cours vont au projet.

  • Comment le plug-in Maven, Hudson et Nexus traitent-ils la façon dont vous configurez vos multi-projets (peut-être une question géante, c'est plus si quelqu'un a été rattrapé par la façon dont une construction multi-projets a été configurée)?

Le pom parent de l'entreprise doit être libéré en premier. Pour les multiprojets, des règles standard s'appliquent. Le serveur CI doit tout savoir pour construire correctement le projet.

cetnar
la source
1
Il existe donc deux types de projets / poms parents. Un sans déclaration de <modules>. C'est celui qui est utilisé pour l'héritage. Et un projet parent avec déclaration <multimodule>. C'est celui dont les sous-modules n'héritent pas, c'est juste pour gérer la construction du projet de hold. Ai-je raison ?
lisak
22
  1. Un parent indépendant est la meilleure pratique pour partager la configuration et les options entre des composants autrement non couplés. Apache a un projet parent pom pour partager les mentions légales et certaines options d'emballage courantes.

  2. Si votre projet de niveau supérieur contient un réel travail, comme l'agrégation de javadoc ou l'empaquetage d'une version, vous aurez alors des conflits entre les paramètres nécessaires pour effectuer ce travail et les paramètres que vous souhaitez partager via le parent. Un projet parent uniquement évite cela.

  3. Un modèle courant (ignorant # 1 pour le moment) est que les projets avec code utilisent un projet parent comme parent et qu'ils utilisent le niveau supérieur comme parent. Cela permet aux choses essentielles d'être partagées par tous, mais évite le problème décrit dans # 2.

  4. Le plugin du site deviendra très confus si la structure parente n'est pas la même que la structure du répertoire. Si vous souhaitez créer un site agrégé, vous devrez faire quelques manipulations pour contourner ce problème.

  5. Apache CXF est un exemple du modèle dans # 2.

bmargulies
la source
2
J'ai jeté un œil à ibilio et beaucoup de projets semblent préférer le pom parent "indépendant". Hibernate, ActiveMQ, Jetty, XStream etc. Ce qui suggère que c'est le mécanisme de facto.
Jamie McCrindle
2
Un autre inconvénient du parent indépendant semble être que le plugin de publication maven semble vouloir que le parent soit épinglé à une version avant de faire une version. Probablement pas beaucoup de problème car le parent ne devrait pas trop changer.
Jamie McCrindle
9

Il y a un petit hic avec la troisième approche. Étant donné que les POM agrégés (myproject / pom.xml) n'ont généralement pas de parent du tout, ils ne partagent pas la configuration. Cela signifie que tous ces POM agrégés n'auront que des référentiels par défaut.

Ce n'est pas un problème si vous n'utilisez que des plugins de Central, mais cela échouera si vous exécutez le plugin en utilisant le format plugin: goal de votre référentiel interne. Par exemple, vous pouvez avoir foo-maven-pluginavec le groupId de org.examplefournir un objectif generate-foo. Si vous essayez de l'exécuter à partir de la racine du projet à l'aide de la commande like mvn org.example:foo-maven-plugin:generate-foo, il ne fonctionnera pas sur les modules d'agrégation (voir la note de compatibilité ).

Plusieurs solutions sont possibles:

  1. Déployer le plugin sur le Maven Central (pas toujours possible).
  2. Spécifiez la section du référentiel dans tous vos POM agrégés (casse DRY principe ).
  3. Configurez ce référentiel interne dans le fichier settings.xml (dans les paramètres locaux à ~ / .m2 / settings.xml ou dans les paramètres globaux à /conf/settings.xml). Cela fera échouer la construction sans ces settings.xml (pourrait être OK pour les grands projets internes qui ne sont jamais censés être construits en dehors de l'entreprise).
  4. Utilisez le parent avec les paramètres de référentiels dans vos POM agrégés (peut-être trop de POM parents?).
Ivan Dubrov
la source