Plugins

A plugin is a way to use external code in a build definition.
A plugin can be a library used to implement a task (you might use
Knockoff 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. For example, a plugin might add a
proguard task and associated (overridable) settings. Finally, a plugin
can define new commands (via the commands setting).

sbt 0.13.5 introduces auto plugins, with improved dependency management
among the plugins and explicitly scoped auto importing.
Going forward, our recommendation is to migrate to the auto plugins.
The Plugins Best Practices page describes
the currently evolving guidelines to writing sbt plugins. See also the general
best practices.

Using an auto plugin

A common situation is when using a binary plugin published to a repository.
If you’re adding sbt-assembly, create project/assembly.sbt with the following:

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.11.2")

Alternatively, you can create project/plugins.sbt with
all of the desired sbt plugins, any general dependencies, and any necessary repositories:

See using plugins in the Getting Started guide for more details on using plugins.

By Description

A plugin definition is a project under project/ folder. This
project’s classpath is the classpath used for build definitions in
project/ and any .sbt files in the project’s base
directory. It is also used for the eval and set commands.

Specifically,

Managed dependencies declared by the project/ project are
retrieved and are available on the build definition classpath, just
like for a normal project.

Unmanaged dependencies in project/lib/ are available to the build
definition, just like for a normal project.

Sources in the project/ project are the build definition files and
are compiled using the classpath built from the managed and
unmanaged dependencies.

Project dependencies can be declared in project/plugins.sbt
(similarly to build.sbt file in a normal project) or
project/project/Build.scala (similarly to project/Build.scala in
a normal project) and will be available to the build
definition sources. Think of project/project/ as the build
definition for the build definition (worth to repeat it here again:
“sbt is recursive”, remember?).

The build definition classpath is searched for sbt/sbt.autoplugins
descriptor files containing the names of
sbt.AutoPlugin implementations.

The reload plugins command changes the current build to
the (root) project’s project/ build definition. This allows manipulating
the build definition project like a normal project. reload return changes back
to the original build. Any session settings for the plugin definition
project that have not been saved are dropped.

An auto plugin is a module that defines settings to automatically inject into
projects. In addition an auto plugin provides the following feature:

Automatically import selective names to .sbt files and the eval and set commands.

Plugin dependencies

When a traditional plugin wanted to reuse some functionality from an existing plugin, it would pull in the plugin as a library dependency, and then it would either:

add the setting sequence from the dependency as part of its own setting sequence, or

tell the build users to include them in the right order.

This becomes complicated as the number of plugins increase within an application, and becomes more error prone. The main goal of auto plugin is to alleviate this setting dependency problem. An auto plugin can depend on other auto plugins and ensure these dependency settings are loaded first.

Suppose we have the SbtLessPlugin and the SbtCoffeeScriptPlugin, which in turn depends on the SbtJsTaskPlugin, SbtWebPlugin, and JvmPlugin. Instead of manually activating all of these plugins, a project can just activate the SbtLessPlugin and SbtCoffeeScriptPlugin like this:

This will pull in the right setting sequence from the plugins in the right order. The key notion here is you declare the plugins you want, and sbt can fill in the gap.

A plugin implementation is not required to produce an auto plugin, however.
It is a convenience for plugin consumers and because of the automatic nature, it is not always appropriate.

Global plugins

The ~/.sbt/1.0/plugins/ directory is treated as a global plugin
definition project. It is a normal sbt project whose classpath is
available to all sbt project definitions for that user as described
above for per-project plugins.

Creating an auto plugin

A minimal sbt plugin is a Scala library that is built against the version of
Scala that sbt runs (currently, 2.12.4) or a Java library.
Nothing special needs to be done for this type of library.
A more typical plugin will provide sbt tasks, commands, or settings.
This kind of plugin may provide these settings
automatically or make them available for the user to explicitly
integrate.

To make an auto plugin, create a project and configure sbtPlugin to true.

sbtPlugin := true

Then, write the plugin code and publish your project to a repository.
The plugin can be used as described in the previous section.

projectSettings and buildSettings

With auto plugins, all provided settings (e.g. assemblySettings) are provided by the plugin directly via the projectSettings method. Here’s an example plugin that adds a command named hello to sbt projects:

This example demonstrates how to take a Command (here, helloCommand) and
distribute it in a plugin. Note that multiple commands can be included
in one plugin (for example, use commands ++= Seq(a,b)). See
Commands
for defining more useful commands, including ones that accept arguments
and affect the execution state.

If the plugin needs to append settings at the build-level (that is, in ThisBuild) there’s a buildSettings method. The settings returned here are guaranteed to be added to a given build scope only once
regardless of how many projects for that build activate this AutoPlugin.

override def buildSettings: Seq[Setting[_]] = Nil

The globalSettings is appended once to the global settings (in Global).
These allow a plugin to automatically provide new functionality or new defaults.
One main use of this feature is to globally add commands, such as for IDE plugins.

The requires method returns a value of type Plugins, which is a DSL for constructing the dependency list. The requires method typically contains one of the following values:

empty (No plugins)

other auto plugins

&& operator (for defining multiple dependencies)

Root plugins and triggered plugins

Some plugins should always be explicitly enabled on projects. we call
these root plugins, i.e. plugins that are “root” nodes in the plugin
dependency graph. An auto plugin is by default a root plugin.

Auto plugins also provide a way for plugins to automatically attach themselves to
projects if their dependencies are met. We call these triggered plugins,
and they are created by overriding the trigger method.

For example, we might want to create a triggered plugin that can append commands automatically to the build. To do this, set the requires method to return empty, and override the trigger method with allRequirements.

The build user still needs to include this plugin in project/plugins.sbt, but it is no longer needed to be included in build.sbt. This becomes more interesting when you do specify a plugin with requirements. Let’s modify the SbtLessPlugin so that it depends on another plugin:

As it turns out, PlayScala plugin (in case you didn’t know, the Play framework is an sbt plugin) lists SbtJsTaskPlugin as one of it required plugins. So, if we define a build.sbt with:

lazy val root = (project in file("."))
.enablePlugins(PlayScala)

then the setting sequence from SbtLessPlugin will be automatically appended somewhere after the settings from PlayScala.

This allows plugins to silently, and correctly, extend existing plugins with more features. It also can help remove the burden of ordering from the user, allowing the plugin authors greater freedom and power when providing feature for their users.

Controlling the import with autoImport

When an auto plugin provides a stable field such as val or object
named autoImport, the contents of the field are wildcard imported
in set, eval, and .sbt files. In the next example, we’ll replace
our hello command with a task to get the value of greeting easily.
In practice, it’s recommended to prefer settings or tasks to commands.

Usage example

Global plugins example

The simplest global plugin definition is declaring a library or plugin
in ~/.sbt/1.0/plugins/build.sbt:

libraryDependencies += "org.example" %% "example-plugin" % "0.1"

This plugin will be available for every sbt project for the current
user.

In addition:

Jars may be placed directly in ~/.sbt/1.0/plugins/lib/
and will be available to every build definition for the current user.

Dependencies on plugins built from source may be declared in
~/.sbt/1.0/plugins/project/Build.scala as described at
.scala build definition.

A Plugin may be directly defined in Scala
source files in ~/.sbt/1.0/plugins/, such as
~/.sbt/1.0/plugins/MyPlugin.scala.
~/.sbt/1.0/plugins//build.sbt
should contain sbtPlugin := true. This can be used for quicker
turnaround when developing a plugin initially:

Edit the global plugin code

reload the project you want to use the modified plugin in

sbt will rebuild the plugin and use it for the project.

Additionally, the plugin will be available in other projects on
the machine without recompiling again. This approach skips the
overhead of publishLocal and cleaning the plugins directory of the
project using the plugin.

These are all consequences of ~/.sbt/1.0/plugins/ being a standard
project whose classpath is added to every sbt project’s build
definition.

Using a library in a build definition example

As an example, we’ll add the Grizzled Scala library as a plugin.
Although this does not provide sbt-specific functionality, it
demonstrates how to declare plugins.

Note that this approach can be useful used when developing a plugin. A
project that uses the plugin will rebuild the plugin on reload. This
saves the intermediate steps of publishLocal and update. It can also
be used to work with the development version of a plugin from its
repository.

It is however recommended to explicitly specify the commit or tag by appending
it to the repository as a fragment:

One caveat to using this method is that the local sbt will try to run
the remote plugin’s build. It is quite possible that the plugin’s own
build uses a different sbt version, as many plugins cross-publish for
several sbt versions. As such, it is recommended to stick with binary
artifacts when possible.

2) Use the library

Grizzled Scala is ready to be used in build definitions. This includes
the eval and set commands and .sbt and project/*.scala files.