ColOfAbRiX
ColOfAbRiX

Reputation: 1059

Different options for test on a multiproject Scala SBT using ThisBuild

I have an SBT project with 2 subprojects and I want to have test compiler settings different from the normal compiler settings, for all the subprojects. I.e. I want to enforce -Xfatal-warnings for the main code but not for tests.

I'm looking for a solution that doesn't involve setting each subproject individuall but all at once.

I'm working with SBT 1.3.9 and Scala 2.13.3

This is a sample of what I have in SBT:

lazy val root: Project = project
  .in(file("."))
  .aggregate(projectA, projectB)

lazy val projectA: Project = project
  .in(file("projectA"))
  .settings(
    name := "projectA",
  )

lazy val projectB: Project = project
  .in(file("projectA"))
  .settings(
    name := "projectA",
  )

I tried plenty of options but I can't set test options different to compile options. As a quick summary, I tried to play around with scoping:

This question is the closest to what I need but it doesn't work, probably beucase it's not meant for multiproject files.

UPDATE:

I've just discovered that if I scope the setting to a specific project then I have the behaviour I want:

projectA / Compile / scalacOptions := Seq(XXX)
projectA / Test / scalacOptions := Seq(YYY)
projectB / Compile / scalacOptions := Seq(XXX)
projectB / Test / scalacOptions := Seq(YYY)

but if I use ThisBuild it doesn't work

ThisBuild / Compile / scalacOptions := Seq(XXX)
ThisBuild / Test / scalacOptions := Seq(XXX)

Do I have a wrong understanding of something or is this a bug?

Upvotes: 3

Views: 559

Answers (1)

Mario Galic
Mario Galic

Reputation: 48420

ThisBuild scope axis value is often misunderstood when attempting to define common settings for multiple subprojects. Please note it does not mean

add this common setting to all the subprojects in this build

Instead the meaning is closer to

If a subproject does not define this setting, then, possibly, delegate (fall back) to ThisBuild

For example, executing inspect Test / scalacOptions on basic hello world project gives

...
[info] Provided by:
[info]  ProjectRef(uri("file:/my/Path/To/Project/"), "root") / Test / scalacOptions
...
[info] Delegates:
[info]  Test / scalacOptions
[info]  Runtime / scalacOptions
[info]  Compile / scalacOptions
[info]  scalacOptions
[info]  ThisBuild / Test / scalacOptions
[info]  ThisBuild / Runtime / scalacOptions
[info]  ThisBuild / Compile / scalacOptions
[info]  ThisBuild / scalacOptions
[info]  Zero / Test / scalacOptions
[info]  Zero / Runtime / scalacOptions
[info]  Zero / Compile / scalacOptions
[info]  Global / scalacOptions
...

The Provided by section shows the scope with highest precedence

ProjectRef(uri("file:/my/Path/To/Project/"), "root") / Test / scalacOptions

then Delegates section shows the remainder of precedence order where we notice there are bunch of scopes "above" the ones using ThisBuild as project axis. Therefore because of how sbt scope delegation rules work

ThisBuild / Test / scalacOptions

does not mean tests within subprojects will automatically pick up the new value as it is quite low in the picking order.

I believe the most straightforward approach around sbt's arguably confusing scoping rules is to define a val with common settings and then simply add that value to each subproject, or define an auto plugin

Auto plugins can inject project settings across the board

Consider my related answer which demonstrates the two approaches.

Upvotes: 1

Related Questions