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 . The build.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

results matching ""

    No results matching ""