10

We have a multitude of smaller sbt projects, which we would like to keep separate (no multi-project build). However we would like to share configuration between the builds. In order to do so we currently have yet another project, which all the projects use as a libraryDependency in their project/project/Build.scala files. We were able to centralize build configuration using only built-in sbt features this way.

What we haven't figured out is how to centralize plugin specific build configuration. For example, we use sbt-assembly for several of our services. We are adapting the assembly mergeStrategy and would like to use that in all projects. How can we re-use the configuration?

Also how can we automatically make certain sbt-plugins available to all of our builds, such as the assembly or scalariform plugins, without manually adding it to each build?

cvogt
  • 11,260
  • 30
  • 46

1 Answers1

14

This is one of the usage pattern we had in mind for auto plugins. Auto plugins can depend on sbt-assembly or sbt-scalariform and introduce the settings automatically to all projects.

build.sbt

sbt-your-company can include sbt-scalariform as a library dependency as follows in build.sbt:

lazy val commonSettings = Seq(
  organization := "com.example",
  version := "0.1.0"
)

lazy val root = (project in file(".")).
  settings(
    commonSettings ++
    addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.3.0")
  : _*).
  settings(
    sbtPlugin := true,
    name := "sbt-your-company",
    // other settings here
  )

Since addSbtPlugin(...) normally appear only in project/plugins.sbt this may be a bit odd, but if you look at the implementation of addSbtPlugin is basically libraryDependencies with a few extra attributes:

def addSbtPlugin(dependency: ModuleID): Setting[Seq[ModuleID]] =
  libraryDependencies <+= (sbtBinaryVersion in update, scalaBinaryVersion in update) { (sbtV, scalaV) => sbtPluginExtra(dependency, sbtV, scalaV) }

src/main/scala/foo/houserules/FormatPlugin.scala

One of the feature added by auto plugin is the ability to trigger a plugin based on other plugins. By triggering your plugin based on plugins.JvmPlugin, you can effectively make a plugin that's enabled by default. Here's an example plugin called FormatPlugin:

package foo
package houserules

import sbt._
import Keys._
import com.typesafe.sbt.SbtScalariform.{ ScalariformKeys => sr, _ }

object FormatPlugin extends AutoPlugin {
  override def requires = plugins.JvmPlugin
  override def trigger = allRequirements

  override def projectSettings: Seq[Def.Setting[_]] = baseSettings

  lazy val baseSettings: Seq[Setting[_]] = scalariformSettings ++ Seq(
    sr.preferences := formatPrefs
  )

  def formatPrefs = {
    import scalariform.formatter.preferences._
    FormattingPreferences().setPreference(AlignSingleLineCaseStatements, true)
  }
}

This plugin introduces sbt-scalariform's scalariformSettings and custom format preferences.

usage

All you have to do is include sbt-your-company to your builds. In case one of your projects want to opt-out of the FormatPlugin you can use disablePlugins(...). See Using plugins.

For full example, see also sbt-houserules I just created. (Coincidentally I've been meaning to create this for sbt modularization.)

other usages for in-house plugin

You can use also auto plugins to configure other things like version of common libraries like Akka version, or excluding all logging libraries etc.

Eugene Yokota
  • 94,654
  • 45
  • 215
  • 319
  • I had troubles to enable the `scalastyle-sbt-plugin`. I have tried `addSbtPlugin` in `myplugin\build.sbt #project.settings` and `addSbtPlugin` in `myplugin\src\main\scala\com\me\MyPlugin #buildSettings` but without success. I had to copy your `StylePlugin` to actiavet it. But this custom autoplugin doesn't enable `scalastyle-sbt-plugin`... Could you explain how it works ? – gervais.b Oct 18 '16 at 07:26