Tasks & Settings

Task and Settings are the core building blocks of our build, which is a graph representing the dependencies between tasks and settings. Both, tasks and settings, return values. This allows use to depend on the actual return value of a task or setting and not on the possible side-effects of a task/setting.

We will use the empty build.sbt we created in the previous step and insert all the following snippets there.

In this section we will configure our build with some basic information.

Operators

Assign settings or tasks

SBT defines a single operator with which you can configure any setting or task. Because a setting or task can depend on other settings or tasks a simple assignment operator wouldn't be sufficient.

taskOrSettingKey := ???

The := is SBT's assignment operator. We will use it throughout this section to customize our build.

Get a setting or task value

If a task or setting needs the value of another task or setting, we need to access it's value. We do this by calling .value on the setting or task. We can assign values from one setting or task to another.

taskA := taskB.value

Settings

A setting is a static value that is configured once and does not change. Because of this constraint a setting can only depend on other settings, never on a task.

SBT defines a lot of settings by default that every build needs. First we will set the name of our project, the version and an organization.

name := "Hello World"
scalaVersion := "2.12.2"

We start sbt and see the effect of our changes

$ sbt

To display the value of a setting or task we use the show command. show takes the setting or task key as the first argument.

> show name
[info] Hello World

We can get a list of the most important settings with the settings command.

> settings

Exercise

Beginner

Configure the organization setting to com.example and the version _to 1.0-SNAPSHOT_.

Advanced

Configure the organization setting to com.example. The version setting that

  • if the environment variable _BUILD_NUMBER is set, the version is 1.BUILD_NUMBER
  • otherwise it's 1.0-SNAPSHOT

Hint: Write simple scala code. Use the sys.env property map to access environment variables.


Tasks

A task defines a dynamically generated output. Tasks define how source files are compiled, resources generated or packages bundled. A task can depend on settings or other tasks to perform its action.

We start with compiling our project sources

> compile
[success] Total time: 1 s, completed 01.05.2017 18:36:13

When we use the show command, sbt displays the output of compile

> show compile
[info] Analysis: 1 Scala source, 3 classes, 2 binary dependencies
[success] Total time: 0 s, completed 01.05.2017 18:52:51

Change an existing task

Before we define custom tasks, we learn how to change existing ones. The easiest change is to override a task with itself.

compile := compile.value

We define the compile task with the value of the existing compile task. If the task output types don't match, SBT won't compile.

Extend a task

Now we do a bit more. We override the packageBin task that creates a binary artifact and log the size of the created jar file.

packageBin := {
  // depend on the current packageBin file
  val jarFile = packageBin.value

  // sbt logging accessible via the streams task
  val log = streams.value.log

  log.info(s"jar file size: ${jarFile.length} byte")

  // return the jar file
  jarFile
}

We depend by accessing the.value of a task on two tasks in our custom implementation. The original packageBin definition and the streams tasks. This dependency is reflected in our build ( which is a dependency graph for settings and tasks ). So both tasks are executed before our new packageBin tasks is evaluated.

Create a dependency between two tasks

You can add a dependency explicitly if the task itself doesn't depend on the other task. This is useful if you have side effects that can't be managed otherwise. Imagine we have an external build step like yarn install and yarn test. We want to make sure that install is called before test. Fore simplicity we assume these two tasks are already defined as yarnTest and yarnInstall.

yarnTest := (yarnTest dependsOn yarnInstall).value

A task can dependOn another task. This doesn't change the output of the initial yarnTest task and only creates a dependency. To assign the output of the old yarnTest we access it with .value and assign it to the new yarnTest definition.

Define a new task

This is covered in depth in the AutoPlugins section. The API is

// inlined in a sbt file
lazy val newTask = taskKey[String]("a task returning a string")

// in an AutoPlugin
val newTask = TaskKey[String]("new-task", "a task returning a string")

Exercise

Beginner

Find the task that runs the main method in your project.

Advanced

Find the task that runs the main method in your project. Create a second main class and try to rerun.
Find another task that takes the main class you want to execute.

results matching ""

    No results matching ""