Skip to content

melix/gradle-buildscan-recipes

Build Scans Recipes Gradle Plugin

Build Status (travis) Apache License 2

This plugin enhances the information published in Build Scans with custom values and tags.

This sample Build Scan was generated using this plugin, for example, on Travis CI. This other one was generated locally, using this plugin too: you will notice that it is marked as dirty and shows the git status.

Usage

Build script snippet for use in all Gradle versions:

build.gradle
buildscript {
  repositories {
     maven {
        url "https://plugins.gradle.org/m2/"
     }
  }

  dependencies {
     classpath "com.gradle:build-scan-plugin:1.10.1"
     classpath 'me.champeau.gradle:buildscan-recipes-plugin:0.2.3'
  }
}

apply plugin: 'com.gradle.build-scan'
apply plugin: me.champeau.gradle.buildscans.RecipesPlugin

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

buildScanRecipes {
   recipes 'git-commit', 'git-status', 'teamcity', 'gc-stats'
}

Build script snippet for new, incubating, plugin mechanism introduced in Gradle 2.1:

build.gradle
plugins {
  id 'com.gradle.build-scan' version '1.10.1'
  id 'me.champeau.buildscan-recipes' version '0.2.3'
}

Configuration

The plugin provides a number of recipes that can be used to automatically add tags and custom values to Build Scans. The following recipes are available:

  • git-commit : Tries to determine the Git commit ID for the build

  • git-status : Outputs the result of git status, and tags the build as dirty if there are uncommitted or changes files locally

  • git-diff-to-gist : Pushes the result of git diff to a Gist and creates a link in the build scan to this diff

  • teamcity : Detects a build running under TeamCity, tags it as CI, and adds a link to the build

  • travis-ci : Detects a build running under Travis CI, tags it as CI and outputs information about the Travis environment

  • disk-usage : Shows information about Gradle disk usage. It will scan your $HOME/.gradle directory as well as your project directory. Note that depending on your disk type, OS, disk usage and file system, this can turn to be very slow and add a non negligeable time at build start. You should therefore use this recipe with care. This recipe only works on Linux and Mac OS.

  • gc-stats : Shows statistics about garbage collection happening during your build.

  • gist : Allows to use a recipe found in a GitHub Gist

  • remote : Allows to use a recipe found in any remote URL

  • file-leak-detection : Attemps to identify tasks which leak file handles (experimental)

Recipe specific parameters

git-commit

The git-commit recipe accepts an optional baseUrl parameter. If specified, a link to the commit will also be created. For example:

buildScanRecipes {
    recipe 'git-commit', baseUrl: 'https://github.com/melix/gradle-buildscan-recipes/tree'
}

git-diff-to-gist

This recipe will take the result of the git diff command and paste it as a Gist. By default, this will create a private Gist, but still be aware than anyone with the link can view the diff. For this recipe to work, you need a GitHub account and an API Token. We strongly recommend that you create a token specifically for this recipe, limited to the gist access rights. The recipe takes 3 optional parameters:

  • user is your GitHub username

  • token is your API token. If not specified explicitly, will look for a project property named "gistToken"

  • public (by default "false") tells if the Gist should be public ("true") or private ("false").

All those arguments are optional. For security reasons, we recommend not setting the user and token directly in your build file. For this reason, the recipe will by default search for a project property gistUsername for the username and gistToken for the token. You can set those properties in your home directory gradle.properties file:

~/gradle.properties
gistUsername=buildscansrulez
gistToken=github-generated-api-token

If you do this, the simples configuration looks like this:

buildScanRecipes {
   ...
   recipes 'git-diff-to-gist'
}

In addition, if you don’t want to systematically publish the diff, you can run with -PnoGist:

./gradlew -PnoGist someTask

teamcity

The teamcity recipe accepts 2 optional parameters:

  • baseUrl needs to be set to the CI server base URL

  • guest, if set, will generate a URL with anonymous login

file-leak-detection

This recipe will attempt to detect which tasks leak file handles (a leaking file handle is often referred to a file which is open but never closed). If a file is opened during a build, but never closed, subsequent builds may fail, dependending on your operating system, because of those. Typically, your build could fail removing a jar file because the previous build opened it, but never closed it. This is problematic in Gradle if you use the daemon, which is now on by default. So it is important to track which tasks do not properly close their files, so that you can either report to the plugin author (for tasks defined in a plugin) or fix your build.

The recipe works by loading a Java agent that will track file handles. If leaking files are detected, the build scan will report a LEAKING FILE HANDLES tag, and in custom values you will see each file that leaks a file, with the files and details as to where it happens (for debugging).

For example, imagine the following build file:

task foo1 {
   doLast {
      def fos = file('/tmp/foo1.txt').newOutputStream()
   }
}

task foo2 {
   doLast {
      def fos = file('/tmp/foo2.txt').newOutputStream()
      fos.close()
   }
}

The foo1 task is opening a file, but never closes it. The foo2 task, on the contrary, closes it properly. Here’s the resulting build scan. The details file contains the stack trace to the file open, so you could see:

...snip...
	at build_733t8o56jehucx5ms8s6ul86j$_run_closure6$_closure11.doCall(/home/cchampeau/DEV/PROJECTS/GITHUB/buildscan-recipes-plugin/test/build.gradle:67)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...snip...

And therefore find out where the file is opened and never closed.

This recipe is still experimental, as it could potentially detect files opened by Gradle, which are closed after a build is finished.

If the recipe is applied, it is still possible to avoid loading the agent and paying the overhead of detection by using -PdisableLeakDetection.

External recipes

In addition to the bundled recipes, it is possible to use recipes on external resources. The first recipe allows to reference another recipe found in a GitHub Gist:

gist

buildScanRecipes {
   recipe 'gist', user: 'melix',
                  id: '5944cb701d6c9650ecaccccd4642ea5f',
                  rev: '4b40b45559929ee2baaa7599e29dd78e51c3843a',
                  recipe: 'my-recipe',
                  // external recipe parameters
                  name: 'Bob'
}

The gist recipe accepts the following parameters:

  • user: username of the gist owner

  • id id of the gist

  • recipe name of the file containing the gist

  • rev revision of the gist. If absent, the compiled recipe will not be cached.

Any additional parameter will be passed to the remote recipe (here, the name parameter).

If the rev parameter is present, we’re pointing at a specific version of the Gist, so the recipe will fetch it only once, compile it and cache it in the $USER_HOME/.gradle/buildScanRecipes directory. If it is absent, it is going to point to HEAD, meaning that each time the recipe is called, it’s going to fetch it remotely, compile it, but it will not cache the result.

remote

As an alternative to the gist recipe, you can simply reference any remote URL, using the remote recipe:

   recipe 'remote',
          url: 'https://gist.githubusercontent.com/melix/5944cb701d6c9650ecaccccd4642ea5f/raw//my-recipe.groovy',
          cache: 'true',
          // external recipe parameters below:
          name: 'Bob'

This recipe will fetch the remote recipe, compile it, and cache it if and only if the cache flag is set to true. The recipe accepts 2 parameters:

  • url : the URL of the script, pointing at a Groovy recipe script

  • cache : if true, the URL will only be fetched the first time, then it will compile the script and subsequent executions will reuse the result, avoiding a network call and compile phase.

Any additional parameter will be passed to the remote recipe (here, the name parameter).

It’s worth noting that this recipe can be used to compile local recipes too, or to test recipes before you publish them on a Gist or anywhere else:

buildScanRecipes {
   recipe 'remote',
          url: file('recipes/my-awesome-recipe.groovy').toURL(),
          // local recipe parameters below
          name: 'Bob'
}

Adding recipes

Recipes are written in Groovy and can be found in the recipes directory. Note that the rules are statically compiled and expose 2 variables:

  • buildScan, of type BuildScanExtension, providing ability to tag a build scan, add a link, or add custom values

  • gradle, giving access to the Gradle instance of the build

  • params, a Map<String, String> of parameters (non-null, but maybe empty)

Recipes are bundled with this plugin.

About

A Gradle plugin for Build Scans

Resources

License

Apache-2.0, Apache-2.0 licenses found

Licenses found

Apache-2.0
LICENSE
Apache-2.0
LICENSE.txt

Stars

Watchers

Forks

Packages

No packages published