Github: automated Github release for Spring Boot jar using Github Actions

Github Actions provide the ability to define a build workflow directly in Github.  The workflow steps are defined as yaml and can be triggered by various events, including a code push, branch, or tagging in the repository.

In this article I will detail the steps of creating a simple Spring Boot web application that when tagged with a semantic value (e.g. ‘v1.0.1’) will package the git commit messages as Release Notes and the binary Jar as a release in the repository.

Prerequisites

OpenJDK 17+ for testing local compilation

# view candidate list of JDK
sudo apt search openjdk-* | grep '^openjdk\-' | grep '\-jdk'
sudo apt install openjdk-17-jdk

Github CLI for creating github repo from console

See my article here for installing the Github CLI

Create Spring Boot web starter project

A convenient way of getting the basic layout and scaffolding of a Spring Boot project is to use start.spring.io to download a project starter.

# setup project values
id=spring-boot-github-action-example
artifact_id=$id
SpringAppClassName=SpringMain
version="1.0.0"
groupId="org.fabianlee"
javaVersion=17
springBootVersion=2.7.5

# returns archive containing SpringBoot project, extract
curl -s https://start.spring.io/starter.tgz \
    -d type=gradle-project \
    -d dependencies=web,prometheus,devtools,actuator \
    -d javaVersion=$javaVersion \
    -d bootVersion=$springBootVersion \
    -d groupId=$groupId \
    -d artifactId=$artifact_id \
    -d name=$SpringAppClassName \
    -d version=$version | tar -xzvf -

# validate files have been created in directory
cd $id
ls -l

You now have a directory named “spring-boot-github-action-example” containing all the basic structure and files required for a Spring Boot web application.

You can copy-paste the commands above, or download start-spring-io-webapp.sh from my github.

Test Spring Boot web locally

This minimal web application will create a web server on port 8080 when run locally.  Validate by compiling and running the Spring Boot web app.

# locally compiles Spring Boot jar
./gradlew bootJar

# web server running locally on 8080
./gradlew bootRun

From another console (or even a local browser), you should be able to get a valid HTTP response from port 8080.

# test from another console
$ curl http://localhost:8080/actuator/health
{"status":"UP"}

Modify build.gradle

Then we need to customize the build.gradle file to support building the Spring Boot jar with a static name, to make it easier to work with.

You can download my full build.gradle here, or copy-paste the contents below.

plugins {
	id 'org.springframework.boot' version '2.7.5'
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
	id 'java'
}

// ADDED as source of plugins
repositories {
  mavenCentral()
}

group = 'org.fabianlee'
version = '1.0.0'
sourceCompatibility = '17'

// ADDED want consistent name for jar
bootJar {
  archiveFileName = "springBoot.jar"
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-actuator'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'io.micrometer:micrometer-registry-prometheus'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
	useJUnitPlatform()
}

Create Github repository

Let’s go ahead and create the remote Github repository for this starter project and our Dockerfile and build.gradle modifications.  We will add the Github Action workflows in the next sections.

# create remote repo (the 'id/repo' from output will need to be used below)
$ CURDIR=${PWD##*/}
$ gh repo create $CURDIR --public
✓ Created repository fabianlee/spring-boot-github-action-example on GitHub

# initialize repo and add files
git init
git add *
git add .gitignore

# commit files and create main branch
git commit -a -m "first commit"
git branch -M main

# push files to remote Github repo
# use id/repo value from above for remote name
git remote add origin https://github.com/fabianlee/spring-boot-github-action-example.git
git push -u origin main

View remote Github repository in browser

The remote repository URL is shown by using the command below.

$ git remote -v
origin	https://github.com/fabianlee/spring-boot-github-action-example.git (fetch)
origin	https://github.com/fabianlee/spring-boot-github-action-example.git (push)

Pulling this URL up in your browser should looking something like the screenshot below.

Adding Github Action, overview

We will be adding a Github Action workflow by adding a yaml manifest file into the “.github/workflows” directory of our repository.

Workflows support various triggering events, we will choose to trigger when there is push to the repository of a tag that looks like a semantic version.

These workflows are run remotely on Github-hosted runners.

Add Github Action for Boot jar release

Our workflow will kick off when any new semantic tag (e.g. v1.0.1) is pushed to the repository.  I will go over key areas below, but download the full version of github-actions-release.yml from my github.

Trigger

on:
  push:
    tags: ['v*']

Checkout Code

Checkout and fetch all the history from the repo, because we will need this later when determining the release notes.

    - uses: actions/checkout@v3
      with:
        fetch-depth: 0 # get all tags, needed to get git log
        ref: main

Java and Gradle setup

Install Java with setup-java on the Gitlab runner.

      - name: setup Java
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: adopt
          cache: gradle

Build Spring Boot jar

Then we have gradle build the Spring Boot jar.

    - name: Execute Gradle build
      run: ./gradlew bootJar

Build Release Notes from commit log

Because this is a small independent project we simply want to use the commit messages made from the last semantic tag up to the current tag as the Release Notes for this release.

We take advantage of the idea that you can query for a range of commits using ellipsis.

git log fromTagName...toTagName

The script below writes the commits as a list into the file “body.log”.

    - name: get semantic tag version and release notes from commit messages
      id: tag 
      run: |
        curtag=${GITHUB_REF_NAME}
        major_minor=$(echo "$curtag" | cut -d'.' -f1-2)
        patch=$(echo "$curtag" | cut -d'.' -f3)
        # avoid empty patch number
        [ -n "$patch" ] && ((patch--)) || patch=".x"
        prevtag="${major_minor}.${patch}"
        echo "" > body.log
        if git tag | grep $prevtag ; then
          git log -q ${curtag}...${prevtag} --pretty="- %s" -q --no-color >> body.log
        else
          git log --pretty="- %s" -q --no-color >> body.log
        fi
        line_count=$(cat body.log | wc -l)
        echo "curtag=$curtag" >> $GITHUB_OUTPUT
        echo "prevtag=$prevtag" >> $GITHUB_OUTPUT
        echo "line_count=$line_count" >> $GITHUB_OUTPUT

Publish release

We finish off by using the custom release-action to push the Spring Boot jar built at ‘build/libs/springBoot.jar’ with release notes generated at “body.log” in the previous step.

    - uses: ncipollo/release-action@v1
      with:
        name: ${{ env.GITHUB_REF_NAME }}
        tag: ${{ env.GITHUB_REF_NAME }}
        artifacts: "build/libs/springBoot.jar"
        bodyFile: "body.log"
        token: ${{ secrets.GITHUB_TOKEN }}

The “secrets.GITHUB_TOKEN” used as authentication to the Github API is a special variable pre-populated by Github.

Trigger Github Workflow

As mentioned earlier, this workflow is invoked by pushing a tag that looks like a semantic version.  Here are the git commands for creating a tag and pushing it remotely.

# check for any changes that might need to be checked in first
git status

# create new tag that triggers workflow, push tag
newtag=v1.0.0
git tag $newtag && git push origin $newtag

This will almost immediately create a workflow which you can view in real-time by going to your Github repository > Actions tab.

You can view the real-time progress by clicking into the task.  The icon will indicate when the workflow is complete.

Validate Releases

The Github Release can be reached from the Github web UI.  Click on “Releases” > spring-boot-github-action-example, and the releases will be listed with Release Notes and binary download available.

 

 

REFERENCES

actions/checkout

actions/setup-java

ncipollo/release-action

stackoverflow, github action invoking python

github source, slackapi/slack-github-action

github cli, create repo

github cli, create secret