Automate your development workflow with Github Actions

HACENE KASDI
6 min readApr 29, 2020

Hi everybody. My name is Hacene. I am a software craftsmanship and interested in DevOps. Today I will show you how to automate the development workflow life cycle using Github Actions.

On November 13, 2019, Github engineers revealed some news: GitHub Actions is supporting CI/CD now, and it’s free for public repositories! We can manage and automate our development workflows right in our repository using GitHub Actions. The API supports multiple Operating Systems (Linux, Windows, MacOS…) and different languages.

In this article, I will give you an example of a CI/CD pipeline using Github Actions for Spring boot 2.x (java 8) web service.

INTRODUCTION

The idea is to automate the development workflow by building a CI/CD pipeline using Github Actions. The aim is deploying a Spring Boot web service on a remote server. We will use a succession of jobs to build, test, generate code coverage report and deploy our code right from GitHub. The generated package will be deployed on the remote server.

Below a diagram illustrating the workflow :

There are two ways to create a required workflow file :

  • By creating a workflow in the Github repository. The YAML file must be stored in the .github/workflows directory in the root of our Github repository. The workflow must have at least one job which contains a set of steps that perform individual tasks. Steps can run commands or use an action. Our workflow file should respect a YAML syntax and must have either a .yml or .yaml file extension. If you want to learn more about YAML, see "Learn YAML in five minutes."
  • By creating a workflow file in the Actions section on GitHub repository. We choose maven workflow :

When we clic on Set up this workflow, we will see the pre-filled maven workflow below :

The jobs are based on Matrix builds. A matrix build can generate at most 256 jobs per workflow run.

We configure a workflow to start when a GitHub event occurs. The jobs will be triggered after pushing code or making a pull request on the master branch. The main job in this example, is launching mvn package command. As it’s specified in the YAML file, we have to commit the changes to the master branch.

TESTING THE WORKFLOW

Let’s test it and see what happens …

After launching the workflow process, the configuration executed will define some actions that should be performed inside the Ubuntu container. The job makes a checkout of my git repository on the master branch and sets up a JDK 1.8, then it starts mvn build command and puts up the required maven packages included in my pom.xml. In the end, it runs the tests and generates the JAR file.

Here are some limits about using Github Actions, check this link.

ENHANCING THE WORKFLOW

Now, we will divide our workflow into different jobs:

compile job: checks out the Github source code and compiles it.

test job: runs unit tests (it requires a compile job).

build job: runs mvn build command and generates the code coverage report, which will be sent to codecov.io.

Below the complete file :

name: Java CI with Maven

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:

compile:
runs-on: ubuntu-latest
name: Running Java ${{ matrix.java }} compile
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Compile code
run: mvn compile

test:
runs-on: ubuntu-latest
name: Running tests
needs: compile
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Run unit tests
run: mvn test

build:
runs-on: ubuntu-latest
name: Run mvn build and generate coverage report
needs: compile
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Build with Maven
run: mvn -B package --file pom.xml -Dmaven.test.skip=true
- name: generate report codecov
run: mvn cobertura:cobertura
- name: Upload coverage
if: success()
run: |
curl -s https://codecov.io/bash | bash
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
shell: bash

We use encrypted secrets that allow us to store sensitive information. A field CODECOV_TOKEN, is a token retrieved from codecov.io, it’s persisted as a secret in Github environment.

Once the actions have been performed, we can see the result in the Actions tab:

In the last step, we need to add a job to deploy the jar file on the remote server. This job is pretty much the same as the precedent ones. We have to copy the executable file to the remote server, this operation is based on SFTP protocol.

To get this working, we will use actions shared by the GitHub community and we will customize them as needed, garygrossgarten/github-action-scp@release and fifsky/ssh-action@master, then we have to add the secrets (environment variables for ssh connection) on Github secrets section of our repository. These variables will be available in the container that was started with Github Actions :

Adding a job to deploy the executable file:

deploy:
runs-on: ubuntu-latest
name: Deploy the JAR file to the remote server
needs: build
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Generate the package
run: mvn -B package --file pom.xml -Dmaven.test.skip=true
- name: Deploy the package to the remote server
uses: garygrossgarten/github-action-scp@release
with:
local: target/workflow-github-actions-1.0-SNAPSHOT.jar
remote: hacene/demo/actions/workflow-github-actions.jar # My remote directory
host: ${{ secrets.HOST }}
username: ${{ secrets.SSH_USER }}
password: ${{ secrets.SSH_PASSWORD }}
- name: Run a script on remote server (start the application)
if: always()
uses: fifsky/ssh-action@master
with:
command: |
cd hacene/demo/actions/ && java -jar workflow-github-actions.jar &
host: ${{ secrets.HOST }}
user: ${{ secrets.SSH_USER }}
pass: ${{ secrets.SSH_PASSWORD }}
args: "-tt"
# The & in the command runs the process on background

The result looks like this :

After deploying and running the container using POSTMAN, we call an exposed endpoint:

Everything seems to be working. Now we add the well-deserved badge markdown on our README.md.

![Java CI with Maven](https://github.com/kasdihacene/workflow-github-actions/workflows/Java%20CI%20with%20Maven/badge.svg)

In README.md, the result looks promising :

CONCLUSION

I hope that you have enjoyed the post and learned how to use Github actions to automate your CI/CD workflow 😉

Personally, I used to work on CI platform with Jenkins that requires a lot of prerequisites to set up the workflow. So, I’m pretty surprised how well the CI/CD pipeline is working, flawlessly and quickly using Github Actions. We can take advantage of this flexibility to create and maintain customized development workflows to automate the software development lifecycle processes.

You can find the mentioned project on GitHub, you can also ask me your questions on my blog.

--

--

HACENE KASDI

FullStack craftsman engineer, passionate about new technologies, Agile methodologies, clean code and the Cloud Native Applications.