A more realistic case – the transportation project

It's time to bring together all the bricks just discussed. In Chapter 1, Maven and Its Philosophy, we introduced a real project called the transportation project. Here, we apply a CI process to the proposed project.

The following list shows the organization of the proposed project:

  • transportation-acq-ear
    • transportation-acq-ejb
    • transportation-acq-war
    • transportation-common-jar
  • transportation-reporting-ear
    • transportation-reporting-war
    • transportation-reporting-ejb
    • transportation-common-jar
  • transportation-statistics-batch-jar

The project is based on two ear components sharing a common jar library and a single batch component. All the artifacts have the same pom.xml parent file. In this case, we will ignore the dependencies from third-party libraries (JEE, Spring, and so on), since these libraries are not active components during the release process; in other words, we do not need to release or assign a version to third-party libraries.

The proposed project elicits some issues:

  • The developer requires to release each component (transportation-acq-ear, transportation-reporting-ear, or transportation-statistics-batch-jar) with no other components: how to choose the project to build using the CI tool?
  • Two components share a common component (transportation-common-jar): how to assign the version number and release it?
  • The single batch component, transportation-statistics-batch-jar, can be released without any dependencies: how to assign the version number and how to release it?
  • Two components (transportation-acq-ear and transportation-reporting-ear) have three subcomponents: how to assign the version number?

Choosing the component to build

When a large project consists of many components/modules such as a web API, a client, and some libraries, not everything has to be re-released every time a component changes. Maven allows the user to specify an alternate pom.xml file through the –f option:

$ mvn -f my-pom.xml

Therefore, on a multimodule project, it is common practice to define an aggregator pom.xml file that lists the modules to be executed as a group.

The following pom.xml file defines the POM aggregator (called transportation-acq.xml) for the multimodule project, transportation-acq-ear. We assume that the transportation-acq-ear, transportation-acq-ejb, and transportation-acq-war projects have been included on a subdirectory called transportation-acq (the name must be coherent with the name of the aggregator's artifact ID). Therefore, the final directory structure is as follows:

Choosing the component to build

Configure the pom.xml file of the project as follows:

<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                      http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
  <groupId>com.packt.examples</groupId>
  <artifactId>transportation-project</artifactId>
  <version>0.0.1 </version>
</parent>
<artifactId>transportation-acq</artifactId>
<version>0.0.1-SNAPHOST</version>
<packaging>pom</packaging>

<modules>
<module>transportation-acq/transportation-acq-ejb</module>  
<module>transportation-acq/transportation-acq-ear</module>
<module>transportation-acq/transportation-acq-war</module>
 
</modules>
</project>

We can run the following command to build only the transportation-acq-ear and its related modules:

$ mvn -f transportation-acq.xml clean install deploy

Order is not important; Maven will sort the modules such that dependencies will always be built before the dependent modules.


Tip

You can build specific reactors through the –pl -am options.

The next step is to configure Hudson to ask the user which project aggregator POM should be built on.

From the Hudson home screen, click on the New Job option from the left-hand side menu and copy settings from an existing job or create a new one. Perform the following steps:

  1. Click on Configure Job.
  2. Navigate to Add Parameter | Choice parameter.
  3. In the Name field, write projectName.
  4. In the Choices field, write the list of projects (see the following screenshot):
    Choosing the component to build

    Configuring artifact parameters in Hudson

Finally, we have to configure the build section. In the build section, perform the following steps:

  1. Click on Advanced.
  2. In the POM File field, write ${projectName}/pom.xml.

Hudson is ready to ask the user which module to build.

Tip

The ${projectName}/pom.xml parameter is a simple convention adopted by authors, but you can adopt your own convention. The aggregator filename and the name configured on Hudson, however, must be coherent.

Preparing the version of a multimodule component

The release process of a single component has been extensively described in the previous sections. In a multimodule component, however, dependencies to common artifacts and module versioning require a different configuration. Indeed, even if the submodules are versioned with the same version number of the EAR project, common projects should follow a different lifecycle.

In the transportation project, the proposed strategy will require the team of developers to release common projects (transportation-common-jar) such as a unitary component, and assign the same version of the EAR project to each submodule (transportation-acq-ejb, transportation-acq-war, transportation-reporting-ejb, or transportation-reporting-war).

This mixed strategy is a good compromise between the release automation and fine-grained controls of a component's versions. Alternatively, developers can set the version to each component manually and use Maven SCM Plugin only to tag the code. This way, however, is not exactly the idea of CI, where all processes (not developing) must be as automatic and easy as possible.

We configured Maven Release Plugin as explained in the previous sections, and we can execute the following command:

$ mvn –-batch-mode 
-DallowTimestampedSnapshots=true -DignoreSnapshots=true 
-f transportation-acq.xml  
clean install release:clean release:prepare

The outcome is as follows:

[…]
[INFO] Transforming 'transportation-acq-ejb'...
[INFO] Transforming 'transportation-acq-war'...
[INFO] Transforming 'transportation-acq-ear'... 
[…]
[INFO] Tagging release with the label transportation-acq-pom-0.0...
[…]

The -batch-mode option will force Maven to assign the version number automatically, without any further user interaction. All the submodules will be released with the same version, upgrading the final development (SNAPSHOT) version with a +1 on the latest number.

We can force the version number, as follows:

$ mvn –-batch-mode -f transportation-acq.xml 
-DallowTimestampedSnapshots=true -DignoreSnapshots=true 
-DreleaseVersion=0.0.2 
clean install release:clean release:prepare

The project will be delivered with the provided versions.

Obviously, the plugin allows us to provide the number for each component using the following syntax:

-DdevelopmentVersion=1.3-SNAPSHOT

We can also use the following syntax:

-Dproject.dev.groupId:projectName=1.3-SNAPSHOT 

Alternatively, use the following syntax:

-Dproject.rel.groupId:projectName=1.3

However, we prefer a more easy strategy.

Configuring Hudson

Hudson can be easily configured by asking the user for the releaseVersion parameter.

Perform the following steps from the left-hand side menu:

  1. Click on Configure Job.
  2. Navigate to Add Parameter | String parameter.
  3. In the Name field, write releaseVersion.

Finally, configure a new Maven build step, as follows:

  1. From the Build section, navigate to Add build Step | Invoke Maven 3.
  2. Replace clean install with release:clean release:prepare.
  3. From the Build section, navigate to Add build Step | Invoke Maven 3.
  4. Replace clean install with release:perform.

Hudson will show the following output:

[…]
[artifact:mvn] [INFO] Building transportation-acq 0.0.1-SNAPSHOT
[…]
[artifact:mvn] [INFO] Building transportation-acq 0.0.1
[…]
[artifact:mvn] [INFO] Tagging release with the label transportation-acq -0.0.1
[…]
[artifact:mvn] [INFO] Transforming 'transportation-acq'...
[artifact:mvn] [INFO] Not removing release POMs
[artifact:mvn] [INFO] Checking in modified POMs...
[…]

Preparing the version of a multimodule with a flat structure (an alternative way)

In some cases, it is not acceptable to adopt a hierarchical structure of folders, and we might therefore prefer a flat environment, as is shown in the following screenshot:

Preparing the version of a multimodule with a flat structure (an alternative way)

In this case, the current version of Maven Release Plugin will not tag the submodules.

In the previous sections, we introduced the Ant Maven task. We can use this task to loop over modules in order to release artifact by artifact. The Ant script works with the For task, and the Ant Maven task will cycle between modules and release each artifact.

The script reads the aggregator POM, transportation-acq.xml, through the Xmlproperty task.

In the root directory of your project, create a build.xml file with the following content:

<project name="maven-release" default="release" basedir="." xmlns:artifact="antlib:org.apache.maven.artifact.ant">
  
<taskdef name="for" classname="net.sf.antcontrib.logic.ForTask"
classpath="${basedir}/lib/ant-contrib-1.0b3.jar" />
  
<typedef resource="org/apache/maven/artifact/ant/antlib.xml"
uri="antlib:org.apache.maven.artifact.ant"
path="${basedir}/lib/maven-ant-tasks-2.1.3.jar" />
  
  <target name="release">
  
    <xmlproperty file="${basedir}/${projectName}.xml"
       collapseAttributes="true"/>

   <for param="line" 
      list="${project.modules.module}" 
      delimiter=",">
      <sequential>
      <echo>@{line}</echo>
    <artifact:mvn pom="${basedir}/@{line}/pom.xml">
      <arg value="-DallowTimestampedSnapshots=true" /> 
      <arg value="-DignoreSnapshots=true" />
      <arg value="release:clean"/>
      <arg value="release:prepare"/>
          
    </artifact:mvn>
  </sequential>
  </for>
  </target>
</project>

In Hudson, we need to replace the Maven release step with an Ant step and configure a new Ant build step:

  1. From the Build section, navigate to Add build step | Invoke Ant.
  2. In the Targets field, write release.
  3. Replace Invoke Maven 3 with release:perform.

Hudson will show the following output:

[…]
[artifact:mvn] [INFO] Building transportation-acq-ejb 0.0.1-SNAPSHOT
[…]
[artifact:mvn] [INFO] Building transportation-acq-ejb 0.0.1
[…]
[artifact:mvn] [INFO] Tagging release with the label transportation-acq-ejb-0.0.1
[…]
[artifact:mvn] [INFO] Transforming 'transportation-acq-ejb'...
[artifact:mvn] [INFO] Not removing release POMs
[artifact:mvn] [INFO] Checking in modified POMs...
[…]

Note

This strategy is strongly discouraged by authors, but should be a good work-around for old projects released in a production environment.

Finalizing the release

In the previous sections, we tested, versioned, and tagged the software. Then, we packaged and released the component on the repository server. Now, it's time to alert the delivery team about the new available version.

Hudson (or Jenkins) allows us to send an e-mail after the build step. Perform the following steps from the left-hand side menu:

  1. Click on Configure Job.
  2. In the Post-build Actions section, click on Editable Email Notification.
  3. Click on Advanced and add Success Trigger.
  4. Click on Expand.
  5. In the Recipient List field, write the list of the e-mails of users to be notified.
  6. In the Content field, write New version: ${ENV, var="projectName"} ${ENV, var="releaseVersion"} (see the following screenshot):
    Finalizing the release

    Hudson's configure notification phase

In the case of build success, the delivery team will be notified.

Sometimes, we also need to communicate some related information such as the prerequisites for installation (new features or configurations of DB); this information can be easily sent in the body of an e-mail or (better) attached as a child issue of the bug issue just solved. Indeed, in the previous sections, we showed how to integrate and automate the issue-tracking system (MantisBT). The most popular bug-tracking systems (MantisBT and JIRA) support this function, and it is common to use these features.

Our environment is now ready to be built; we can now release and deploy our amazing ideas.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset