Minimal Gradle Post | What you need to know

I’ve been using Gra­dle for some­time at the work­place and I find it to be a good build tool. In the past I’ve SBT, Maven and Nant as well as, well, MSBuild. It was only MSBuild that I grew much famil­iar with back in my .net days.

This is a min­i­mal Gra­dle post for who­ev­er wants to get start­ed with it with little/no fuss. Let’s get right into it.

What’s Gra­dle used for — It’s a build man­age­ment tool. What this means is that you can use Gra­dle to man­age build­ing your projects, man­age depen­den­cies with­in projects and exter­nal to them, man­age how tests are run, write pre/post build tasks/targets, and so on. You get the idea.

Two main ideas in Gra­dleProjects and tasks

A gra­dle build can con­sist of one or more projects and each project can have one more more tasks. Tasks are noth­ing but units of work need to be done. A gra­dle project needs to have at least one build.gradle file. If there is only one such file it needs to be present in the root direc­to­ry of the project. But you can addi­tion­al­ly have build.gradle for each project in your project. Gra­dle build files con­tain DSL code and can also con­tain Groovy or Kotlin code. The DSL is basi­cal­ly a declar­a­tive kind of lan­guage.

At this point, let’s dive into code and see a few things first hand. I will be using Intel­liJ IDEA to set up a Gra­dle project. You are free to use any edi­tor of your choice as long as it has sup­port for Gra­dle.

Down­load Intel­liJ, install Gra­dle plu­g­in (it would be checked by default), Set­up a new ‘Gra­dle’ project. You will see a build.gradle file set­up for you as well as a settings.gradle file.

Note that you will also see a few more things — gradlewrap­per, gradlew.sh and gradlew.bat files

So, what’s gradlewrap­per?
Say you run mul­ti­ple projects on your lap­top. Some might be using SBT, some Maven, some Gra­dle, etc. Gradlewrap­per let’s you use Gra­dle local to your project by pro­vid­ing Gra­dle jars that don’t need to be avail­able sys­tem wide. Mean­ing that you won’t need to install Gra­dle on your sys­tem. You can use the Gra­dle jars and scripts that come with Gradlewrap­per and that’s the end of sto­ry. To use Gra­dle through Gradlewrap­per you will need to sub­mit your Gra­dle com­mands to the scripts that ship with Gradlewrap­per — gradlew.bat for win­dows and gradlew.sh for *nix, much the same way as you would use the ‘gra­dle’ com­mand from com­mand line.

so, for exam­ple a nor­mal gra­dle com­mand could look some­thing like


gradle 

but if you don’t want to install Gra­dle on your sys­tem and rather just use Gradlewrap­per, you will write some­thing like


./gradlew 

Project list­ing goes in settings.gradle
settings.gradle will con­tain at least one project name — the root project, by default it’s the name of the direc­to­ry con­tain­ing the main/root project of your set­up. You can of course, change this name to any­thing of your lik­ing. Over time, if you have more projects, their names also go in settings.gradle file.

The Gra­dle sys­tem is rich with plu­g­ins. All plu­g­ins avail­able can be seen at this url. Plu­g­ins pro­vide addi­tion­al func­tion­al­i­ty to your Gra­dle set­up. Plu­g­ins might have pre-writ­ten tasks that you might not want/have to write your­self, apart from lot more func­tion­al­i­ties.
For exam­ple, if you want Scala to be the lan­guage for your project and you’d like Gra­dle to make src/test direc­to­ries for the same, you can use the ‘scala’ plu­g­in and ‘refresh’ your build.gradle and you will see the scala relat­ed direc­to­ries in your project struc­ture.
(By the way, you can also do a ‘refresh’ by exe­cut­ing gra­dle –refresh-depen­den­cies task from com­mand line)

For instance, my build.gradle file for this exer­cise looks like this —


group 'org.practice'
version '1.0-SNAPSHOT' //when version is set you will have a jar file with 
//name like mylibName-1.0-SNAPSHOT.jar, in this case

apply plugin: 'scala'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    //example on how to target jars in a specific local directory
    //compile files('/home/vaibhav/spark/spark-2.1.0/core/target/spark-core_2.11-2.1.0.jar')
    compile group: 'org.apache.spark',name: 'spark-core_2.11', version: '2.1.0'
    testCompile group: 'junit', name: 'junit', version: '4.11'
}

Cou­ple of things to note above -
1. You can see how to apply a plu­g­in.
2. When you might have set­up your sam­ple project(as men­tioned above) as a gra­dle project, you would have been asked to sup­ply groupId and arti­fac­tId. GroupId, Arti­fac­tId and Ver­sion, also called GAV, is a pret­ty stan­dard way in the mvn world to iden­ti­fy a library. Gra­dle fol­lows the same mvn con­ven­tion and in fact, the gra­dle project struc­ture by con­ven­tion, you will find, is much like mvn project struc­ture.

src/main/scala
src/test/scala

3. There would be a source­Com­pat­i­bil­i­ty option mean­ing that you com­pile your code to be com­pat­i­ble with a cer­tain ver­sion of java run time.
4. Under ‘repos­i­to­ries’, you can list the repos Gra­dle will hit to search for the depen­den­cies men­tioned under ‘depen­den­cies’. You can men­tion any num­ber of repos by pro­vid­ing a url. Maven­Cen­tral is avail­able by default.
You can also spec­i­fy local file sys­tem path to load depen­den­cies from, some­thing like

run­time files(‘lib/project1.jar’,‘lib2/project2.jar’)
There are many ways to spec­i­fy how to pick, from where to pick, and what to exclude. I am sure you can find the right syn­tax when you need it.

5. You can see that // works for com­ments, as well as /* .… */
6. When men­tion­ing what depen­den­cies to down­load, you pro­vide their GAV. By the way, if you don’t tell gra­dle where to down­load your depen­den­cies, it will do so by default at ~/.gradle/caches/
7. You can group your depen­den­cies — above you can see that I don’t need junit in my main project but I need it in my test project. So I use a pre-built group ‘test­Com­pile’. Sim­i­lar­ly, for the ‘com­pile’ group.

If you’d rather not use gradlewrap­per, you can install gra­dle using brew in Mac or apt-get install on Ubun­tu, etc. You might need to set GRADLE_HOME if the instal­la­tion does not already does that for you.

gradle.properties
You can spec­i­fy your gra­dle spe­cif­ic set­tings like what jvm to use, whether to keep gra­dle dae­mon alive(recommended set­ting), etc. in a gradle.properties file. If you are using gradlewrap­per, you should already have gradle-wrapper.properties file for you.

Gra­dle Tasks
So far, we’ve talked about set­ting up gra­dle and about projects. Let’s take a look at tasks now.
A build.gradle file can have many tasks, these tasks can be grouped or not grouped. When not grouped, a task is con­sid­ered a ‘pri­vate’ task and will show up under ‘Oth­er tasks’ when see­ing the out­put of com­mand ‘gra­dle tasks’, which lists all tasks. Here’s an exam­ple of a grouped task and an ungrouped task-


task calledOnce {
    println("I will get printed first")
}

task helloworld {
    group 'some group name'
    description 'this is desc for task helloworld'

    doFirst {
        println("hello world task begins")
    }

    doLast {
        println("hello world task ends")
    }
}

> gradle helloworld

> I will get printed first
> hello world task begins
> hello world task ends

doFirst, doLast are phas­es with­in a task. State­ments in task clo­sure not under any phase by default go into con­fig­u­ra­tion phase and are exe­cut­ed once before any oth­er phas­es, no mat­ter whether you call that par­tic­u­lar task or not.

Tasks can depend on each oth­er
This is a nor­mal pro­ce­dure for most build scripts. Exe­cu­tion order of tasks depends on which tasks depend on which ones.

exam­ple,


defaultTasks 'compile' //since a default task has been specified, on the command line it will suffice to just type 'gradle'

apply plugin: 'scala'

task compile(dependsOn: 'compileScala') {
   doLast { 
       println("compile task")
   }
}

//shorter syntax for defining doLast, doFirst
compileScala.doLast(dependsOn: 'clean') {
    println("compileScala task given by scala plugin")
}

task clean {
    doLast { 
       println("clean task")
   }
}

Note that you can also cre­ate your own tasks by extend­ing the Default­Task class, but this is not some­thing we are going to try in this post.

Mul­ti-project build struc­ture
Usu­al­ly you would have a few sub-projects or mod­ules in your project and they also need to be built, tests exe­cut­ed for them and there might be depen­den­cies among these sub-projects. Of course, gra­dle gives you option here. Let’s say you have project struc­ture like this —

root_project
— Web
— Core
— Util

In this case, your settings.gradle would con­tain ‘include’ some­thing like this —


include 'Core', 'Web', 'Util' //telling gradle we have sub projects

Now, the build.gradle file needs to cater for these sub-projects as well. There will be some tasks that are spe­cif­ic to sub-projects, some tasks com­mon for all, etc. Take a look —



//will be called once for each project, including root
allprojects {
    //groupId: ....
    //version: ....
}

//does not apply to root
subprojects {
    //apply specific plugins, etc.
}

//root_project specific dependencies
project(':org.practice.root_project').dependencies {
    compile project(':org.practice.Core'), project(':Util') 
    compile 'some lib'
}

or,


allprojects {
...
}

subprojects {
...
}

//Core specific stuff
project(':Core') {
    dependencies {
    ...
    }
}

//Util specific stuff
project(':Util') {
...
}

//Web specific stuff
project(':Web') {
...
}

Note that sub-project spe­cif­ic stuff could also go under their own sep­a­rate build.gradle files.

Pub­lish­ing arti­facts
Pub­lished files are called arti­facts. Pub­lish­ing is usu­al­ly done with the help of some plu­g­in, like maven.


apply plugin: 'maven'

uploadArchives { //maybe some nexus repo or local
    repositories {
        mavenDeployer {
            repository(url:"some url")
        }
    }
}

Hope the above gives you nec­es­sary infor­ma­tion to get going with gra­dle! Thanks for read­ing!

Leave a Reply

Your email address will not be published. Required fields are marked *