One of CircleCI’s features is a persistent dependency cache that saves time on any subsequent builds. This works especially well for Maven builds, which typically spend most of their time resolving and downloading dependencies.

This guest post by Julio Capote of packagecloud will show you how to use CircleCI’s caching along with packagecloud to keep your Maven builds as fast as possible.

For this example, we’ll setup a basic Maven project on CircleCI that deploys our artifacts to a Maven repository hosted by packagecloud. We’ll demonstrate how to best set up your Maven goals to maximize the use of the dependency cache. Follow along by cloning circleci-maven-project on GitHub.

Configuring a Maven project for CircleCI

Before we build and deploy our Maven project, we need to ensure it has all of the necessary files to use both CircleCI and packagecloud.

Add the following code to .circleci.settings.xml in your Maven project:

<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-examplecorp</id>
      <password>${env.EXAMPLECORP_PACKAGECLOUD_API_TOKEN}</password>
    </server>
  </servers>
</settings>

This code tells Maven to use an environment variable as the password for any repositories with the id of packagecloud-examplecorp. We’ll configure this environment variable with our packagecloud credentials later.

Copy the following build steps into circle.yml to configure CircleCI:

dependencies:
  override:
    - mvn -DskipTests clean install dependency:resolve-plugins dependency:go-offline

test:
  override:
    - mvn -o surefire:test

deployment:
  main:
    branch: master
    commands:
      - mvn -s .circleci.settings.xml -DskipTests deploy

dependencies phase

CircleCI provides a dependency cache that persists across builds for a particular project and branch. Since Maven is a supported platform, it will automatically persist the $HOME/.m2 directory, which is the default location of the local Maven repository.

All we have to do is ensure that Maven downloads all of its dependencies and plugins to the local repository. We can do that by adding the following line to the override section of the dependencies phase:

mvn -DskipTests clean install dependency:resolve-plugins dependency:go-offline

This tells Maven to prepare for offline use with the dependency:go-offline plugin. It’s important to run the dependency:resolve-plugins goal as part of this command, otherwise the plugins won’t be resolved and downloaded to the local Maven repository.

test phase

We’re running our tests with the mvn -o flag, which puts Maven in “offline mode”. This means it will only use dependencies and plugins located in the local Maven repository.

deployment phase

Since our example is using a SNAPSHOT version, we can simply run mvn deploy after every commit to the master branch. We pass our .circleci.settings.xml file as an argument so Maven knows to use the EXAMPLECORP_PACKAGECLOUD_API_TOKEN environment variable for the repository password. Alternatively, you can configure CircleCI to only run deployments on tagged commits.

Consult the deployment documentation for more information.

Create packagecloud Maven repository

If you haven’t already, get a free Maven repository from packagecloud. In our example, we created a user named exampleCorp with a Maven repository called core.

Add your repository to <distributionManagement/>

In the <distributionManagement/> section of the project’s pom.xml file, we tell Maven to deploy to our newly-created, private Maven repository:

<distributionManagement>
  <repository>
    <id>packagecloud-examplecorp</id>
    <url>packagecloud+https://packagecloud.io/exampleCorp/core</url>
  </repository>
  <snapshotRepository>
    <id>packagecloud-examplecorp</id>
    <url>packagecloud+https://packagecloud.io/exampleCorp/core</url>
  </snapshotRepository>
</distributionManagement>

Note that id is set to packagecloud-examplecorp, which is what we used in our .circleci.settings.xml above.

Add the packagecloud plugin to your Maven project

Finally, in the <build/> section of pom.xml, add the plugin that lets Maven natively deploy artifacts to packagecloud repositories.

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

Note: this plugin is only needed to upload artifacts. No plugin is required for downloading artifacts. Any Maven-compatible build tool can use your Maven repository.

CircleCI Setup

Now we’re ready to add our Maven project to CircleCI.

Sign up with either GitHub or Bitbucket. Head to your dashboard and select the circleci-maven-project.

Copy your packagecloud API Token. Then, click the gear icon next to your project’s name to access build settings.

Once you’re in build settings, navigate to the ‘Environment Variables’ section.

Selenium Maven Dependency

Click the ‘Add Variable’ button. Then, enter EXAMPLECORP_PACKAGECLOUD_API_TOKEN into the ‘Name’ field and paste your API token into the ‘Value’ field.

docker maven plugin

On the next commit, the variable should be uploaded to your packagecloud Maven repository. If everything went according to plan, you should see your freshly-uploaded SNAPSHOT artifact:

4-17-17-maven-done.png

Conclusion

Using CircleCI in conjunction with SNAPSHOT versions and packagecloud Maven repositories is a great combination for quickly iterating on software used by multiple teams. The project in this post, for example, only takes a minute and a half to clone, build, test and deploy!


Julio Capote is a software engineer at packagecloud, which provides private repositories for Maven, RPM, DEB, PyPi, and RubyGem packages.