Monthly Archives: December 2017

Essential Gradle – A Birdie’s Look.

This blog is to help the reader understand essentials of Gradle build tool.

Introduction

Building a software is a craft by itself; build process usually involve a series of task such as picking the right libraries, compiling the source code, package distributed executable,  test using automated scripts and report process progress. Each task can be broken down into further activities, for example directing the execution order, resolving dependencies, resource identification and  component configuration.

Gradle is the new build automation tool that assists with continuous delivery.  Gradle offers flexibility in the ways projects are put together, it optimizes the build in interesting ways and it is extremely customizable.  The documentation can be found here. You may find detailed installation instructions here.

Gradle uses Groovy syntax. Groovy is a powerful, optionally typed and dynamic language, with static-typing and static compilation capabilities, for the Java platform aimed at improving developer productivity thanks to a concise, familiar and easy to learn syntax. It integrates smoothly with any Java program, and immediately delivers to your application powerful features.

Gradle includes interesting features such as scripting, DSL (Domain-Specific Language) authoring, run-time and compile-time meta-programming and functional programming features. Thus programming language Groovy is its natural choice. Groovy is concise, readable and expressive syntax, easy to learn for Java developers.

Gradle Build Scripts

Gradle is composed of two components (1) Project and (2) Task. Each Gradle build comprises of one or more projects. A project represent a thing to be done, such as deploying your application to staging or production environments. Each project is made up of one or more tasks. A task represents some atomic piece of work which a build performs. This might be compiling some classes, creating a Java archive, generating Java documentation, or publishing an archive to a repository.

The Gradle works on the principle that every build has two phases (1) The Configuration Phase and (2) The Execution Phase. During the configuration phase, the Gradle kernel will scan at all the configuration details in the build, figures out how the various tasks are laid out, and also the dependencies between tasks in form of a ‘Directed Acyclic Graph’. All customization that are specific to a task is done during the execution phase. The execution phase is done as a built-in auto-generated-task or custom specific task directed by the developer.

Defining Tasks and Closures

Let us dive into the basics and syntax soup – assuming you have proper installation and set up done. Say for example, a simple task is defined as below:


task helloWorld { 
 doLast {
    println 'Hello world.'
   }
 }

Here, we have defined a helloWorld task and method doLast. When executed, the task will print the words ‘Hello world.’ on the console. The println is a Groovy method to print text to the console and is basically a shorthand version of the System.out.println Java method. A task can comprise of any number of methods. Alternatively, we can use the << left shift operator as synonym for the doLast method.


 task helloWorld <<  {       println 'Hello world.' }

Gradle support closures. Closures are reusable pieces of code, whose result can be stored in a variable or passed to a method. Closures are represented by a pair of curly parenthesis ( {. . .} ). We can pass one or more parameters to a closure. On instances where there is only one parameter, that parameter can be referred via it.  Parameters can also be explicitly named. See the following examples below.


task sometask { 
   doLast { 
    // Using implicit 'it' closure parameter. 
    // The type of 'it' is a Gradle task. 
    println "Running ${it.name}" 
   } 
}

task sometask { 
   doLast { Task task -> 
   // Using explicit name 'task' as closure parameter. 
   // We also defined the type of the parameter. 
   println "Running ${task.name}" 
   } 
}

Defining Actions

We can add actions to a task. This is an implementation class from the org.gradle.api.Action interface. Usually an action has one execute method that us invoked when the task is executed. See the simple example below:


task sometask { 
  doFirst( 
     new Action() { 
            void execute(O task) { 
                println "Running ${task.name}" 
            } 
     } 
 ) 
}

Defining Dependency

We can add task dependencies with the dependsOn method for a task. We can specify a task name as the String value or task object as the argument. We can even specify more than one task name or object to specify multiple task dependencies. The dependency between tasks is lazy. Dependencies can be defined via tasks or closures. We can define a dependency on a task that is defined later in the build script. Gradle will set up all task dependencies during the configuration phase and not during the execution phase. The order of the tasks doesn’t matter in the build script. Some examples below


task third(dependsOn: 'second') << { task -> 
 println "Run ${task.name}" 
} 
 
task second(dependsOn: 'first') << { task -> 
 println "Run ${task.name}" 
} 
 
task first << { task -> 
 println "Run ${task.name}" 
}

Another example. We define a dependency for the second task on all tasks in the project with task names that have the letter f in the task name. For this 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’.


def printTaskName = { task -> 
    println "Run ${task.name}" 
} 

task second << printTaskName 

// We use the dependsOn method 
// with a closure. 
second.dependsOn {
    project.tasks.findAll { task -> 
           task.name.contains 'f' } } 

task first << printTaskName 

task beforeSecond << printTaskName

Besides, tasks can be also be organised, task defaults can be specified, tasks can be grouped, additional project/task properties can be defined and certain tasks can be skipped.

Defining the Java Plugin

In Gradle, we have the concept of introducing additional extra functionalities beyond tasks and properties via plugins. we can apply plugins to our project. Also the concept of plugin keeps these extra functionalities decoupled from the core build logic. Gradle ships with plugins that are ready out of the box; it also allows us to write our won. For example, Gradle has a Java plugin. This plugin adds tasks for compiling, testing, and packaging Java source code related to our project.

Dependency Management

Gradle provides control of project dependencies via a manageable ‘Dependency Tree’. It also has provisions for designing custom dependencies and declare non-managed dependencies. Gradle can help in producing run time dependency report. The tree structure makes it natural for the tool to dynamic scale into multiple projects avoiding version conflict. Inclusion and exclusion can be  well scoped within the branches of the trunk.

Test Support

Gradle supports compilation and execution of tests. It offers testCompile and testRuntime dependency configurations for this purpose. Gradle offers support to JUnit, Test NG and direct test annotations from few other frameworks that can run on JVM. Gradle also helps in producing test reports in XML and HTML formats as configured by the test engineer.

Build and Publish

Any software project is composed of artifacts we may want to publish. Such articles are stored in jar, war or zip file formats. Gradle allows developers to publish their artifacts in a central repository, thereby enabling other developers in the organization to be able to access via intranet or internet.

Concluding Remarks

So here in this blog we have understood the basic syntax of Gradle and composed a simple task using the same.  Gradle supports incremental builds. To further the horizon, the next steps of advancement would be to learn to build more complex tasks, multi project composition, dependency management and task graph design.

Pointers from here

Gradle official documentation site: https://gradle.org/docs/

Gradle and Spring Boot: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/

Gradle Essentials Book: https://www.packtpub.com/web-development/gradle-essentials

Time stamp validity: The blog content is relevant as of December 2017