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

Docker build Jenkins Pipeline Release/Versioning/Git tags Scalafmt config Git ignore config Stub for Main class Template parts

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

Simple files: .scalafmt.conf, .gitignore Jenkinsfile.groovy Build scripts for Jenkins (Ammonite Scripts) SBT-release plugin configuration (in build.sbt) SBT-native-packager plugin configuration (in build.sbt) Main Scala class to hold the application main thread and let the Dockercontainer 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-service Project description name [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 all the details on how to create your own template is here: http://www.foundweekends.org/giter8/template.html