Gradle project properties best practices

Gradle project properties best practices

Gradle project properties provide an easy way to customise builds which may need to run slightly differently each time. In this article you’ll learn the most effective ways to use and set properties, along with some common scenarios you might come across in your Gradle project.

Why do we need project properties in a Gradle build?

A Gradle project property is a property that can be accessed in your project’s build.gradle and gets passed in from an external source when your build is executed.

Just like you might externalise configuration properties for an application in order that it can execute differently in different scenarios, the same applies to your Gradle build.

Let’s look at some reasons where you might use project properties.

Credentials or other sensitive information shouldn’t be stored in version control

The following build.gradle configures the Gradle maven-publish plugin to publish a jar file built by the java plugin:

plugins {
    id 'java'
    id 'maven-publish'
}

publishing {
    publications {
        maven(MavenPublication) {
            from components.java
        }
    }
    repositories {
        maven {
            url 'http://localhost:8081/repository/snapshots'
            credentials {
                username 'tom'
                password 'buttons123'
            }
        }
    }
}

group 'org.example'
version '1.0-SNAPSHOT'

The above code will publish a jar file to Maven when ./gradlew publish is run, resulting in output like this:

But, as you can see the username and password for the Maven repository are hard-coded. Assuming we’re committing our code into version control, then this represents bad practice since anyone who checks out our code would immediately have access to the credentials.

Much better would be to pass the credentials in externally, using Gradle project properties. The build.gradle just needs to be modified slightly:

            ...
            credentials {
                username mavenUsername
                password mavenPassword
            }
            ...

Now when we call the publish task we can pass the properties in using the Gradle -P flag, like this:

./gradlew publish -PmavenUsername=tom -PmavenPassword=buttons123

The build may need to be run differently depending on the situation

Sometimes rather than hard-coding parts of our build, we may need to be more flexible and allow it to run differently in different situations. For example, in the previous section the Maven repository URL was hard coded, like this:

        maven {
            url 'http://localhost:8081/repository/snapshots'
            credentials {
                username mavenUsername
                password mavenPassword
            }
        }

There may be a requirement to sometimes push to a different repository, in which case we’d also want to externalise this property using a project property.

Some other scenarios like this include:

  • deployment – if your Gradle build is responsible for also deploying then you may need to pass in extra information such as the environment and region to which to deploy
  • database connection string – if your build needs to connect to a database to run tests, you could use a project property to provide the option to connect to a different database. This would allow developers to more easily diagnose problems.

What ways are there to configure project properties?

Gradle provides several ways to pass properties into a build, some of which have higher priority than others. Or in other words, the same property key can be passed into the build in multiple ways, but the one with highest priority wins.

Here’s a quick overview of how that hierarchy works:

We’ll run through the ways to configure project properties from highest to lowest priority.

1) On the command line when calling Gradle using -P

When you run a Gradle command you can pass as many -PpropertyName=propertyValue flags as you like. For example:

./gradlew <task-name> -PmyPropName1=myPropValue1 -PmyPropName2=myPropValue2

2) As Java system properties using -D

You can pass Java system properties using the following syntax:

./gradlew <task-name> -Dorg.gradle.project.myPropName1=myPropValue1 -Dorg.gradle.project.myPropName2=myPropValue2

3) As environment variables

Lastly, you can pass project properties as environment variables using the following syntax:

ORG_GRADLE_PROJECT_myPropName1=myPropValue1 ORG_GRADLE_PROJECT_myPropName2=myPropValue2 ./gradlew publish

4) In a gradle.properties file (Gradle user home directory)

A gradle.properties file is a list of key values pairs, each of which represents a property name and value. For example:

myPropName1=myPropValue1
myPropName2=myPropValue2

A properties file can be located in the GRADLE_USER_HOME directory, which is usually ~/.gradle

5) In a gradle.properties file (project root directory)

Similar to above, a gradle.properties file can be placed in the project root directory.

How can we access project properties in builds?

Once a property has been passed into our Gradle build, we can use these three ways of accessing it:

1) Directly as a variable

You can treat a project property as a variable, and just reference it by its name.

For example, if we passed in a project property with ./gradlew <task-name> -PmyPropName1=myPropValue1 then it could be accessed in build.gradle like this:

println myPropName1

If the property is not found, then a MissingPropertyException is thrown.

Also note, that with this method IDEs may have a problem understanding and show a syntax error. Here’s the output from IntelliJ IDEA:

Cannot infer argument type error

2) Using the property method

Gradle provides the following method to access a property:

Object property(String var1) throws MissingPropertyException

For example, if we called ./gradlew <task-name> -PmyPropName1=myPropValue1 then the property could be accessed like this:

println property('myPropName1')

Like before, if the property is not found, then a MissingPropertyException is thrown.

3) Using the findProperty method

For when we need to access a property but we don’t want an exception to be thrown when it’s not provided, Gradle also provides the findProperty method:

Object findProperty(String var1)

If we called ./gradlew <task-name> -PmyPropName1=myPropValue1 then the property could be accessed like this:

println findProperty('myPropName1')

This time, if the property is not found null is returned. This can be very useful if we want to return a default value, which we can do using Groovy’s Elvis operator:

println findProperty('myPropName1') ?: 'defaultValue'

Checking if a property exists with hasProperty

Lastly, we can check for the presence of the property using the hasProperty method:

boolean hasProperty(String var1)

This could be used where we have some build logic that’s only enabled if a specific property is set, for example:

if (hasProperty('myPropName1')) {
    println 'Doing some conditional build logic'
}

Summary

Here’s a quick summary of the 3 ways to access a property value:

Throws MissingPropertyException?IDE understands?
As a variableYesNo
property methodYesYes
findProperty methodNoYes

Resources

Documentation

See this Gradle documentation which covers project properties, as well as other types of properties you can set.

Video

If you prefer to learn in video format, check out the accompanying video to this post on the Tom Gregory Tech YouTube channel.

Gradle project properties best practices

Leave a Reply

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

Scroll to top

To keep up to date with all things to do with scaling developer productivity, subscribe to my monthly newsletter!