Giter8 Scala Microservice template

Alexey Novakov
SE Notes by Alexey Novakov
4 min readSep 21, 2018

Once you start writing similar services in Scala with SBT, you find that you are doing a lot of copy-paste work from your previously written project. At this point, your own Giter8 SBT template might be a good thing to create. This will take up to 10 mins, if you already have all the pieces which you want to include into a template. Let’s imagine typical microservice requirements:

Template requirements

  1. Docker build

2. Jenkins Pipeline

3. Release/Versioning/Git tags

4. Scalafmt config

5. Git ignore config

6. Stub for Main class

Template parts

In order to cover above requirements we create the following files and specific configuration:

  1. Simple files: .scalafmt.conf, .gitignore
  2. Jenkinsfile.groovy
  3. Build scripts for Jenkins (Ammonite Scripts)
  4. SBT-release plugin configuration (in build.sbt)
  5. SBT-native-packager plugin configuration (in build.sbt)
  6. Main Scala class to hold the application main thread and let the Docker container running

Eventually, we will produce the following structure:

IntelliJ Idea files views

src/main/g8 folder contains everything which will be used as content of new project once template is going to be executed.

Giter8 own configuration

File src/main/g8/default.properties contains Java properties for our template. Its content:

name = Project Name
scalaVersion
= 2.12.6
verbatim
= *.sc

First two property will be user-prompted once we run the template. Current values will be considered as default once, if we do not provide new values on shell prompt. Property names are defined by user, so you can define whatever properties/variables you would need.

verbatim property indicates which files need be left/skipped without modifications.

Giter8 template variables

G8 will substitute any variables found in any file of g8 folder. Example of a variable usage in a file:

scalaVersion := "$scalaVersion$"

$scalaVersion$ value will be taken from default.properties or from the user prompt when it is set.

SBT plugins

src/main/g8/project/plugins.sbt

addSbtPlugin("com.typesafe.sbt" %% "sbt-native-packager" % "1.3.2")
addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.6")

SBT project configuration

There are normal project configuration and sbt-release and sbt-native-packager configuration:

import sbtrelease.ReleaseStateTransformations._

lazy val root = (project in file(".")).
settings(
inThisBuild(List(
organization := "org.alexeyn",
scalaVersion := "$scalaVersion$" // variable
)),
name := "$name;format="lower,hyphen"$", // variable
mainClass in Compile := Some("org.alexeyn.StubMain")
).enablePlugins(JavaAppPackaging) // enables Docker image build

val dwDockerRegistry = "my-docker-registry:5000"

dockerRepository := Some(dwDockerRegistry)
// if you have a base image, then use below line, otherwise remove // it. Note there is a backslash needed to ignore $ sign
dockerBaseImage := s"\$dwDockerRegistry/service-base-image:latest"
releaseProcess := Seq.empty[ReleaseStep]

releaseProcess
++= (if (sys.env.contains("RELEASE_VERSION_BUMP"))
Seq[ReleaseStep](
checkSnapshotDependencies,
inquireVersions,
setReleaseVersion,
commitReleaseVersion,
tagRelease
)
else Seq.empty[ReleaseStep])

releaseProcess ++= (if (sys.env.contains("RELEASE_PUBLISH"))
Seq[ReleaseStep](inquireVersions, setNextVersion, commitNextVersion)
else Seq.empty[ReleaseStep])

Scala stub class

src/main/g8/src/main/scala/org/alexeyn/StubMain.scala

package org.alexeyn

object StubMain extends App {

println("Hello!")
while(true) {}
}

Run template

I am running template via g8 cmd tool using local path to a template, however one can run it via “sbt new” command if a template is pushed to Github:

bash-3.2$ g8 file://./my-scala-proj
Project description
name [Project Name]: new-service
scalaVersion [2.12.6]:
Template applied in /Users/an/dev/git/./new-serviceProject descriptionname [Project Name]: new-service
scalaVersion [2.12.6]:
Template applied in /Users/an/dev/git/./new-service

Result:

Bonus Part. Jenkins pipeline

Now let’s look how the Jenkins pipeline could be configured based on SBT command calls. Although below snippet was taken from real-world example, it is only to show you high-level idea how this can be organized.

Jenkins pipeline is implemented using so-called scripted pipeline approach, which is in fact a Jenkinsfile.groovy. I omit part how to create new custom pipeline at Jenkins UI.

Below Jenkins script is calling Ammonite scripts for some of the stages of the Jenkins job. I am keeping all scripts and Jenkinsfile itself in jenkins folder. :-)

Examples of script calls in Jenkinsfile:

stage('Versionbump') {
if (isMasterBranch) {
sh 'amm jenkins/bump_version.sc'
} else {
println("On branch \${env.BRANCH_NAME} - skipping
Versionbump"
)
}
}
stage('Compile') {
sh 'sbt clean compile'
}

stage("Sbt Test") {
sh "LANG='en_US.UTF-8' sbt test"
}

stage('Docker' || params.dockerImg == 'Yes') {
if (isMasterBranch) {
sh 'sbt docker:publish'
} else {
println("On branch \${env.BRANCH_NAME} - skipping Docker
images build"
)
}
}

stage('Publish') {
if (isMasterBranch) {
sh 'amm jenkins/publish_version.sc'
} else {
println("On branch \${env.BRANCH_NAME} - skipping Publish")
}
}

As you might noticed, releasing steps are only running for jobs, which are triggered for a master branch.

Summary

I hope you are inspired now to create your own template with common configuration/scripts you always copy in your next microservice project.

Official Giter8 documentation with more details how to create own template is here:

Update: this template on Github

https://github.com/novakov-alexey/scala-service.g8

--

--