Gradle global variable not in scope within buildscript - gradle

I have something like this in my top level build.gradle (Gradle 2.2)
ext.repo = "https://my-artifactory-repo"
buildscript {
repositories {
maven {
credentials {
username foo
password bar
}
url repo //doesn't work
}
}
dependencies {
classpath 'com.android.tools.build:gradle:0.14.1'
}
}
allprojects {
repositories {
maven {
credentials {
username foo
password bar
}
url repo //works
}
}
}
This is the error
Could not find property 'repo' on org.gradle.api.internal.artifacts.repositories.DefaultMavenArtifactRepository_Decorated#718afa64.
So it works in allprojects but not buildscript.

You can define your variable as an extra property with ext in the buildscript {...}. This variable is then also accessible in the scope of allprojects {...}:
buildscript {
ext {
repo = "https://my-artifactory-repo"
}
repositories {
maven {
url repo // works
}
}
}
allprojects {
repositories {
maven {
url repo // works
}
}
}

This is happening because the buildscript {...} configuration closure is always evaluated first, so the property is not yet defined. A workaround would be to define the property outside of the build script, either by placing it in a gradle.properties file or via the command line.

Related

Gradle common repositories for multi module project

I have below project setup for gradle scripts, but I would like to keep one single common repository file for both main and subprojects.
apply from : "$rootDir/gradle/repositories.gradle" does not work inside build.gradle for this purpose. It would work only if I declare repositories again inside build.gradle
**build.gradle**
--------------------------
{
repositories {
maven {
url "https://myprivate.repo.com/artifactory"
credentials {
username = "user1"
password = "psswd"
}
}
}
dependencies {
# some list of dependencies
}
}
**gradle/repositories.gradle**
-------------------------
repositories {
maven {
url "https://myprivate.repo.com/artifactory"
credentials {
username = "user1"
password = "psswd"
}
}
}
**subprojects.gradle**
--------------------------
subprojects {
apply from : "$rootDir/gradle/repositories.gradle"
}

Gradle doesn't use repositories from "allprojects"

If I comment "repositories" on my buildscript, I get an error - even though the repositories are already declared on my "allprojects".
allprojects {
//...
buildscript {
repositories {
maven {
url "http://www.exemple.com/repositories"
}
}
}
}
}
buildscript {
// repositories {
// maven {
// url "http://www.exemple.com/repositories"
// }
// }
dependencies {
classpath group: 'com.exemple', name: 'exemple', version: '1.2.3'
}
}
Why does gradle not use the repositories defined on allprojects ? The error that I get:
> Could not resolve all dependencies for configuration ':classpath'.
> Cannot resolve external dependency com.exemple:exemple:1.2.3 because no repositories are defined.
buildscript block refers to the classpath for the current script, not a project. You can use it only for a Gradle script. For example:
example.gradle
buildscript {
repositories {
maven {
url "http://www.example.com/repositories"
}
}
dependencies {
classpath group: 'com.example', name: 'example', version: '1.2.3'
}
}
}
}
// do something, add tasks, etc.
build.gradle
subprojects {
apply from: 'example.gradle'
}

Using gradle project variable in buildscript scope

There is a similar question here Access project extra properties in buildscript closure
but i found a "workaround" which does not look like the optimum
I have a multi gradle project - im declaring the repository in the main gradle file
using
subprojects {
repostiories {
maven {..}
}
}
now i also have to set these for the build script because im using a plugin !
so again buildscript { repositories ...
Now instead of pasting the URLs twice i wanted to use a property - as i figured project.ext properties are not set during the buildscript stage thus i put them
in my gradle.settings file
i couldnt set rootProject.ext.xx settings so i had to use
gradle.ext {
mavenURLs = [ companyURL1, companyURL2 ... etc]
}
Now i could use gradle.ext.mavenURLs in my build.gradle file
Is there a better way ?
Is there a way to set the buildscript and dependency repositories for all project in one block without repeating once for buildscript and once for the dependency ?
def repoClosure = { RepositoryHandler repoHandler ->
repoHandler.mavenLocal()
repoHandler.mavenCentral()
['http://mycompany/repo1', 'http://mycompany/repo2'].each { mavenURL ->
repoHandler.maven {
url mavenURL
credentials {
username 'foo'
password 'bar'
}
}
}
}
project.with {
allprojects {
repoClosure(buildscript.repositories)
repoClosure(repositories)
}
}
Simply create my-repositories.gradle file, with content like:
def repoClosure = {
maven {
url uri("${rootProject.rootDir}/offline-repository")
}
google()
mavenCentral()
['http://mycompany/repo1', 'http://mycompany/repo2'].each { mavenURL ->
maven {
url mavenURL
credentials {
username 'my-name'
password 'my-password'
}
}
}
}
project.with {
allprojects {
buildscript {
ext.myVariable = "Just an example!"
repositories(repoClosure)
}
repositories(repoClosure)
}
}
Then in your build.gradle apply it, like:
buildscript {
apply from: './my-repositories.gradle'
ext {
kotlin_version = '1.5.30'
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.4'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
// ...

Can I add a custom repository to gradle.properties?

I'd like to be able to define a repository in settings (ideally user gradle.properties)
The end goal is something like this:
repositories {
mavenCentral() // Can't/don't want to use this
nexusCentral() // Can use these - on network Nexus server
nexusSnapshot()
}
How would I go about doing this? Again, this would go in the user-level gradle.properties file ideally, so we don't have to reference it in every single module.
This is just a plain maven style artifact repository provided by Maven, the manual way would be:
maven {
url "http://path/to/nexus"
}
One other requirement is the use of the "publish" task, which has credentials defined for a repository (that Jenkins uses to publish the module):
publishing {
...
maven {
url "http://path/to/nexus"
// Jenkins provides these as -P Gradle parameters.
credentials {
username = "${uploaderUser}"
password = "${uploaderPassword}"
}
}
These credentials would not be known to regular users, but would ideally be configured in Jenkin's gradle.properties. We wouldn't want users builds to fail because they can't resolve the credentials - they would never even use the "publish" task.
You can use somenthing like this:
maven {
credentials {
username getCredentialsMavenUsername()
password getCredentialsMavenPassword()
}
url 'xxxxx'
}
/**
* Returns the credential username used by Maven repository
* Set this value in your ~/.gradle/gradle.properties with CREDENTIALS_USERNAME key
* #return
*/
def getCredentialsMavenUsername() {
return hasProperty('CREDENTIALS_USERNAME') ? CREDENTIALS_USERNAME : ""
}
/**
* Returns the credential password used by Maven repository
* Set this value in your ~/.gradle/gradle.properties with CREDENTIALS_PASSWORD key
* #return
*/
def getCredentialsMavenPassword() {
return hasProperty('CREDENTIALS_PASSWORD') ? CREDENTIALS_PASSWORD : ""
}
If the user hasn't the credentials the script doesn't fail.
Not sure if that answers your question, but you can put this in the gradle.properties file:
nexusUrl=http://path/to/nexus
and do this in the build.gradle:
maven {
url project.property(nexusUrl)
}
EDIT:
regarding your credentials, all you should need is something like
if (project.hasProperty('uploaderUser') && project.hasProperty('uploaderPassword')) {
credentials {
username = project.property('uploaderUser')
password = project.property('uploaderPassword')
}
}
Solved this issue by replacing jcenter() in Project/andoird/build.gradle with maven { url 'http://nexusUrl' } under buildscript and allprojects:
buildscript {
repositories {
google()
maven { url 'http://nexusUrl' }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
}
}
allprojects {
repositories {
google()
maven { url 'http://nexusUrl' }
}
}
and in fluttersdk/packages/flutter_tools/gradle/flutter.gradle replaced jcenter with maven { url 'http://nexusUrl' } under buildscript:
buildscript {
repositories {
google()
maven { url 'nexusUrl' }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
}
}

Gradle Custom buildScriptRepository methods

I would like to make a custom buildScript repository method so I can easily reference our internal maven repo. Right now I'm required to declare a maven block everywhere we use our plugin.
Here is the current setup
buildscript {
repositories {
jcenter()
maven { url 'http://myNexus:8081/nexus/content/repositories/My-Release' }
}
dependencies {
classpath 'com.example.plugin:my-plugin:1+'
}
}
What I would like to do is something like this
buildscript {
repositories {
jcenter()
myReleaseRepo()
}
dependencies {
classpath 'com.example.plugin:my-plugin:1+'
}
}
How can I make a method available to create a repository anywhere we may use the plugin in the future?
Another solution is to add custom methods on RepositoryHandler using some Groovy goodness. Just chuck this in ~/.gradle/init.gradle
RepositoryHandler.metaClass.myReleaseRepo = {
delegate.maven {
name 'myReleaseRepo'
url 'http://myNexus:8081/nexus/content/repositories/My-Release'
}
}
After that, you can use it just as you described:
buildscript {
repositories {
myReleaseRepo()
}
}
Metaclasses in Groovy are just great. The delegate in this case is pretty much like the javascript this. This code is essentially using the RepositoryHandler instance (delegate keyword) and just calling repositoryHandlerInstance.maven(name, url).
It is possible to add a repo to an init script which would then apply to all gradle invocations that use the init script - without having to individually declare your maven repo in each build.gradle.
Solution 1:
Partial solution, does not do exactly what you're asking for. In init.gradle:
allprojects{
buildscript{
repositories{
maven{ url 'http://myNexus:8081/nexus/content/repositories/My-Release' }
}
}
}
Then your build.gradle can skip buildscript repo declaration entirely:
buildscript {
dependencies {
classpath 'com.example.plugin:my-plugin:1+'
}
}
Solution 2:
In fact, you can even move your buildscript classpath declaration to init and have the plugin apply to all projects that use the init script:
beefier init.gradle
allprojects{
buildscript{
repositories{
maven{ url 'http://myNexus:8081/nexus/content/repositories/My-Release' }
}
dependencies {
classpath 'com.example.plugin:my-plugin:1+'
}
}
}
gives you a lighter build.gradle
apply plugin: 'my-plugin'
I tried to, but apparently you cannot move the apply line to init.gradle as well. see this defect.
Solution 3:
I retract what I said in the comment above, I figured out how to do exactly what you're asking for. Apparently you can create extensions for the buildscript block using the initscript. However I still prefer solution2, because it gives you a cleaner build.gradle.
To create a buildscript extension, in your init.gradle:
class customRepos {
def buildscript
customRepos(buildscript) {
this.buildscript = buildscript
}
void addMyRepo() {
buildscript.repositories {
maven{ url 'http://myNexus:8081/nexus/content/repositories/My-Release' }
}
}
}
allprojects {
extensions.create('myRepo', customRepos, buildscript)
}
which then allows you to do this in your build.gradle
buildscript{
myRepo.addMyRepo()
dependencies {
classpath 'com.example.plugin:my-plugin:1+'
}
}
apply plugin: 'my-plugin'

Resources