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.sbt
is 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