Nigel Eke
Nigel Eke

Reputation: 531

Running custom sbt plugin task for one project in a multi-project build.sbt

I am writing a custom sbt plugin, whose tasks are intended to target specific projects from another multi-project.

Note that the 'plugin' and 'multi-project' client are two separate projects, so the plugin gets published (locally) and then used via an addSbtPlugin in the multi-project's plugins.sbt file.

The build.sbt for the multi-project client is:

val scala3Version = "3.3.0-RC3"

organizationName := "Nigel Eke"
organization     := "nigeleke"

lazy val root = project
  .in(file("."))
  .settings(
    name           := "sbt-example-client",
    publish / skip := true
  )
  .aggregate(core, client)

lazy val core = project
  .settings(
    name         := "core",
    scalaVersion := scala3Version
  )

lazy val client = project
  .enablePlugins(MyPlugin)
  .settings(name := "client")

where my custom plugin is only intended for the client project.

A minimal plugin example is:

package nigeleke.sbt

import sbt.*
import Keys.*

import scala.sys.process.*

object MyPlugin extends AutoPlugin {

  object autoImport {
    val myTask = taskKey[Unit]("Do something.")
  }

  import autoImport._

  override def requires = empty

  override def trigger = allRequirements

  override lazy val projectSettings = Seq(
    myTask := {
      println(s"project: ${thisProject.value.id}  plugins: ${thisProject.value.plugins}")
    }
  )

}

When I go back to the multi-project client and run sbt myTask I get the following output:

project: client  plugins: nigeleke.sbt.MyPlugin
project: root  plugins: <none>
project: core  plugins: <none>

This indicates to me that the plugin code is being called for all projects, regardless whether it has been enabled or not. My expectation was that it would only be called for those in which it is enabled.

I would appreciate some help regarding why this expectation appears incorrect.

Secondly: the custom plugin can see that it is enabled by referencing the thisProject.value.plugins attribute. The only way I can see to "test" this is to convert thisProject.value.plugins to a string and see if it contains "nigeleke.sbt.MyPlugin". I'd like to do this in a more typesafe manner though, but that doesn't appear to be possible.

Upvotes: 2

Views: 137

Answers (1)

Nigel Eke
Nigel Eke

Reputation: 531

I amended the trigger override to noTrigger and myTask worked as expected.

package nigeleke.sbt

import sbt.*
import Keys.*

import scala.sys.process.*

object MyPlugin extends AutoPlugin {

  object autoImport {
    val myTask = taskKey[Unit]("Do something.")
  }

  import autoImport._

  override def requires = empty

  override def trigger = noTrigger

  override lazy val projectSettings = Seq(
    myTask := {
      println(s"project: ${thisProject.value.id}  plugins: ${thisProject.value.plugins}")
    }
  )

}

The trigger method takes a parameter of type PluginTrigger, which is a sealed trait that defines the possible values that can be used to trigger the plugin. Values are

  • allRequirements:

    This is the default value and indicates that the plugin should be triggered for all projects in the build. This means that the plugin will be automatically enabled for all projects, regardless of whether they explicitly enable it or not.

  • noTrigger:

    This value indicates that the plugin should not be triggered automatically for any projects. Instead, projects must explicitly enable the plugin using enablePlugins.

  • some:

    This value allows you to specify a list of other plugins that must be enabled for the plugin to be triggered. For example, if you set trigger to some(Seq(pluginA, pluginB)), then your plugin will only be triggered if both pluginA and pluginB are also enabled for the project.

[This response was elicited with the help of ChatGPT]

Upvotes: 3

Related Questions