Order of precedence for defining gradle properties

From the documentation, gradle currently applies properties in this order:

project gradle.properties home gradle.properties properties specified on the command line with -P

The last one to define a property wins. I’m thinking it makes sense to have more specific things override less specific things, as is the case with the command line, where the specific command line overrides anything in a general properties file.

But I’m not too sure about the first two. I think the gradle.properties file in a file specific to a project should override the value in the more generic gradle home directory. This would allow me to set up property files that would, in effect, say “use this value everywhere except for this project”.

What do you think?

1 Like

The order of evaluation follows the common strategy of having user-specific values override project-specific ones, and invocation-specific values override user-specific ones. If you need more control, you can provide an ‘~/init.gradle’ that registers an appropriate callback. For example, ‘gradle.allprojects { … }’ should kick in before any configuration done in ‘build.gradle’, and possibly also before a project-level ‘gradle.properties’.

In general, it seems more desirable to have users declare their differences from the project configuration, rather than the other way around.

That makes sense. Thank you for the explanation.

Steve

I do have a follow up question:

Is there a way to tell where a property was set? I have a plugin that reads gradle-.properties files. The idea is that I can store configurations for different environments with the project itself, and simply specify the environment for which I’m building th load that configuration. I’m thinking that a property should be evaluated in the following order:

  1. project gradle.properties file 2) project gradle-.properties file 3) user gradle.properties file 4) command line -P properties.

1, 3, and 4 are done by gradle before it even gets to my plugin. When my plugin is applied, I can check to see of the value of a property in the gradle-.properties file is already set, but is there a way to tell if it was set from #1, in which case I want to override it, or if it was set by #3 or #4, in which case I don’t?

In a pinch , I can simply re-read the files in the same order as Gradle, does, but that still doesn’t tell me if there was a value passed in at the command line.

Thanks,

Steve

Gradle doesn’t provide any information on the source of a property.

The current order of evaluation conflicts with being able to provide a consistent build environment.

There are cases where a project MUST be built with a specific property value and so that property needs to be managed by a VCS. Project gradle.properties is the obvious candidate and the manual even suggests this (20.1), but because home gradle.properties may override it, any use of project gradle.properties cannot be relied upon - indeed its presence and any content only serve to give misleading reassurance to team members about how a project will be built.

I’d argue that the evaluation order should change so that: + Home property specifies the user’s preferred/default behaviour + Project property specifies required behaviour for that project + Command line property overrides other behaviour (typically for experimental use)

The [user manual 20.1][http://www.gradle.org/docs/current/userguide/build_environment.html#sec:gradle_configuration_properties] says >“certain settings like JVM memory settings, Java home, daemon on/off can be more useful if they can versioned with the project in your VCS so that the entire team can work with consistent environment. Setting up a consistent environment for your build is as simple as placing those settings into a gradle.properties file”

… but any home gradle.properties breaks that behaviour (and worse, does so silently)

A couple of specific use cases: + Generally I want to build with JDK 7, but project ABC must be built with JDK 6 + Generally I want the performance improvement of using the daemon, but project XYZ must disable the daemon as it causes a problem for some third-party plugin

Any thoughts on changing the evaluation order? init.gradle doesn’t seem natural to use for the use cases above (if it would even work?)

I don’t think that changing the evaluation order is an option. First, there are use cases where per-user configuration needs to win, and second it would be a huge breaking change. If upmost consistency is your goal, don’t use per-user configuration files and make every build fully self-contained. If you need to enforce this, you can search for per-user configuration files and fail the build if you find any.

Thanks for the quick answer, yes I can see there will be opposing use cases (actually JDK was a bad example from me as org.gradle.java.home needs to be a win per-user; disabling the daemon though is a real issue) so actually you can’t satisfy both. Perhaps you should change that section of the manual though as it explicitly describes a mechanism for a consistent environment that doesn’t work (or at least isn’t guaranteed to) Thanks for the suggestion re enforcing consistency; that will be the way we have to go, although it seems a bit unwieldy to need to ensure that the versioned files represent the canonical view of the build, rather than that being the default.

I agree that changing order might cause unexpected behavior.

But what about adding support for some hooks so user can inject his own property files during gradle properties loading?

I’m dealing with the same issue as Steve Saliman. I’m using gradle for running integration tests against different environments and I’d like to be able to specify env-specific properties with this priority: cmd arguments -> ~/.gradle/gradle.properties -> env-staging.properties -> env-common.properties-> gradle.properties

There is really no clean way for doing this right now.

The gradle properties plugin (https://github.com/stevesaliman/gradle-properties-plugin) was created for exactly this situation. It allows you to specify environment specific files with properties that override the ones in the project’s gradle.properties file.

However, those properties will still be overwritten by the user’s gradle.properties file. I wanted to keep the ordering consistent with what Gradle does out of the box to avoid confusion.

If you have properties that you NEED to have set in an environment file, you could get clever and check for them before applying the plugin, failing the build if they are set before the plugin has had the chance to read them from environment files.