- 1 about this cookbook
- 2 general issues
- 3 plugins
- 3.1 ClassLoader plugin
- 3.2 Exec plugin
- 3.3 Env plugin
- 3.4 Example of a simple custom task within buildSrc
- 4 web development
- 5 missing features
- 5.1 running things from Gradle
- 5.2 running single tests
- 5.3 Creating source and resource directories
- 5.4 Creating GroovyEclipse project files
- 6 Dependencies
- 6.1 Creating a fat jar
- 6.2 Gathering all dependencies (libs) in one folder
- 6.3 Graphviz dependency report
- 6.4 Custom repository structure and its access patterns
- 6.5 How to refer to multiple artifacts within the same module
- 7 Ant integration
- 8 Maven2 integration
- 9 3rd party tools
- 9.1 using Cobertura
- 9.2 using Findbugs
- 9.3 Alternative Findbugs using subproject injection
- 9.4 using PMD
- 9.5 using JDepend
- 9.6 using JavaNCSS
- 9.7 using Checkstyle
- 10 CI servers
- 11 command line
- 11.1 bash completion
- 11.2 aliases
- 12 testing
- 12.1 TestNG
- 12.1.1 add listeners
- 12.1.2 add reporters
- 12.2 easyb
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:
- http://docs.codehaus.org/display/GRADLE/Gradle+0.9+Breaking+Changes
- http://docs.codehaus.org/display/GRADLE/Gradle+0.8+Breaking+Changes
- http://docs.codehaus.org/display/GRADLE/Gradle+0.7+Breaking+Changes
- http://docs.codehaus.org/display/GRADLE/Gradle+0.6+Breaking+Changes
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
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:
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:
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:
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:
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
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:
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:
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:
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:
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:
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:
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:
test {
useTestNG()
options {
jvmArgs << "-Dnet.sourceforge.cobertura.datafile=${cobSerFile}"
}
}
JUnit example:
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.
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.
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.
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.
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.
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:
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).
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
#!/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):
alias gt='gradle -t' alias gec='gradle eclipse' alias gfull='gradle clean javadoc install'
testing
Are you test-infected ?
TestNG
add listeners
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.
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:
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.
