Travis - Go Green

It’s been a while since I posted the last update. I was on the brink of madness figuring out a way to run coala process inside IntelliJ and capture its output for further processing. As I was working on this, my mentor gave me a new task, set-up Travis CI for checking the plugin build process and running tests. This sure looked interesting than the work I was doing. Setting-up Travis should hardly take a few hours and then I could get going with my original task with a better mindset. But before I start, I’m sure you might have a few questions in your mind: What is CI? What is Travis? Why should I care about CI? Let’s get started.


What is Continuous Integration (CI)?

Taking directly from Travis’ beginner’s guide, Continuous Integration is the practice of merging in small code changes frequently - rather than merging in a large change at the end of a development cycle. The goal is to build healthier software by developing and testing in smaller increments.

Basically, you should not merge huge code changes at once, because if anything should break, well good luck finding the cause of the problem. Rather, incremental code changes must be done, ensuring the changes do not break your product. Even if a problem is detected, due to small code changes the error could be easily traced.

Let’s face it, we developers tend to push broken code, obviously not deliberately (unless you hate the project you’re working on), but it happens. Instead of pushing that broken code into production, letting users run into the problem, get frustrated, throw in a bad rating, and submit a bug report, and then working on to fix the problems, it would be better if any failures are recognized in the development phase so that appropriate measures can be taken. This is where Continuous Integration platforms come into play. They take your modified code, run tests against it, and alert you if the changes result in unexpected failures. And finally, if all systems are green, automatically compile the code and push to production. It can also be used to detect code incompatibility introduced by changes in dependencies.


What is Travis CI?

Again, taken from Travis’ beginner’s guide, As a continuous integration platform, Travis CI supports your development process by automatically building and testing code changes, providing immediate feedback on the success of the change. Travis CI can also automate other parts of your development process by managing deployments and notifications.


Now that the introduction to CI is out of the way, let us set up Travis CI for my GSoC project.

Note I'll skip the basic parts, for example, creating an account, selecting a repository, etc and hop on directly to the next level of creating a configuration and build scripts.


Setting up Travis CI

When a repository is monitored by Travis, it constantly looks out for any new commits/merges. When the changes are detected, an instance of the sandboxed environment is fired up to test your code. Travis looks for the configuration file .travis.yml in the root of your project. This file contains all the settings related to Travis, such as the sandbox environment to use, list of environment variables, dependencies to install, scripts to execute, type of notifications and the medium to show them and many more.

Here’s the initial .travis.yml that I set up:

language: java
sudo: false

env:
  - BUILD=CI

jdk:
  - oraclejdk11

script:
  - ./travis.sh

before_cache:
  - rm -f  $HOME/.gradle/caches/modules-2/modules-2.lock
  - rm -fr $HOME/.gradle/caches/*/plugin-resolution/

cache:
  directories:
    - $HOME/.gradle/caches/
    - $HOME/.gradle/wrapper/

notifications:
  email: false

Let’s dig in.

  • Travis provides a lot of testing environments according to your project needs. Be it language profiles, like python, java or whole distributions, like ubuntu, fedora, Mac OSX, etc. My project is a java based project relying heavily on gradle, hence the java preset should be good to go.

  • We also define the JDK version that should be used, in this case, Oracle JDK 11. Travis providesopen JDK as well, and also the ability to switch between multiple JDKs if you’re targetting multiple JDK versions.

  • The script value, self-explanatory. The main script that should be run. We’ll be adding build plugin and testing logic in the script.

  • Travis provides the feature of caching directories across multiple builds. Why not use it and save bandwidth as well as build time.

  • Travis also provides a feature to send notifications to alert the team of a potential build failure. You can send notifications directly to developer’s emails, to an IRC channel or maybe even to a slack channel if that’s what you are using. You can even configure webhooks. And you can also set the events you need to be notified about; build start, build failure, build success. I monitor my GitHub every day, and for the time being, would not require any email notifications.


That was easy. Now let’s write up the travis.sh script. travis.sh contains the actual logic to build the plugin and run the tests. At this moment, we are only setting up Continuous Integration, Continuous Delivery (equivalent to publishing code for production) will be set up later. Here is a simple travis.sh script:

#!/bin/bash

set -euox pipefail

function logInformation() {
    echo " "
    echo "==================== $1 ===================="
    echo " "
}

logInformation 'Initializing Travis Script'

logInformation 'Checking Build Mode'

case "$BUILDMODE" in

CI)
    logInformation 'Building Plugin'
    ./gradlew clean buildPlugin check --stacktrace --debug
    ;;

*)
    logInformation 'Unsupported Build Mode'
    exit 1
    ;;

esac

  • set -euox pipefail is used to make the script more robust. -e flag means, if any command exits with a non-zero status code, the script must fail at once and report the error. -x flag prints out all the bash commands before executing them.

  • Here a simple case command is being used to check the value of BUILDMODE environment variable. If we are in Travis (BUILDMODE equal to CI), the gradle command is executed, else the script exits with an error. This case command would be particularly useful when the testing logic would include commands specific to Travis. Be prepared for the future!

  • ./gradlew clean buildPlugin check --stacktrace --debug is the main command used to execute a Gradle task. Let’s take a look at a few arguments:

    • clean instructs gradle to run all the tasks even if they were run before and their status was cached.
    • buildPlugin as the name suggests, build the plugin and run the tests. Failure would indicate something is wrong with the code and a fix is required.
    • stacktrace and debug are used to print all the debugging information and also the stacktrace in case of any errors.

A few hours and we’ve configured Travis CI with our project. All the commits that anyone makes in the repository, in the future must make sure to keep the CI happy. If you don’t your code won’t be accepted 😉

Now setting-up CI was really simple wasn’t it? If you find yourself interested in trying out Travis CI then I have and a piece of good news for you. Travis CI is completely free for all your open-source projects. So go and get your hands dirty right away. CI would surely improve the code quality and provide assurance to the developers as well as the end users.



Soon.