web-dev-qa-db-fra.com

Définir des plugins Maven dans pom parent, mais invoquer des plugins dans des projets enfants

J'ai un ensemble de projets qui ont tous besoin d'exécuter la même série d'exécutions de plug-ins Maven au cours de leurs générations. J'aimerais éviter de re-déclarer toute cette configuration dans chaque projet. Je les ai donc fait hériter d'un projet "template" de pom parent qui ne contient que les exécutions de plug-ins (8 mojos différents). Mais je veux que ces exécutions de plug-in ne s'exécutent que sur les projets enfants et non sur le projet parent pendant les générations Maven.

J'ai essayé d'accomplir cela de quatre manières différentes, chacune avec un effet secondaire que je n'aime pas.

  1. Déclarez les exécutions de plugins dans l'élément build/plugins du pom parent et utilisez properties-maven-plugin pour activez les propriétés skip sur d'autres plugins dans le projet parent. Cela n'a pas fonctionné car l'un des objectifs du plugin (maven-dependency-plugin: build-classpath) ne possède pas de propriété skip.

  2. Déclarez les exécutions de plug-in dans l'élément build/pluginManagement du pom parent. Malheureusement, cela nécessite que je redéclare chacun des huit plugins dans l'élément build/plugins du pom de chaque projet enfant, comme:

    <plugin>
        <artifactId>maven-Assembly-plugin</artifactId>
    </plugin>
    ...
    

    C’est trop répétitif et problématique si j’ai un jour besoin de changer les plugins dans le template pom.

  3. Déclarez les exécutions de plug-in dans un profil du pom parent activé par le manque d'un fichier nobuild.txt (qui existe dans le pom parent, les plugins ne sont donc pas exécutés là):

    <profiles>
        <profile>
            <activation>
                <file>
                    <missing>nobuild.txt</missing>
                </file>
            </activation>
            <build>
                ....
            </build>
        </profile>
    </profiles>
    

    Cela fonctionne pour la plupart, sauf que le chemin du fichier dans l'élément missing semble être basé sur le répertoire de travail en cours} au lieu du projet basedir. Cela casse certaines des constructions multimodules que j'aimerais pouvoir réaliser. Edit: pour clarifier, le projet "modèle" parent est en réalité un module dans un projet multimodule, et la construction se casse lorsque j'essaie, par exemple, de faire un mvn install à la racine. La structure du projet ressemble à ceci:

    + job
    |- job-core
    |- job-template
    |- job1                   inherits from job-template
    |- job2                   inherits from job-template
    
  4. Configurez un cycle de vie et un emballage personnalisés. Cela semble me permettre de lier les plugins aux phases du cycle de vie, mais de ne spécifier aucune configuration .

Alors, existe-t-il un autre moyen de spécifier un ensemble d'exécutions de plug-in Maven pouvant être réutilisées sur plusieurs projets (avec une répétition minimale dans chacun des poms de ces projets)?

28
matts

J'ai fini par écrire mon propre plugin qui utilise mojo-executor pour invoquer d'autres mojos. Cela me permet de 1) centraliser la configuration de construction et 2) de minimiser le nombre de configurations dupliquées dans chacun des projets enfants.

(Au cas où vous seriez curieux de savoir la raison de tout cela: chaque projet enfant est un travail qui sera exécuté à partir de la ligne de commande. La construction configure un script Shell invocateur et l'attache à la construction afin qu'elle soit archivée dans notre artefact. Un script de déploiement les récupère plus tard sur la machine sur laquelle ils vont fonctionner.)

Parties pertinentes du pom du projet de modèle:

<project ...>
    <parent> ... </parent>
    <artifactId>job-template</artifactId>
    <packaging>pom</packaging>
    <name>job project template</name>
    <build>
        <pluginManagement>
            <plugin>
                <groupId>...</groupId>
                <artifactId>job-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>generate-sources-step</id>
                        <goals><goal>job-generate-sources</goal></goals>
                    </execution>
                    <execution>
                        <id>package-step</id>
                        <goals><goal>job-package</goal></goals>
                    </execution>
                    ... (a couple more executions) ...
                </executions>
            </plugin>
        </pluginManagement>
    </build>
</project>

Il a fallu créer un nouveau projet maven-plugin (job-maven-plugin). Pom ressemble à:

<project ...>
    <parent> ... </parent>
    <artifactId>job-maven-plugin</artifactId>
    <packaging>maven-plugin</packaging>
    <name>job maven executor plugin</name>
    <dependencies>
        <dependency>
            <groupId>org.twdata.maven</groupId>
            <artifactId>mojo-executor</artifactId>
            <!-- version 1.5 supports Maven 2, while version 2.0 only supports Maven 3 -->
            <version>1.5</version>
        </dependency>
    </dependencies>
</project>

Comme vous pouvez le constater dans le projet de modèle, il y avait plusieurs mojos dans mon plugin (un par phase nécessitait que des choses se passent). Par exemple, le paquet de travaux mojo est lié à la phase de paquet et utilise la bibliothèque mojo-executor pour exécuter deux autres mojos (qui attachent seulement quelques artefacts de construction):

/**
 * @goal job-package
 * @phase package
 */
public class PackageMojo extends AbstractMojo {
    /**
     * @parameter expression="${project}"
     * @required
     * @readonly
     */
    protected MavenProject project;
    /**
     * @parameter expression="${session}"
     * @required
     * @readonly
     */
    protected MavenSession session;
    /**
     * @component
     * @required
     */
    protected PluginManager pluginManager;

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        ExecutionEnvironment environment = executionEnvironment(project, session, pluginManager);

        // Attach script as a build artifact
        executeMojo(
            plugin(
                groupId("org.codehaus.mojo"),
                artifactId("build-helper-maven-plugin"),
                version("1.7")
            ),
            goal("attach-artifact"),
            configuration(
                element("artifacts",
                    element("artifact",
                        element("file", "${project.build.directory}/script.shl"),
                        element("type", "shl")
                    )
                )
            ),
            environment
        );

        // Zip up the jar and script as another build artifact
        executeMojo(
            plugin(
                groupId("org.Apache.maven.plugins"),
                artifactId("maven-Assembly-plugin"),
                version("2.3")
            ),
            goal("single"),
            configuration(
                element("descriptors",
                    element("descriptor", "${project.build.directory}/job/descriptor.xml")
                )
            ),
            environment
        );
    }
}

Ensuite, dans les projets enfants, il me suffit de me référer au plugin une fois. À mon avis, cela est nettement préférable que de réitérer chacun des plug-in des coulisses de chaque projet enfant (ce qui augmente de manière inacceptable le couplage entre poms). Si je souhaite ajouter ultérieurement une exécution mojo à la procédure de construction, il me suffit de modifier un emplacement et de supprimer un numéro de version. Le pom du projet enfant ressemble à:

<project ...>
    <parent>
        <groupId> ... </groupId>
        <artifactId>job-template</artifactId>
        <version> ... </version>
        <relativePath>../job-template</relativePath>
    </parent>
    <artifactId>job-testjob</artifactId>
    <name>test job</name>
    <build>
        <plugins>
            <plugin>
                <groupId> ... </groupId>
                <artifactId>job-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

En outre, la structure de répertoires multimodule entière ressemble maintenant à ceci:

+- job
  +- job-core
  +- job-maven-plugin
  +- job-template
  +- job-testjob1               (inherits from job-template)
  +- job-testjob2               (inherits from job-template)

À mon avis, cette solution n’est pas tout à fait optimale, car j’ai maintenant une configuration de plug-in intégrée à une série de mojos au lieu d’un pom, mais elle répond à mes objectifs de centralisation de la configuration et de réduction des duplications entre poms de projets enfants.

(Une dernière remarque: je viens de découvrir maven-aggreg-plugin qui semble permettre de regrouper plusieurs exécutions de plug-in dans le pom. Cela aurait peut-être résolu le problème de manière légèrement plus souhaitable, mais je ne suis pas d'humeur à le faire. reprendre les dernières heures de travail, mais peut être bénéfique pour quelqu'un d'autre.)

10
matts

Personnellement, j'irais pour la solution 2. La répétition est minime et vous devriez essayer d'éviter les profils si possible pour éviter de devoir commencer à documenter quels profils doivent être activés pour quels projets. 

Un projet doit pouvoir être construit correctement en effectuant simplement une mvn (clean) install.

5
Stijn Geukens

Voici une autre option que j'ai découverte ici en cherchant une solution au même problème. Je l'affiche ici car il s'agit déjà d'une bonne collection d'options - dans l'espoir que cela puisse aider d'autres à ne pas passer des heures à résoudre ce problème:

Etant donné que le plugin a la possibilité d’ignorer l’exécution, cette option peut être activée dans le pom parent (section), avec le drapeau "inherit" défini sur false pour qu’il ne soit pas propagé aux enfants:

<plugin>
    <artifactId>maven-Assembly-plugin</artifactId>
    <executions>
        <execution>
            <id>make-Assembly</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
            <inherited>true</inherited>
            <configuration>
               ...
            </configuration>
        </execution>
    </executions>
    <!-- Skip plugin execution for parent pom but enable it for all children -->
    <configuration>
        <skipAssembly>true</skipAssembly>
    </configuration>
    <inherited>false</inherited>
</plugin>

Bien que je sois assez sceptique à propos de cette solution lorsque je l'ai lue pour la première fois, cela a fonctionné pour moi, du moins pour le plugin Assembly.

2
Timi

Une autre option: au lieu d'utiliser une propriété "skip", vous pouvez changer la phase d'exécution d'une exécution liée à une valeur inexistante telle que never.

Cela fonctionne très bien avec l'approche <inherited>false</inherited> proposée par @Timi

1
Jakub Bochenski

Voici la cinquième façon. Je pense que cela présente un minimum d'inconvénients: pas de profil, pas de cycle de vie personnalisé, pas de déclaration dans les POM enfants, pas d'exigence de "saut" pour les plugins.

Copié à partir de https://stackoverflow.com/a/14653088/2053580 - merci beaucoup à utilisateur final !

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <!-- Main declaration and configuration of the plugin -->
                <!-- Will be inherited by children -->
                <groupId>org.Apache.maven.plugins</groupId>
                <artifactId>maven-checkstyle-plugin</artifactId>
                <version>2.9.1</version>
                <executions>
                    <execution>
                        <!--This must be named-->
                        <id>checkstyle</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>check</goal>
                        </goals>
                    </execution>
                </executions>
                <!-- You may also use per-execution configuration block -->
                <configuration...>
            </plugin>
        </plugins>
    </pluginManagement>
    <plugins>
        <plugin>
            <!-- This declaration makes sure children get plugin in their lifecycle -->
            <groupId>org.Apache.maven.plugins</groupId>
            <artifactId>maven-checkstyle-plugin</artifactId>
            <!-- Configuration won't be propagated to children -->
            <inherited>false</inherited>
            <executions>
                <execution>
                    <!--This matches and thus overrides execution defined above -->
                    <id>checkstyle</id>
                    <!-- Unbind from lifecycle for this POM -->
                    <phase>none</phase>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
0
Oleg Efimov