Settings.gradle not finding properties from gradle.properties

Problem

I’m getting this error message in a 2.14 project:

FAILURE: Build failed with an exception.

* Where:
Settings file 'E:\dev\myProject\settings.gradle' line: 3

* What went wrong:
A problem occurred evaluating settings 'myProject'.
> Could not get unknown property 'artifactoryBaseUrl' for object of type org.gradle.plugin.repository.internal.DefaultMavenPluginRepository.

Gradle Files

Here is settings.gradle:

pluginRepositories {
    maven {
        url "$artifactoryBaseUrl/libs-local"
        credentials {
            username mavenRepoUser
            password mavenRepoPassword
        }
    }
    maven {
        url "$artifactoryBaseUrl/plugins-release"
        credentials {
            username = mavenRepoUser
            password = mavenRepoPassword
        }
    }
    gradlePluginPortal()
}

Here is gradle.properties:

mavenRepoUser=myArtifactoryUser
mavenRepoPassword=myArtifactoryPassword
artifactoryBaseUrl=http://artifactory.service.net

Question

Why is settings.gradle not able to find properties defined in gradle.properties?

Observations

If I replace the property names in settings.gradle with their string literals, not only does the error go away, but these same properties are successfully resolved within build.gradle, which makes use of the same properties. So, it seems that only settings.gradle is having this problem.

Environment

Windows 8.1, jdk 1.8.0_u91 (64-bit)

build.gradle, settings.gradle, and gradle.properties are all co-located in the same project directory. I have no gradle.properties file in my user home directory.

I’m using the 2.14 gradle wrapper with this command line:

gradlew tasks

Here are the contents of MANIFEST.MF found in gradle/wrapper/gradle-wrapper.jar:

Manifest-Version: 1.0
Implementation-Title: Gradle
Implementation-Version: 2.14

Here are the contents of gradle/wrappper/gradle-wrapper.properties:

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip

AFAIK the settings.gradle file is one of the very first evaluated by Gradle to detect the projects to build. This file tells Gradle what are the modules to build.

Unless I’m wrong, the gradle.properties file is only evaluated when evaluating the corresponding project.

So this means that you don’t have access to the properties defined in the gradle.properties when evaluating the settings.gradle file because this file is evaluated later in the kinematics

This seems different from the documentation for settings.gradle:

Using Settings in a Settings File

Dynamic Properties

In addition to the properties of this interface, the Settings object makes some additional read-only properties available to the settings script. This includes properties from the following sources:

  • Defined in the gradle.properties file located in the settings directory of the build.
  • Defined the gradle.properties file located in the user’s .gradle directory.
  • Provided on the command-line using the -P option.

I can also confirm that I do not see this error when attempting to reference properties defined in gradle.properties for projects using the 2.12 wrapper.

@mark_vieira: seems like this might be a defect in 2.14’s handling of the new pluginRepositories block. It only exhibits when there are property references in the pluginRepositories block. Property references outside the pluginRepositories block are resolved without error in 2.14.

That is, with this gradle.properties file:

someUrl=http://some-server.net

…this settings.gradle will produce an unknown property error for someUrl:

pluginRepositories {
    maven {
        url "$someUrl/libs-local"
    }
    gradlePluginPortal()
}
println "Here's someUrl: $someUrl"

…but this one will not:

pluginRepositories {
    maven {
        url "http://some-server.net/libs-local"
    }
    gradlePluginPortal()
}
println "Here's someUrl: $someUrl"
1 Like

The current state of the world is that this is “Not Working … As Intended.”

We are striving to make the pluginRepositories {} block as declarative as possible. That is, we want to be able to take advantage of performance optimizations and things which would require the data of the specification to cacheable (just as an example.)

We are likely to loosen the syntactic restrictions as we continue to develop the feature. But, since it is always easier to loosen than to tighten such restrictions, we’ve started out by being very conservative.

So, the actual nature of the issue is not that settings.gradle is not finding the properties in gradle.properties, but rather, that we are ignoring anything that might be volatile or dynamic in the pluginRepositories {} block. This is similar to the restrictions spelled out in this documentation about the plugins {} block.

However, by contrast, we don’t have such a thorough disclaimer about the constrained syntax in the documentation of the pluginRepositories block. I’m opening a bug for us to flesh out the documentation to help avoid this sort of confusion (at least until we do loosen the syntax.)

In the meantime:

  1. Can you workaround this problem by just hard-coding the value in the settings.gradle file?
  2. Can you tell me more about your use-case? Is it basically that you have different development and production plugin repositories?

I do want to be clear that this is exactly the sort of feedback we are looking for. We want to be reasonable about supporting our users needs but also making sure that we don’t introduce complexities that needlessly add complexity and hurt performance.

Thanks for the clarification - I agree that a documentation note on constraints in the pluginRepositories section would be great.

Can you workaround this problem by just hard-coding the value in the settings.gradle file?

I currently have this workaround in place:

pluginRepositories {
    // NOTE: gradle 2.14 doesn't recognize properties from
    //       gradle.properties in the pluginRepositories
    //       block. If this changes in a future revision,
    //       the variable def's below can all be deleted
    def mavenRepoUser = "myUser"
    def mavenRepoPassword = "myPassword"
    def baseUrl = "http://artifactory.service.net"

    maven {
        url "$baseUrl/libs-local"
        credentials {
            username mavenRepoUser
            password mavenRepoPassword
        }
    }
    maven {
        url "$baseUrl/plugins-release"
        credentials {
            username = mavenRepoPassword
            password = mavenRepoPassword
        }
    }
    gradlePluginPortal()
}

Can you tell me more about your use-case? Is it basically that you have different development and production plugin repositories?

@eljobe: Here, the interest in gradle.properties isn’t so much in the multiple repositories, it’s in defining repo configuration (the baseUrl, username, and password properties) in just one place so they can be used in multiple gradle files (settings.gradle and build.gradle in this case).

We do, at the moment, have a different repo for internally-developed plugins versus those provided by Artifactory, but even with just one internal repo, we would still want to use the gradle.properties values in the pluginRepositories block.

1 Like

Please let me know if there is an issue for using Gradle properties in both pluginSettings {} and plugins {} sections. I’d vote for it.

Hello,

I can confirm, we’ve got the same problem in our company. Strange thing is - it works on our local machines, but is not working on the remote CI-Server (jenkins).

1 Like

I would also like to have url and credentials read from gradle.properties. I’d like to use the pluginRepositories section exactly like @chefhoobajoob described in the original post.

I would also like to be able to use variables from gradle.properties in the pluginRepositories block. I’d like my plugins to come from artifactory and keep settings.gradle in source control, but ~/.gradle/gradle.properties has my artifactory credentials.

This will be fixed in Gradle 3.0

We have been using ~/.gradle/init.d/artifactory.gradle a file we created with contents like

allprojects {
  ext {
    local_artifactory_user = 'example.user'
    local_artifactory_password = 'ExampleArtifactoryApiKey'
  }
}

Then in build.gradle these are available as e.g. project.ext[‘local_artifactory_user’]. We also added a separate mechanism where it could come from this value or an environment variable based on a Jenkins secret credential set before the build. Each user has their own separate credentials and access rights, but no per-project setup work to do.

It is a little ugly, but it works every day on dozens of machines.

Was this ever fixed? I’m seeing the same behavior with v3.4 – variables defined in ~/.gradle/gradle.properties are not available in settings.gradle.

2 Likes

Might make sense to open this as an issue on GitHub as this seems to affect multiple groups of people. It at least seems to sort-of work for a gradle.properties in the same project.

At least with 3.5-rc-1 right now:

settings.gradle

ratpackVersion=1.4.5

settings.gradle

pluginManagement {
  it.resolutionStrategy {
    it.eachPlugin {
      if (it.requested.id.id == 'io.ratpack.ratpack-java') {
        it.useVersion("${ratpackVersion}")
      }
    }
  }
}

That seems to work, but…

gradle.properties

ratpack.version=1.4.5

pluginManagement {
  it.resolutionStrategy {
    it.eachPlugin {
      if (it.requested.id.id == 'io.ratpack.ratpack-java') {
        it.useVersion("${ratpack.version}")
      }
    }
  }
}

This one fails (at least using gradle-script-kotlin:0.8.0) with:

Caused by: groovy.lang.MissingPropertyException: Could not get unknown property 'ratpack' for object of type org.gradle.plugin.management.internal.DefaultPluginResolveDetails.
        at org.gradle.internal.metaobject.AbstractDynamicObject.getMissingProperty(AbstractDynamicObject.java:88)
        at org.gradle.internal.metaobject.ConfigureDelegate.getProperty(ConfigureDelegate.java:134)

For the record, I coincidentally filed an issue for this: https://github.com/gradle/gradle/issues/1697. Thanks for your comment over there!

1 Like

For anyone else struggling to find a solution for this issue, you can access a property defined inside the ~/.gradle/gradle.properties from the settings.gradle this way:

settings.ext.find('MY_PROPERTY')
1 Like

Which issue are you talking about?
You can simply do println(MY_PROPERTY) and it works in settings.gradle.

Sorry, you are right: println(MY_PROPERTY) works fine. But settings.ext.find('MY_PROPERTY') can still be useful to test if a property is defined (if you try to access a non existing property you get a build error).

For example like this:

// https://docs.gradle.com/build-cache-node/
buildCache {
    boolean isCiServer = System.getenv().containsKey("CI")
    boolean isEnabled = settings.ext.find('GRADLE_BUILD_CACHE_NODE_USR') != null && settings.ext.find('GRADLE_BUILD_CACHE_NODE_PWD') != null
    remote(HttpBuildCache) {
        enabled = isEnabled
        push = isCiServer
        allowUntrustedServer = true
        url = 'https://myserver/cache/'
        if (isEnabled) {
            credentials {
                username = GRADLE_BUILD_CACHE_NODE_USR
                password = GRADLE_BUILD_CACHE_NODE_PWD
            }
        }
    }
}

But, in this example, the check for isEnabled can be skipped using settings.ext.find():

buildCache {
    boolean isCiServer = System.getenv().containsKey("CI")
    boolean isEnabled = settings.ext.find('GRADLE_BUILD_CACHE_NODE_USR') != null && settings.ext.find('GRADLE_BUILD_CACHE_NODE_PWD') != null
    remote(HttpBuildCache) {
        enabled = isEnabled
        push = isCiServer
        allowUntrustedServer = true
        url = 'https://myserver/cache/'
        credentials {
            username = settings.ext.find('GRADLE_BUILD_CACHE_NODE_USR')
            password = settings.ext.find('GRADLE_BUILD_CACHE_NODE_PWD')
        }
    }
}

But then better use something like

println(hasProperty('MY_PROPERTY') ? MY_PROPERTY : '<not set>')

or

println(settings.hasProperty('MY_PROPERTY') ? settings.MY_PROPERTY : '<not set>')

Whenever you use ext, it is more a dirty work-around, there are usually better and more appropriate ways.

buildCache {
    boolean isCiServer = System.getenv().containsKey("CI")
    String user = settings.hasProperty('GRADLE_BUILD_CACHE_NODE_USR') ? settings.GRADLE_BUILD_CACHE_NODE_USR : null
    String pass = settings.hasProperty('GRADLE_BUILD_CACHE_NODE_PWD') ? settings.GRADLE_BUILD_CACHE_NODE_PWD : null
    remote(HttpBuildCache) {
        enabled = user && pass
        push = isCiServer
        allowUntrustedServer = true
        url = 'https://myserver/cache/'
        credentials {
            username = user
            password = pass
        }
    }
}
1 Like

Got it, thanks for the explanation.