How to Deploy Maven Artifacts with Travis CI and packagecloud

This is a guest blog post from Joe Damato, CEO and cofounder at packagecloud.

This post will go through the steps needed to implement continuous delivery for Java projects using Maven and Travis CI. Every time a tagged commit is pushed to Github, Travis CI will automatically build the project and push it to your Maven repository on packagecloud.

Configuring Maven for packagecloud and Travis CI

Add a .travis.yml file to your Maven project

If you’d like to follow along with this post, take a look at the java-test-package github repository for an example Maven project.

We’ll start with the example .travis.yml file:

sudo: false
language: java
services:
- docker
cache:
  directories:
  - "$HOME/.cache"

deploy:
  provider: script
  script: "cp .travis.settings.xml $HOME/.m2/settings.xml && mvn deploy"
  skip_cleanup: true
  on:
    tags: true

Running mvn test

Because we are specifying language: java, Travis CI will run mvn test on our project by default, so we don’t need to specify mvn test anywhere.

Running mvn deploy

We are using the ‘script’ deployment provider to run mvn deploy for us.

The deployment script consists of two steps:

  1. Copy .travis.settings.xml from repository to the required Maven directory

  2. Run mvn deploy

We also set on: tags: true so that deployments are triggered only when a tagged commit is pushed.

For detailed documentation on the deploy section, refer to the deployment and script sections of the Travis CI docs.

Add a .travis.settings.xml file to your Maven project

Maven reads repository authentication information from a file located at $HOME/.m2/settings.xml. Since we’ll be exporting our API token as an environment variable, we just need to copy over a static configuration that tells Maven to use an exported PACKAGECLOUD_TOKEN as the password for repositories with an id of packagecloud-travis.

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                      http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <servers>
    <server>
      <id>packagecloud-travis</id>
      <password>${env.PACKAGECLOUD_TOKEN}</password>
    </server>
  </servers>
</settings>

Add the packagecloud plugin to <build/>

This tells Maven to use the maven-packagecloud-wagon plugin, which allows Maven to upload to packagecloud repositories natively.

NOTE: This plugin is only needed when uploading to packagecloud repositories. Any build tool (Maven, Gradle, Leiningen, SBT) can resolve and download from packagecloud Maven repositories without needing a plugin.

Make sure the <build/> section of your pom.xml contains the following extension:

<build>
  <extensions>
    <extension>
      <groupId>io.packagecloud.maven.wagon</groupId>
      <artifactId>maven-packagecloud-wagon</artifactId>
      <version>0.0.4</version>
    </extension>
  </extensions>
</build>

Create your packagecloud Maven repository

If you haven’t already, get a free maven repository from packagecloud.io.

Add your repository to <distributionManagement/>

We are using an id of packagecloud-travis so that it matches against the .travis.settings.xml configuration we are using above. Our repository for this example is capotej/java-test-package.

Set the <distributionManagement/> section in your pom.xml to the following:

<distributionManagement>
  <repository>
    <id>packagecloud-travis</id>
    <url>
      packagecloud+https://packagecloud.io/capotej/java-test-package
    </url>
  </repository>
  <snapshotRepository>
    <id>packagecloud-travis</id>
    <url>
      packagecloud+https://packagecloud.io/capotej/java-test-package
    </url>
  </snapshotRepository>
</distributionManagement>

Configure Travis CI

Now that our Maven project is configured and has all of the required files, we’re ready to configure Travis CI.

Sign in to Travis CI with your Github Account

This will give Travis CI access to list all of your Github repositories.

sign into travis

Enable the repository

Under your Travis account settings, find your Maven project repository and enable it.

enable github repository on travis

Create PACKAGECLOUD_TOKEN environment variable

Visit the packagecloud.io API Token page to get your packagecloud API Token. Then visit your Travis CI project settings page and add that API token as an environment variable named PACKAGECLOUD_TOKEN.

NOTE: Make sure that “Display value in build log” is set to OFF, or else anyone will be able to see your token!

add packagecloud token environment variable

Set the version and push

Edit and commit the desired version in the <version/> section of your pom.xml, for example 2.0.0.

Then, create that version as a git tag:

git tag -a 2.0.0 -m '2.0.0'

Push all of your changes to Github (origin):

git push origin master

This will start a build on Travis CI, but it will not deploy.

In order to actually deploy, you have to push up your version git tag to Github (origin):

git push origin --tags

This should start another build on Travis CI, which will start the deploy to packagecloud once it finishes.

If everything went according to plan, you should now see your Java package in your packagecloud repository!

the capotej/java-test-package packagecloud repository

Using your packagecloud Maven repository

To use your newly published artifact, we have to add the repository and dependency to the Maven, SBT, Gradle, and/or Leiningen projects that intend to use it. The example steps below are for Maven, but if you navigate to your package page on packagecloud you can see instructions are provided for all supported build tools. Similarly, authentication instructions are also provided for private Maven repositories.

add-java-test-package-dependency

Add the repository to yourpom.xml

You install this Maven repository by adding it to the <repositories> section of your pom.xml. No special plugins or extensions are required.

<repositories>
  <repository>
    <id>capotej-java-test-package</id>
    <url>
      https://packagecloud.io/capotej/java-test-package/maven2
    </url>
    <releases>
      <enabled>true</enabled>
    </releases>
    <snapshots>
      <enabled>true</enabled>
    </snapshots>
  </repository>
<repositories>

Add the dependency to your pom.xml

To depend on java-test-package 2.0.0, add this to the <dependencies> section of your pom.xml.

<dependency>
  <groupId>io.packagecloud</groupId>
  <artifactId>java-test-package</artifactId>
  <version>2.0.0</version>
</dependency>

Bonus: Using SNAPSHOT versions

The setup described in this post only deploys when a tagged commit is pushed up. However, this can be extended to support different workflows. For instance, if you use a SNAPSHOT version, you can set it to deploy on every commit. This way, your users can develop against the latest SNAPSHOT version, like 2.0.0-SNAPSHOT, then once you are ready for release, just remove -SNAPSHOT and tag/commit as usual. All packagecloud Maven repositories support SNAPSHOT and release versions side by side, making this workflow seamless.

Conclusion

Using packagecloud and Travis CI to automate your Java project release process can dramatically speed up your software development cycles and reduce the amount bad or broken releases.