Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Continuous Integration to Maven Central (for Free)

DZone's Guide to

Continuous Integration to Maven Central (for Free)

This tutorial shows you how to set up continuous integration between GitHub and the Maven Central repository with Travis CI.

· Integration Zone
Free Resource

Share, secure, distribute, control, and monetize your APIs with the platform built with performance, time-to-value, and growth in mind. Free 90-day trial of 3Scale by Red Hat

If you have some small open source projects or libraries that you want to release to Maven Central, and you do not want to host your own CI environment, then this blog post might help. I mostly wrote it for myself (to remember) but I am sure it might be useful to others. All this information is somewhere on the internet; this blog just brings it together.

Context

Image title

So you have some projects on your PC, coding in your favorite IDE (Netbeans, in my case), and you can build your artifacts in Maven. This blog will explain how to get from there via GitHub to build on Travis CI, create a release back into GitHub, release to Sonatype Nexus OSS and publish to the Central repository, and then send a Slack notification.

I'll be using one of my own projects as an example: https://github.com/phillip-kruger/apiee.

GitHub

Just head over to https://github.com/ and sign up. You can then create a new repository by clicking on the + button.

Remember to add an open source license :

Image title

You can now clone the repository and add your code to it. Pushing code to the upstream will make your code available on the GitHub page:

Image title

Add a README.md with some information about your project. GitHub also has a built-in wiki (example) to add more documentation about your project.

Some more info:

Travis CI

"Easily sync your GitHub projects with Travis CI and you’ll be testing your code in minutes!" -travis-ci.org.

Adding Travis CI to Github is very easy- just go to the GitHub marketplace and select "Continuous integration" and then "Travis CI" (or this direct link).

Click "Configure access" and follow the instructions. This will add Travis CI as an Installed GitHub App on your account: https://github.com/settings/applications.

You can now also log into Travis CI using your GitHub account. You will then see all your public GitHub projects. Simply select the projects you want Travis to build for you:

Image title

Your initial build might fail, as you need a .travis.yml file in your project root.

In Your Project Root

Add a .travis.yml file. For now, we just want to tell Travis that we are using Java:

language: java

Commit and push the change. Because you have linked your GitHub to your Travis CI account, Travis will automatically kick off a build if it detects a change. You can see the result in your Travis project page:

Image title

You can now add the "build passing" image to your README.md or wiki page in your GitHub project; for example:

Build status: [![build_status](https://travis-ci.org/phillip-kruger/apiee.svg?branch=master)](https://travis-ci.org/phillip-kruger/apiee)

Then it's easy to see the build status in GitHub:

Image title

Release Back Into GitHub

So now Travis built your project on every push. We can now setup Travis to create a release in GitHub for every build.

1) Get the project version:

In .travis.yml, add the following:

before_deploy:
   - mvn help:evaluate -N -Dexpression=project.version|grep -v '\['
   - export project_version=$(mvn help:evaluate -N -Dexpression=project.version|grep -v '\[')

This will set the project version (as defined in your pom.xml) to an environment variable project.version.

Some more info:

2) Install the Travis client:

You need Ruby installed on your system to use the Travis client. In my case (Arch Linux) it's as simple as:

sudo pacman -S ruby

Then you can install Travis:

gem install travis

This will allow you to create some entries in your .travis.yml file. 

You can test that the client installed correctly:

travis version
1.8.8 

3) Create the release instruction:

To create the release part in your .travis.yml file, run the following command in the root of your project:

travis setup releases

You will be prompted for your GitHub username and password.
This will create the deploy part in your .travis.yml file:

deploy:
    provider: releases
        api_key:
            secure: **** (some long encrypted key)
        file:
            - apiee-core/target/apiee-core-$project_version.jar
            - apiee-providers/target/apiee-providers-$project_version.jar
            - apiee-example/target/apiee-example.war
        skip_cleanup: true
        on:
            repo: phillip-kruger/apiee
        name: $project_version

You can replace the version in the file with the $project_version variable as set above.
Also, add a name for the tag. In my case, I just used the project version. If the generated deploy part does not have the skip_cleanup part, add that.

Commit and push, this will kick off a build in Travis and a new release in GitHub after a successful build.

Image title

All the files as defined in .travis.yml will be available for download.

Some more info:

Sonatype Nexus OSS

There is no way (at least that I could find) to release directly to Maven Central from Travis CI. The way that we will do it is via Sonatype OSS and using Maven.

To do this we need to do the following:

  1. Create a Sonatype User account.

  2. Make sure your Group Id and other pom details are correct.

  3. Create a GPG certificate.

  4. Add the necessary plugins to the pom.xml file

  5. Hook the Maven profile build into Travis

1) Create a Sonatype User account

Your Group Id has to be your GitHub profile (reverse domain).

For example, my GitHub Profile is https://github.com/phillip-kruger, so my Group Id is com.github.phillip-kruger.

Image title

Just explain in the description that you want to publish your open source projects to Maven Central.

"The initial setup for your OSSRH repository requires some manual steps and human review (see why), after which your deployment process is typically modified to get components into OSSRH. These are all one-time steps. "

My original JIRA for reference:
https://issues.sonatype.org/browse/OSSRH-32216.

This takes a day or two, and then you can publish.

Some more info:

2) Make sure your Group Id and other pom details are correct.

While you wait for the staff at Sonatype to get back to you, you can make sure your project is correct.

- Make sure you use the correct groupId in your pom.xml, example:

<groupId>com.github.phillip-kruger</groupId>

Remember to update other references to your artifact in other poms or dependencies.

- Make sure your package base name reflect your group Id (optional):

package com.github.phillipkruger.apiee;

- Make sure your pom.xml includes a licenses, scmdistributionManagement, and developers section. Take note of the snapshotRepository and the repository. Example:

<licenses>
  <license>
    <name>Apache License, Version 2.0</name>
    <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
    <distribution>repo</distribution>
  </license>
</licenses>

<scm>
  <connection>scm:git:https://github.com/phillip-kruger/apiee.git</connection>
  <url>https://github.com/phillip-kruger/apiee</url>        
</scm>

<distributionmanagement>
  <site>
    <id>api.wiki</id>
    <url>https://github.com/phillip-kruger/apiee/wiki</url>
  </site>

  <snapshotrepository>
    <id>ossrh</id>
    <url>https://oss.sonatype.org/content/repositories/snapshots</url>
  </snapshotrepository>
  <repository>
    <id>ossrh</id>
    <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
  </repository>

</distributionmanagement>

<developers>
  <developer>
    <name>Phillip Kruger</name>
    <email>phillip.kruger@gmail.com</email>
    <organizationurl>http://www.phillip-kruger.com</organizationurl>
  </developer>
</developers>

Some more info:

3) Create a GPG certificate:

 "One of the requirements for publishing your artifacts to the Central Repository is that they have been signed with PGP. GnuPG or GPG is a freely available implementation of the OpenPGP standard."

Make sure GnuPG is installed on your system, example:

sudo pacman -S gnupg

Then you can generate a key:

gpg --gen-key

You should then see your key listed:

gpg2 --list-keys

Distribute your public key:

gpg2 --keyserver hkp://pool.sks-keyservers.net --send-keys C6EED57A

The –keyserver parameter identifies the target key server address and use –send-keys is the keyid of the key you want to distribute.You can get your keyid by listing the public keys. (gpg2 --list-secret-keys)

Some more info:

4) Add the necessary plugins to the pom.xml file

To let maven do the publish to Sonatype OSS, you need to add some plugins to your pom.xml:

  • You need to generate javadoc.
  • You need to attach the source.
  • You need to sign the artifacts.
  • You need to release to Sonatype.

I do this in a profile so that I can build locally without having to do this, and then I can do a mvn clean install -Prelease if I want to release. Example:

<profiles>
  <!-- Activate using the release property: mvn clean install -Prelease -->
  <profile>
    <id>release</id>
    <activation>
      <property>
        <name>release</name>
      </property>
    </activation>

    <build>
      <plugins>
        <!-- To release to Maven central -->
        <plugin>
          <groupid>org.sonatype.plugins</groupid>
          <artifactid>nexus-staging-maven-plugin</artifactid>
          <version>1.6.8</version>
          <extensions>true</extensions>
          <configuration>
            <serverid>ossrh</serverid>
            <nexusurl>https://oss.sonatype.org/</nexusurl>
            <autoreleaseafterclose>true</autoreleaseafterclose>
          </configuration>
        </plugin>
        <!-- To generate javadoc -->
        <plugin>
          <groupid>org.apache.maven.plugins</groupid>
          <artifactid>maven-source-plugin</artifactid>
          <version>3.0.1</version>
          <executions>
            <execution>
              <id>attach-sources</id>
              <goals>
                <goal>jar-no-fork</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
        <plugin>
          <groupid>org.apache.maven.plugins</groupid>
          <artifactid>maven-javadoc-plugin</artifactid>
          <version>2.10.4</version>
          <executions>
            <execution>
              <id>attach-javadocs</id>
              <goals>
                <goal>jar</goal>
              </goals>
            </execution>
          </executions>
        </plugin>

        <!-- To sign the artifacts -->
        <plugin>
          <groupid>org.apache.maven.plugins</groupid>
          <artifactid>maven-gpg-plugin</artifactid>
          <version>1.6</version>
          <executions>
            <execution>
              <id>sign-artifacts</id>
              <phase>verify</phase>
              <goals>
                <goal>sign</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
      </plugins>        

    </build>
  </profile>
</profiles>

To run this on your local PC, you also need to add this to your maven settings.xml:

<settings>
<servers>
<server>
      <id>ossrh</id>
      <username>your-jira-id</username>
      <password>your-jira-pwd</password>
    </server>
</servers>
  <profiles>
  <profile>
    <id>ossrh</id>
    <activation>
    <activeByDefault>true</activeByDefault>
    </activation>
    <properties>
    <gpg.executable>gpg2</gpg.executable>
    <gpg.passphrase>your-gpg-pwd</gpg.passphrase>
    </properties>
  </profile>
  </profiles>
</settings>

Replace your-jira-id and your-jira-pwd with your own Sonatype Jira id and your-gpg-pwd with the one created above.

5) Hook the Maven profile build into Travis:

Once the staff at Sonatype get back to you w.r.t your account, you should now be able to release to Maven using the release Maven profile:

mvn clean install -P release

You will then see the artifacts in Sonatype OSS.

Image title

It takes a few minutes before you will see it in Maven Central.

Image title

This also means your artifact can now be included in any pom.xml!

<dependency>
<groupid>com.github.phillip-kruger</groupid>
    <artifactid>apiee-core</artifactid>
    <version>1.0.1</version>
 </dependency>

Now make it part of the Travis CI Build:

Create a Maven settings file we can distribute with the project that contains all the things we added to your local settings.xml.

In the root of your project, add a .maven.xml file:

<settings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/SETTINGS/1.0.0" xsi:schemalocation="http://maven.apache.org/SETTINGS/1.0.0
                      http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <servers>
        <server>
            <!-- Maven Central Deployment -->
            <id>ossrh</id>
            <username>${env.SONATYPE_USERNAME}</username>
            <password>${env.SONATYPE_PASSWORD}</password>
        </server>
    </servers>

    <profiles>
      <profile>
        <id>ossrh</id>
        <activation>
          <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
          <gpg.executable>${env.GPG_EXECUTABLE}</gpg.executable>
          <gpg.passphrase>${env.GPG_PASSPHRASE}</gpg.passphrase>
        </properties>
      </profile>
    </profiles>
</settings>

This will now be available when you push your code and you can reference it from the .travis.yml.
We need to define the variables that we used above in the .maven.xml file on the Travis CI site.
To hide your Sonatype username from Travis, log into Sonatype OSS Nexus, go to your profile, and select User token. Example: https://oss.sonatype.org/#profile;User%20Token.

Click on "Access User Token" to get a user token. This will give you values to use in the SONATYPE_USERNAME and SONATYPE_PASSWORD values. GPG_EXECUTABLE will be gpg and GPG_PASSPHRASE will be your GPG password you create above at "Create a GPG certificate."

In the settings of your Travis CI project add the following environment variables:

Image title

(We will add the GPG_OWNERTRUST and GPG_SECRET_KEYS later)

What about the local GPG certificates?

On your local PC, you have created the GPG certificates that allow you to sign the artifacts when building. We now need to transfer these to Travis CI so that the build there can do the same.
To do that, we need to create base64 encoded values of the secrets and add them to Travis CI as environment variables. On cmdline:

gpg -a --export-secret-keys <your-email-address> | base64 -w 0

Add the output to an env variable called GPG_SECRET_KEYS in Travis CI as described above.

Do the same for Owner trust:

gpg --export-ownertrust | base64 -w 0

Add the output to an env variable called GPG_OWNERTRUST in Travis CI.

Update the .travis.yml:

We can now update the .travis.yml file to build using our defined Maven profile.

First, we need to export the GPG details:

## export GPG details
before_install:
    - echo $GPG_SECRET_KEYS | base64 --decode | $GPG_EXECUTABLE --import
    - echo $GPG_OWNERTRUST | base64 --decode | $GPG_EXECUTABLE --import-ownertrust

This will make the GPG details that we added as env variables available in the build. Travis will replace GPG_SECRET_KEYS and GPG_OWNERTRUST with the correct values.
We then define the build commands that Travis uses so that we can pass in our settings file and define the profile to use:

install:
    mvn --settings .maven.xml install -DskipTests=true -Dgpg.skip -Dmaven.javadoc.skip=true -B -V

## Build and release to maven central  
script: 
    mvn clean deploy --settings .maven.xml -DskipTests=true -B -U -Prelease

Commit and Push

This should do it. If you commit and push your code that contains your new .maven.xml and changes to .travis.yml, your build will now run under the release profile that publishes to Maven Central.

Slack

Lastly, if you want to get a slack message on a build you can simply sign up for a free Slack account. After your setup, you can create a channel for build notifications. I called mine #travis.

In your Slack menu (on the left), select the + next to Apps to browse and search for apps. Find the Travis app and install it. You can then select the channel you created earlier. You will then see instructions on how and what to add to your .travis.yml file.

notifications:
notifications:
    email: false
    slack:
        secure:<some-key>

Commit your change, and soon you will get the notification!

Image title

That's it. Now when you commit and push your code to GitHub, it will create a release in GitHub, publish to SonaType OSS Nexus, and release to Maven Central before sending you a Slack message.

You can see the final .travis.yml and .maven.xml file on the Apiee Github page:

Explore the core elements of owning an API strategy and best practices for effective API programs. Download the API Owner's Manual, brought to you by 3Scale by Red Hat

Topics:
github ,maven central ,open source ,sonatype ,travis ci ,integration ,continuous integration

Published at DZone with permission of Phillip Kruger. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}