Build scans are an important tool for developing and maintaining Gradle builds. They provide insights into exactly what your builds are doing, helping you identify problems with the build environment, dependencies, performance, and more. They can also help you understand and improve the build more generally, and make collaborating with others easier.

build scan service overview
Figure 1. An overview of how build scans work

Gradle Cloud Services is hosted by Gradle Inc. and accessed through HTTPS. It can be used by anyone that agrees to the terms of service—see the setup instructions—and has an internet connection. Gradle Enterprise is a commercial product for companies that can be hosted on their own systems and provides some additional features on top of the ones available in Gradle Cloud Services. This manual covers both products and explains the differences between them in the relevant sections.

You can check out the build scan quick start project to get familiar with creating build scans before using them on your own projects.

Getting set up

There are two aspects to working with build scans:

  • Data collection

  • Publishing

You can have data collection without publishing the information, but you usually want to do both.

Here’s an example that enables the data collection—by applying the build scan plugin— and publishes a build scan every time you run the build:

Sample conventional Java build that always publishes build scans to Gradle Cloud Services
plugins {
    id 'com.gradle.build-scan' version '1.6'                    (1)
    id 'java'
}

version = '1.0'

buildScan {
    licenseAgreementUrl = 'https://gradle.com/terms-of-service' (2)
    licenseAgree = 'yes'                                        (2)

    publishAlways()                                             (3)
}
1 Applies the build scan plugin
2 Configures acceptance of the terms of service
3 Publishes a build scan every time a build runs

If that’s exactly what you require, then there’s no need to continue with the rest of the section as you can copy and paste the code from the above example. However, if you want to enable data collection for all your builds without changing their build files, publish to a Gradle Enterprise instance or use Gradle 2.0, then you should read on.

Let’s assume you want to publish build scans, not just collect the data. In that case, you need to:

  • Enable data collection by applying the build scan plugin (for a single build or all your builds)

  • Configure the publication target (Gradle Cloud Services or a Gradle Enterprise instance)

The next sections take you through all the relevant options related to these steps.

Applying the plugin

You can apply the build scan plugin to individual builds, or to all builds on a machine via an init script. Let’s take a look at the configuration you need for each of these scenarios.

For individual builds

You apply the build scan plugin to a build file in the same way that you apply any other plugin. If you’re using version 2.1 or later of Gradle, then we recommend this form:

Preferred option for Gradle 2.1 and above
plugins {
    id 'com.gradle.build-scan' version '1.6'
}

As a fallback, for example if you’re using Gradle 2.0, then you can use the older mechanism for applying plugins:

For Gradle 2.0 and above (build scans are unsupported by earlier versions of Gradle)
buildscript {
    repositories {
        maven { url 'https://plugins.gradle.org/m2/' }
    }

    dependencies {
        classpath 'com.gradle:build-scan-plugin:1.6'
    }
}

apply plugin: 'com.gradle.build-scan'

We recommend you always use the latest version of the plugin, which you can find on the Gradle Plugin Portal. That page will also show you what’s new in each version of the plugin.

If you are publishing build scans to a Gradle Enterprise instance you must use a compatible version of the plugin. See Plugin compatibility with Gradle Enterprise for details.

Regardless of which syntax you use to apply the plugin, make sure you declare it before any other plugin. This ensures that any relevant configuration data from those plugins is included in the build scans. For example, prefer this:

plugins {
    id 'com.gradle.build-scan' version '1.6'
    id 'java'
}

over this

plugins {
    id 'java'
    id 'com.gradle.build-scan' version '1.6'
}

The order used by the second example won’t break the build scans that you publish, but they will be missing useful information.

The build scan plugin must be applied to the root project only, not to subprojects.

For all your builds

You may find build scans so useful that you want to enable them always, regardless of which build you are running. If that’s the case, you can create a Gradle init script that automatically applies the build scan plugin to every build. Here’s an example init script that you can use to do just that:

~/.gradle/init.d/buildScan.gradle
initscript {
    repositories {
        maven { url 'https://plugins.gradle.org/m2' }
    }

    dependencies {
        classpath 'com.gradle:build-scan-plugin:1.6'
    }
}

rootProject {
    apply plugin: com.gradle.scan.plugin.BuildScanPlugin
}

Note The ~ in the file path for the init script represents the absolute path to your user home directory. This is the same as the %UserProfile% environment variable on Windows.

Applying the plugin enables the data collection, but you won’t be able to publish build scans until you’ve added some extra configuration. What that configuration looks like depends on where you want to publish those build scans.

Enabling publication of build scans

The last bit of configuration you need depends on whether you are publishing to Gradle Cloud Services or a Gradle Enterprise instance. In the case of the former, you need to accept the terms of service. The latter requires you to specify the service’s location.

Accept the terms of service

There is no interactive option to accept the terms of service when you attempt to publish a build scan to Gradle Cloud Services. Instead, you have to do indicate your acceptance in advance by setting the appropriate build scan plugin options.

To accept the terms of service, add the following configuration to the build script—or the rootProject {} block of the init script if you’re using that approach—ensuring that it appears after the plugin is declared/applied:

Accepting the GCS license agreement in your build or init script
buildScan {
    licenseAgreementUrl = 'https://gradle.com/terms-of-service'
    licenseAgree = 'yes'
}

Before committing to this, be sure to check the terms of service at the URL shown in the above code fragment. Note that if you don’t accept the terms of service, you won’t be able to publish build scans to Gradle Cloud Services.

Once your build file or init script contains these two lines, you’re ready and can start publishing build scans to Gradle Cloud Services.

Set the location of your Gradle Enterprise instance

When you publish build scans to a Gradle Enterprise instance, you don’t need to include the license agreement settings. Instead, you must tell the build scan plugin where to publish the build scans.

Add the following configuration to the build script—or the rootProject {} block of the init script if you’re using that approach—ensuring that it appears after the plugin is declared or applied:

Specifying a custom server for build scans
buildScan {
  server = 'https://gradle.my-company.com'
}

The precise URL you need depends on the hostname your Gradle Enterprise instance has been configured with. If in doubt, be sure to ask whomever manages that instance.

You may encounter a warning about an untrusted certificate every time you try to publish a build scan to an HTTPS URL. The ideal solution is for someone to add a valid SSL certificate to the Gradle Enterprise instance, but we recognise that you may not be able to do that. In which case, set the allowUntrustedServer option to true:

Disabling SSL certificate checks
buildScan {
    server = '...'
    allowUntrustedServer = true
}

This is a convenient workaround, but you shouldn’t use it as a long-term solution.

Controlling when scans are published

Once you’ve gone through the initial setup of the previous section, you’re ready to start publishing build scans. But when should you publish them? Every time you run a build? Only when the build fails? It’s up to you. The build scan plugin has several options that allow you to use whatever approach works best.

Publishing on demand

We imagine that when you first start experimenting with build scans, you won’t want to publish them all the time until you become familiar with the implications. Even then, you may have good reason not to go all-in and automate the process. That’s where one-off, or ad-hoc, build scans come in.

As long as build scans are enabled for a build, you can publish one by passing a scan system property to Gradle. For example, each of the following will result in a published build scan:

$ gradle assemble -Dscan
$ gradle clean build -Dscan

Behind the scenes, Gradle captures information about the build while it runs and then publishes the data to the configured Gradle Build Scan Service at the end.

There may be occasions when you want to publish a build scan for the previous run. Perhaps you noticed something interesting about the build from its output and would like to review a build scan for it. The build scan plugin supports this situation by providing a buildScanPublishPrevious task that publishes the data that was collected from the previous run:

$ gradle buildScanPublishPrevious

Since the task name is quite long, it’s worth taking advantage of Gradle’s abbreviated command line notation for tasks:

$ gradle bSPP

Be aware that the task only works for the previous build execution, so if you remember too late and want to publish the build scan for three builds ago, you’ll need to run the build again. At that point, you should consider automating the publication of build scans.

Publishing every build run

There are advantages to publishing build scans regularly, such as being able to track the behavior and performance of a build over time. It makes no sense relying on the scan system property in such a situation as it’s easy to forget this little tweak to the command line.

When you want to publish every build run, you can use the publishAlways setting:

Publishing a build scan for every build execution
buildScan {
    publishAlways()
}

This approach means that you get a build scan for every successful and failed build that runs, including from your continuous integration infrastructure and your developers. That may work for you, but if you find it overwhelming or simply not useful, add some publication criteria as demonstrated in the following section.

Publishing based on criteria

Many of you will want a bit more control over exactly when build scans are published without resorting to using -Dscan each time. Perhaps you only want to publish build scans when the build fails, or if the build is running on your continuous integration infrastructure. Such scenarios are covered by the options in the following table.

Table 1. Options for automatic publishing based on criteria
Option Description

publishAlwaysIf(boolean)

Publish a build scan if the given condition is true, regardless of whether the build succeeds or fails.

publishOnFailure()

Publish a build scan only when the build fails.

publishOnFailureIf(boolean)

Publish a build scan only if the condition is true and the build fails.

For example, let’s say you only want to publish build scans from your CI system, which is identified by having a CI environment variable. This configuration will do the trick:

Restricting build scans to a CI system
buildScan {
    publishAlwaysIf(System.getenv('CI'))
}

You can use the other options in the same way. If you want to configure several things based on a set of criteria, you can use an if condition instead:

buildScan {
    if (System.getenv('CI')) {
        publishAlways()
        tag 'CI'
    }
}

Extending build scans

(build scan plugin v1.1+)

You can easily include extra custom information in your build scans in the form of tags, links and values. This is a very powerful mechanism for capturing and sharing information that is important to your build and development process.

This information can be anything you like. You can tag all builds run by your continuous integration tool with a CI tag. You can capture the name of the environment that the build published to as a value. You can link to the source revision for the build in an online tool such as GitHub. The possibilities are endless.

You can see how the custom data appears in figure 2:

scan with custom data
Figure 2. A build scan containing the different types of custom data

Gradle Enterprise allows listing and searching across all of the build scans in the system. You can find and filter build scans by tags and custom values, in addition to project name, outcome and other properties. In figure 3, for example, we are filtering for all scans that have the tag "CI" and a git branch name of "master":

build scan filtered list
Figure 3. A filtered list of build scans in Gradle Enterprise

Adding tags

Tags are typically used to indicate the type or class of a build, or a key characteristic. They are prominent in the user interface and quickly inform a user about the nature of a build. A build can have zero or more tags.

They can be added at build time via the tag() method:

Adding tags to a build’s scans
buildScan {
    if (System.getenv('CI')) {
        tag 'CI'
    } else {
        tag 'Local'
    }

    tag System.getProperty('os.name')
}

As demonstrated by the example above, tags are typically applied either as fixed strings within a conditon or evaluated at runtime from the environment. But there are no set rules that you need to follow—these are only suggestions.

The syntax for adding a tag is:

tag <label>

where the label is a string.

Note that the order in which you declare the tags doesn’t affect the build scan view. They are displayed in alphabetical order, with any all-caps labels displayed before the rest.

Builds rarely live in isolation. Where does the project source live? Is there online documentation for the project? Where can you find the project’s issue tracker? If these exist and have a URL, you can add them to the build scan.

They can be added at build time via the link() method:

Adding a VCS URL to a build’s scans
buildScan {
    link 'VCS', 'https://github.com/myorg/sample/tree/${System.getProperty('vcs.branch')}'
}

The above example demonstrates how you can attach a link to an online VCS repository that points to a specific branch provided as a system property.

The syntax for adding a link is:

link <label>, <URL>

The label is simply a string identifier that you choose and that means something to you.

You can see the effect of a custom link in figure 2, which shows how a label Source becomes a hyperlink that anyone viewing the build scan can follow.

Adding custom values

Some information just isn’t useful without context. What does "1G" mean? You might guess that it represents 1 gigabyte, but of what? It’s only when you attach the label "Max heap size for build" that it makes sense. The same applies to git commit IDs, for example, which could be interpreted as some other checksum without a suitable label.

Custom values are designed for these cases that require context. They’re standard key-value pairs, in which the key is a string label of your choosing and the values are also strings, often evaluated from the build environment.

They can be added at build time via the value() method:

Adding custom values to a build’s scans
buildScan {
    value 'Build Number', project.buildNumber
}

The above example demonstrates how you can read the build number from a project property—assuming you have your build set up for this—and attach it to the build scans as a custom value.

The syntax for adding a value is:

value <label>, <value>

where both the label and the value are strings.

As with tags, you can filter build scans by custom values in Gradle Enterprise.

Adding data at the end of the build

(build scan plugin v1.2+)

The examples you have seen so far work well if when the custom data is available at the beginning of the build. But what if you want to attach data that’s only available later? For example, you might want to label a build as "built-from-clean" if the clean task was run. But you don’t know if that’s the case until the task execution graph is ready.

The build scan plugin provides a buildFinished() hook that you can use for these situations. It defers attaching custom data until the build has finished running. As an example, imagine you want to report how much disk space was taken up by the output build directory. The build doesn’t know this until it’s finished, so the solution is to calculate the disk space and attach it to a custom value in the buildFinished() hook:

Adding a custom disk usage value at the end of the build
buildScan {
    buildFinished {
        value 'Disk usage (output dir)', buildDir.directorySize()
    }
}

The buildFinished() closure has access to the rest of the build, including the Project instance, so it can extract all sorts of information. It also has access to a BuildResult instance that you can use to determine whether the build failed or not, like so:

Checking build status from buildFinished()
import com.gradle.scan.plugin.BuildResult
...
buildScan {
    buildFinished { BuildResult result ->
        if (result.failure) {
            value 'Failed with', result.failure.message
        }
    }
}
The Gradle build tool has a BuildListener interface that also contains a buildFinished() hook. However, you cannot use this to attach custom data because it is triggered too late. You can use hooks like project.afterEvaluate() or the buildStarted() method of BuildListener because they are executed early enough.

Providing custom data via system properties

(build scan plugin v1.3+)

The examples up to this point have shown how your build file or init script can pull information from the environment, via environment variables and system properties. The build scan plugin also allows you to inject any form of custom data through the use of specially named system properties. This can help you keep your build files clean of too much environment-specific information that may not be relevant to most of the users of the build.

These system properties take the following forms, depending on whether you want to inject a link, a tag or a custom value:

-Dscan.tag.<label>
-Dscan.link.<label>=<URL>
-Dscan.value.<label>=<value>

Here are some concrete examples, which assume that the build has been configured to publish build scans automatically:

$ gradle build -Dscan.tag.CI
$ gradle build -Dscan.link.VCS=https://github.com/myorg/my-super-project/tree/my-new-feature
$ gradle build "-Dscan.value.CI Build Type=QA_Build"

This feature is particularly useful for continuous integration builds as you can typically easily configure your CI tool to specify system properties for a build. It’s even common for CI tools to be able to inject system properties into a build that are interpolated with information from the CI system, such as build number.

$ gradle build "-Dscan.value.buildNumber=$CI_BUILD_NUMBER"

Appendix A: Plugin compatibility with Gradle Enterprise

When using the build scan plugin in conjunction with a Gradle Enterprise instance you must ensure you are using a compatible plugin version. Scans created using a plugin version later than the maximum version supported by your Gradle Enterprise instance will be rejected.

Table 2. Gradle Enterprise maximum supported plugin versions
Gradle Enterprise versions Minimum plugin version Maximum plugin version

2016.0 - 2016.2

1.0

1.0.x

2016.3

1.0

1.1.x

2016.4

1.0

1.3.x

2017.1

1.0

1.6.x