AutoPlugins
The sbt documentation on plugins describes them like this
A plugin is a way to use external code in a build definition. A plugin can be a library used to implement a task to write a markdown processing task). A plugin can define a sequence of sbt settings that are automatically added to all projects or that are explicitly declared for selected projects.
Since 0.13.15 SBT has AutoPlugins which add a way to declare dependencies between AutoPlugins and scoped auto importing of settings, task, methods, etc. into your sbt files.
When to write an AutoPlugin
There are a couple of reasons to write your own plugin in your build.
- You should not inline logic into your
build.sbt. Thebuild.sbtis mostly a declarative description of your build. It contains the what, an AutoPlugin contains the how. - Define new task and settings along with their implementation.
- Reimplement an existing task
- Couple a set of task and settings definitions together
Also see the Best practices for AutoPlugins documentation.
Write an AutoPlugin
In the Project section we learned that the build itself is a project that gets compiled. So we put our source files directly in the project folder of our build. We'll call our plugin MyPlugin. The build should look something like this
build.sbt
/project/build.properties
/project/MyPlugin.scala
Plugin stub
We start with an empty plugin, doing nothing.
package myplugin
import sbt._
import sbt.Keys._
// (1) extend AutoPlugin to define an AutoPlugin
object MyPlugin extends AutoPlugin {
// (2) define the plugins this plugin depends on
override val requires: Plugin = super.requires
// (3) when to enable this plugin. By default `noTrigger` is used
override val trigger: PluginTrigger = super.trigger
// (4) everything in this object will be automatically imported in sbt files
object autoImport { }
// (5) this is not an sbt file so we have to import it ourselves
import autoImport._
// (6) the settings that this plugins applies to the project
override def projectSettings: Seq[Setting[_]] = Seq.empty
}
Require another plugin
You should almost always require the JvmPlugin as it sets a lot of defaults you may use or change in your plugin.
import sbt.plugins.JvmPlugin
object MyPlugin extends AutoPlugin {
override val requires: Plugin = JvmPlugin
}
To require more than one plugin use the && operator.
object MyPlugin extends AutoPlugin {
override val requires: Plugin = PluginA && PluginB && PluginC
}
Define and implement custom tasks
A good place to define your task is in the autoImport object. It will be automatically available in your sbt files.
import sbt._
import scala.util.Random
object MyPlugin extends AutoPlugin {
object autoImport {
// (1) a setting, the generator is set once and doesn't change
val randomGenerator = SettingKey[Random]("random-generator", "random number generator")
// (2) generate a new number
val randomNumber = TaskKey[Int]("random-number", "generate a random number")
}
// (3) implementation
override def projectSettings: Seq[Setting[_]] = Seq(
randomGenerator := new Random(),
randomNumber := randomGenerator.value.nextInt()
)
}
In our build.sbt we need to enable this plugin. No imports required.
enablePlugins(MyPlugin)
In your sbt shell we can now call this task
> show randomNumber