build.sbt - iteration over sub projects for common settings in monorepo

Viewed 162

I'm implementing a monorepo using SBT. I would like to iterate over my subprojects in order to initialize them (as the have the same configuration) and prevent code duplication.

In my build.sbt:

lazy val root = (project in file("."))
    .aggregate(projects: _*)
    .settings(
        crossScalaVersions := Nil,
        publish / skip := true
    )

lazy val projects = Seq("projectA", "projectB", "projectC")
    .map((projectName: String) => (project in file(projectName))
        .settings(
            name := projectName,
            commonSettings,
            libraryDependencies ++= ModulesDependencies.get(projectName))
        .project
    )

I'm getting the error:

 error: project must be directly assigned to a val, such as `val x = project`. Alternatively, you can use `sbt.Project.apply`

Based on the error message, I also tried to use sbt.Project.apply(projectName, file(projectName)).settings(...) instead, but I'm also facing some funny errors.

From what I understand, it seems that SBT expects me to declare as lazy val projectA = (project in file("projectA")).settings(...), which works fine but I would have to duplicate this code for all my sub projects.

Is this iteration that I try to implement even possible?

1 Answers

Utility method might help with some of the duplication, for example

def createProject(projectName: String) = {
  Project(projectName, file(projectName))
    .settings(
      name := projectName,
      commonSettings,
      libraryDependencies ++= ModulesDependencies.get(projectName)
    )
}

lazy val projectA = createProject("projectA")
lazy val projectB = createProject("projectB")
lazy val projectC = createProject("projectC")

lazy val root = (project in file("."))
  .aggregate(projectA, projectB, projectB)
  .settings(
    crossScalaVersions := Nil,
    publish / skip := true
  )
Related