# CI/CD for Spring Boot applications using Travis-CI

Author: [Siva](https://www.sivalabs.in/) | Published: 2018-01-24 | Updated: 2026-11-10 | Topics: DevOps, travis-ci, Spring Boot | Canonical: https://www.sivalabs.in/blog/ci-cd-springboot-applications-using-travis-ci/


In this article, we are going to learn how we can use **Travis CI** for Continuous Integration and Continuous Deployment (CI/CD)
of a **Spring Boot** application. We will learn how to run Maven build goals, perform test coverage validation using the JaCoCo plugin,
run Code Quality checks using **SonarCloud**, build a Docker image and push it to **DockerHub**, and finally deploy it to **Heroku**.

<!--more-->

> The source code for this article is at https://github.com/sivaprasadreddy/jblogger

Last week, I was talking to my friend about how easy it has become to build and deploy a Java application using Spring Boot. During the discussion, one point came up about how much it costs to build a Java application and deploy it somewhere (in the cloud). So, I thought of exploring more about the free services that we can use to automate all project development activities with minimal or no cost at all.

A few years ago, I used **CloudBees** and **CloudFoundry** to build and deploy my pet projects, which were offering free hosting services, but they are not providing free services anymore.

In the past, I have used **Travis CI** for my Java projects just for preliminary testing purposes, but looking at their documentation, I realized they provide a lot more features.

So I thought of checking if I can use Travis CI for my projects to do all the usual tasks, such as:

*   Checkout the latest code
*   Compile and run Unit and Integration Tests
*   Run JaCoCo code coverage and fail the build if the desired percentage is not met
*   Run SonarQube code quality checks
*   Optionally, build a Docker image and publish it to Docker Hub
*   Deploy the application on some free cloud hosting service like Heroku or OpenShift

After going through their documentation, I realized that we can do all these tasks by using some of the free online services and Travis CI's integration with them.

*   **GitHub** for the code repository
*   **SonarCloud** for a free SonarQube service
*   **Docker Hub** for publishing Docker images
*   **Heroku** for deploying the application

Let us see how we can do all the above-mentioned tasks using Travis CI for a Spring Boot project.

## Step 1: Create a Spring Boot project

Create a Spring Boot project either using http://start.spring.io or from your IDE. I am using the Maven build tool; you can use Gradle also if you prefer. Now commit the project into your GitHub repository.

## Step 2: Create a .travis.yml file

In order to enable Travis CI integration, we need to create a **.travis.yml** file in the project's root folder.
As we are creating a Maven-based Java project, create a `.travis.yml` file with the following content:

**.travis.yml**

```yml
language: java
jdk: oraclejdk8
```

This minimal configuration is sufficient for Travis CI to recognize our Maven-based Java project and build it.
If there is a `build.gradle` file in our project's root folder, Travis will treat it as a Gradle project, or if there is a `pom.xml`, it will treat it as a Maven project. If both `build.gradle` and `pom.xml` are there, then the Gradle build script will take priority.

By default, Travis will run **mvn test -B** for building the project.
If Travis finds the `mvnw` wrapper, then it will be used like **./mvnw test -B**.

But if you want to run a different command or want to run multiple commands, we can use a script block to customize it.

Now commit and push the `.travis.yml` file to GitHub.

## Step 3: Enable Travis CI for the GitHub repository

Go to https://travis-ci.org/ and **Sign in with GitHub**.

Now click on **Add New Repository** (+ symbol).

Enable Travis for the repository. After enabling Travis, click on that repository, and you can trigger a build by selecting
**More Options -> Trigger build**.

Now you can see that the build is running, tests are being executed, and an email notification will be sent to your email regarding the build status.

## Step 4: Add JaCoCo Code Coverage check

Add the Maven JaCoCo plugin to `pom.xml` with options like what is the desired code coverage percentage, packages/classes to ignore, etc.

```xml
<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.7.9</version>
    <configuration>
        <excludes>
            <exclude>com/sivalabs/jblogger/entities/*</exclude>
            <exclude>com/sivalabs/jblogger/*Application</exclude>
        </excludes>
    </configuration>
    <executions>
        <execution>
            <id>default-prepare-agent</id>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
        <execution>
            <id>default-prepare-agent-integration</id>
            <goals>
                <goal>prepare-agent-integration</goal>
            </goals>
        </execution>
        <execution>
            <id>default-report</id>
            <phase>verify</phase>
            <goals>
                <goal>report</goal>
            </goals>
        </execution>
        <execution>
            <id>default-report-integration</id>
            <goals>
                <goal>report-integration</goal>
            </goals>
        </execution>
        <execution>
            <id>default-check</id>
            <goals>
                <goal>check</goal>
            </goals>
            <configuration>
                <rules>
                    <!-- implementation is needed only for Maven 2 -->
                    <rule implementation="org.jacoco.maven.RuleConfiguration">
                        <element>BUNDLE</element>
                        <limits>
                            <!-- implementation is needed only for Maven 2 -->
                            <limit implementation="org.jacoco.report.check.Limit">
                                <counter>COMPLEXITY</counter>
                                <value>COVEREDRATIO</value>
                                <minimum>0.60</minimum>
                            </limit>
                        </limits>
                    </rule>
                </rules>
            </configuration>
        </execution>
    </executions>
</plugin>
```

## Step 5: Run Unit and Integration Tests

As I mentioned earlier, by default, Travis runs **mvn test -B**, which will **only run Unit tests**.

We want to run Unit tests and Integration tests separately by using the **maven-failsafe-plugin**.
We will follow the convention by naming **Unit tests** as **\*Test.java/\*Tests.java** and **Integration tests** as **\*IT.java**.

Add the **maven-failsafe-plugin** as mentioned below:

```xml
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <configuration>
        <includes>
            <include>**/*IT.java</include>
        </includes>
    </configuration>
    <executions>
        <execution>
            <id>failsafe-integration-tests</id>
            <phase>integration-test</phase>
            <goals>
                <goal>integration-test</goal>
            </goals>
        </execution>
    </executions>
</plugin>
```

While configuring the `maven-failsafe-plugin` for a Spring Boot project, I hit this issue: https://github.com/spring-projects/spring-boot/issues/6254.
To fix this issue, I have added the **classifier** configuration to the `spring-boot-maven-plugin` as follows:

```xml
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <classifier>exec</classifier>
    </configuration>
</plugin>
```

Now we are going to use the **script** block to specify our custom Maven goal to run instead of the default goal.

**.travis.yml**

```yml
language: java
jdk: oraclejdk8
 
script:
- ./mvnw clean install -B
```

## Step 6: SonarQube code quality checks using SonarCloud

SonarCloud, which is built on **SonarQube**, offers free code quality checks for Open Source projects.

**Login with GitHub**, go to **My Account -> Security**, and generate a new token for your project and save it somewhere.
Now click on the **Organizations** tab and create an Organization with a unique key.

Travis CI provides the ability to encrypt sensitive data (https://docs.travis-ci.com/user/encryption-keys/) so that we can encrypt any keys or passwords and configure them in the `.travis.yml` file.

`> sudo gem install travis`

From the project root folder, run the following command to encrypt data:

**travis encrypt SOMEVAR="secretvalue"**

This will generate output like:

**secure: "…. encrypted data …."**

We can add all the secrets as global environment variables as follows:

```yml
env:
  global:
  - secure: "....encrypted data....."
```

Now let us encrypt the SonarCloud Token as follows:

**travis encrypt SONAR_TOKEN="my-sonar-token-here"**

Finally, let us add SonarCloud support as an AddOn (https://docs.travis-ci.com/user/sonarcloud/) as follows:

```yml
language: java
jdk: oraclejdk8
 
env:
  global:
  - secure: "....encrypted sonar token here....."
 
addons:
  sonarcloud:
    organization: "sivaprasadreddy-github"
    token:
      secure: $SONAR_TOKEN
 
script:
- ./mvnw clean install -B
- ./mvnw clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar
```

Note that we used **$SONAR_TOKEN** to refer to the encrypted token variable and added one more command to run in the **script** block to run the **sonar:sonar** goal.

## Step 7: Build a Docker image and publish it to DockerHub

Travis CI builds can run and build Docker images, and can also push images to Docker repositories.
For more information, read https://docs.travis-ci.com/user/docker/.

Create a **Dockerfile** in the project's root folder for our Spring Boot application as follows:

```Dockerfile
FROM frolvlad/alpine-oraclejdk8:slim
VOLUME /tmp
ADD target/jblogger-0.0.1-SNAPSHOT.jar app.jar
RUN sh -c 'touch /app.jar'
ENV JAVA_OPTS="-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8787,suspend=n"
EXPOSE 8080 8787
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -Dspring.profiles.active=docker -jar /app.jar" ]
```

To use Docker, add the following settings to **.travis.yml**:

```yml
sudo: required
 
services:
  - docker
```

Now we can run Docker commands in our build.

Once the build is successful, we may want to build the Docker image and push it to Docker Hub.
We can leverage the **after_success** section to perform this action.

We need to log in to DockerHub before pushing the image; we are going to configure the DockerHub credentials by encrypting them.

```shell
travis encrypt DOCKER_USER="dockerhub-username"
travis encrypt DOCKER_PASS="dockerhub-password"
```

Add these 2 secrets to the **env.global** section of `.travis.yml`.

Now we can add our Docker commands to build the image and publish it to Docker Hub in the **after_success** section as follows:

```yml
after_success:
- docker login -u $DOCKER_USER -p $DOCKER_PASS
- export TAG=`if [ "$TRAVIS_BRANCH" == "master" ]; then echo "latest"; else echo $TRAVIS_BRANCH; fi`
- export IMAGE_NAME=sivaprasadreddy/jblogger
- docker build -t $IMAGE_NAME:$COMMIT .
- docker tag $IMAGE_NAME:$COMMIT $IMAGE_NAME:$TAG
- docker push $IMAGE_NAME

```

## Step 8: Deploy to Heroku

Travis CI provides options to deploy on a wide range of platforms, including Heroku, OpenShift, AWS, Azure, etc.
Travis CI can automatically deploy your Heroku application after a successful build.

We are going to deploy our Spring Boot application on Heroku using Travis: https://docs.travis-ci.com/user/deployment/heroku/. Before deploying our application to Heroku, first we need to log in to https://www.heroku.com/ and create an application from the Dashboard.

Now create a **Procfile** in the root folder of the project as follows:

```shell
web java -Dserver.port=$PORT -Dspring.profiles.active=heroku $JAVA_OPTS -jar target/jblogger-0.0.1-SNAPSHOT-exec.jar
```

First, we need to get the Heroku API Key and add it as an encrypted secret.

**travis encrypt HEROKU_API_KEY="your-heroku-api-key-here"**

We can deploy to Heroku from Travis by adding a **deploy** section as follows:

```yml
deploy:
  provider: heroku
  api_key: $HEROKU_API_KEY
  app: jblogger
```

Now the complete `.travis.yml` file will look as follows:

```yml
sudo: required
language: java
jdk: oraclejdk8
 
services:
- docker
 
env:
  global:
  - secure: "encrypted-sonar-token"
  - secure: "encrypted-dockerhub-username"
  - secure: "encrypted-dockerhub-password"
  - secure: "encrypted-heroku-api-key"
  - COMMIT=${TRAVIS_COMMIT::7}
 
addons:
  sonarcloud:
    organization: "sivaprasadreddy-github"
    token:
      secure: $SONAR_TOKEN
 
script:
- ./mvnw clean install -B
- ./mvnw clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar
 
after_success:
- docker login -u $DOCKER_USER -p $DOCKER_PASS
- export TAG=`if [ "$TRAVIS_BRANCH" == "master" ]; then echo "latest"; else echo $TRAVIS_BRANCH; fi`
- export IMAGE_NAME=sivaprasadreddy/jblogger
- docker build -t $IMAGE_NAME:$COMMIT .
- docker tag $IMAGE_NAME:$COMMIT $IMAGE_NAME:$TAG
- docker push $IMAGE_NAME
 
deploy:
  provider: heroku
  api_key: $HEROKU_API_KEY
  app: jblogger
```

Once the build is successful and deployed on Heroku, you should be able to access the application at `https://<app>.herokuapp.com/`.

I have just covered the most commonly performed tasks in Java applications, but Travis CI can do a lot more.
Check out the Travis CI documentation at https://docs.travis-ci.com/.

