About this post

Already working on an sbt-based Scala project with two sub-projects, I wanted to create a third sub-project, a Play2 application. The following describes what worked for me.

Creating the sub-project structure

Before adding the third sub-project, my sbt project structure looked like this:

importer/
└  src/
   ├  main/
   └  test/
spark/
└  src/
   ├  main/
   └  test/
project/
└  plugins.sbt

build.sbt

Within build.sbt, the sub-projects where declared as follows (shortened for brevity):

name := "journeymonitor-analyze"

val commonSettings = Seq(
  organization := "com.journeymonitor",
  version := "0.1"
)

lazy val testDependencies = Seq (
  "org.scalatest" %% "scalatest" % "2.2.4" % "test"
)

lazy val cassandraDependencies = Seq (
  "com.datastax.cassandra" % "cassandra-driver-core" % "2.1.8",
  "com.chrisomeara" % "pillar_2.11" % "2.0.1"
)

lazy val spark = project
  .settings(commonSettings:_*)
  .settings(libraryDependencies ++= (testDependencies))

lazy val importer = project
  .settings(commonSettings:_*)
  .settings(libraryDependencies ++= (testDependencies ++ cassandraDependencies))

lazy val main = project.in(file("."))
  .aggregate(spark, importer)

I wanted to name the new sub-project “api”, and it should reside in a folder of the same name.

First, I installed the TypeSafe Activator onto my Mac OS X system via brew install typesafe-activator. Next, I changed to the root folder of my project, and ran activator new api play-scala. This resulted in the following structure:

api/
├  build.sbt
├  api/
├  conf/
├  public/
├  test/
└  project/
   └  plugins.sbt
importer/
└  src/
   ├  main/
   └  test/
spark/
└  src/
   ├  main/
   └  test/
project/
└  plugins.sbt

build.sbt

Next, I added the content of the newly added api/project/plugins.sbt to the existing project/plugins.sbt file, and removed the former. Then, I extended the existing build.sbt file as follows:

name := "journeymonitor-analyze"

val commonSettings = ...

lazy val testDependencies = ...

lazy val cassandraDependencies = ...

lazy val spark = project ...

lazy val importer = project ...

lazy val api = project
  .settings(commonSettings:_*)
  .settings(assemblyJarName in assembly := "journeymonitor-analyze-api-assembly.jar")

lazy val main = project.in(file("."))
  .aggregate(spark, importer, api)

This declares the api sub-project and applies the commonSettings to it, but doesn’t configure it further. This happens via the sub-project specific configuration in file api/build.sbt:

name := """api"""

version := "1.0-SNAPSHOT"

enablePlugins(PlayScala)

scalaVersion := "2.11.7"

libraryDependencies ++= Seq(
  jdbc,
  cache,
  ws,
  specs2 % Test
)

resolvers += "scalaz-bintray" at "http://dl.bintray.com/scalaz/releases"

routesGenerator := InjectedRoutesGenerator

The above shows two changes that were necessary: on line 5, the val declaration needs to be removed, leaving only the enablePlugins call, and on line 7, I changed the scalaVersion from “2.11.6″ to “2.11.7″.

With this, I was now able to run sbt from the root folder, switch to the new sub-project within sbt via project api, and successfully run the Play2 test suite via test.

Commit 4a899b0 on the journeymonitor/analyze repo on Github shows the differences before and after adding the new sub-project.

If you would like to be informed on updates to this post, just follow @manuelkiessling