Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Gradle builds the foundation


May 25, 2021 Gradle


Table of contents


Build the foundation

Projects and tasks

Projects and tasks are the two most important concepts in Gradle.

Any Gradle build consists of one or more projects. E ach project includes many buildable components. I t all depends on what you're building. F or example, each project might be a jar package or a web app, or it could be a zip compression package made up of jars generated in many other projects. A project does not have to describe that it can only be built. I t can also deploy your app or build your environment. D on't worry about it being as big as it sounds. Gradle's build-by-convention lets you define exactly what a project should do.

Each project consists of multiple tasks. E ach task represents an atomic operation during the build execution process. Such as compiling, packaging, generating javadoc, publishing to a warehouse, and so on.

So far, we've found that we can define some simple tasks in one project, and subsequent chapters will cover multi-project building and multi-project multitasing.

Hello world

You can execute the build by running the gradle command on the command line, which looks for the build.gradle file from the current directory. W e call the build.gradle file a build script. Strictly speaking, this is actually a build configuration script, and you'll learn later that the build script defines a project and some default tasks.

You can create the following script to build.gradle in To try this out, create the following build script named build.gradle.

The first build script

build.gradle

task hello {
    doLast {
        println 'Hello world!'
    }
}

The gradle -q hello is then executed in the directory where the file is located

-q What is the role of the parameters?

Many of the examples in this document add -q parameters when calling the gradle command. T his parameter controls the log level of the gradle and guarantees that only what we need is output. You can refer to the Chapter 18 log in this document for more parameters and information.

Execute the script

Output of gradle -q hello
> gradle -q hello
Hello world!

The script above defines a task called hello and adds an action to it. W hen the gradle hello is executed, Gralde calls the hello task to perform the given action. These operations are actually a closure written in groovy.

If you think it looks like targets in Ant, you're right. G radle's tasks are equivalent to targets in Ant. B ut you'll find him more powerful. W e just changed another term that's more graphic than target. U nfortunately, this happens to conflict with the terminology in Ant. T here are such things as javac, copy, tasks in the ant command. S o when tasks are mentioned in the document, unless the ant task is specifically specified. Otherwise, it refers to the tasks in Gradle.

Quickly define tasks

Define the hello task above in a more concise way.

Quickly define tasks

build.gradle

task hello {
    println 'Hello world!'
}

Once again, the above script defines a task called hello in a closed-pack manner, which we will define more in subsequent chapters of this document.

Note: Deprecated in Gradle 4.x and removed in Gradle 5.0, see: Gradle 4.x.com

Example: Task slt;lt;?println 'Hello world!': Remove or use doLast to solve.

Code is a script

The Gradle script is written in Groovy as an appetizer, and here's an example.

Use groovy in the gradle task

build.gradle

task upper << {
    String someString = 'mY_nAmE'
    println "Original: " + someString
    println "Upper case: " + someString.toUpperCase()
}
Output of gradle -q upper
> gradle -q upper
Original: mY_nAmE
Upper case: MY_NAME

Or

Use groovy in the gradle task

build.gradle

task count << {
    4.times { print "$it " }
}
Output of gradle -q count
> gradle -q count
0 1 2 3

Task dependency

You can create dependencies between tasks as follows

Indicate the dependency between the two tasks

build.gradle

task hello << {
    println 'Hello world!'
}
task intro(dependsOn: hello) << {
    println "I'm Gradle"
}

The output of the gradle -q intro

Output of gradle -q intro
\> gradle -q intro
Hello world!
I'm Gradle

Adding a dependent task also does not have to declare the dependent task first.

Delayed dependency

build.gradle

task taskX(dependsOn: 'taskY') << {
    println 'taskX'
}
task taskY << {
    println 'taskY'
}

Output of gradle -q taskX

 \> gradle -q taskX
taskY
taskX

As you can see, taskX was defined before taskY, which is useful in multi-project builds.

Note: You cannot run a task using a short tag method when the referenced task is not yet defined.

Dynamic tasks

With Groovy's power, you can define simple tasks and do more. For example, you can define tasks dynamically.

Create dynamic tasks

build.gradle

4.times { counter ->
    task "task$counter" << {
        println "I'm task number $counter"
    }
}

The output of gradle -q task1.

Output of gradle -q task1
\> gradle -q task1
I'm task number 1

Task manipulation

Once a task is created, the tasks can access each other through the API. T his is also different from Ant. For example, you can add some dependencies.

Communication between tasks through the API - increase dependencies

build.gradle

4.times { counter ->
    task "task$counter" << {
        println "I'm task number $counter"
    }
}
task0.dependsOn task2, task3

The output of the gradle -q task0.

Output of gradle -q task0
\> gradle -q task0
I'm task number 2
I'm task number 3
I'm task number 0

Add behavior to existing tasks.

Communication between tasks through the API - Increase task behavior

build.gradle

task hello << {
    println 'Hello Earth'
}
hello.doFirst {
    println 'Hello Venus'
}
hello.doLast {
    println 'Hello Mars'
}
hello << {
    println 'Hello Jupiter'
}
Output of gradle -q hello
> gradle -q hello
Hello Venus
Hello Earth
Hello Mars
Hello Jupiter

DoFirst and doLast can make multiple calls. T hey are added at the beginning and end of the task, respectively. T hese actions are performed in a given order when the task begins to execute. Where the operator is a short-form of doLast.

Short marking method

You've noticed for a long time, yes, each task is a script property that you can access:

Access the task as a property

build.gradle

task hello << {
    println 'Hello world!'
}
hello.doLast {
    println "Greetings from the $hello.name task."
}

The output of the gradle -q hello

Output of gradle -q hello
\> gradle -q hello
Hello world!
Greetings from the hello task.

Built-in tasks provided for plug-ins. This is particularly convenient (e.g. complie)

Add custom properties

You can add additional properties to a task. F or example, add a property called myProperty and give him an initial value in the form of ext.myProperty. This adds a custom property.

Add custom properties to the task

build.gradle

task myTask {
    ext.myProperty = "myValue"
}

task printTaskProperties << {
    println myTask.myProperty
}

The output of the gradle -q printTaskProperties

Output of gradle -q printTaskProperties
\> gradle -q printTaskProperties
myValue

Custom properties aren't limited to tasks, they can do more.

Call the Ant task

The Ant task is a first-class citizen in Gradle. G radle uses Groovy to integrate Ant tasks well. G radle brings its own AntBuilder, which makes it easier and more powerful to call Ant tasks in Gradle than in .xml in build. The following example lets you learn how to invoke an Ant task and how to communicate with properties in Ant.

Use AntBuilder to perform ant.loadfile

build.gradle

task loadfile << {
    def files = file('../antLoadfileResources').listFiles().sort()
    files.each { File file ->
        if (file.isFile()) {
            ant.loadfile(srcFile: file, property: file.name)
            println " *** $file.name ***"
            println "${ant.properties[file.name]}"
        }
    }
}

The output of the gradle -q loadfile

Output of gradle -q loadfile
\> gradle -q loadfile
*** agile.manifesto.txt ***
Individuals and interactions over processes and tools
Working software over comprehensive documentation
Customer collaboration  over contract negotiation
Responding to change over following a plan
 *** gradle.manifesto.txt ***
Make the impossible possible, make the possible easy and make the easy elegant.
(inspired by Moshe Feldenkrais)

You can also do more with Ant in your script. For more information, see Call Ant in Gradle.

Method extraction

The power of Gradle depends on how you write scripting logic. For the above example, the first thing to do is to extract the method.

Use methods to organize script logic

build.gradle

task checksum << {
    fileList('../antLoadfileResources').each {File file ->
        ant.checksum(file: file, property: "cs_$file.name")
        println "$file.name Checksum: ${ant.properties["cs_$file.name"]}"
    }
}
task loadfile << {
    fileList('../antLoadfileResources').each {File file ->
        ant.loadfile(srcFile: file, property: file.name)
        println "I'm fond of $file.name"
    }
}
File[] fileList(String dir) {
    file(dir).listFiles({file -> file.isFile() } as FileFilter).sort()
}

The output of the gradle -q loadfile

Output of gradle -q loadfile
\> gradle -q loadfile
I'm fond of agile.manifesto.txt
I'm fond of gradle.manifesto.txt

In a later section you'll see that methods like this can be called in sub-projects in multi-project builds. No matter how complex the build logic is, Gradle can provide you with an easy way to organize them.

Define the default task

Gradle allows you to define multiple default tasks in a script.

Define the default task

build.gradle

defaultTasks 'clean', 'run'
task clean << {
    println 'Default Cleaning!'
}
task run << {
    println 'Default Running!'
}
task other << {
    println "I'm not a default task!"
}

The output of gradle -q.

Output of gradle -q
\> gradle -q
Default Cleaning!
Default Running!

This is the same as calling the gradle clean run effect directly. I n a multi-project build, each sub-project can specify a separate default task. If the child item is not specified, the default task specified by the parent project is called.

Configure by DAG

After you've detailed the configuration phase and the run phase of Gradle later, Gradle understands that all the tasks to be performed, Gradle, provides a hook to capture this information. A n example is the possible check to see if any of the tasks that have been performed have been released. From this, you can give different values to some variables.

In the following example, different version values are given for distribution and release tasks.

Depends on the different outputs of the task

build.gradle

task distribution << {
    println "We build the zip with version=$version"
}
task release(dependsOn: 'distribution') << {
    println 'We release now'
}
gradle.taskGraph.whenReady {taskGraph ->
    if (taskGraph.hasTask(release)) {
        version = '1.0'
    } else {
        version = '1.0-SNAPSHOT'
    }
}

The output of the gradle -q distribution

Output of gradle -q distribution
\> gradle -q distribution
We build the zip with version=1.0-SNAPSHOT

The output of the gradle -q release

Output of gradle -q release
\> gradle -q release
We build the zip with version=1.0
We release now

WhenReady affects the execution of published tasks before they are published. Even if the published task is not the primary task (that is, even if the task is not called directly from the command line)

The next goal

In this chapter, we learned what a task is, but it's not detailed enough. For more information, see chapter Task Details.

In addition, you can continue to learn about Java Build Getting Started and relying on the management foundation.