How to exclude a module from a Maven reactor build?
Asked Answered
C

7

129

We have a Maven 2 project with lots of modules in it. Example:

<modules>
  <module>common</module>
  <module>foo</module>
  <module>data</module>
  <module>bar</module>
  ... more ...
</module>

Let's say the "data" module is time consuming to build and we want to exclude it when the project is build by a CI server. Currently we use two pom.xml files to achieve this. One has all modules in it and the other one has all modules except the ones which can be left out for CI. But that's pretty annoying because sometimes we forget to put a new module into both files.

Is there a solution which doesn't need two separate module lists?

Chalcocite answered 4/4, 2011 at 13:41 Comment(0)
M
91

The easiest might be to use profiles like this:

<project>
  ...
  <modules>
    <module>common</module>
    <module>foo</module>
    <module>bar</module>
  <modules>
  ...
  <profiles>
    <profile>
      <id>expensive-modules-to-build</id>
      <modules>
        <module>data</module>
      </modules>
    </profile>
  </profiles>
</project>

You should then check out ways you can activate profiles

Maureenmaureene answered 4/4, 2011 at 18:38 Comment(5)
Whay would you do if you need data to happen prior to common? In this case the profile modules will be placed after the default modules in reactor order. Is there a pattern for forcing order?Cline
The order of module is NOT the order in which they will appear in the reactor. The only way to affect the order, is to create dependencies between modules, i.e. using the <dependency> tag. You cannot rely on the declaration order for this.Maureenmaureene
@Maureenmaureene Actually, as of Maven 3.0.5 the Reactor will take in account the order in 'modules', although the order dictated by dependencies is of a higher priority.Cyclamate
This will break some other plug-ins who fail to detect the module in the profile even the profile is enabledHereinbefore
It would be nice if you add any example about activation and examples of call from consoleCircumscription
C
215

With Maven 3.2.1, you can now use -pl '!<module_name>,!<module_name>' to exclude certain modules from the reactor build:

mvn install -pl '!:module1,!:module2'

See this feature request: https://issues.apache.org/jira/browse/MNG-5230

Cowper answered 1/4, 2014 at 10:50 Comment(6)
Don't forget to escape the exclamation mark on the shell command line. It has a very special meaning, see e.g. unix.stackexchange.com/questions/3747/…Erigena
@Pavel: or just use - instead of !, i.e. -pl -<module_name>Akerboom
You have to give like -pl [groupId]:artifactId, eg. mvn clean install -pl !com.test:demoprojectGaur
The only problem is that if you run it in Linux, it'll be treated as one of bash command switches, so to workaround that, I have to use the colon such as -pl "-:module-name"Slowpoke
This worked for me - mvn package -pl '!server' . Need to escape the exclamation mark using single quotes.Crypto
In my experience, putting both !: and quoting with ' fails, so this answer is wrong: either use mvn install -pl '!module1,!module2' or mvn install -pl "!:module1,!:module2". I tried editing and apparently fixing the answer makes no sense to the reviewers, so posting as a comment instead.Pitchfork
M
91

The easiest might be to use profiles like this:

<project>
  ...
  <modules>
    <module>common</module>
    <module>foo</module>
    <module>bar</module>
  <modules>
  ...
  <profiles>
    <profile>
      <id>expensive-modules-to-build</id>
      <modules>
        <module>data</module>
      </modules>
    </profile>
  </profiles>
</project>

You should then check out ways you can activate profiles

Maureenmaureene answered 4/4, 2011 at 18:38 Comment(5)
Whay would you do if you need data to happen prior to common? In this case the profile modules will be placed after the default modules in reactor order. Is there a pattern for forcing order?Cline
The order of module is NOT the order in which they will appear in the reactor. The only way to affect the order, is to create dependencies between modules, i.e. using the <dependency> tag. You cannot rely on the declaration order for this.Maureenmaureene
@Maureenmaureene Actually, as of Maven 3.0.5 the Reactor will take in account the order in 'modules', although the order dictated by dependencies is of a higher priority.Cyclamate
This will break some other plug-ins who fail to detect the module in the profile even the profile is enabledHereinbefore
It would be nice if you add any example about activation and examples of call from consoleCircumscription
G
52

The projects to build can also be specified on the mvn command line. This would remove the need for a separate pom, but instead you would have to change the CI configuration everytime there is a new module.

-pl,--projects <arg>                Comma-delimited list of specified
                                    reactor projects to build instead
                                    of all projects. A project can be
                                    specified by [groupId]:artifactId
                                    or by its relative path.

Maybe a combination of this flag and --also-make-dependents or --also-make would reduce this maintenance burden again.

-am,--also-make                     If project list is specified, also
                                    build projects required by the
                                    list
-amd,--also-make-dependents         If project list is specified, also
                                    build projects that depend on
                                    projects on the list
Garotte answered 4/4, 2011 at 14:13 Comment(2)
This has the same problems as using two separate poms. We have to places where we define the modules. That's what I'm trying to avoid.Chalcocite
This is a good solution. Don't have to update the pom. mvn clean install -pl mysubprojectShanly
N
24

I assume you want the default build to always build everything, regardless of speed, so that new developers can get started quickly without having to understand lots about the POM. You can use profiles like this:

<modules>
    <module>common</module>
    <module>foo</module>
    <module>bar</module>
  </modules>
  ...
  <profiles>
    <profile>
      <id>expensive-modules-to-build</id>
      <activation>
         <activeByDefault>true</activeByDefault>
      </activation>
      <modules>
        <module>data</module>
      </modules>
    </profile>
  </profiles>
</project>

The problem with this is that if a developer specifies another profile on the command line, then the expensive-modules-to-build isn't included (unless the developer also specifies it). This makes it complicated to remember which profiles need to be included.

Here is a hacky way around that. Both profiles are always included, because the pom.xml file always exists. So to exclude the expensive modules, you can use -P!full-build on the command line.

<profiles>
    <profile>
        <id>full-build</id>
        <activation>
            <file>
                <exists>pom.xml</exists>
            </file>
        </activation>
        <modules>
            <module>data</module>
        </modules>
    </profile>
    <profile>
        <id>short-build</id>
        <activation>
            <file>
                <exists>pom.xml</exists>
            </file>
        </activation>
        <modules>
           <module>common</module>
           <module>foo</module>
           <module>bar</module>
        </modules>
    </profile>
</profiles>
Nevis answered 11/7, 2012 at 9:49 Comment(4)
Nice answer. But do you really need two profiles in the 2nd code example? Wouldn't the single profile from the 1st code example with a changed activation element work?Maltzman
@Arendv.Reinersdorff yes it would, however this answer also works with other profiles in the build that you may want to include by default. Overall though, I think the other answer with -pl !<module_name>,!<module_name> is better than this old oneNevis
Good activation trick. It solved me the problems with <activeByDefault> that isn't always active!Phase
just adding that the <modules> section in the root <profiles> element can be skipped entirely, to be put into the individual <profile> section as above, in whatever combination is needed - this way you only have to specify the profile during the Maven build.Pakistan
G
9

Another idea: Reactor modules can be nested, so it should be possible to group your fast and slow-building modules into separate poms and then add another aggregator pom containing these two as modules. Your CI Server could then only reference the pom containing the fast building modules.

<artifactId>fast</artifactId>
<modules>
    <module>fast-a</module>
    <module>fast-b</module>
    <module>fast-c</module>
</module>

<artifactId>all</artifactId>
<modules>
    <module>fast</module>
    <module>slow</module>
</module>
Garotte answered 4/4, 2011 at 15:32 Comment(0)
P
1

You could be to use maven profiles. In our build environment, we created a profile quick that disables many plugins and test execution.

This is done by

<profile>
  <id>quick</id>
  <properties>
    <skipTests>true</skipTests>
    <!-- others... -->
  </properties> 
  <build>
    <plugins>
      <!-- configuration... -->
    </plugins>
  </build>
</profile>

And then we invoke maven the following way

mvn groupId:artifactId:goal -P quick

You could maybe disable compilation and other standard plugins in the pom of your module to speed it up.

Pellegrini answered 4/4, 2011 at 14:17 Comment(3)
Yes, for disabling tests this works great. But how can I use profiles to exclude modules WITHOUT having two separate modules lists in the pom? As far as I know I need to put the full module list into one profile section and the quick-build module list into an other profile section. So this has the same problem as using two separate poms: I have two module lists to maintain.Chalcocite
Excluding module is not really the way to do things in maven and my experience with maven is that is better to stick with the way things are done, else you run in so many problems... So really what I'm proposing is not to remove the module, but to make this module less time consuming.Pellegrini
The problem with maven is that 'the way things are done' is frequently not in alignment with 'the way things are done in the real world', making the maven experience poor and painful. The developers would do well to take a dose of UX training.Dacey
R
0

Not exactly the answer these folks were asking for. My situation was I wanted to deploy only the parent pom. I'm using the spring-boot-thin-layout in a child module. This requires the parent module be deployed into artifactory. I added the following into my project. It enables skipping of install and/or deploy phase.

In my parent pom:

<properties>
    <disable.install>true</disable.install>
    <disable.deploy>true</disable.deploy>
    <enable.deployAtEnd>true</enable.deployAtEnd>
</properties>

<profiles>
    <profile>
        <id>deploy-parent</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <disable.install>true</disable.install>
            <disable.deploy>true</disable.deploy>
            <deployAtEnd>${enable.deployAtEnd}</deployAtEnd>
        </properties>
        <build>
            <finalName>${project.version}</finalName>
        </build>
    </profile>
</profiles>

And the in my child pom(s) or any module you don't want deployed with parent:

<properties>
    <maven.install.skip>${disable.install}</maven.install.skip>
    <maven.deploy.skip>${disable.deploy}</maven.deploy.skip>
    <deployAtEnd>${enable.deployAtEnd}</deployAtEnd>
</properties>

So effectively when I run mvn deploy on the parent pom, it will compile all the modules, not run install on anything, and then at the end deploy any module not having <maven.deploy.skip>${disable.deploy}</maven.deploy.skip> in it's properties. So in my case only deploying the parent.

Race answered 9/4, 2020 at 15:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.