Tag Archives: lifecycle

Re-configuring the Default Lifecycle Goals in Maven 2.2

One of the interesting features that has appeared in Maven 2.2 is the ability to add configuration specifically to the goal execution supplied by default lifecycle bindings.

Previously, you could only do this at the plugin level, for example:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.4.3</version>
  <configuration>
    <excludes>
      <exclude>**/selenium/**</exclude>
    </excludes>
  </configuration>
</plugin>

There are two problems with this:

  1. it may not be appropriate for all goals in the plugin to take this configuration. This is a common problem with the Compiler plugin, where you may want different parameters for the compile and testCompile goals (such as the JDK level – a problem well known by TestNG users developing on JDK 1.4!)
  2. you can’t erase configuration through inheritance – so as the example above shows, you are stuck with those excludes even if you define a new goal to run a second set of tests

Consider the addition of the following to the above:

<profile>
  <id>selenium</id>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <executions>
          <execution>
            <id>selenium-tests</id>
            <configuration>
              <includes>
                <include>**/selenium/**</include>
              </includes>
            </configuration>
            <goals>
              <goal>test</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</profile>

This will do nothing, since only the Selenium tests are to be run (includes), but all Selenium tests are disabled (by inheritance of excludes).

This leads to a convoluted combination of turning off the default binding, re-adding it with its configuration, as a modification to the first sample:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.4.3</version>
  <configuration>
    <skip>true</skip>
  </configuration>
  <executions>
    <execution>
      <id>unit-tests</id>
      <configuration>
        <skip>false</skip>
        <excludes>
          <exclude>**/selenium/**</exclude>
        </excludes>
      </configuration>
      <goals>
        <goal>test</goal>
      </goals>
    </execution>
  </executions>
</plugin>

The skip flag also needed to be added to the Selenium profile.

Maven 2.2 adds a simple solution to this problem – all of the executions in the default lifecycle are assigned IDs of the form default-phase. Because Maven’s inheritance merges executions with identcial IDs, you can assign configuration directly to the built in goal and no others.

This means that the previous section can be reduced back closer to the original, like so:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.4.3</version>
  <executions>
    <execution>
      <id>default-test</id>
      <configuration>
        <excludes>
          <exclude>**/selenium/**</exclude>
        </excludes>
      </configuration>
    </execution>
  </executions>
</plugin>

The goals are not necessary in the execution, since they were already given in the default binding.

This results in a more intuitive pattern for setting up multiple test executions (a common occurrence with profiles and integration tests), as well as use cases such as configuration the compiler plugin goals separately.

One more thing to watch out for – taking advantage of this will mean the build is no longer compatible with earlier versions of Maven. To make sure you don’t get caught out, you should add the Enforcer plugin somewhere in the build:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-enforcer-plugin</artifactId>
  <version>1.0-beta-1</version>
  <executions>
    <execution>
      <id>enforce</id>
      <goals>
        <goal>enforce</goal>
      </goals>
      <configuration>
        <rules>
          <requireMavenVersion>
            <version>[2.2.0,)</version>
          </requireMavenVersion>
        </rules>
      </configuration>
    </execution>
  </executions>
</plugin>

In addition to changing the defaults, you can also now supply configuration that is targeted at command line invocations (without affecting the main build). More information on all of these can be found in the new Guide to Configuring Default Execution IDs.

Enjoy!