maven

6 posts

JGit Flow Maven plugin integration with Bamboo

JGit Flow is a good plugin to apply git-flow practice with Maven projects. Since it's a pure Java implementation, it's very easy to integrate with most CI servers.

However, if you are using Atlassian Bamboo, there are some workarounds for particular issues.

Git repository url

Bamboo use a fake Git repository after checkout. The repository's url is something like file:///nothing. So JGit Flow cannot perform actual Git operations on this repository. You can:

1) Set repository url in plugin configuration

<configuration>  
    <defaultOriginUrl>[repository url]</defaultOriginUrl>
    <alwaysUpdateOrigin>true</alwaysUpdateOrigin>
</configuration>  

2) Use Git command to update repository url

${bamboo.capability.system.git.executable} remote set-url origin ${bamboo.repository.git.repositoryUrl}

Git repository authentication

You can use -Dusername and -Dpassword in JGit Flow plugin to set the repository's username and password. To execute Bamboo shell script with Git commands, a .netrc file with authentication details needs to be created. This can be done via agent start script or using echo in inline script.

machine bitbucket.org  
login <username>  
password <password>  

Clean old release branches

After finishing a release using release-finish, the remote release branch is deleted by default. But the branch may still exist in local. These old release branches should be removed, otherwise next release-start goal will fail.

${bamboo.capability.system.git.executable} fetch --prune --verbose

${bamboo.capability.system.git.executable} branch -vv | awk '/: gone]/{print $1}' | xargs ${bamboo.capability.system.git.executable} branch -d 2> /dev/null

echo 'stale branches deleted'  

Build Apache Camel Custom Component

If you create a custom Apache Camel component, you can build it using Maven to generate necessary metadata, then this component can be auto-discovered by Camel.

Create a custom component following the guide. Add file META-INF/services/org/apache/camel/component/FOO to src/main/resources folder with content like below:

class=com.example.CustomComponent  

Then add following code to Maven's pom.xml. Maven plugin camel-package-maven-plugin is used to generate component.properties file.

<build>  
    <plugins>
        <plugin>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-package-maven-plugin</artifactId>
            <version>${camel.version}</version>
            <executions>
                <execution>
                    <goals>
                        <goal>prepare-components</goal>
                    </goals>
                    <phase>generate-resources</phase>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>  

Then add Maven dependency of org.apache.camel:apt. This apt module processes Camel annotations and generate component JSON schema and HTML documentation. See Camel 2.15 release note.

<dependency>  
    <groupId>org.apache.camel</groupId>
    <artifactId>apt</artifactId>
    <version>${camel.version}</version>
    <scope>provided</scope>
</dependency>  

After this, you should be able to list your component and its JSON schema from JMX.

Maven failsafe plugin to fail builds

Maven failsafe plugin is used to run integration tests. If you only add this plugin to integration-test phase, it won't fail the build. So you will have builds with failed integration tests. This design is to make sure the post-integration-test phase can run and tear down the environment correctly. This is because integration tests usually involve preparing the environment (DB, file system, network, etc.) before tests run, so cleaning up is required. To check the result of integration tests, verify phase needs to be used and fail builds correctly in this phase.

From the manual,

The Failsafe Plugin is used during the integration-test and verify phases of the build lifecycle to execute the integration tests of an application. The Failsafe Plugin will not fail the build during the integration-test phase, thus enabling the post-integration-test phase to execute.

So mvn verify should be used to invoke Maven when running integration tests.

A typical example of failsafe plugin configuration should be:

<plugin>  
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-failsafe-plugin</artifactId>
  <version>2.18.1</version>
  <executions>
    <execution>
      <id>integration-test</id>
      <phase>integration-test</phase>
      <goals>
        <goal>integration-test</goal>
      </goals>
    </execution>
    <execution>
      <id>integration-test-verify</id>
      <phase>verify</phase>
      <goals>
        <goal>verify</goal>
      </goals>
    </execution>
  </executions>
</plugin>  

Atlassian Bamboo

If you are using Atlassian Bamboo to build, make sure **/target/failsafe-reports/*.xml is added to test results directory. Then Bamboo can correctly display integration tests results. The option Look in the standard test results directory may not work due to this bug as **/target/failsafe-reports/*.xml is not added to the standard test results directory.

Bamboo Maven failsafe settings

Atlassian Elastic Bamboo - Update Maven Settings

When using Atlassian Elastic Bamboo to build Maven project, it's a common task to update Maven settings.xml to add private repository information, e.g. credentials to access company's private repository.

Below are two approaches I find to update Maven settings.

Add settings.xml to code repository

The first approach you can take is to add the settings.xml to your code repository, then specify the path to settings.xml file using -s option of mvn command.

Suppose the settings.xml is in the root directory of your project, use mvn -s settings.xml clean deploy as the command line to invoke Maven.

Update settings.xml in Bamboo image

If an Amazon EBS volume is added to the Bamboo agent, you can directly change the settings.xml file. Atlassian has a guide on how to do this. Below is a much simpler guide on how to do it.

  1. Start the Bamboo agent
  2. Edit the file /mnt/bamboo-ebs/maven/.m2/settings.xml. Not the one /home/bamboo/.m2/settings.xml. /home/bamboo/.m2/settings.xml is copied from /mnt/bamboo-ebs/maven/.m2/settings.xml after agent started.
  3. Find the EBS volume used by the running agent.
  4. Create a snapshot from the EBS volume.
  5. Update Bamboo elastic image configurations to attach the new snapshot.
  6. Done!

Maven JGitFlow - Working tree has uncommitted changes

When I was trying to start a new release using Maven jgitflow plugin, it always complained about Working tree has uncommitted changes. I checked Git repository using git status -s and it seemed that all changes had been committed. I even tried to use git clean -f -d to clean all untracked files, even though I'm pretty sure that I already configured jgitflow to allow untracked files using <allowUntracked>true</allowUntracked>. But still no luck.

After searching for a while, I found out jgitflow actually has a gitflow log file. The log file is .git\jgitflow.log in your project's directory. After checking the log file, I found out it's caused by case insensitive path on Windows for Git. The momentjs library I'm using has changed the name of readme file from readme.md to README.md. But this change is not detected after I used Bower to update the library due to case insensitive path.

After knowing that, the fix is quite easy. Just use git mv to rename the file, git mv -f moment/readme.md moment/README.md. Then commit the change and jgitflow starts working again.

The key takeaway point here is to remember to check .git\jgitflow.log log file if you have jgitflow issues.

Deploy Maven Site to Nexus

Maven has a handy site plugin which can generate a website about your Maven project. Once the website is generated, normally it needs to be published to somewhere. A simple web server using Apache httpd or Nginx will be enough. Use a SSH/SCP wagon to upload website files to the server. Or website can be published to AWS S3 using wagon provided by community. Nexus can also host Maven websites. So if you are already using Nexus as internal Maven server, then it's a better choice to use Nexus to host the Maven site.

Add a new site in Nexus

First a new Hosted repository with Provider Site.

!Add a new site in Nexus.

Once new site is added, go to Summary tab and find out the URL of the new site, i.e. http://nexus:8081/nexus/content/sites/myproject.

Update POM file

Maven project's pom.xml needs to be updated to use this site configuration. Add <site> configuration in <distributionManagement> element. See code below:

<distributionManagement>  
  <site>
    <id>myproject-site</id>
    <url>dav:http://nexus:8081/nexus/content/sites/myproject</url>
  </site>
</distributionManagement>  

Please note the protocol dav: before the site URL. WebDAV is used to upload content to the site.

Update Maven settings

Usually Nexus has user authentication. The user's credentials should be added in Maven's settings.xml file. See code below:

<servers>  
  <server>
    <id>myproject-site</id>
    <username>username</username>
    <password>password</password>
  </server>
</servers>  

The id of <server> must match the id in <distributionManagement>.

Configure Maven site plugin

In the <pluginManagement>, configure Maven site plugin, see code below:

<plugin>  
  <artifactId>maven-site-plugin</artifactId>
  <version>3.4</version>
  <dependencies>
    <dependency>
      <groupId>org.apache.maven.wagon</groupId>
      <artifactId>wagon-webdav-jackrabbit</artifactId>
      <version>2.6</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-simple</artifactId>
      <version>1.7.7</version>
    </dependency>
  </dependencies>
</plugin>  

Dependencies wagon-webdav-jackrabbit and slf4j-simple are required.

In <build> configuration, add the WebDAV extension as below:

<extensions>  
  <extension>
    <groupId>org.apache.maven.wagon</groupId>
    <artifactId>wagon-webdav-jackrabbit</artifactId>
    <version>2.6</version>
  </extension>
</extensions>  

Publish site

To generate and publish site, run mvn site:site site:stage site:deploy. site:stage goal is required if you project has multiple modules. After publish, you should be able to access the site using the URL.