Using Travis CI to deploy to Maven repositories and GitHub Releases
This post outlines the steps needed to simultaneously deploy to Maven repositories and to GitHub Releases. Every time a tagged commit is pushed, a Travis CI build will be triggered automatically and start the release process. This blog post uses Sonatype Nexus as an example for a Maven repository manager.
Preparing GitHub Releases
Sergey Mashkov has written a Maven plugin that allows us to create a new release on our project’s releases page and upload our build artifacts to a release. The following sections describe how we need to configure our pom.xml
in order to use this plugin.
The plugin uses the scm
settings to find out for which project the new release should be created. Right now, there’s still a bug in the plugin which restricts the format for our git URIs. The only working format is
. Neither scm:git:git@github.com:...
nor scm:git:https://github.com/...
work, but a pull request has been created that adds this functionality.scm:git:ssh://git@github.com/...
So add an
section to your pom that looks like this:scm
The second step is to include the plugin in our pom. Right now the plugin is only available from bintray.com so we need to add it as a plugin repository. We only want to create a new release on GitHub when we are building a new release. Hence we configure the plugin in an extra release profile section. This leads to the plugin being executed only if Maven is started with
and only if the deploy goal is invoked. For more information on how to configure the plugin options please refer to its documentation and the pitfalls below.-Prelease
Preparing for Maven releases
If you don’t already have a repository where you want to deploy to, you need to create a release and a snapshot repository and add them to
.You might also want to create a separate user that has access only to your target repositories. This user will be used to upload the releases.distributionManagement
Putting it all together
So far we have configured the GitHub release plugin to deploy our artifacts to the GitHub Releases page and setup Maven releases. Now it’s time to glue the parts together. In order to do this we have to create a
for use with Maven, a settings.xml
that manages our Travis CI builds and we have to configure some environment variables in Travis CI itself. Furthermore we need a small shell script that orchestrates our release..travis.yml
Maven settings
Create a new
file in your repository, e.g in a settings.xml
.travis/
directory. The content of this file should look like the following snippet. The
ids have to match the ids in <server>
and the <distributionManagement>
<serverId>
of the GitHub release plugin exactly. Do not use static credentials here! You don’t want everyone who stumbles upon your repository on GitHub to have write access to your Nexus/Artifactory and GitHub. We will use Travis CI’s capability to inject environment variables into builds; the environment variables will be configured soon.
Release script
We need a small shell script that orchestrates our releases. This script sets the correct version, creates a release and uploads it to our Maven repository and to GitHub. To release the correct version the
environment variable will be used. Travis CI uses this variable to inject the value of the git tag into the build.TRAVIS_TAG
The script first sets the
in the pom exactly to our git tag’s value. So your tag always matches the version you want to release, e.g. <version>
or 1.0
1.5.1
. The second part creates the release. We need to reference the Maven settings in our repository here so that Travis CI has access rights to the Maven repositories and GitHub Releases. The important part here is to activate the
profile. This tells Maven to not only create and upload a Maven release but also to create a new GitHub Release.release
Name this script
, put it inside the release.sh
directory and make it executable (.travis/
).chmod +x
Build configuration
Travis CI uses a file named
at the root of a GitHub repository. The snipped contains the necessary steps..travis.yml
In a normal build we just want to execute a simple
. The clean verify
verify
goal will execute unit and integration tests. To make subsequent builds faster, we want to cache the m2 repositories during builds.
The most important part is the deploy section. Here we configure Travis CI to run the
script if and only if a tag has been pushed (release.sh
) on the repo tags: true
.example/project
Configuring Travis CI itself
Now we need to teach Travis CI the values of the environment variables used in our Maven settings. To do this navigate to the Travis CI settings for your project:
Add
and NEXUS_USER
for your newly created user. You also need to configure NEXUS_PASSWORD
and GITHUB_USERNAME
. But even though the field is called password, what your really want to configure here is your GitHub API token. Otherwise, the GitHub release plugin will not be able to upload artifacts. You can obtain your personal access token here. The token needs access to the repo scope.GITHUB_TOKEN
And that’s it. Now you can simply create a new tag in your repository (
), push it to GitHub and Travis CI will trigger the release process. Happy releasing!git tag -a 1.1 -m "Release 1.1"
Pitfalls
Some advice so that you do not encounter the same problems we did:
- Do not forget to make
release.sh
executable otherwise the Travis CI build will fail with a rather unhelpful message:
Script failed with status 127
. - The
in the GitHub release plugin’s configuration refers to aserverId
entry in Maven’s<server>
.settings.xml
- Do not be tempted to use your GitHub account password to configure the server settings for the GitHub release plugin. Even though the field is called password it’s really an API token that is needed here.
- Do not change the value of
when configuring the GitHub release plugin. Using anything different from the project’s version (i.e. the git tag’s value), will lead to recursive release builds. This happens because the release plugin will create and push a new tag if it does not already exist. Pushing a tag invokes another Travis CI build which will create a new tag and so on.<tagName>