Continuous integration with Github Actions

Continuous Integration

Continuous Integration (CI) is a software development practice where developers integrate code into a shared repository frequently, ideally several times a day! Among the benefits of this practice is that you can detect errors quickly and resolve them more easily. Watch this 6 mins video for an intro to CI.

Build Pipeline

tip

A build pipeline is a set of steps that move code from development to production.

In modern software development, the build pipeline is often automated. That means, for instance, when you commit and push your code into the repository, a cascade of actions will be triggered that include "compiling the code," "executing tests," etc., which eventually result in deploying (software) artifacts. Automated build pipelines are great for implementing continuous integration workflows for software.

In this reading, we'll look at building a simple build pipeline using Github Actions.

Github Actions

Previously, we used Travis CI as our cloud-based continuous integration tool in this class. However, Github released Github Actions in November 2019 to public. Github Actions "is an API for cause and effect on GitHub: orchestrate any workflow, based on any event, while GitHub manages the execution, provides rich feedback, and secures every step along the way." Since Github Actions is integrated directly into Github, is easy/starightforward to set up, and offers lots of automationa flexibility, we focus on it in the class but feel free to explore other alternatives such as Travis.

Creating a Build Pipeline with Github Actions

In order to utilize Github Actions, you need to setup a .yml configuration file. Create a folder named .github in the root of your project. Then, create a subdirectory inside it named workflows. Inside workflows folder, create a file named main.yml and paste the following content in it:

# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: Java CI/CD with Gradle and Deploy to Heroku
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build jar
- name: Commit to the repo
uses: EndBug/add-and-commit@v4.4.0
- name: Deploy to Heroku
uses: AkhileshNS/heroku-deploy@v3.5.7
with:
heroku_api_key: ${{secrets.HEROKU_API_KEY}}
heroku_app_name: "boiling-stream-95315" #Provide your unique app name here
heroku_email: "abc@def.com" #Provide your Heroku email address here

In this file, we specify a set of events and triggers. In our case, we are inetersted in pushes to as well as pull requests on the master branch. Upon either of these events, a set of jobs are triggered where each job in return is comprised of actions. These are listed under steps. We first checkout the content of the repo so that it is available to our workflow. Then, we set up a Java environment in the requested Github runner machine (i.e. ubuntu). Next, we make sure gradlew is executable by running chmod +x gradlew before using it to build a fresh fat-jar file out of our project. Once, the jar file is produced, we commit the workspace back to our repo and finally we deploy to Heroku from there.

Furthermore, we need to authorize Github so that it can deploy to our Heroku account on our behalf. This is done by setting up a Github secret: First, go to your Heroku account and go to Account Settings. Scroll to the bottom until you see API Key. Copy this key and go to your project's repository on GitHub. In your repo, go to Settings -> Secrets and click on New Secret. Then enter HEROKU_API_KEY as the name and paste the copied API Key as the value. Also, make sure the heroku app name as well as your heroku email are set correctly in the yaml file.

Procfile

Since we are not using Gradle-Heroku plugin to deploy the app, we must tell Heroku how to run our application after it is deployed by Github Actions. To this aim, you need to add a file named Procfile to the root of your application directory with the following content:

web: java -jar build/libs/HerokuDemo-1.0-SNAPSHOT.jar

Now, try making a new push to your repo. If things are set up correctly and work as expected, upon the push, the Github Actions should execute all the steps and push a fresh build to Heroku.