JavaTMP Bootstrap Template Documentation Index

Gradle Essentials

Building a software artifact is a complex process involving various activities such as compiling source code, running automated tests, packaging distributable files, and so on. These activities are further split into many steps, often dependent on the execution order, fetching dependent artifacts, resolving configuration variables, and so on. Executing all these activities manually is cumbersome and often error-prone. A good build automation tool helps us reduce the effort and time it takes to build correct artifacts in a repeatable manner.

Introduction

Gradle is

Gradle’s Main Features

Installing Gradle

The Gradle command-line interface

Gradle build script

// The project object has several properties and methods and it is available in our build scripts
// Assign value to description property.
project.description = 'Simple project' // or
project.setDescription('Simple project')
// DSL to create a new task using
// Groovy << operator.
task simple << {
    println 'Running simple task for project ' +
      project.description
}
// Or Use create method to add new task instead of Groovy << operator
project.getTasks().create('simple') {
    println 'Running simple task for project ' + project.description
}
task first {
    doFirst {
        println 'Running first'
    }
}
task second {
    doLast { Task task ->
        println "Running ${task.name}"
    }
}
// OR
task second {
    doLast {
        // Using implicit 'it' closure parameter.
        // The type of 'it' is a Gradle task.
        println "Running ${it.name}"
    }
}
// Or
task second {
    doLast { Task task ->
        // Using explicit name 'task' as closure parameter.
        // We also defined the type of the parameter.
        // This can help the IDE to add code completion.
        println "Running ${task.name}"
    }
}
// Here we use the << operator
// as synonym for the doLast method.
task third << { taskObject ->
    println 'Running ' + taskObject.name
}
task first {
    doFirst(
        new Action() {
          void execute(O task) {
            println "Running ${task.name}"
          }
       }
    )
}
def printTaskName = { task ->
    println "Run ${task.name}"
}
task second << printTaskName
// We use the dependsOn method
// with a closure.
second.dependsOn {
    // We use the Groovy method findAll
    // that returns all tasks that
    // apply to the condition we define
    // in the closure: the task name
    // starts with the letter 'f'.
    project.tasks.findAll { task ->
        task.name.contains 'f'
    }
}
task first << printTaskName
task beforeSecond << printTaskName
defaultTasks 'first', 'second'
task first {
    doLast {
        println "I am first"
    }
}
task second {
    doFirst {
        println "I am second"
    }
}
defaultTasks 'second'
// Use description property to set description.
task first(description: 'Base task') << {
    println "I am first"
}
task second(
    dependsOn: first,
    description: 'Secondary task') << {
    println "I am second"
}
// Define name of task
// as a variable.
def simpleTask = 'simple'
// Variable is used for the task name.
task(simpleTask) << { task ->
    println "Running ${task.name}"
}
// Name of task as variable.
def simpleTask = 'simple'
// Using Groovy GString with
// ${} expression to use variable
// as task name.
task "${simpleTask}" << { task ->
    println "Running ${task.name}"
}
// Or use loops to create multiple tasks.
['Dev', 'Acc', 'Prod'].each { environment ->
    // A new task is created for each element
    // in the list ['Dev', 'Acc', 'Prod'].
    task "deployTo${environment}" << { task ->
        println "Deploying to ${environment}"
    }
}
def printTaskName = { task ->
    println "Running ${task.name}"
}
// Use tasks project variable to get access
// to the TaskContainer object.
// Then we use the create method of
// TaskContainer to create a new task.
project.tasks.create(name: 'first') << printTaskName
// Let Gradle resolve tasks to project variable.
tasks.create(name: 'second', dependsOn: 'first') << printTaskName
task first(description: 'First task')
task second(description: 'Second task')
tasks.addRule(
    "Pattern: desc<TaskName>: " +
    "show description of a task.") { taskName ->
    if (taskName.startsWith('desc')) {
        // Remove 'desc' from the task name.
        def targetTaskName = taskName - 'desc'
      // Uncapitalize the task name.
      def targetTaskNameUncapitalize =
        targetTaskName[0].toLowerCase() +
          targetTaskName[1..-1]
      // Find the task in the project we search
      // the description for.
      def targetTask =
        project.tasks.findByName(
          targetTaskNameUncapitalize)
      if (targetTask) {
          task(taskName) << {
          println "Description of task ${targetTask.name} " +
            " -> ${targetTask.description}"
        }
      }
    }
}
// Create a simple task.
task simple << { task ->
    println "Running ${task.name}"
}
// The simple task is available as
// project property.
simple.description = 'Print task name'
// We can invoke methods from the
// Task object.
simple.doLast {
    println "Done"
}
// We can also reference the task
// via the project property
// explicitly.
project.simple.doFirst {
    println "Start"
}
// Create simple task.
task simple << {
    println "Hello ${message}"
}
// We set the value for
// the non-existing message
// property with the task extension
// support.
simple.ext.message = 'world'
def printTaskName = { task ->
    println "Running ${task.name}"
}
task 'one' {
    // Invoke doFirst method to add action.
    doFirst printTaskName
}
// Assign action through left-shift operator (<<).
task 'two' << printTaskName
task 'three' {
    // This line will be displayed during configuration
    // and not when we execute the task,
    // because we use the configuration closure
    // and forgot the << operator.
    println "Running three"
}
defaultTasks 'one', 'two'
import static java.util.Calendar.*
task longrunning {
    // Only run this task if the
    // closure returns true.
    onlyIf { task ->
        def now = Calendar.instance
        def weekDay = now[DAY_OF_WEEK]
        def weekDayInWeekend = weekDay in [SATURDAY, SUNDAY]
        return weekDayInWeekend
    }
    // Add an action.
    doLast {
        println "Do long running stuff"
    }
}
// Create a new File object.
def file = new File('data.sample')
task handleFile {
    // Use Spec implementation to write
    // a conditon for the onlyIf method.
    onlyIf(new Spec() {
        boolean isSatisfiedBy(task) {
            file.exists()
        }
    })
    doLast {
        println "Work with file ${file.name}"
    }
}
// Define closure with the task actions.
def printTaskName = { task ->
    println "Running ${task.name}"
}
// Create first task.
task first << printTaskName
// Use doFirst method with closure
// that throws exception when task
// is executed during work hours.
first.doFirst {
    def today = Calendar.instance
    def workingHours = today[Calendar.HOUR_OF_DAY] in 8..17
    if (workingHours) {
        throw new StopExecutionException()
    }
}
// Create second task that depends on first task.
task second(dependsOn: 'first') << printTaskName
task listDirectory {
    def dir = new File('assemble')
    // Set value for enabled task property.
    enabled = dir.exists()
    // This is only executed if enabled is true.
    doLast {
        println "List directory contents: " +
                dir.listFiles().join(',')
    }
}
task convert {
    def source = new File('source.xml')
    def output = new File('output.txt')
    doLast {
      def xml = new XmlSlurper().parse(source)
      output.withPrintWriter { writer ->
          xml.person.each { person ->
            writer.println "${person.name},${person.email}"
        }
      }
      println "Converted ${source.name} to ${output.name}"
    }
}
// change the definition of our task so that Gradle can determine whether the task needs to be executed based on
// changes in the input file or output file of the task.
// A task has the properties inputs and outputs that are used for this purpose.
// rewrite our task to make it support Gradle's incremental build feature
// We can use the --rerun-tasks command-line option to ignore the incremental build feature.
task convert {
    def source = new File('source.xml')
    def output = new File('output.txt')
    // Define input file
    inputs.file source
    // Define output file
    outputs.file output
    doLast {
      def xml = new XmlSlurper().parse(source)
      output.withPrintWriter { writer ->
        xml.person.each { person ->
          writer.println "${person.name},${person.email}"
        }
      }
      println "Converted ${source.name} to ${output.name}"
    }
}
// If these methods are not appropriate for our build, we can even use the upToDateWhen method for the outputs property.
// We pass a closure or implementation of the org.gradle.api.specs.Spec interface to define a predicate that determines
// whether the output of the task is up to date.
project.version = '1.0'
task createVersionDir {
    def outputDir = new File('output')
    // If project.version changes then the
    // task is no longer up-to-date
    inputs.property 'version', project.version
    outputs.dir outputDir
    doLast {
        println "Making directory ${outputDir.name}"
        mkdir outputDir
    }
}
task convertFiles {
    // Define multiple files to be checked as inputs.
    // Or use inputs.dir 'input' to check a complete directory.
    inputs.files 'input/input1.xml', 'input/input2.xml'
    // Use upToDateWhen method to define predicate.
    outputs.upToDateWhen {
        // If output directory contains any file which name
        // starts with output and has the xml extension,
        // then the task is up-to-date.
        // We use the Groovy method any to check
        // if at least one file applies to the condition.
        // The ==~ syntax is a Groovy shortcut to
        // check if a regular expression is true.
        new File('output')
            .listFiles()
            any { it.name ==~ /output.*\.xml$/ }
    }
    doLast {
        println "Running convertFiles"
    }
}

Gradle Wrapper

Default Gradle tasks

Building Java Projects

apply plugin: 'java'
archivesBaseName = "my-app"

Unit testing

Adding the JUnit to the classpath

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    testCompile 'junit:junit:4.12'
}

Bundling an application distributable

Building the distribution archive

Generating IDE project files

$ gradle eclipse
$ gradle idea
.idea/
*.iml
*.ipr
*.iws
.classpath
.project
.settings/

Building a Web Application

apply plugin: 'war'

repositories {
    mavenCentral()
}

dependencies {
    providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
}
plugins {
    id "org.akhikhl.gretty" version "2.0.0"
}
plugins {
    id "org.akhikhl.gretty" version "1.2.4"
    id "war"
}
gretty {
    servletContainer = 'tomcat8'
    port = 8080
}

or

gretty {
    servletContainer = 'jetty9'
    port = 9080
}

Project dependencies

External libraries

dependencies {
    compile 'org.springframework:spring-core:4.0.6.RELEASE'
    compile group:'org.springframework', name:'spring-core', version:'4.0.6.RELEASE'
}
runtime ('org.slf4j:slf4j-nop:1.7+') {
    transitive = false
}
runtime ('org.slf4j:slf4j-nop:1.7.2') {
    force = true
}

Dependency configurations

Repositories

repositories {
    mavenCentral()  // shortcut to maven central
    mavenLocal()    // shortcut to maven local (typically ~/.m2)
    jcenter()       // shortcut to jcenter
    maven {
        url "http://repo.company.com/maven"
    }
    ivy {
        url "http://repo.company.com/ivy"
    }
    flatDir { // jars kept on local file system
        dirs 'libDir'
    }
}

Gradle Build Scripts

Groovy for Gradle build scripts

int c = 10
println c.getClass() // print => class java.lang.Integer
def name = "Gradle"
println "$name is an awesome build tool"
def number = 4
println "number is even ? ${number % 2 == 0 }"
def multilineString = '''\
    Hello
    World
'''
println multilineString
def r = /(\d)+/
println r.class
def pattern = ~/(\d)+/
println pattern.class // print > class java.util.regex.Pattern
// or
if ("groovy" ==~ /gr(.*)/)
  println "regex support rocks"
def cl1 = {
    println "hello world!"
}
cl1.call()
def cl2 = { n ->
    println "value of param : $n"
}
cl2.call(101)
3.times(cl2)
3.times { println it * it }
def aList = [] // In Groovy, [] is actually a Java's List instance and not an array.
println aList.getClass()
def anotherList = ['a','b','c']
def list = [10, 20, 30] + [40, 50]
list  <<  60
list = list – [20, 30, 40]
list  -= [20,30,40]
list.each {println it}
def aSet = [1,2,3] as Set
println aSet.class // print > class java.util.LinkedHashSet
TreeSet anotherSet = [1,2,3]
println anotherSet.class
// Adding elements to a set is just like a list using an indirection operator
aSet << 4
aSet << 3
println aSet // [1, 2, 3, 4]
// Map can be declared using the map literal [:]:
def a = [:]
def tool = [version:'2.8', name:'Gradle', platform:'all']
println tool.name
println tool["version"]
println tool.get("platform")
tool.version = "2.9"
tool["releaseDate"] = "2015-11-17"
tool.put("platform", "ALL")
int sum(int a, int b) {
  return a + b;
}
def sum(a, b) {
  a + b // we omitted the return statement as the evaluation of the last expression is automatically returned by a method.
}
sum(1,2)
sum 1, 2
def divide(number, by=2) {
    number/by
}
println divide (10, 5)
println divide (10)
// Methods with map parameters/named parameters
def method(Map options) {
    def a = options.a ?: 10
    def b = options.b ?: 20 // options.a ? options.a : 10
}
method([a:10,b:20])
// We can omit the square brackets ([]) because maps have special support in the method call
method(a:10, b:20)
// The order of parameters is not important and all the parameters need not be passed.
// Also, the parenthesis wrapping is optional, just like any method call:
method b:30, a:40
method b:30
// varags are denoted by ..., but providing the type is optional:
def sumSquares(...numbers) {
    numbers.collect{ it * it }.sum()
}
sumSquares 1, 2, 3
// Closures are important and, hence, Groovy has a special syntax for closures
// if the closure is the last parameter of a method signature:
// the third call is the special syntactical support in which the parenthesis just wraps the other parameters,
// while the closure is written outside the parenthesis, as if it were a method body.
def myMethod (param, cls) {
    ...
}
myMethod(1,{ ... })
myMethod 2, {... }
myMethod(3) {...}
class Person {
  def name, age
}
// In addition to the default constructor, classes in Groovy get a special constructor,
// which takes the map of properties of the class. Here is how we use it:
def person = new Person(name:"John Doe", age:35)
println person.age
person.age = 36
println person.age
// We can provide our own getters and/or setter for the desired fields,
// which will take precedence over the generated one
void setAge(age){
    if (age < 0)
        throw new IllegalArgumentException("age must be a positive number")
    else
        this.age = age
}
// We can add an instance and static methods to classes just like we do in Java:
def speak(){
  println "${this.name} speaking"
}
static def now(){
  new Date().format("yyyy-MM-dd HH:mm:ss")
}
apply plugin: 'java' // apply is a method.
apply(plugin: 'java')
apply([plugin: 'java'])
// the apply method is implicitly applied on the project object.
// So, we can also call it on the project object's reference:
project.apply([plugin: 'java'])

Gradle – an object-oriented build tool

Build phases

Gradle Project API

project.apply plugin: 'java'
project.repositories {
    mavenCentral()
}
project.dependencies {
    testCompile 'junit:junit:4.11'
}
// or
project.repositories({...})
project.dependencies({...})
// Project Properties:
description = "a sample project"
version = "1.0"
task printProperties << {
    println project.version
    println project.property("description")
}
ext.abc = "123"
task printExtraProperties << {
    println project.abc
    println project.property("abc")
    println project.ext.abc
}

Tasks

project.task "myTask"
project.task("myTask")
Task task(String name)
Task task(String name, Closure configureClosure)
Task task(Map<String, ?> args, String name)
Task task(Map<String, ?> args, String name, Closure configureClosure)
someTask.doLast({
    println "this should be printed when the task is run"
})
someTask {
    doLast {
        println "third line that should be printed"
    }
}
someTask << {
    println "the action of someTask"
}
// $ gradle compile dist
task compile << {
    println 'compling the source'
}
task dist(dependsOn: compile) << {
    println "preparing a jar dist"
}
task distUsingTemp << {
  println ("preapring dist using a temp dir")
}
task cleanup << {
  println("removing tmp dir")
}
distUsingTemp.finalizedBy cleanup
cleanup.onlyIf { file("/tmp").exists()}
build.mustRunAfter clean
build.shouldRunAfter clean
10.times { number ->
  task "dynamicTask$number" << {
    println "this is dynamic task number # $number "
  }
}
task copyDocumentation(type:Copy) {
from file("src/docs/html")
into file("$buildDir/docs")
}
class Print extends DefaultTask {
  @Input
  String message = "Welcome to Gradle"
  @TaskAction
  def print() {
    println "$message"
  }
}
task welcome(type: Print)
task thanks(type: Print) {
  message = "Thanks for trying custom tasks"
}
task bye(type: Print)
bye.message = "See you again"
thanks.dependsOn welcome
thanks.finalizedBy bye

Multiprojects Build

The settings.gradle file

Organizing build logic in multiproject builds

allprojects {
    task whoami << {println "I am ${project.name}"}
}
// or
allprojects {
  task("describe${project.name.capitalize()}") << {
    println project.name
  }
}

Applying build logic to subprojects

subprojects {
  apply plugin: 'java'
}

Dependency on subprojects

project(':services') {
  dependencies {
    compile project(':repository')
  }
}
dependencies {
  compile project(':services')
}

Gradle Scripts Examples

Free Gradle script to compile and build a Java project:

The gradle plugin provides the flexibility to configure the plugin based on the project’s need as the following code snippt shows:

apply plugin:'java'
task cleanDir << {
    delete "build"
    delete "dist"
}
task createDirs(dependsOn:'cleanDir') << {
    def classes = file("build/classes")
    def dist = file("dist")
    classes.mkdirs()
    dist.mkdirs()
}
compileJava {
    File classesDir = file("build/classes")
    FileTree srcDir = fileTree(dir: "src")
    source srcDir
    destinationDir classesDir
}
task createJar(type: Jar) {
    destinationDir = file("dist")
    baseName = "JavaProject-1.0"
    from "build/classes"
}
createJar.dependsOn compileJava
compileJava.dependsOn createDirs

Migrating from a Maven to Gradle project

dependencies{
    compile(' org.apache.logging.log4j: log4j-core:1.2')
}
- Repositories configuration. This is the location from where you download dependencies.
In Gradle, you can mention the repository using the following syntax: ``` repositories {
maven {
    url "http://companylocalrepository.org"
} } ```

Publishing artifacts

Continuous Integration

Generating documentation

Testing and Reporting with Gradle

Testing with TestNG

apply plugin:'java'
repositories {
  mavenCentral()
}
dependencies {
  testCompile 'org.testng:testng:6.8.21'
}
test {
  ignoreFailures = true
  useTestNG(){
    suites("src/test/resources/testng.xml")
  }
}
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1" verbose="1" >
  <listeners>
    <listener class-name="org.testng.reporters.EmailableReporter" />
  </listeners>
  <test name="Smoke Test">
  <groups>
    <run>
      <exclude name="Integration"  />
      <include name="Smoke"  />
    </run>
  </groups>
  <classes>
    <class name="com.packtpub.ge.ch7.HashTest">
    </class>
  </classes>
  </test>
</suite>

Integration testing

apply plugin: 'java'
sourceSets {
   integrationTest {
       java.srcDir file('src/integrationTest/java')
       resources.srcDir file('src/integrationTest/resources') // to add the resources
   }
}
task runIntegrationTest(type: Test) {
   testClassesDir = sourceSets.integrationTest.output.classesDir
   classpath = sourceSets.integrationTest.runtimeClasspath
}
dependencies {
    // other configuration dependencies
    integrationTestCompile 'org.hibernate:hibernate:3.2.3.ga'
}

Code coverage

apply plugin: 'java'
apply plugin: 'jacoco'
repositories {
  mavenCentral()
}
dependencies {
  testCompile 'org.testng:testng:6.8.8'
}
test{
    systemProperty "url",System.properties['url']
    useTestNG()
}
jacocoTestReport.dependsOn test
jacoco {
    toolVersion = "<Required-Version>"
    reportsDir = file("Path_to_Jacoco_ReportDir")
}
jacocoTestReport {
    reports {
        xml.enabled false
        html.destination "<Path_to_dircectory>"
    }
}

Code analysis reports

apply plugin: 'java'
apply plugin: "sonar-runner"

repositories {
    mavenCentral()
}

version = '1.0'
repositories {
    mavenCentral()
}

sonarRunner {
  sonarProperties {
    property "sonar.host.url", "http://<IP_ADDRESS>:<PORT>"
    property "sonar.jdbc.url",
    "jdbc:h2:tcp://<IP_ADDRESS>:<PORT>/sonar"
    property "sonar.jdbc.driverClassName", "org.h2.Driver"
    property "sonar.jdbc.username", "sonar"
    property "sonar.jdbc.password", "sonar"
  }
}

Organizing Build Logic and Plugins

Extracting build logic to buildSrc

apply plugin: CustomPlugin
class CustomPlugin implements Plugin<Project> {
  void apply(Project project) {
    project.task('task1') << {
      println "Sample task1 in custom plugin"
    }
    project.task('task2') << {
      println "Sample task2 in custom plugin"
    }
  }
}
task2.dependsOn task1
task1.doLast {
    println "Added more functionality to task1"
}
task2.dependsOn task1

Gradle Plugin

buildscript {
    repositories {
        flatDir {dirs "../CustomPlugin/build/libs/"}
    }
    dependencies {
        classpath group: 'ch8', name: 'CustomPlugin',version: '1.0'
    }
}
apply plugin: 'customplugin'

Configuring plugins

// Create the CustomPluginExtension.groovy class as follows:
class CustomPluginExtension {
def location = "/plugin/defaultlocation"
}
// register this class to your plugin class:
class CustomPlugin implements Plugin<Project> {
    void apply(Project project) {
        def extension = project.extensions.create("customExt",CustomPluginExtension)
        project.task('task1') << {
            println "Sample task1 in custom plugin"
            println "location is "+project.customExt.location
        }
    }
}
// To change this field to some other value, add customExt closure
// to your build.gradle file with a different value configured for the location:
buildscript {
    repositories {
        flatDir {dirs "../CustomPlugin/build/libs/"}
    }
    dependencies {
        classpath group: 'ch8', name: 'CustomPlugin',version: '1.0'
    }
}
apply plugin: 'customplugin'
customExt {
    location="/plugin/newlocation"
}

Working with Gradle Build Scripts

// Use String for file reference.
File wsdl = file('src/wsdl/sample.wsdl')
// Use File object for file reference.
File xmlFile = new File('xml/input/sample.xml')
def inputXml = project.file(xmlFile)
// Or a URI instance.
def uri = new URI('file:/README')
def readmeFile = file(uri)
// Use a closure to determine the
// file or directory name.
def fileNames = ['src', 'web', 'config']
def configDir = file {
    fileNames.find { fileName ->
        fileName.startsWith('config')
    }
}
// Use Callable interface.
def source = file(new Callable<String>() {
    String call() {
        'src'
    }
})
// Suppose, we want to work with a directory named config in our build script. The directory must be present, otherwise the build will stop:
def dir = project.file(new File('config'),    PathValidation.DIRECTORY)
// Check file or directory exists.
def readme = project.file('README', PathValidation.EXISTS)
// Check File object is really a file.
def license = project.file('License.txt', PathValidation.FILE)
// Use String instances.
def multiple =
    files('README', 'licence.txt')
// Use File objects.
def userFiles =
    files(new File('README'), new File('INSTALL'))
// We can combine different argument types.
def combined = files('README', new File('INSTALL'))
// We can pass a URI or URL object, just as we could with the file() method:
def urlFiles =
    files(new URI('file:/README'),
        new URL('file:/INSTALL'))
// We can also use an array, Collection, or Iterable object with file names
// or another ConfigurableFileCollection instance as an argument:
// Use a Collection with file or directory names.
def listOfFileNames = ['src', 'test']
def mainDirectories = files(listOfFileNames)
// Use an array.
// We use the Groovy as keyword to
// force an object to a certain type.
mainDirectories = files(listOfFileNames as String[])
// Or an implementation of the Iterable interface.
mainDirectories = files(listOfFileNames as Iterable)
// Combine arguments and pass another file collection.
def allDirectories = files(['config'], mainDirectories)
// We can also use a closure or instance of the Callable interface to define a list of files, as follows:
import java.util.concurrent.Callable
def dirs = files {
    [new File('src'), file('README')]
    .findAll { file ->
        file.directory
    }
}
def rootFiles = files(new Callable<List<File>>() {
    def files = [new File('src'),
            file('README'),
            file('INSTALL')]
    List<File> call() {
        files.findAll { fileObject ->
            fileObject.file
        }
    }
})
// we can pass a Task object as an argument to the files() method. The outputs property of the task is used to determine
// the file collection or we can directly use the TaskOutputs object instead of letting Gradle resolve
// it via the outputs property of the Task object.
// To get the file collection object in our build script,
we simply pass the Task instance as an argument to the files() method:
task convert {
    def source = new File('source.xml')
    def output = new File('output.txt')
    // Define input file
    inputs.file source
    // Define output file
    outputs.file output
    doLast {
        def xml = new XmlSlurper().parse(source)
        output.withPrintWriter { writer ->
            xml.person.each { person ->
                writer.println "${person.name},${person.email}"
            }
        }
        println "Converted ${source.name} to ${output.name}"
    }
}
// Get the file collection from
// the task outputs property.
def taskOutputFiles = files(convert)
// Alternatively we could use
// the outputs property directly.
taskOutputFiles = files(convert.outputs)
// The ConfigurableFileCollection interface has useful methods to manipulate the collection, for example,
// we can use + and - operators to add or remove elements from the collection, respectively:
// Define collection.
def fileCollection = files('README', 'INSTALL')
// Remove INSTALL file from collection.
def readme = fileCollection - files('INSTALL')
// Add new collection to existing collection.
def moreFiles =
    fileCollection +
    files(file('config',
            PathValidation.DIRECTORY))
// To get the absolute path names for the elements in ConfigurableFileCollection, we can use the asPath property.
task collectionPath << {
    def fileCollection = files('README', 'INSTALL')
    println fileCollection.asPath
}
// To get the File objects that make up the file collection, we can use the files property.
def fileCollection = files('README', [new File('INSTALL')])
// Get all elements as File objects.
def allFiles = fileCollection.files
// Or use casting with as keyword.
def fileObjects = fileCollection as File[]
def singleFileCollection = files('INSTALL')
// Get single file as File object.
def installFile = singleFileCollection.singleFile
// we can apply a filter to our file collection with the filter() method.
task filterFiles << {
    def rootFiles = files('INSTALL', 'README')
    // Filter for files with a txt extension.
    def smallFiles = rootFiles.filter { file ->
        file.name.endsWith 'txt'
    }
    rootFiles = rootFiles + files('LICENSE.txt')
    // smallFiles now contains 2 files:
    // INSTALL and LICENSE
}
// Create file tree with base directory 'src/main'
// and only include files with extension .java
def srcDir = fileTree('src/main').include('**/*.java')
// Use map with arguments to create a file tree.
def resources =
    fileTree(dir: 'src/main',
        excludes: ['**/*.java', '**/*.groovy'])
// Create file tree with project directory as base
// directory and use method include() on tree
// object to include 2 files.
def base = fileTree('.')
base.include 'README', 'INSTALL'
// Use closure to create file tree.
def javaFiles = fileTree {
    from 'src/main/java'
    exclude '*.properties'
}
// To filter a file tree, we can use the filter() method as we do with file collections, but we can also use the matching() method.
We pass a closure to the matching() method or an instance of the org.gradle.api.tasks.util.PatternFilterable interface.
We can use include, includes, exclude, and excludes methods to either include or exclude files from the file tree, as follows:
def sources = fileTree {
    from 'src'
}
def javaFiles = sources.matching {
    include '**/*.java'
}
def nonJavaFiles = sources.matching {
    exclude '**/*.java'
}
def nonLanguageFiles = sources.matching {
    exclude '**/*.scala', '**/*.groovy', '**/*.java'
}
def modifiedLastWeek = sources.matching {
    lastWeek = new Date() - 7
    include { file ->
        file.lastModified > lastWeek.time
    }
}
// We can use the visit() method to visit each tree node
def testFiles = fileTree(dir: 'src/test')
testFiles.visit { fileDetails ->
    if (fileDetails.directory) {
        println "Entering directory ${fileDetails.relativePath}"
    } else {
        println "File name: ${fileDetails.name}"
    }
}
def projectFiles = fileTree(dir: 'src/test')
projectFiles.visit(new FileVisitor() {
    void visitDir(FileVisitDetails details) {
        println "Directory: ${details.path}"
    }
    void visitFile(FileVisitDetails details) {
        println "File: ${details.path}, size: ${details.size}"
    }
})
// To copy files in Gradle, we can use the Copy task
task simpleCopy(type: Copy) {
    from 'src/xml'
    into 'definitions'
}
// uses the include() and exclude() methods to select the set of files to be copied:
// Define a closure with ANT-style
// pattern for files.
def getTextFiles = {
    '**/*.txt'
}
task copyTask(type: Copy) {
    // Copy from directory.
    from 'src/webapp'
    // Copy single file.
    from 'README.txt'
    // Include files with html extension.
    include '**/*.html', '**/*.htm'
    // Use closure to resolve files.
    include getTextFiles
    // Exclude file INSTALL.txt.
    exclude 'INSTALL.txt'
    // Copy into directory dist
    // resolved via closure.
    into { file('dist') }
}
// Another way to copy files is with the Project.copy() method. The copy() method accepts a CopySpec interface implementation
task simpleCopy << {
    // We use the project.copy()
    // method in our task. We can
    // leave out the project reference,
    // because Gradle knows how to
    // resolve it automatically.
    copy {
        from 'src/xml'
        into 'definitions'
    }
}
task archiveDist(type: Zip) {
    from 'dist'
    // Create output filename.
    // Final filename is:
    // dist-files-archive-1.0-sample.zip
    baseName = 'dist-files'
    appendix = 'archive'
    extension = 'zip'
    version = '1.0'
    classifier = 'sample'
}
// By using task type Zip we instruct
// Gradle to create an archive
// in ZIP format.
task archiveFiles(type: Zip) {
    from 'dist'
    // Copy files to a directory inside the archive.
    into 'files'
    // Set destination directory for ZIP file.
    // $buildDir refers to default Gradle
    // build directory 'build/'.
    destinationDir = file("$buildDir/zips")
    // Set complete filename at once.
    archiveName = 'dist-files.zip'
}
// To create a TAR archive with the optional gzip or bzip2 compression, we must use the tarFiles task
task tarFiles(type: Tar) {
    from 'dist'
    // Set destination directory.
    destinationDir = file("$buildDir/tarballs")
    // Set filename properties.
    baseName = 'dist-files'
    // Default extension for tar files
    // with gzip compression is tgz.
    extension = 'tar.gz'
    // Use gzip compression.
    compression = Compression.GZIP // or Compression.BZIP2
}
version = '1.0'
group = 'Sample'
description = 'Sample build file to show project properties'
task defaultProperties << {
    println "Project: $project"
    println "Name: $name"
    println "Path: $path"
    println "Project directory: $projectDir"
    println "Build directory: $buildDir"
    println "Version: $version"
    println "Group: $project.group"
    println "Description: $project.description"
    println "AntBuilder: $ant"
}
// Define new property.
ext.customProperty = 'custom'
// Or we can use ext{} script block.
ext {
  anotherCustomProperty = 'custom'
}
task showProperties {
    ext {
        customProperty = 'override'
    }
    doLast {
        // We can refer to the property
        // in different ways:
        println customProperty
        println project.ext.customProperty
        println project.customProperty
    }
}
task showProperties {
    doLast {
        println "Version: $version"
        println "Custom property: $customProperty"
    }
}
// Run By: $ gradle -Pversion=1.1 -PcustomProperty=custom showProperties
task showProperties {
    doLast {
        println "Version: $version"
        println "Custom property: $customProperty"
    }
}
// run: gradle -Dorg.gradle.project.version=2.0 -Dorg.gradle.project.customProperty=custom showProperties
task showProperties {
    doLast {
        println "Version: $version"
        println "Custom property: $customProperty"
    }
}
// we set ORG_GRADLE_PROJECT_version and ORG_GRADLE_PROJECT_customProperty environment variables,
// then we run our showProperties task:
task showProperties {
    doLast {
        println "Version: $version"
        println "Custom property: $customProperty"
    }
}
// Run by : $ gradle --debug logLevels . $ gradle --info logLevels . $ gradle logLevels
// Simple logging sample.
task logLevels << {
    logger.debug 'debug: Most verbose logging level'
    logger.log LogLevel.DEBUG, 'debug: Most verbose logging level'
    logger.info 'info: Use for information messages'
    logger.log LogLevel.INFO, 'info: Use for information messages'
    logger.lifecycle 'lifecycle: Progress information messages'
    logger.log LogLevel.LIFECYCLE,
      'lifecycle: Progress information messages'
    logger.warn 'warn: Warning messages like invalid        configuration'
    logger.log LogLevel.WARN,
      'warn: Warning messages like invalid configuration'
    logger.quiet 'quiet: This is important but not an error'
    logger.log LogLevel.QUIET,
      'quiet: This is important but not an error'
    logger.error 'error: Use for errors'
    logger.log LogLevel.ERROR, 'error: Use for errors'
}

we know that every Gradle project and task has a logger we can use. However, we can also explicitly create a logger instance with the Logging class

class Simple {
    // Create new logger using the Gradle
    // logging support.
    private static final Logger logger = Logging.getLogger('Simple')
    int square(int value) {
        int square = value * value
        logger.lifecycle "Calculate square for ${value} = ${square}"
        return square
    }
}
logger.lifecycle 'Running sample Gradle build.'
task useSimple {
    doFirst {
        logger.lifecycle 'Running useSimple'
    }
    doLast {
        new Simple().square(3)
    }
}
logging.captureStandardOutput LogLevel.INFO
println 'This message is now logged with log level info instead of quiet'
task redirectLogging {
    doFirst {
      // Use default redirect log level quiet.
      println 'Start task redirectLogging'
    }
    doLast {
      logging.captureStandardOutput LogLevel.INFO
      println 'Finished task redirectLogging'
    }
}
// Creating wrapper scripts
$ gradle wrapper
$ gradle wrapper --gradle-version=2.12
// Customizing the Gradle Wrapper
task createWrapper(type: Wrapper) {
    // Set Gradle version for wrapper files.
    gradleVersion = '2.12'
    // Rename shell scripts name to
    // startGradle instead of default gradlew.
    scriptFile = 'startGradle'
    // Change location and name of JAR file
    // with wrapper bootstrap code and
    // accompanying properties files.
    jarFile = "${projectDir}/gradle-bin/gradle-bootstrap.jar"
}
// run by $ gradle createWrapper
// To change the URL from where the Gradle version must be downloaded, we can alter the distributionUrl property.
task createWrapper(type: Wrapper) {
    // Set URL with custom Gradle distribution.
    distributionUrl = 'http://intranet/gradle/dist/gradle-custom-2.12.zip'
}

Using Gradle for Java Projects

apply plugin: 'java'
task sourceSetJavaProperties << {
    sourceSets {
        main {
            println "java.srcDirs = ${java.srcDirs}"
            println "resources.srcDirs = ${resources.srcDirs}"
            println "java.files = ${java.files.name}"
            println "allJava.files = ${allJava.files.name}"
            println "resources.files = ${resources.files.name}"
            println "allSource.files = ${allSource.files.name}"
            println "output.classesDir = ${output.classesDir}"
            println "output.resourcesDir = ${output.resourcesDir}"
            println "output.files = ${output.files}"
      }
    }
}
apply plugin: 'java'
sourceSets {
    main {
        java {
            srcDir 'src/java'
        }
        resources {
            srcDir 'resources/java'
        }
    }
    test {
        java {
            srcDir 'test/unit/java'
        }
        resources {
            srcDir 'resources/test'
        }
    }
    'integeration-test' {
        java {
            srcDir 'test/integration/java'
        }
        resources {
            srcDir 'resources/test'
        }
    }
}
task showConvention << {
    println sourceSets.main.name
    println project.sourceSets.main.name
    println project.convention.plugins.java.sourceSets.main.name
}
apply plugin: 'java'
archivesBaseName = 'gradle-sample'
version = '1.0'
sourceCompatibility = JavaVersion.VERSION_1_8 // Or '1.8' or 8
jar {
    manifest {
      attributes(
        'Implementation-Version' : version,
        'Implementation-Title' : 'Gradle Sample'
      )
    }
}
apply plugin: 'java'
javadoc {
    source sourceSets.api.allJava
}
// to set some of the options for the javadoc task in our project:
javadoc {
    source sourceSets.api.allJava
    title = 'Gradle Sample Project'
    options.links = ['http://docs.oracle.com/javase/6/docs/api/']
    options.footer = "Generated on ${new Date().format('dd MMM yyyy')}"
    options.header = "Documention for version ${project.version}"
}
apply plugin: 'java'
archivesBaseName = 'gradle-sample'
version = '1.0'
sourceSets {
    api
    main {
        compileClasspath += files(api.output.classesDir)
    }
}
classes.dependsOn apiClasses
task apiJar(type: Jar) {
    // Define appendix that will be
    // appended to the archivesBaseName
    // for the JAR.
    appendix = 'api'
    // Define the input for the JAR file.
    from sourceSets.api.output
}

Dependency Management

Dependency configuration

Every Gradle build has a ConfigurationContainer object. This object is accessible via the Project property with the name containers. We can use a closure to configure the container with Configuration objects. Each Configuration object has at least a name, but we can change more properties. We can set a resolution strategy, if a configuration has version conflicts with dependencies, or we can change the visibility of a configuration so that it will not be visible outside of our project. A Configuration object also has a hierarchy. So we can extend from the existing Configuration objects to inherit the settings.

configurations {
    commonsLib {
        description = 'Common libraries'
    }
    mainLib {
        extendsFrom commonsLib
        description = 'Main libraries'
    }
}
// Reference mainLib configuration
// using [] syntax for the
// configuration container.
println configurations['mainLib'].name
// Reference commonsLib in another way,
// just use the name directly as property.
println configurations.commonsLib.name

Repositories

Defining dependencies

repositories {
    jcenter()
}
configurations {
    springLibs
}
dependencies {
    springLibs('org.springframework:spring-web:4.2.3.RELEASE')
}
task copyCompileDeps(type: Copy) {
    from configurations.springLibs
    into "$buildDir/compileLibs"
}
dependencies {
    compile files('spring-core.jar', 'spring-aop.jar')
    compile fileTree(dir: 'deps', include: '*.jar')
}

Testing, Building, and Publishing Artifacts

apply plugin: 'java'
repositories {
    jcenter()
}
dependencies {
    testCompile('junit:junit:4.12')
}
test {
    // Add System property to running tests.
    systemProperty 'sysProp', 'value'
    // Use the following JVM arguments for each test process.
    jvmArgs '-Xms256m', '-Xmx512m'
    // Enable debugging mode.
    debug = true
    // Ignore any test failues and don't fail the build.
    ignoreFailures = true
    // Enable assertions for test with the assert keyword.
    enableAssertions = true
    // Run four tests in parallel.
    maxParallelForks = 4
    // Restart proces after
    // 10 executions.
    forkEvery = 10
    // Disable automatic scanning
    // for test classes.
    scanForTestClasses = false
    // Include test classes.
    include('**/*Test.class', '**/*Spec.class')
    // Exclude test classes.
    exclude('**/Abstract*.class', '**/Run*.class')
    // Set exception format to full
    // instead of default value 'short'.
    testLogging.exceptionFormat 'full'
    // We can also use a script block to configure
    // the testLogging property.
    testLogging {
        // No log level specified so the
        // property is set on LIFECYCLE log level.
        // We can pass arguments to determine
        // which test events we want to see in the
        // command-line output.
        events 'passed'
        // Show logging events for test methods.
        minGranularity = 3
        // All valid values for the stackTrace output.
        stackTraceFilters 'groovy', 'entry_point', 'truncate'
        // Show System.out and System.err output
        // from the tests.
        showStandardStreams = true
        // Configure options for DEBUG log level.
        debug {
            events 'started'
        }
    }
}
apply plugin: 'java'
repositories {
    jcenter()
}
dependencies {
    testCompile('junit:junit:4.12')
}
task testReport(type: TestReport) {
    destinationDir = file("$buildDir/test-reports")
    testResultDirs = files("$buildDir/test-results")
    reportOn(test)
}
// If the test task is finished,
// we want the testReport to be executed.
test.finalizedBy(testReport)
apply plugin: 'java'
task runJava(dependsOn: classes,
    description: 'Run gradle.sample.SampleApp') << {
    javaexec {
        // Java main class to execute.
        main = 'gradle.sample.SampleApp'
        // We need to set the classpath.
        classpath sourceSets.main.runtimeClasspath
        // Extra options can be set.
        maxHeapSize = '128m'
        systemProperty 'sysProp', 'notUsed'
        jvmArgs '-client'
    }
}
repositories {
    jcenter()
}
apply plugin: 'java'
task runJava(type: JavaExec) {
    dependsOn classes
    description = 'Run gradle.sample.SampleApp'
    // Java main class to execute.
    main = 'gradle.sample.SampleApp'
    // We need to set the classpath.
    classpath sourceSets.main.runtimeClasspath
    // Extra options can be set.
    systemProperty 'sysProp', 'notUsed'
    jvmArgs '-client'
    // We can pass arguments to the main() method
    // of gradle.sample.SampleApp.
    args 'mainMethodArgument', 'notUsed'
}
apply plugin: 'application'
mainClassName = 'gradle.sample.SampleApp'
// Extra configuration for run task if needed.
run {
    // Extra options can be set.
    systemProperty 'sysProp', 'notUsed'
    jvmArgs '-client'
    // We can pass arguments to the main() method
    // of gradle.sample.SampleApp.
    args 'mainMethodArgument', 'notUsed'
}
apply plugin: 'application'
mainClassName = 'gradle.sample.SampleApp'
archivesBaseName = 'gradle-sample'
version = '1.0'

apply plugin: 'java'
version = '1.0'
// Custom archive task with
// specific properties for a WAR archive.
task war(type: War) {
    dependsOn classes
    from 'src/main/webapp'
    // Files copied to WEB-INF.
    webInf {
        from 'src/main/webInf'
    }
    // Copied to WEB-INF/classes.
    classpath sourceSets.main.runtimeClasspath
    // Copied to WEB-INF/lib.
    classpath fileTree('libs')
    // Custom web.xml.
    webXml = file('  ')
    baseName = 'gradle-webapp'
}
assemble.dependsOn war

Multi-project Builds

Maintaining Code Quality

Writing Custom Tasks and Plugins

Gradle in the Enterprise

Read more about Gradle