Cake Team Blogs

Cake Solutions architects, implements and maintains modern and scalable software, which includes server-side, rich browser applications and mobile development. Alongside the software engineering and delivery, Cake Solutions provides mentoring and training services. Whatever scale of system you ask us to develop, we will deliver the entire solution, not just lines of code. We appreciate the importance of good testing, Continuous Integration and delivery, and DevOps. We motivate, mentor and guide entire teams through modern software engineering. This enables us to deliver not just software, but to transform the way organisations think about and execute software delivery.



Full-fat SBT projects

Posted by Jan Machacek

Find me on:

30/07/13 16:59

Akka Extras use the full .scala SBT syntax. This is different from the .sbt syntax, so let us explore how to construct the Scala syntax build, including publishing to Sonatype. We will explore this on the real EigengoBuild object.

The build object

The EigengoBuild extends the Build object, which is the project settings. In this file, we will define the modules as well as the root module, which aggregates the child modules. Let's explore the overall stucture.

object EigengoBuild extends Build {
  // contains the modules and build settings

object Publish {
  // contains settings for publishing

object Dependencies {
  // contains dependencies

Let's explore the EigengoBuild's main structure. We begin with the settings and the modules. The settings and defaultSettings hold the global and module-specific SBT settings. We then refer and use these settings sequences.

The override val settings holds the global settings for the project. We set the organisation, version and scalaVersion SBT settings. The defaultSettings holds the settings that will be used in each module. These include the compiler options (scalac and javac), the threading behaviour and the artefact resolvers. If you have a local/enterprise repository, you will need to add it to the resolverssequence. Notice that some of the keys in the settings are pulled from our Publish object as well as objects that the plugins define. (Ex gratia graphSettings, defined in net.virtualvoid.sbt.graph.Plugin.)

object EigengoBuild extends Build {

  override val settings = super.settings ++ Seq(
    organization := "org.eigengo.akka-extras",
    version := "0.1.0",
    scalaVersion := "2.10.1"

  lazy val defaultSettings =
    Defaults.defaultSettings ++
    Publish.settings ++
    graphSettings ++
      scalacOptions in Compile ++= Seq("-encoding", "UTF-8",
      javacOptions in Compile ++= Seq("-source", "1.6",
                                      "-target", "1.6",
    javaOptions += "",
    javaOptions += "-Xmx2G",
    outputStrategy := Some(StdoutOutput),
    fork := true,
    maxErrors := 1,
    resolvers ++= Seq(
      "Spray Releases" at "",
    parallelExecution in Test := false
  ) ++ ScctPlugin.instrumentSettings // ++ ScalastylePlugin.Settings


Now that we have the settings, we can define the modules and pull in the settings we have defined above. Here, we have all the modules that make up Akka Extras. We use underscore for the variable name and dash for the directory name. So, the apple_push variable defines a module that lives in the apple-push directory.

The modules include settings, which usually define the libraryDependencies. The variables that hold the depndencies themselves are defined further down, in the Dependencies object. (Hence the import Dependencies._ above.) Under each directory, we have the usual Maven-esque structure src/main/scala,
src/main/resources; src/test/scala and so on.

object EigengoBuild extends Build {

  override val settings = ...

  lazy val defaultSettings = Defaults.defaultSettings ++
                             Publish.settings ++
                             graphSettings ++ ...

  def module(dir: String) =
    Project(id = dir, base = file(dir), settings = defaultSettings)

  import Dependencies._

  lazy val apple_push = module("apple-push") settings(
    libraryDependencies += akka,
    libraryDependencies += specs2 % "test"

  lazy val freemarker_templating = module("freemarker-templating") settings (
    libraryDependencies += freemarker,
    libraryDependencies += specs2 % "test"

  lazy val javamail = module("javamail") settings (
    libraryDependencies += mail,
    libraryDependencies += scalaz_core,
    libraryDependencies += typesafe_config,
    libraryDependencies += akka,
    libraryDependencies += specs2 % "test",
    libraryDependencies += dumbster % "test",
    libraryDependencies += akka_testkit % "test",

    publishArtifact in Compile := true

  lazy val main = module("main")
    dependsOn(apple_push, freemarker_templating, javamail)

We are nearly at the end. The last thing we need to do is to aggregate all these projects into the root project. It does not have any further libraryDependencies, but it includes all other modules.

object EigengoBuild extends Build {

  lazy val root = Project(
    id = "parent",
    base = file("."),
    settings = defaultSettings ++
               ScctPlugin.mergeReportSettings ++
               Seq(publishArtifact in Compile := false),
    aggregate = Seq(apple_push, freemarker_templating, javamail)



In the full-blown Scala builds, we define the individual dependencies as variables; it makes sense to separate them out to their own object. And that's exactly what we've done in the Dependencies object.

object Dependencies {
  val akka_version    = "2.1.2"

  val akka            = "com.typesafe.akka" %% "akka-actor"   % akka_version
  val scalaz_core     = "org.scalaz"        %% "scalaz-core"  % "7.0.0"
  val typesafe_config = "com.typesafe"       % "config"       % "1.0.0"
  val akka_testkit    = "com.typesafe.akka" %% "akka-testkit" % akka_version
  val specs2          = "org.specs2"        %% "specs2"       % "1.14"
  val mail            = "javax.mail"         % "mail"         % "1.4.2"
  val freemarker      = "org.freemarker"     % "freemarker"   % "2.3.19"
  val dumbster        = "dumbster"           % "dumbster"     % "1.6"

Publishing and the Publish object

We are publishing our artefacts to Sonatype OSS hosting; and we are using the sbt-release plugin. The plugin needs some settings that we define in the Publish object. The code follows the Publishing guide, but uses the full-blown .scala syntax instead of the .sbt syntax.

We define the settings variable: the sequence of SBT settings that is the Scala-syntax equivalent of writing

pomExtra  := ...
publishTo := ...

and others in the .sbt syntax. To keep things readable, we have pulled out the actual values like akkaExtrasPomExtra, which is a proper variable in the Publish object; and we refer to it when we construct the SBT settings in this sequence. (Viz pomExtra := akkaExtrasPomExtra.)

The akkaExtrasCredentials is loaded from the ~/.sonatype file. (You don't want to publish your credentials to GitHub--remember the sorry episode with people pushing their keyphrase-less private keys?)

This file must contain the realm, host, username and password property-like lines.

realm=Sonatype Nexus Repository Manager

So, onwards to the Publish object.

object Publish {

  lazy val settings = Seq(
    crossPaths := false,
    pomExtra := akkaExtrasPomExtra,
    publishTo < <= version { v: String =>
      val nexus = ""
      if (v.trim.endsWith("SNAPSHOT"))
        Some("snapshots" at nexus + "content/repositories/snapshots")
        Some("releases" at nexus + "service/local/staging/deploy/maven2")
    credentials ++= akkaExtrasCredentials,
    organizationName := "Eigengo",
    organizationHomepage := Some(url("")),
    publishMavenStyle := true,
    // Maven central cannot allow other repos.
    // TODO - Make sure all artifacts are on central.
    pomIncludeRepository := { x => false }

  val akkaExtrasPomExtra = (

  val akkaExtrasCredentials = Seq(Credentials(Path.userHome / ".sonatype"))



This completes the post about how we build the multi-module Akka Extras project. I hope you will find it useful for your own projects. The source code is at

Topics: Sbt

Posts by Topic

see all

Subscribe to Email Updates





Case Studies



Find out more



Find out more



Find out more