Gradle is a build tool for the JVM with a
Groovy-based DSL for building projects. The Gradle web site describes it as follows:
Projects and Tasks
Each Gradle build is composed of one or more projects and each project is composed of tasks. The core of the Gradle build is the build.gradle file (which is called the build script).
To try it out, go to www.gradle.org and install Gradle. Then create your own build.gradle file.
Tasks can be defined by writing
task and then a task name followed by a closure. Use the
doLast method with a closure to
execute any arbitrary code. For example:
1 task upper { doLast {
2 String someString = 'test'
3 println "Original: $someString"
4 println "Uppercase: " + someString.toUpperCase()
5 }}
Tasks can contain any Groovy code.
Much like in Ant, a task can depend on other tasks, which means they need to be run before the task. You simply call
dependsOn with any number of task names as the arguments. For example:
1 task buildApp {
2 dependsOn clean, installApp, processAssets
3 }
You can also use the following alternative syntax:
1 task buildApp(dependsOn: [clean, installApp, processAssets])
Once you’ve defined your tasks, you run them by invoking
gradle <task_name> at the command line. There are some built-in tasks. For example, to list all available tasks, invoke the following:
Plugins
Gradle core has very little built-in, but it has powerful
plugins to allow it to be very flexible. A plugin can do one or more of the following:
Add tasks to the project (e.g., compile and test).
Pre-configure added tasks with useful defaults.
Add dependency configurations to the project.
Add new properties and methods to existing type via extensions.
We’re going to concentrate on building Groovy-based projects, so we’ll be using the Groovy plugin (however, Gradle is not limited to Groovy projects!):
This plugin uses Maven’s conventions. For example, it expects to find your main source code under src/main/groovy and your test source code under src/test/groovy.
Configuring a Task
Once you’ve added some plugins, you might want to configure some of the properties of a task for your purposes.
For example, you might want to specify a version of Gradle for the Gradle
wrapper task
:
1 task wrap(type: Wrapper) {
2 gradleVersion = '5.4.1'
3 }
The properties available depend on what task you are configuring. In the preceding case, we’re configuring Gradle’s Wrapper task to use Gradle version 5.4.1. Running this task would create a "gradlew" script file
that can be run in place of gradle so that the same version of Gradle is run regardless of what is installed on the current machine. This is useful to make sure the build runs the same way every time.
Extra Configuration
To provide extra properties within your Gradle build file, use the ext method
. You can define any arbitrary values within the closure, and they will be available throughout your project.
You can also apply properties from other Gradle build files. For example:
1 ext {
2 apply from: 'props/another.gradle'
3 myVersion = '1.2.3'
4 }
The properties defined within this closure can be used in your tasks or when defining your dependencies.
Dependencies
Every Java project tends to rely on many open source projects to be built. Gradle builds on Maven so you can easily include your
dependencies using a simple DSL, like in the following example:
1 apply plugin: 'java'
2
3 sourceCompatibility = 1.11
4
5 repositories {
6 mavenLocal()
7 mavenCentral()
8 }
9
10 dependencies {
11 compile 'com.google.guava:guava:27.1-jre'
12 compile 'org.groocss:groocss:1.0-M2'
13 testCompile group: 'junit', name: 'junit', version: '5.+'
14 testCompile "org.mockito:mockito-core:2.28.2"
15 }
This build script uses sourceCompatibility to define the Java source code version of 1.11 (which is used during compilation). Next it tells Maven to use the local repository first (mavenLocal) and then Maven central.
In the dependencies block, this build script defines two dependencies for the compile scope and two for testCompile scope. Jars in the testCompile scope are only used by tests and won't be included in any final products.
The line for JUnit shows the more verbose style for defining dependencies. It also specifies, using +, that the version be 5.0 or greater.
You can also specify your own Maven
repository by calling
maven with a closure supplying the appropriate parameters (at least an URL). For example (in the
repositories section):
1 maven {url "https://oss.sonatype.org/content/repositories/snapshots/" }
2 maven { url = "$nexus/content/groups/public"
3 credentials {
4 username 'deployment'
5 password deploymentPassword
6 }
7 }
The second example demonstrates using a secured Maven repository. It also demonstrates using the variables nexus and deploymentPassword
which could (probably should) be stored in a gradle.properties file.
Gradle Properties
The
gradle.properties file
allows you to specify Gradle properties and other properties available to your build script. For example, you can specify JVM arguments and whether you want to use the Gradle daemon (which runs in the background and speeds up subsequent Gradle builds; this is the default):
1 org.gradle.daemon=true
2 org.gradle.jvmargs=-Xms128m -Xmx512m
You could also specify build-specific values that you don’t want to keep in your versioning system (such as Nexus credentials). For example, you might add the following to your local
gradle.properties file:
nexusUser=user
nexusPassword=changeme123
Now both nexusUser and nexusPassword would
be available properties in your Gradle build file.
Multiproject Builds
A multiproject build can include any number of sub-projects that are built together. Each sub-project should be put in a directory under a single top directory, where the name of each directory is the name of the sub-project.
Separate builds in a multiproject build may depend on one another. You can express dependencies on any number of sub-projects using the following syntax:
1 dependencies {
2 compile project(':subproject1')
3 compile project(':subproject2')
4 }
The top-level
build.gradle file of multiproject should look something like the following:
1 allprojects {
2 apply plugin: "groovy"
3 }
4 project(":subproject1") {
5 dependencies {}
6 }
7 project(":subproject2") {
8 dependencies {}
9 }
You can create sub-projects by creating a directory and putting a
build.gradle file there. For example (on a Unix-like system):
mkdir subproject1
touch subproject1/build.gradle
mkdir subproject2
touch subproject2/build.gradle
Finally, you should create a file named
settings.gradle that calls
include with a list of
sub-projects. For example, given the above sub-projects, use the following in
settings.gradle:
include 'subproject1', 'subproject2'
File Operations
Since Gradle evaluates tasks before actually executing them, you should generally not use
java.util.File directly for defining files or
directories. Instead, Gradle provides a number of built-in methods and tasks. For example, you should use the
file method for single files or directories and the
files method to define a collection of files or directories.
1 outputDir = file("libs/x86")
There’s also a
fileTree method
for recursively listing a directory of files. For example, you can depend on all files under the
lib directory in the following way:
1 dependencies {
2 compile fileTree('lib')
3 }
To copy files from one place to another, use the
Copy task. Here’s a good example:
1 task copyImages(type: Copy) {
2 from 'assets'
3 into 'build/images'
4 include '**/*.jpg'
5 exclude '**/*test*'
6 }
This task would copy all images that end with .jpg from the assets directory
into the build/images directory
, excluding any files containing the word test.
Exploring
Remember you can also easily list properties of an object in Groovy using
.properties. This can help you explore available Gradle properties at runtime. For example:
1 task testIt {
2 doLast { println sourceSets.main.properties }
3 }
Completely Groovy
Remember that all of Groovy’s goodness is available in Gradle. For example, the following one-liner sets the encoding option to
UTF-8 for two
tasks using the “star-dot” notation (this is useful when your code contains non-ASCII characters):
1 [compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
Summary
This chapter taught you the following about Gradle:
How to create tasks
How to use plugins
How to specify dependencies
What gradle.properties is all about
How to create multiproject builds
Using built-in methods for file operations