Cookbook


about this cookbook

This page will contain short information on "how to do X, Y and Z using Gradle". It is not a Gradle tutorial, nor is it a comprehensive source of knowledge. The aim of this cookbook is to give you fast answers to your urgent needs.


It differs both from the the userguide (which contains so much information that it is sometimes hard to find interesting bits) and from the FAQ (which says what can be done with Gradle, but does not explain how to do it).

How can you help ?

  • Add new information here (for example if you find an interesting topic on the mailing lists).
  • Make sure that the existing information are still valid (maybe the latests version of Gradle makes things easier ?).
  • Correct mistakes, errors and typos.

general issues

problems after upgrade to newer version of Gradle

If something doesn't work after you upgraded Gradle, please have a look at "breaking changes" sites:


plugins

Information on plugins (apart from what is described in the userguide).

ClassLoader plugin

tbd. short info on what is the purpose ?

author: Robert Fisher
how-to available at: http://github.com/RobertFischer/gradle-plugins/blob/master/README.md

Exec plugin

Allows to execute shell commands.

author: Robert Fisher
how-to available at: http://github.com/RobertFischer/gradle-plugins/blob/master/README.md

Env plugin

Allows easy access to environment variables.

author: Robert Fisher
how-to available at: http://github.com/RobertFischer/gradle-plugins/blob/master/README.md

Example of a simple custom task within buildSrc

In your build.gradle, add

task copyToLib(type: CopyToLib)

and put the class in buildSrc/src/main/groovy

CopyToLib.groovy
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction

class CopyToLib extends DefaultTask {

    CopyToLib() {
        dependsOn("jar")
    }

    @TaskAction
    def run() {
        libDir = project.file('build/output/lib')
        libDir.mkdirs()
        project.configurations.default.each { File file ->
            ant.copy(file: file.path, toDir: libDir)
        }
        project.configurations.default.allArtifacts.each { artifact ->
            ant.copy(file: artifact.file, todir: libDir)
        }
    }

}

and then you can do

gradle copyToLib

web development

Small but useful hints on web development.

creation of exploded war

To create an exploded war simply add this snippet to build.gradle:

build.gradle
war.doLast {
  ant.unzip(src: war.archivePath, dest: "$buildDir/exploded")
}

running selenium tests

tbd.


missing features

This section gathers description of how to achieve things that users of other build tools might expect to be available "out of the box".

Hopefully this is the only section of this cookbook that will shrink over time till it vanishes completely...

running things from Gradle

If you need functionality a'la exec-maven-plugin:

build.gradle
ant.java(classname: 'com.my.classname', fork: true,
         classpath: "${sourceSets.main.runtimeClasspath.asPath}")

running single tests

As of Gradle 0.8, you need to write some code to allow a single test to be run. Here is an example which allows you to specify an Ant-style pattern to select which tests to run:

build.gradle
test {
    if (project.hasProperty('testPattern')) {
        include testPattern
    }
}

Then, you can run gradle test -PtestPattern=**/SomeTest.*

Please check this JIRA issue.

Creating source and resource directories

You've just created a new Java project but you're too lazy to create the source and resource directory layout. This code does that for you:

build.gradle
usePlugin 'java'

convention.sourceSets.all*.java.srcDirs*.each { it.mkdirs() }
convention.sourceSets.all*.resources.srcDirs*.each { it.mkdirs() }

Creating GroovyEclipse project files

For use with http://groovy.codehaus.org/Eclipse+Plugin

build.gradle
    if (plugins.findByName('groovy')) {        eclipseCp.doFirst {
            eclipseCp.srcDirs += sourceSets.main.groovy.srcDirs
            eclipseCp.testSrcDirs += sourceSets.test.groovy.srcDirs
        }

        eclipseProject.doLast {
            def projectFile = project.file(eclipseProject.PROJECT_FILE_NAME)

            def reader = new org.dom4j.io.SAXReader()
            def doc = reader.read(projectFile)
            def natures = doc.selectSingleNode('/projectDescription/natures')
            natures.addElement('nature')
                .addText('org.eclipse.jdt.groovy.core.groovyNature')
            // Eclipse pulls the decoration from the first nature. Make groovy be first.
            natures.setContent(natures.content().reverse())

            def writer = new org.dom4j.io.XMLWriter(projectFile.newWriter(), org.dom4j.io.OutputFormat.createPrettyPrint())
            writer.write(doc)
            writer.close()
        }
    }

Dependencies

Everything you wanted to know about the dependencies ...but were afraid to read the whole userguide.

Creating a fat jar

For Gradle 0.9 you will need to ... tbd.

For Gradle 0.8 you can use the following code to modify the jar task to create a fat jar containing all class files from libs in your compile dependencies:

jar.doFirst {
    for(file in configurations.compile) {
        jar.merge(file)
    }
}

Include all runtime dependencies

For Gradle 0.9 you will need to ... tbd.

For Gradle 0.8
The above snippet will only include the compile dependencies for that project, not any transitive runtime dependencies. If you also want to merge those, you can use the following snippet:

jar.doFirst {
    for(file in configurations.runtime.resolve()) {
        jar.merge(file)
    }
}

Gathering all dependencies (libs) in one folder

For gradle 0.8:

task copyToLib(dependsOn: configurations.default.buildArtifacts, type: Copy) {
    into('build/output/lib')
    from configurations.default
    from configurations.default.allArtifacts*.file
}

For gradle 0.7 the internal repository doesn't have versions in the jar file name, so we fish it out of the path.

task copyToLib(dependsOn: uploadDefaultInternal) << { task ->
        libDir = task.project.file('build/output/lib')
        libDir.mkdirs()
        task.project.configurations.default.each { File file ->
            outFile = ''
            splitPath = file.path.split("/")
            if (splitPath[-6] == 'internal-repository') {
                outFile = splitPath[-4]+'-'+splitPath[-3]+'.jar'
            } else {
                outFile = file.name
            }
            ant.copy(file: file.path, toFile: new File(libDir, outFile))
        }        task.project.configurations.default.allArtifacts.each { artifact -> ant.
copy(file: artifact.file, todir: libDir) }
    }

Graphviz dependency report

tbd.

Custom repository structure and its access patterns

Sample repository structure:

... librepo/groovy/1.6-RC-1/groovy-all-1.6-RC-1.jar

Reference to the repository:

build.gradle
repositories {
  add(new org.apache.ivy.plugins.resolver.URLResolver()) {
    name = 'Repo'
    addIvyPattern 'http://www.your.server/librepo/([organization]/)[module]/([revision]/)[artifact](-[revision])(-[classifier]).[ext]'
    addIvyPattern 'http://www.your.server/librepo/([organization]/)[module]/([revision]/)[artifact](-[classifier]).[ext]'
    addIvyPattern 'http://www.your.server/librepo/([organization]/)[module]/[artifact](-[revision])(-[classifier]).[ext]'
    addArtifactPattern 'http://www.your.server/librepo/([organization]/)[module]/([revision]/)[artifact](-[revision])(-[classifier]).[ext]'
    addArtifactPattern 'http://www.your.server/librepo/([organization]/)[module]/([revision]/)[artifact](-[classifier]).[ext]'
    addArtifactPattern 'http://www.your.server/librepo/([organization]/)[module]/[artifact](-[revision])(-[classifier]).[ext]'
    descriptor = 'Lib repo'
  }

This is technically using module artifact and revision (although gradle really wants to utilize organisation, module and revision).
The IVY tags within parens are optional (meaning they only get filled in if they are provided by default).

Usage is then:

build.gradle
dependencies { 
  compile(':groovy:1.6-RC-1') { 
    artifact { name='groovy-all' ; type='jar' } 
  } 
} 

One needs to specify the explicit type for an artifact (and artifacts are mostly hidden within gradle and there aren't many good examples of using them). There is no "short-form" specification that utilizes artifact names. (Notice that organization isn't being filled in, since the ':' comes first.)

Using the 3 patterns above this would look in:

groovy/1.6-RC-1/groovy-all-1.6-RC-1.jar 
groovy/1.6-RC-1/groovy-all.jar 
groovy/groovy-all-1.6-RC-1.jar 

One can utilize the recommended pattern, but that means "groovy" is the organization, and "groovy-all" the module. Gradle contains all the resolving power (and more) of IVY, but it tries hard to constrain its use to Maven resolving patterns.

How to refer to multiple artifacts within the same module

Sample repository structure:

... librepo/apache-river/2.1.1/jsk-platform.jar
... librepo/apache-river/2.1.1/jsk-lib.jar
... librepo/apache-river/2.1.1/mahalo.jar

When artifacts's naming do not follow a regular pattern, here is a solution:

build.gradle
dependency(':apache-river:2.1.1') { 
     artifact { name='jsk-platform' ; type='jar' } 
     artifact { name='jsk-lib' ; type='jar' }
     artifact { name='mahalo' ; type='jar' } 
}

Gradle does not keep it's mapping based upon artifacts but rather at the module level, so the code below will not work, only the first one is resolved, further ones are ignored:

build.gradle
dependency(':apache-river:2.1.1') { 
     artifact { name='jsk-platform' ; type='jar' } 
}
dependency(':apache-river:2.1.1') { 
     artifact { name='jsk-lib' ; type='jar' } 
}

Ant integration

Some tips&tricks on Ant integration not covered by the userguide.

tbd.


Maven2 integration

Some tips&tricks on Maven2 integration not covered by the userguide.

use local Maven2 cache repository

To download artifacts from local Maven2 cache repository (by default $HOME/.m2/repository) do the following:

build.gradle
repositories {
  mavenRepo urls: "file://" + System.getProperty('user.home') + "/.m2/repository/"
}

translate Maven2 dependencies to Gradle dependencies

There is no such functionality (yet). Please take a look at this JIRA link to learn what is the status of this issue.


3rd party tools

This section explains how to use various tools (like Cobertura, PMD, Findbugs) from Gradle.

In general, if the tool you intend to use has Ant task, than go for it !

Please notice, that there are some efforts to make 3rd party tools easier accessible from Gradle, so check out this JIRA issue to make sure that no better solution exists.

using Cobertura

For Gradle 0.8 you can follow this example:

build.gradle
usePlugin('java')

def cobSerFile="${project.buildDir}/cobertura.ser"
def srcOriginal="${sourceSets.main.classesDir}"
def srcCopy="${srcOriginal}-copy"

repositories {
    mavenCentral()
}

dependencies {
        testRuntime 'net.sourceforge.cobertura:cobertura:1.9.3'
        testCompile 'junit:junit:4.5'
}

test.doFirst  {
    ant {
        // delete data file for cobertura, otherwise coverage would be added
        delete(file:cobSerFile, failonerror:false)
        // delete copy of original classes
        delete(dir: srcCopy, failonerror:false)
        // import cobertura task, so it is available in the script
        taskdef(resource:'tasks.properties', classpath: configurations.testRuntime.asPath)
        // create copy (backup) of original class files
        copy(todir: srcCopy) {
            fileset(dir: srcOriginal)
        }
        // instrument the relevant classes in-place
        'cobertura-instrument'(datafile:cobSerFile) {
            fileset(dir: srcOriginal,
                   includes:"my/classes/**/*.class",
                   excludes:"**/*Test.class")
        }
    }
}

test {
    // pass information on cobertura datafile to your testing framework
    // see information below this code snippet
}

test.doLast {
    if (new File(srcCopy).exists()) {
        // replace instrumented classes with backup copy again
        ant {
            delete(file: srcOriginal)
            move(file: srcCopy,
                     tofile: srcOriginal)
        }
        // create cobertura reports
        ant.'cobertura-report'(destdir:"${project.buildDirName}/test-results",
             format:'html', srcdir:"src/main/java", datafile:cobSerFile)
    }
}

As you can see Cobertura Ant Task is used.

Don't forget to tell JUnit/TestNG where the cobertura.ser file is !

TestNG example:

build.gradle
test {
  useTestNG()
  options {
    jvmArgs << "-Dnet.sourceforge.cobertura.datafile=${cobSerFile}"
  }
}

JUnit example:

build.gradle
test {
  options.systemProperties['net.sourceforge.cobertura.datafile']="${cobSerFile}"
}

Example of Cobertura integration for Gradle 0.6 can be found here.

using Findbugs

The script below uses Findbugs Ant task. One thing is worth noticing. Because class is a reserved word in Groovy it must be surrounded by quotes: "class".

Of course you need to change values of home and location attributes.

build.gradle
configurations {
    findbugsConf
}

dependencies {
    findbugsConf 'net.sourceforge.findbugs:findbugs:1.3.2', 'net.sourceforge.findbugs:findbugs-ant:1.3.2'
}

task findbugs << {
    println 'Running findbugs static code analysis'
    ant {
        taskdef(name:'findbugs', classname:'edu.umd.cs.findbugs.anttask.FindBugsTask', classpath: configurations.findbugsConf.asPath)

        findbugs(home: '/home/tomek/bin/findbugs', output:'xml') {
                sourcePath(path: 'src/main/java')
                "class"(location: 'build/libs/findbugs-unspecified.jar')
        }
    }
}

Alternative Findbugs using subproject injection

Thanks to the initial Findbugs cookbook pattern, I was able to generate a more complex version that creates a single ant taskdef that is then utilized by all subprojects (a version that selectively injects this task if and only if there is a jar task for the subproject would be more robust).

Aside from having to put findbugs in a flat-file repository some place there are no values that need to be adjusted. I was toying with adding explicit dependencies upon the missing jars (annotations.jar, asm-3.1.jar, asm-analysis-3.1.jar, asm-commons-3.1.jar, asm-tree-3.1.jar, asm-util-3.1.jar, asm-xml-3.1.jar, bcel.jar, commons-lang-2.4.jar, dom4j-1.6.1.jar, jFormatString.jar, jaxen-1.1.1.jar, jsr305.jar), but haven't done so yet.

At some point I'd like to turn this into a real plugin, but haven't done so yet, and would be glad for someone to clean up and/or simplify this solution.

build.gradle
task findbugsSetup {
  configurations  {
    findbugsConf
  }

  dependencies {
    findbugsConf('edu.umd.cs:findbugs:1.3.9') {
      artifact { name = 'findbugs' ; type = 'jar' }
      artifact { name = 'findbugs-ant' ; type = 'jar' }

      // REVISIT: findbugs.jar expects to find all other jars next to it,
      //          but an explicit path to files where they belong would
      //          be the better long term solution
    }
  }

  ant {
    taskdef(name:'findbugs',
            classname:'edu.umd.cs.findbugs.anttask.FindBugsTask',
            classpath: configurations.findbugsConf.asPath)

    findbugsJarFiles = configurations.findbugsConf.resolve()

    findbugsHome = 'NOT_FOUND'
    findbugsJarFiles.each() {
      jarPath ->
      if (jarPath.getName().equalsIgnoreCase('findbugs.jar')) {
        findbugsHome = jarPath.getParentFile().getCanonicalPath()
      }
    }
  }
}

subprojects {
  task findbugs(dependsOn: ['jar', ':findbugsSetup'],
                description: 'Invokes findbugs on generated jar file.') << {
    Task myTask ->

    proj = myTask.project

    outDir = new File(proj.buildDir.toString() + '/reports/findbugs')
    outFile = outDir.toString() + '/findbugs.xml'
    jarFile = "${proj.libsDir}/${proj.jar.archiveName}"

    if (! new File(jarFile).exists()) {
        myTask.logger.warn("Warning: skipping findbugs as {} does not exist",
                           jarFile)
        return
    }

    ant {
      uptodate(property: 'findbugsUpToDate',
               srcfile: jarFile,
               targetFile: outFile)
    }

    if ("true".equals(ant.properties.findbugsUpToDate)) {
      return
    }

    outDir.mkdirs()

    project(':').ant {
      // NOTE: class is reserved so put into double quotes
      findbugs(home: findbugsHome,
               output: 'xml',
               outputFile: outFile,
               jvmargs: '-Xmx256m') {
        auxClasspath(path: proj.configurations.runtime.asPath)
        sourcePath(path: proj.files(proj.sourceSets.main.java.srcDirs).asPath)
        "class"(location: jarFile)
      }
    }
  }
}

using PMD

This recipe is based on Mockito build script.

The script below does nothing special - inside "pmd" task it defines new Ant task 'pmd' and then configures it (see
PMD Ant task for explanation). It assumes, that rules are stored in conf/pmd-rules.xml file.

build.gradle
configurations {
    pmdConf
}

dependencies {
    pmdConf 'pmd:pmd:4.2.5'
}

task pmd << {
    println 'Running PMD static code analysis'
    ant {
        taskdef(name:'pmd', classname:'net.sourceforge.pmd.ant.PMDTask', classpath: configurations.pmdConf.asPath)

        pmd(shortFilenames:'true', failonruleviolation:'true', rulesetfiles:'conf/pmd-rules.xml') {
            formatter(type:'text', toConsole:'true')
            fileset(dir: "src/main/java") {
                include(name: '**/*.java')
            }
            fileset(dir: "src/test/java") {
                include(name: '**/*.java')
            }
        }
    }
}

Important You'll encounter problems if you try to use rulesets from the PMD jar (e.g. rulesetfiles:'rulesets/basic.xml'). Please take a look at this JIRA link to learn what is the status of this issue.
Basically you can avoid it, by copying the rulesets you use to some other location, e.g. conf directory of your project. Other, but untested workaround, is presented in this mailing post.

using JDepend

The script below uses JDepend Ant task.

build.gradle
configurations {
    jdependConf
}

dependencies {
    jdependConf 'jdepend:jdepend:2.9.1', 'org.apache.ant:ant-jdepend:1.7.1'
}

task jdepend << {
    println 'Running jdepend quality metrics tool'
    ant {
      taskdef(name:'jdepend',
         classname:'org.apache.tools.ant.taskdefs.optional.jdepend.JDependTask',
         classpath: configurations.jdependConf.asPath)
      jdepend (outputfile: 'build/jdepend-report.txt') {
        classespath {
         pathelement(location: 'build')
        }
      }
    }
}

using JavaNCSS

The script below uses JavaNCSS Ant task.

build.gradle
configurations {
    javancssConf
}

dependencies {
    javancssConf 'javancss:javancss:29.50'
}

task javancss << {
    println 'Running javancss quality metrics tool'
    ant {
        taskdef(name:'javancss', classname:'javancss.JavancssAntTask', classpath: configurations.javancssConf.asPath)
        javancss(srcdir:'src/main/java', abortOnFail:'true', generateReport:'true')
    }
}

using Checkstyle

Gradle 0.8 has Checkstyle support built in. By default, the checkstyle tasks will look for a Checkstyle configuration file at $projectDir/config/checkstyle/checkstyle.xml. You can change the location as follows:

build.gradle
usePlugin 'code-quality'

checkstyleConfigFileName = 'conf/sun_checks.xml'

For Gradle 0.7, you can use the Checkstyle Ant task as presented below (this time the rules are stored in conf/sun_checks.xml file).

build.gradle
configurations {
    checkstyle
}

dependencies {
    checkstyle 'checkstyle:checkstyle:5.0'
}

task checkstyle << {
    println 'Running checkstyle tool'
    ant.taskdef(resource: 'checkstyletask.properties', classpath: configurations.checkstyle.asPath)
    ant.checkstyle(config: 'conf/sun_checks.xml') {
        fileset(dir: 'src')
    }
}

CI servers

"Can I use Gradle with my continuous integration server ?" Oh yes, you can ! See below.

Hudson

tbd.

Team City

tbd.

Bamboo

tbd.


command line

Not happy with the default command line features of Gradle ? You will find some more hints here.

bash completion

This recipe was tested on Kubuntu Linux 9.04 but should work for other *nix-es as well (check bash completion documentation for you beloved distro if it doesn't).

Under *nix operating systems you can have bash autocompletion for Gradle. Of course, it will work only for the predefined tasks - bash knows nothing about the tasks you create in your build scripts.

The idea is to put the file presented below to the /etc/bash_completion.d directory (you'll need sudo to do that). Put the tasks that you use most often (or all the tasks you can think of - it is up to you) in the tasks='x y z' line and voila ! Now type
gradle clTAB tTAB
and it will be autocompleted to
gradle clean test.
Sweet, isn't it ?

P.S. don't forget to execute source /etc/bash_completion.d/gradle after you make changes to this file.

P.S. this trick is somehow obsolete because Gradle has a powerful feature of recognizing tags by abbreviations (see userguide), but some old-schools like myself may find it useful

/etc/bash_completion.d/gradle
#!/bin/bash

_gradle_complete()
{
local cur tasks

COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
tasks='clean compile dists javadoc jar test war'
cur=`echo $cur | sed 's/\\\\//g'`
COMPREPLY=($(compgen -W "${tasks}" ${cur} | sed 's/\\\\//g') )
}

complete -F _gradle_complete -o filenames gradle

aliases

It is rather obvious, but maybe you forgot, that your lovely *nix allows you to create aliases, which allows you to easily execute commands with minimal amount of typing. Works best for often used commands, of course. So, update your .bash_aliases file (check your distro documentation) with any gradle specific staff, like this (below some examples, but probably not very interesting, I was in hurry writing them, you know):

.bash_aliases
alias gt='gradle -t'
alias gec='gradle eclipse'
alias gfull='gradle clean javadoc install'

testing

Are you test-infected ?

TestNG

add listeners

build.gradle
dependencies {
	testCompile 'org.testng:testng:5.10:jdk15'
}

test {
    useTestNG()
    options {
        listeners << 'my.listeners.MyTestListener'
    }
}

If you want to disable the default listeners add this to options:

    useDefaultListeners = false

add reporters

Based on ReportNG (https://reportng.dev.java.net/) example.

build.gradle
test {
        useTestNG()
        options {
                listeners << 'org.uncommons.reportng.HTMLReporter,org.uncommons.reportng.JUnitXMLReporter'
                systemProperties.put("org.uncommons.reportng.stylesheet","${projectDir}/resources/hudsonesque.css")
        }
}

easyb

Since Gradle can make use of Ant tasks relatively easily, using easyb in a Gradle build is straightforward. First, add a dependency on easyb to the build, then use the easyb Ant task. The example below adds easyb testing to the Java "check" task, but it would be easy to create a separate Gradle task as well:

build.gradle
dependencies {
    testRuntime("org.easyb:easyb:0.9.6@jar") { transitive = true }
}

check << {

    ant.taskdef(name: "easyb", classname:"org.easyb.ant.BehaviorRunnerTask", classpath: sourceSets.test.runtimeClasspath.asPath)

    ant.easyb( classpath: sourceSets.test.runtimeClasspath.asPath, failureProperty:'easyb_failed' ) {
        report( location:"${project.testResultsDir}/story.txt", format:"txtstory" )
        behaviors( dir: "src/test/stories" ) {
            include( name:"**/*.story" )
        }
   }

    ant.fail( if:'easyb_failed', message: 'Failures in easyb stories' )
}

For more details, see Running easyb stories in a Gradle build at the Agile ICE blog.

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.