Sunday, June 14, 2020

Assembly - CI/CD Series

Now that we have a basic REST service setup and continually running unit tests, we can now work on building a runnable assembly for the service. To do this, we'll leverage:
Project Build

To make use of the sbt-assembly plugin, we first need to enable the plugin by adding the following to our "project/plugins.sbt" file:

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10")

After that is done, we need to define how to build the assembly:

mainClass in assembly := Some("com.github.dwiechert.Main"),

// Ignore tests when running the "assembly" task
test in assembly := {}

The definition above indicates:
  • The main class to be ran
  • Ignore unit tests when running the "assembly" phase
The reason why the tests are ignored is because in the previous post we integrated automated testing in a separate GitHub Actions step. Since we already have unit tests running there is no need to re-run them again when we build the final assembly. It is possible to run both the tests and assembly as one stage, but then debugging issues with the build could be more troublesome. With two distinct jobs (unit test and assemble), we can quickly and easily determine which stage failed. Whereas if they both ran on the same stage we would need to look into the logs to see if the build failed due to unit tests or the building of the jar itself.

Once these settings are in place, we can build the jar with a simple sbt command:

sbt "clean;compile;assembly"

To test that everything works, we can run the jar locally and ensure it starts up correct:

java -jar target/scala-2.13/cicd-series-assembly-0.1.0-SNAPSHOT.jar

CI/CD Setup

Given that we now have a runnable jar, we need to integrate this with our current CI/CD setup. The reason to integrate this build into our CI/CD system is to ensure not only the unit tests pass, but also that the jar can be built properly. 

To do this, we're going to add a new job in our GitHub Actions file which will run the same assembly commands mentioned above:

assemble:
# The type of runner that the job will run on
# https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on
runs-on: ubuntu-latest
# The specific container to use
# https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idcontainer
# https://hub.docker.com/r/hseeberger/scala-sbt/
container: hseeberger/scala-sbt:8u222_1.3.5_2.13.1

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Checkout Repo
uses: actions/checkout@v2

# Assembly artifact
- name: Create Assembly
run: sbt "clean;compile;assembly"

As mentioned above, this is a new GitHub Actions job. The assembly will run in parallel to the job which runs the unit tests we previously created.

In addition to just building our assembly, we will store the jar as an artifact of the build. This will allow us to re-use this jar in later jobs that will be build in the future (PATs, deployment).

# Upload jar as build artifact
- name: Upload Artifact
uses: actions/upload-artifact@v1
with:
name: cicd-series-assembly.jar
path: target/scala-2.13/cicd-series-assembly-0.1.0-SNAPSHOT.jar

Conclusion

We now have a way to not only build a runnable jar for our service but this step happens on each pull request to master. This will help ensure the state of our system is always tracked and can be deployed at any time.

All of the changes discussed can be found on this pull request.

No comments:

Post a Comment