Overriding a Gradle project property which has . and _ characters, without modifying the buildscript

Featured image for sharing metadata for article

Yesterday I was working with a codebase which uses a gradle.properties, and for ✨ reasons ✨ I need to overwrite a given property, without modifying the codebase.

This is something that the docs indicate is a common need:

This feature is useful when you don’t have admin rights to a continuous integration server, and you need to set property values that should not be easily visible. Since you cannot use the -P option in that scenario, nor change the system-level configuration files, the correct strategy is to change the configuration of your continuous integration build job, adding an environment variable setting that matches an expected pattern. This won’t be visible to normal users on the system.

But unfortunately I found it to be particularly painful, as I have a property that includes both a . and _.

(The below is tested with Gradle 7.6.4)

Why is this painful? Let's start with looking at how the project is set up. We've got a gradle.properties like so:

me.jvt.example=something
me.jvt.example_underscore=another_value

In our Gradle Kotlin buildscript, we've got:

var prop = providers.gradleProperty("me.jvt.example").orNull
println("The value of me.jvt.example is: ${prop ?: "<null>"}")

prop = providers.gradleProperty("me.jvt.example_underscore").orNull
println("The value of me.jvt.example_underscore is: ${prop ?: "<null>"}")

Then, we can check that this is loaded correctly:

% ./gradlew

> Configure project :
The value of me.jvt.example is: something
The value of me.jvt.example_underscore is: another_value

Do environment variables work?

I started by using an environment variable, which was recommended in the docs as a way to do it when you can't modify the properties used to execute Gradle, where you can use i.e.:

ORG_GRADLE_PROJECT_foo=bar

However, it wasn't explained in the docs as to how this would work with a property with both a . and _ in it.

I wondered if this would work how Spring Boot's environment variable naming works, but after playing around with different options, the below didn't seem to work:

env ORG_GRADLE_PROJECT_ME_JVT_EXAMPLE_UNDERSCORE=overridden ORG_GRADLE_PROJECT_ME_JVT_EXAMPLE=over_ridden ./gradlew

> Configure project :
The value of me.jvt.example is: something
The value of me.jvt.example_underscore is: another_value

However, it does seem to work when using the plain property names in the environment variables, such as:

env ORG_GRADLE_PROJECT_me.jvt.example=overridden ORG_GRADLE_PROJECT_me.jvt.example_underscore=over_ridden ./gradlew

> Configure project :
The value of me.jvt.example is: overridden
The value of me.jvt.example_underscore is: over_ridden

That works 🚀 Or does it..?

Environment variables with unexpected characters may not work

Interestingly this seemed to work when running interactively in bash, but doesn't work if you try and export the variables:

$ export ORG_GRADLE_PROJECT_me.jvt.example=overridden ORG_GRADLE_PROJECT_me.jvt.example_underscore=over_ridden
bash: export: `ORG_GRADLE_PROJECT_me.jvt.example=overridden': not a valid identifier
bash: export: `ORG_GRADLE_PROJECT_me.jvt.example_underscore=over_ridden': not a valid identifier

As noted on the StackOverflow post "Exporting a variable with dot (.) in it", the shell doesn't deem that to be a valid variable, but using it with env seems to be safe (which is my preference anyway).

I'd also read some docs about how the _ will be implicitly remapped to a ., so I'd have to modify the buildscript to reference me.jvt.example.underscore which was not intended.

However, when I started using that with Renovate, which was the key problem I was trying to solve, it didn't seem to work:

(Note that the below command was intentionally set up to fail with an error code - the important thing here is that we need to get the output of the properties)

       "err": {
         "cmd": "/bin/sh -c ./gradlew exit",
         "stderr": "..."
         "stdout": "...> Configure project :
The value of me.jvt.example is: something
The value of me.jvt.example_underscore is: another_value
",
         "options": {
           "cwd": "/tmp/renovate/repos/github/jamietanna-testing/renovate-testing-gradle-opts",
           "encoding": "utf-8",
           "env": {
             "HOME": "/home/ubuntu",
             "PATH": "/home/ubuntu/.local/bin:/home/ubuntu/bin:/home/ubuntu/.local/bin:/home/ubuntu/bin:/home/ubuntu/.local/bin:/home/ubuntu/bin:/home/ubuntu/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
             "LC_ALL": "C.UTF-8",
             "LANG": "C.UTF-8",
             "ORG_GRADLE_PROJECT_me.jvt.example": "overridden",
             "ORG_GRADLE_PROJECT_me.jvt.example_underscore": "over_ridden",
             "CONTAINERBASE_CACHE_DIR": "/tmp/renovate/cache/containerbase"
           },
           "maxBuffer": 10485760,
           "timeout": 900000
         },

Notice that we've wired in the variables to override the properties which seems to be correct, but they are not working.

Falling back to an GRADLE_OPTS

As it didn't end up working, and had some caveats around usage, I looked for an alternate version.

As this is a Gradle project property, it could be set with i.e.:

./gradlew properties -Pme.jvt.example_underscore=new_value_here

We could try and use JAVA_OPTS, but find that this doesn't work as that's for the underlying JVM being started up, not for the Gradle process itself:

$ env JAVA_OPTS="-Pme.jvt.example_underscore=new_value_here" ./gradlew properties
Unrecognized option: -Pme.jvt.example_underscore=new_value_here
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

Notice that this does not work, as we need to set the org.gradle.project prefix to indicate to Gradle that we're trying to override a project property:

% env GRADLE_OPTS="-Dorg.gradle.project.me.jvt.example_underscore=new_value_here" ./gradlew properties

> Configure project :
The value of me.jvt.example is: something
The value of me.jvt.example_underscore is: new_value_here

Omitting the prefix will result in the property not working:

# NOTE doesn't work
% env GRADLE_OPTS="-Dme.jvt.example_underscore=new_value_here" ./gradlew properties

> Configure project :
The value of me.jvt.example is: something
The value of me.jvt.example_underscore is: another_value

As we can see, using GRADLE_OPTS to specify these project properties are probably the most resilient, and don't require any code changes.

Written by Jamie Tanna's profile image Jamie Tanna on , and last updated on .

Content for this article is shared under the terms of the Creative Commons Attribution Non Commercial Share Alike 4.0 International, and code is shared under the Apache License 2.0.

#blogumentation #gradle #renovate.

This post was filed under articles.

Interactions with this post

Interactions with this post

Below you can find the interactions that this page has had using WebMention.

Have you written a response to this post? Let me know the URL:

Do you not have a website set up with WebMention capabilities? You can use Comment Parade.