2d 3d 3d-scanning 3d-sensor 420 420-6gw-hy 420-cae-hy 420-g 420-gef-hy 420-gel-hy 420-gen-hy 420-gep-hy 420-gep-hy-obligatoire 420-ges-hy 5rj 5rj-android 5rj-javase acceptance-testing aecgis agile ai airplay ajax alpine-linux analytics andengine android android-5-0 android-studio android-update-architecture angular angularjs api app-v ar arcade architecture arduino asp-net asynchronous-programming audio audio-analysis augmented-reality baas backbone-js banana-pi banana-pro banq bash battery bayes bb-8 bcjr bdd beast best-practices bi big-data bintray bluetooth boost-asio build-tool bytebuffer c camera cegep cg2 chess circuit citrix clojure clojurescript cloud cms cntk code-review code-structure collision-detection command-query-separation common-lisp completablefuture completionstage continuous-integration convolutional-coding couchbase cqrs cqs css css3 custom-language data-analysis data-center data-reporting data-storage data-story data-visualization database date-time dbms ddos deep-learning deep-search dependency-injection design-patterns devops dimensionality-reduction django docker dom drivers drone drum dsl e-commerce e-learning ebook ecmascript ecmascript-6 edgehtml efficacite-organisationnelle elasticsearch elearning elixir elk-stack embeded-systems encryption enterprise-search entity-framework erlang es2015 escher esp8266 event-driven examen excel exercices-java exfat express f facebook fat32 filechannel flask fonts for-dummies fpga functionnal-programming game-dev garbage-collector genetic-algorithm geospatial-analysis gimp git github go gof google google-analytics google-apps google-cloud googlecalendar gpio gps gpu gradle graph-database gui gvoice-texts hadoop haskell hci heroku hibernate high-availability hotspot-vm html html5 http-2 ide ifttt immutable-os intellij-idea internet-security ionic ios itil java java-9 java-ide java-module javascript javase jaxb jdbc jdk8 jeu jinja jit jmeter jms jpa jquery jsf json jta junit jvm kali-linux kibana kids kinect kotlin kubernetes laptop latex law-of-demeter ldpc learning legal libgdx linq linux load-balancing load-testing logic-programming logstash machine-learning magento mahout mathematiques maven mean meteo meteor-framework micro-framework microservices microsoft-azure midi mit-scratch mobile-app mongodb monitoring moodle ms-access ms-excel multithread music-instrument music-production musique mvc mvvm mxnet mysql neo4j netty network-as-a-service network-routing neural-networks neuro newsql nfc nixie-tube node-js nosql ntfs oauth open-source opencv opengl opengl-es openstack optimisation ospf otka outdoor-robot ov2460 pares-com pattern-matching pcie pdf pedagogie pentaho performance persistance php physique physique-quantique picat polarized-lenses powershell predictive-analytics privacy prolog pupillometry puppet puredata python qa quantum-computing quantum-gravity quantum-time r-language rails raspberry-pi react reactive-programming real-time refactoring regression-tree repl rest robot ros rpg rsa ruby rust salesforce san scala science scratch-jr scribus scrum search-engine security selenium selenuim-testing-tool semanticweb sensor seo serial-port serrurier serverless service service-manual servlet sitecore soap solar-system-simulator solaris solid solr solus spa spark spark-ml spdy specification sphero splunk spring spring-boot sql sql-server sqlite sre srp statistics statistiques stephanedenis-s-blurblog storm swift-2 tableau-publiic tdd telephonyapi tensorflow test test-driven-development thread threat-analysis time-banking travis-ci typography ubuntu uml unit-tests unity-3d unreal-game-engine usb user-story uwp virtualization-platform visual-studio visualstudio viterbi vmware vr vrealize vsphere wcf wcms wearable web web-design web-framework web-scraping webdriver webview windows windows-10 windows-server wine wireless wsdl wxpython xamarin xen xenapp xml zurb

How to set up a continuous integration process in the cloud - JAXenter

How to set up a continuous integration process in the cloud

Denis Kuniß
Continuous Integration Process
© Shutterstock / Perfect Lazybones

It may not be a major challenge to upload libraries into Maven Central or Bintray, but can it be done in a continuous integration process? In this tutorial, Denis Kuniß explains how you can set up an automatic process to take care of this while maintaining an open source library.

If it’s not on Maven Central, it doesn’t exist!

Having a library not on Maven Central or at least on Bintray is not state of the art. I mean, we are in 2018 and most of the developers would like to use Maven, Gradle or other modern build systems for resolving library dependencies against artifact repositories automatically.

However, the challenge is not only to get a library into these repositories anyhow but to get them in automatically through a continuous integration process.

I took the opportunity to set up such a process for a standardization organization, members of which are maintaining a reference implementation of a standard widely used in a whole industry.

The setup is not very complex, but nowhere I had found it written down at once. So I will do it here for all others who need a similar solution, hoping it is valuable to them. And, I do it also as documentation for the members of this committee.

Tools and services

I will use the following cloud services and tools:

  1. Github for source code hosting and release control
  2. Travis CI for running compilation, tests, and library publishing
  3. Bintray for repository hosting and publishing to Maven Central
  4. Gradle as build system tool
  5. Stefan Oehme’s sobula Gradle plug-in for releasing to Bintray

In fact, Stefan’s article was my starting point for this work and his Gradle plug-in the most helpful tool as releasing to Bintray trough their HTTP service API is the main challenge in this whole process. Thanks to his work resulting in his plug-in, I can implement the process without real programming efforts.

This article shows my experiences to set up a CI process for an organization. To set it up for a single developer is very similar and less complicated. I have it also done (before) for my own libraries.


The first step is to set up an organization after having logged in to GitHub (a GitHub account is needed for that, of course). Goto your profile page and click the Organization menu entry on the menu shown under Personal settings. There will appear a (may be empty) list of already created organizations. On the right upper corner, there will be a button for creating a new organization.

Continuous Integration Process

GitHub dialog for starting creation of an organization

Pushing this button will ask you for the organization’s name and a billing plan.

Continuous Integration Process

GitHub dialog for creating an organization

As we are planning to utilize and Bintray we must give them access to our GitHub organization’s account. This may be done on the OAuth applications dialog in the personal settings.

Continuous Integration Process

GitHub OAuth applications dialog

To get the third party applications displayed it may be necessary to create accounts on and Bintray. You may log in there trough your GitHub account; look for appropriate GitHub icons on the side’s login pages.

After that, click on the bintray and Travis CI links on that page. Check on the subsequent dialog that the particular application is allowed to access your organization. If not, push the appropriate button right from your organization on this page.

Continuous Integration Process

GitHub dialog for authorizing access for Travis CI third-party application

Do the same for the second application, in Bintray.

Continuous Integration Process

GitHub dialog authorizing access for Bintray

Now all is prepared for setting up source code repositories for your organization. I had set up 5 repositories for the committee reference implementation.


The GitHub integration on Bintray is done quite well. An organization would be visible on your’s users profile page. Unfortunately, either Stefan Oehme’s Gradle Bintray publishing plugin or Bintray’s service API itself is not able to handle an automatic publishing for organizations. However, for ordinary users, it works well. Therefore, I have registered an own generic user for the organization. Its account will host the libraries we want to publish.

Continuous Integration Process

Bintray sign up dialog

For an automatic publishing several other preconditions must be met on Bintray. At first, we need a Bintray API key. This key is used like a password to authorize Bintray API calls from the Travic CI service. This API key may be generated at the Bintray user profile when clicking on the API Key menu.

Continuous Integration Process

Bintray API key dialog

This key will later be copied to the project’s Travis CI configuration dialogs. However, that’s not all. For publishing to Maven Central from Bintray all Java libraries must be digitally signed. Bintray supports signing of published libraries through their service APIs. However, the cryptographic key pair for that must be stored at Bintray.

GPG keys

For that, we need to generate a pair of public and private cryptographic keys. The easiest way to do that is using the Linux command line tool gpg. Fortunately, I’m developing under Linux. The command line for generating a new pair is

gpg --gen-key

which will guide you through the key generation, interactively. During this process, you must be prepared to enter some names which should be chosen judiciously.

  1. Your organization’s real name.
  2. An email address of our organization which is related to the context of building libraries. This might be a generic one, e.g.; but emails sent to it should be caught by someone.
  3. A pass-phrase to protect your key pair from misuse. This is something like a password to your keys to avoid someone else, not authorized, is misuse them. In fact, this pass-phrase is stored later on at Travis CI to allow digital signing through the Bintray service using the private key stored at Bintray.

From this gpg will create the generated key’s user ID. The pass-phrase will be requested to be entered in a special dialog box, not shown here.

Continuous Integration Process

Generating digital key pair using gpg

For being prepared for the future you should also create a key revocation certificate now. The command for that is

gpg --output revoke.asc --gen-revoke
Continuous Integration Process

Generating digital key pair using gpg

For storing the public and the private key on Bintray, you have to export them into a text file. Bintray needs it in an armored format:

gpg --armor --output public.gpg --export
Continuous Integration Process

Exporting public key using gpg

The command for the private key is similar:

gpg --armor --output private.gpg --export-secret-key

Be prepared to enter the pass-phrase when export is requested.

The last step is to publish the public key to a public key server. This key server will be queried later on by the Maven Central service when the library gets published to Maven Central repository to check the digital signature.

The gpg command for that is:

gpg --keyserver <public keyserver address> --send-keys

On my side the key ID used for export did not work. I did not figure out why. So, I used the hexadecimal ID shown by the list-key command.

Continuous Integration Process

Sending public key to a public key server

Note: Never use your ordinary cryptographic key pair, what you use in correspondences, for library signing. Even if the pass-phrase and the private key are stored at different service, Bintray and Travis-CI, someone who may have control over both, may compromise your keys! Just create a new one. You may have more than one key in use with gpg.

Both generated keys, the public and private one, now have to be added to Bintray.

Continuous Integration Process

Adding digital keys to Bintray

Maven Central

To get a library published to Maven Central, at first a Jira account at Sonatype is required. Then you may create a New Project ticket. At this ticket, you will need to state

  1. The group ID, the library will be published under. This is the most critical part, as this will be checked manually by a Sonatype employee. The ID must be unique and belong to the requester. So, if it is a domain like “org.your-organization" you should be the owner of that domain.
  2. The GitHub project page.
  3. The GitHub source repository URL (ends on “.git")

This is an on-time task. You have it to do for your first library per group ID only. Subsequent libraries may be published based on the result of this first request.

You will get an e-mail answer when your request has been confirmed.

The Jira password is later required on Travis CI as Sonatype password for authorizing the library publishing to Maven Central.

Travis CI

The Travis CI service is tightly integrated with GitHub. After having logged in to Travis CI using GitHub authorization just synchronize your accounts on your accounts page (there is a button for that on the right upper corner under your profile name). Pushing this button will show all source code repositories of your organization from GitHub on Travis CI.

Continuous Integration Process

Travis CI page showing GitHub repositories

All repositories are disabled, currently. We will enable them project by project as each project needs its own configuration regarding Bintray API key and GPG pass-phrases and so on.

Enable the first project by pushing the project’s slider to the left, it becomes green. Click on the gear wheel right from the slider to get to the configuration page for this project.

Continuous Integration Process

Travis CI project configuration settings

At first, push the slider “Build only if .travis.yml is present" to the left, enabling it. This will avoid the project is being built on every GitHub commit as long as the project is not prepared for Travis CI.

Furthermore, we have to set two environment variables for better build experiences. The slider “Display value in build logs" may be enabled here.

  1. Set TERM to dumb. This will shorten the logging output on Travis builds making it more readable.
  2. Set GRADLE_OPTS to ‘-Xmx1024m -XX:MaxPermSize=512m -Dorg.gradle.daemon=true’ (including the single quotes) to speed up Gradle builds.

At last, we have to set the pass-phrase for library signing, the Bintray API key as authorization for publishing to Bintray, and the Sonatype password as authorization for publishing to Maven Central. Ensure that the slider “Display value in build logs" is not enabled (what is the default); otherwise, the secret values would get visible in the build logs.

  1. Set ORG_GRADLE_PROJECT_bintrayApiKey to the value copied from the API Key page on the Bintray profile.
  2. Set ORG_GRADLE_PROJECT_signingPassword to the pass-phrase the digital key pair was created with.
  3. Set ORG_GRADLE_PROJECT_sonatypPassword to the password the Sonatype account was registered with (the Jira password).

Don’t forget to put your configuration values into single quotes (as on GRADLE_OPTS) if your passphrases or passwords contain empty spaces. Also, bash special characters like ‘\’ or ‘&’ has to be escaped becoming ‘\\’ or ‘\&’. Otherwise the Travis system will not forward them correctly and the build will fail.

Gradle Build

Not a lot left now before automatic building and publishing can start. The build logic has to be put in place. At first, add the reference to Stefan Oehme’s sobula Gradle plugin to the build script.

plugins {
id 'java'
id 'com.github.oehme.sobula.bintray-release' version '0.6.7'

Now add your publishing configurations to the build script.

group = ""
description = "Your cool project description"
contacts {
"" {
moniker "Your Organization's Name"
roles "owner"
github "yourOrganizationsGithubUsername"
bintray.user = "yourOrganizationsBintrayUsername"
bintray.pkg.version.mavenCentralSync.user = "yourSonatypeUsername"

The group definition must be set to the group ID requested for Maven Central. Under contacts, you may enter the email address used for creating the cryptographic key ID. The moniker is the human-readable name of your organization. The roles definition should be set to owner. The other definitions are self-explanatory, I guess. For an example, see this build.gradle file.

The last steps before your project gets automatically built are the following ones.

  • Add a file to a subdirectory .travis in your project. The content of this file is the same for all projects.
  • Add a file travis.yml to the root of our project. The content of this file is normally the same for all projects if you follow a standard project directory structure. It contains some configurations for the Travis CI runtime system. And, it calls the prior added file.

Ensure, file executable permissions for the file has been set; otherwise the Travis-CI server will not be able to execute this script. On Linux, this is quite easy to be achieved on the command line

chmod +x

as well as on the Eclipse’s resource dialog for this file. However, on Windows this is quite a challenge as neither on the command line nor in Eclipse it can be done. You have to use any git client for that:

git update-index --chmod=+x

Your next commit to GitHub, after these changes, will force the first build of your project on Travis CI. From now on, every commit to GitHub will force an automatic build on Travis CI.

Even pull requests from other developers to your project will trigger automatic builds of this pull request on Travis CI. So, you will see immediately whether pull request builds and all test has been passed. This is really productive!


An important thing to get it work must not be forgotten: You have to put an open source license file with name LICENSE in the root of your project. This file is processed by the sobula Gradle plug-in to figure out the license, the project is treated under. For Bintray and Maven Central any project hosted there must have an open source license.

The sobula Gradle plug-in currently supports the following open source licenses:

Choose one of them and download the license file from the given links. The sobula Gradle plug-in expects a text file; do not use HTML files. If the license you need is not supported, just fork the project, add your license under and start a pull request. (Don’t forget the unit tests!)


However, no release is published yet to Bintray and Maven Central. For that, you have to draft a release on GitHub. This will force a build on Travis CI with a subsequent publishing of your library to Bintray if the assemble task itself worked well. The publishing to Maven Central, however, will fail for the first time as your library must be added to Bintray’s jCenter before it can be automatically published to Maven Central.

For adding your library to jCenter, go to your library’s dashboard on your organization’s Bintray profile. On the right side, there is a menu item Maven Central. Hover over it to see the hover tag where is a link you may request your library to be linked to jCenter as a precondition to be synced to Maven Central. This is a one time task and seems to require some manual effort on Bintray side. You will get a mail answer when it is confirmed. It does not need to be repeated for subsequent versions.

From now on your continuous integration is running in the cloud. The only thing you have to do is committing your code changes to and drafting release on GitHub to get your library published on Bintray and Maven Central.

So, there is no excuse anymore, why an open source project does not have a continuous integration pipeline in the cloud …

This post was originally published on Beyond Coding.

comments powered by Disqus