User Stories: AutoPlugins

kenji yoshida edited this page Mar 11, 2014 · 2 revisions

This document details the desired workflow/use cases of the sbt project natures feature. This is a loosely specified, poorly defined set of "stories" (or terminal outputs) that we hope show our goal towards improving the consumption and definition of plugins within the sbt ecosystem.

Story: User adds pgp plugin to the build.

User opens project/plugins.sbt and adds the line:

// Was here before.
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.3.0")

addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "1.0")

The user's build.sbt file is unchanged. The pgp plugin's required natures should be detected on any default/play projects and added to these projects automatically.

Story: User wants to aggregate tasks on a project, but not have that project actually have any behavior.

User takes his existing build.sbt file:

val lib = project

val web = project.addPlugins(Web, PlayPlugin).dependsOn(lib) // scala is default

And declares the root project to be a "non-ivy" project which aggregates the others:

val lib = project

val web = project.addPlugins(Web, PlayPlugin).dependsOn(lib)

val root = Project("root", file(".")).disablePlugins(IvyModule).aggregate(lib,web)

User Story: User wants to create an sbt plugin that enhances play projects.

  1. The user declares a dependency from his plugin to the play plugin:

Note: This is in build.sbt, not project/plugins.sbt

name := "my-play-build-plugin"

organization := "my.company"

version := "1.0"

sbtPlugin := true

addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.3.0")
  1. The user declares his plugin settings via the AutoPlugin interface. This will ensure that the PlayPlugin is enabled for a project before adding its own settings.

src/main/scala/MyPlugin.scala:

import play.PlayPlugin

object MyPlugin extends sbt.AutoPlugin {
  def select = PlayPlugin

  // These will only be added to projects that have the play plugin settings added as well.
  def projectSettings = Seq(sbt.Keys.prompt := "awesome is enabled >")
}

User Story: User attempt to use a plugin which is not configured correctly.

  1. User add the sbt-pgp plugin to project/plugins.sbt:
addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "1.0")

User attempts to call a pgp task from a project where it is not enabled:

sbt>  publishSigned
error: publishSigned is not defined on project 'root'.
       This tasks is defined by the 'com.typesafe.sbt.SbtPgp' plugin but was not enabled.
       To enable, please add the following plugin(s):
       * sbt.plugins.IvyModule

User Story: user wants to create a C++ workflow that does not include the Java workflow

  1. User creates a 'root' plugin representing the core C++ features:
object CppPlugin extends RootPlugin {
   override def projectSettings = ...
   override def globalSettings = ...
}
  1. Create a helper project instantiation.
def cppProject(name: String, dir: File): Project =
    Project(name,file).disablePlugins(plugins.JvmModule).addPlugins(CppPlugin)

User Story: User wants to ensure the plugins contributing tasks can have users control the order.

Currently the order of plugin defined in project/plugins.sbt will be respected, except that plugins which depend on other plugins will have their settings added after their dependencies.

In addition, you can use the following pattern:

We have a pipeline of tasks to perform in an order:

case class PipelineStage(priority: Int, task: Task[Unit])

object PipelinerPlugin extends RootPlugin {
   val rawPipeline = settingKey[Seq[PipelineStage]]
   val pipeline = taskKey[Unit]
   override val projectSettings = Seq(
    rawPipeline := Nil,
    pipeline := (Def.taskDyn {
      rawPipeline.value.sortBy(_.priority).map(_.task).join
    }).value
   )
}

object PipelineStageExamplePlugin extends AutoPlugin {
  val stageExamplePriority = settingKey[Int]("my priority")
  val stageExampleAction = taskKey[Unit]("my task to do stuff")

  def select = PipelinerPlugin

  override val projectSettings = Seq(
     stageExamplePriority := 1,
     stageExampleAction := println("THIS is an example stage")
     rawPipeline += stageExamplePriority.value -> stageExampleAction.toTask.value
  )
}
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.