Config cache friendly use of system properties in init.gradle

Hi there,
I’ve been looking into making configuration caching work for our inhouse builds and plugins. Obviously there is much work to do, but I hit a stumbling block very early on, where I didn’t find any information about.

We use global gradle.properties (in userhome/.gradle) to define some system properties to configure the development environment, like artifact repo urls, credentials etc.
In the init.gradle script these are used to set up repositories for plugin resolution

gradle.properties

systemProp.artifactoryUrl=***
systemProp.artifactoryUser=***
systemProp.artifactoryPassword=***

init.gradle

settingsEvaluated { settings ->
    settings.pluginManagement {
        repositories {
            mavenLocal()
            maven {
                url System.properties["artifactoryUrl"] + "libs/"
                credentials {
                    username = System.properties["artifactoryUser"]
                    password = System.properties["artifactoryPassword"]
                }
            }
        }
    }
}

If I enable the configuration cache I am presented (among others) with the following warnings:

·  ⌄ class init_4z5fpuovzcle9sjlx1adyfjbr$_run_closure1$_closure2$_closure3$_closure4$_closure5📋
    › ⨉read system property artifactoryPassword📋 ?
    › ⨉read system property artifactoryUser📋 ?

·  ⌄ class init_4z5fpuovzcle9sjlx1adyfjbr$_run_closure1$_closure2$_closure3$_closure4📋
    ⌄ ⨉read system property artifactoryUrl📋 ?

What is the intended way to make init.gradle cache friendly while still retaining the possibility to define properties in a central place?

What you are probably after is

settings.providers.systemProperty("artifactoryUrl")

so something like

settingsEvaluated {
    pluginManagement {
        repositories {
            mavenLocal()
            maven {
                url = settings.providers.systemProperty("artifactoryUrl").map { "${it}libs/" }
                credentials {
                    username = settings.providers.systemProperty("artifactoryUser").get()
                    password = settings.providers.systemProperty("artifactoryPassword").get()
                }
            }
        }
    }
}

But what you should strongly reconsider is using mavenLocal() at all and if, then as first and without content filter.
The local maven repo is broken by design.
If you for example also run Maven builds, some dependencies are maybe only partly in there as it is a mixture of repository and cache for Maven and only the actually downloaded things are in there.
If then later a Gradle build needs such an incomplete dependency it might silently misbehave or loudly fail.

1 Like

Thanks alot, that was exactly what I was looking for :smile:

We use mavenLocal() only for local deployment of development artifacts or experimental custom plugin versions, e.g. while refactoring some low level library without breaking everyone elses build. But thanks for the hint!

Yeah, just saying it can break your normal builds if someone also builds some Maven build that happens to use libraries your Gradle build also uses.

It would be better to add mavenLocal() just temporary and with content filter at the time it is necessary.

And even better, if the downstream project is a Gradle project, just use a composite build, then you don’t need Maven Local and manual building / deploying at all, but it just works automatically and rebuilds the downstream project if necessary. :slight_smile: