themel
themel

Reputation: 8895

SBT: Run an action on all projects

I have an SBT project that contains multiple subprojects, i.e.:

> projects
[info] In file:/home/me/src/foo/
[info]     popen
[info]     foobar-core
[info]   * foobar-client
[info]     foobar-db

Is there a way to run an action in each of these subprojects? I'm looking for something like publish-all, since I currently go through all the subprojects and run publish manually, which gets fairly tedious once there are more than a handful of subprojects.

I'm using sbt-0.11.2 out of inertia, but am willing to upgrade if that helps.

Upvotes: 6

Views: 2899

Answers (2)

Nabil A.
Nabil A.

Reputation: 3400

The answer from Kim Stebel works perfectly, but requires an aggregation project.

(The following solution is tested with sbt 1.3.x)

I wanted a more dynamic solution. We have a small sbt plugin, that is used in all our projects anyway. So I added this:

val allProjects = Command.single("allProjects"){ (s,task) =>
  val extracted = Project extract s
  import extracted._
  import currentRef.{ build => curi}
  val build = structure.units(curi)
  build.defined.keys.map(projectId => s"$projectId/$task").foldRight(s)(_ :: _)
}

  override def globalSettings: Seq[Def.Setting[_]] = {
    List(
      commands += allProjects,
      ...
    )
  }

For a single build.sbt just use the first part with the line commands += allProjects added

This creates the command allProjects and can be used like allProjects compile.

The execution happens sequential, so it is blocking.

Better try this

After digging a bit more, I found out, that if no project with path . is created, all projects are by default aggregated in the root project.

Our problem was, that we liked our root project to be named, so we defined it as

lazy val coolProjectName = project.in(file("."))

I changed this in the build.sbt to:

name := "coolProjectName"

This way the default aggregation is still working. And commands/tasks on aggregated projects are executed in parallel.

Upvotes: -1

Kim Stebel
Kim Stebel

Reputation: 42047

You can define a project that aggregates all the other projects. Each action run on this project will be run on all aggregates. Here is an example from the sbt wiki:

import sbt._
import Keys._

object HelloBuild extends Build {
    lazy val root = Project(id = "hello",
                            base = file(".")) aggregate(foo, bar)

    lazy val foo = Project(id = "hello-foo",
                           base = file("foo"))

    lazy val bar = Project(id = "hello-bar",
                           base = file("bar"))
}

Upvotes: 10

Related Questions