Mysterious Dan
Mysterious Dan

Reputation: 1326

sbt subproject aggregation and dependency behavior

I have an sbt project with a few subprojects, each of which publishes some artifacts and has a fairly extensive test suite.

When I run the build on my CI server, I want to publish the artifacts to a staging location and run the tests after the publishing task. Since others may want the artifacts, I'd like to tell sbt that I want it to build all the artifacts for all subprojects, then run all the tests, since by default it seems to run them interleaved in an unspecified order.

I have a ScopeFilter giving me access to all my subprojects, so I can make my ciBuild task depend on something like the following

(test in Test).all(subprojectScopeFilter).dependsOn(myArtifactsTask.all(subprojectScopeFilter))`

However, that doesn't seem to have any real effect on the order, and I definitely see some subprojects running tests before others have run their myArtifactsTask. I'm guessing that I don't fully understand how all works and it might be saying that each independent subproject's test task depends on that same subproject's myArtifactsTask? If that's the case, how can I specify what I want? Is it documented somewhere that I've missed? The manual describes the basics of all but not how it interacts with other constructs.

Upvotes: 2

Views: 1079

Answers (1)

lpiepiora
lpiepiora

Reputation: 13749

SBT will resolve automatically the order between task and projects and build them in that order.

What you could do is - let's assume you have three projects. Root and two sub-projects. I assume that the key myArtifactTask is defined in the root.

project/Build.scala

object MyBuild extends Build {
  val myArtifactTask = TaskKey[Unit]("my-artifact-task", "My Artifact Task")
}

The myArtifactTask is implemented in both sub-projects.

subproject-a/build.sbt

myArtifactTask := {
  println("myArtifactTask:project-a")
}

subproject-a/build.sbt

myArtifactTask := {
  println("myArtifactTask:project-b")
}

What you want to do is to define your root's build.sbt in a way that it calls myArtifactTask in both projects. Then you could define new task testedArtifact which would depend on myArtifactTask.

build.sbt

lazy val testedArtifact = taskKey[Unit]("Runs myArtifactTask followed by tests")

lazy val inAnyProjectButRoot: ScopeFilter = ScopeFilter (
  inAnyProject -- inProjects(ThisProject)
)

myArtifactTask := {
  myArtifactTask.all(inAnyProjectButRoot).value
}

testedArtifact := {
 (test in Test).all(anyProjectButRoot).value
}

testedArtifact <<= testedArtifact.dependsOn(myArtifactTask)

Now calling testedArtifactin the root project will first call all myArtifactTasks in sub-projects followed by tests.

Upvotes: 1

Related Questions