How are gradle extra properties set in the Kotlin DSL? - gradle

I'm trying to organize my build files as I would in groovy, by having values in a separate file to reuse. But I cannot understand the syntax to do the same thing in the kotlin DSL.
Here's what I'm using in root build.gradle.kts:
applyFrom("config.gradle.kts")
buildscript {
repositories {
google()
jcenter()
}
dependencies {
val test = project.extra["minSdkVer"]
classpath("com.android.tools.build:gradle:3.0.0-alpha4")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.2-5")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
mavenCentral()
}
}
and here's whats in the config.gradle.kts that is being referenced:
mapOf(
Pair("minSdkVer", 22),
Pair("targetSdkVer", 25),
Pair("compiledSdkVer", 25),
Pair("buildToolsVer", "26-rc4")
).entries.forEach {
project.extra.set(it.key, it.value)
}
But there's an error:
Cannot get property 'minSdkVer' on extra properties extension as it
does not exist

A correct fix: Gradle collects and applies the buildscript { ... } blocks from your script strictly before executing anything else from it. So, to make your properties from config.gradle.kts available inside the buildscript, you should move applyFrom("config.gradle.kts") to your buildscript { ... } block:
buildscript {
applyFrom("config.gradle.kts")
/* ... */
}
Another possible mistake is using an extra property as extra["minSdkVer"] in a scope of another ExtensionAware, like a task in this example:
val myTask = task("printMinSdkVer") {
doLast {
println("Extra property value: ${extra["minSdkVer"]}")
}
}
In this case, extra.get(...) uses not the project.extra but the extra of the task.
To fix that, specify that you work with the project. Direct usage:
println(project.extra["minSdkVer"])
And for delegation.
val minSdkVer by project.extra

Related

Define global variable for AWS credentials in build.gradle? [duplicate]

I am new to gradle and have some question about project properties.
I need to declare spring boot dependences at multiple locations in my build.gradle and I'd like to use a variable to define the version. What is the best way in gradle? (in Maven, I use properties)
My attempt is use extra properties, but it cannot access the property in the buildscript closure. I googled around and read many articles accessing properties in custom tasks. What did I miss?
ext {
springBootVersion = '1.1.9.RELEASE'
}
buildscript {
print project.springBootVersion //fails here
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${project.springBootVersion}")
}
}
install {
repositories.mavenInstaller {
pom.project {
parent {
groupId 'org.springframework.boot'
artifactId 'spring-boot-starter-parent'
version "${project.springBootVersion}" //this one works
}
}
}
}
Moving the ext block inside the buildscript block solves the problem for me. Not sure if this is officially supported though, as it's effectively configuring project.ext from the (very special) buildscript block.
Because the buildscript block is evaluated first, before springBootVersion has been defined. Therefore, the variable definition must go in the buildscript block before any other definitions:
Source Here
buildscript {
ext {
springBootVersion = '1.1.9.RELEASE'
}
print project.springBootVersion //Will succeed
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${project.springBootVersion}")
}
}
This will not work.
First of all buildscript block is evaluated at the very beginning, before any other part of groovy script. Hence, properties defined in ext block just does not exist at that time.
Secondly, I'm unsure about if exchanging properties between buildscript and other part of script is possible.

Apply external Plugin to a subset of subprojects

I am using the Gradle SSH Plugin to deploy some, but not all subprojects to two different remote machines. I want to configure these remotes in the main build script to avoid duplication, but cannot apply the plugin as per this:
configure([
project(':Subproject1'), project(':Subproject5'), project(':Subproject7')
])
{
buildscript {
dependencies {
classpath 'org.hidetake:gradle-ssh-plugin:2.4.2'
}
}
apply plugin: "org.hidetake.ssh"
ssh.settings {
user = getProperty('ssh.username')
identity = file(getProperty('ssh.identity'))
knownHosts = allowAnyHosts
}
remotes {
tomcat {
host = getProperty('ssh.hosts.tomcat')
}
jboss {
host = getProperty('ssh.hosts.jboss')
}
}
}
Gradle fails with > Plugin with id 'org.hidetake.ssh' not found.
Everything is fine when the contents of the configuration closure are applied per project. How can I elegantly solve this issue?
Guessing here as I haven't reproduced your issue, but the buildscript block is special as it is pre-parsed before normal groovy parsing of the build files and I suspect that having it inside a project block like you have will not work.
Have you tried moving the buildscript block to the root level in the script above?
edit 1: old gradle forums post discussion this can be found here
edit 2: adding a snippet of code in response to a comment.
To remove duplication and only define say the repository references in one place, you could use the following pattern:
buildscript {
ext.RepositoryConfigurator = {
maven {
credentials.username artifactoryReader
credentials.password artifactoryReaderPwd
url artifactoryReaderUrl
}
jcenter()
mavenCentral()
}
ext.DependencyConfigurator = {
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:1.2"
}
ext.ResolutionConfigurator = {
resolutionStrategy.cacheChangingModulesFor 60, 'minutes'
}
repositories RepositoryConfigurator
dependencies DependencyConfigurator
configurations.classpath ResolutionConfigurator
}
apply plugin: "some.plugin.requiring.above.classpath"
gradle.rootProject {
buildscript {
repositories RepositoryConfigurator
dependencies DependencyConfigurator
configurations.classpath ResolutionConfigurator
}
}
gradle.allprojects {
buildscript {
repositories RepositoryConfigurator
dependencies DependencyConfigurator
configurations.classpath ResolutionConfigurator
}
}
In other words: since the buildscript block is special and pre-parsed, you can not use things defined elsewhere in the buildscript block. Going in the other direction is ok though, i.e. you can define things in the buildscript block which are then visible elsewhere. We can use this to define the repository references once inside the buildscript block and then use that reference in other places in the build file.
The above is from a settings.gradle file so might or might not be a perfect fit, but should demonstrate the idea.

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"
}
}
// ...

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'

Access project extra properties in buildscript closure

I am new to gradle and have some question about project properties.
I need to declare spring boot dependences at multiple locations in my build.gradle and I'd like to use a variable to define the version. What is the best way in gradle? (in Maven, I use properties)
My attempt is use extra properties, but it cannot access the property in the buildscript closure. I googled around and read many articles accessing properties in custom tasks. What did I miss?
ext {
springBootVersion = '1.1.9.RELEASE'
}
buildscript {
print project.springBootVersion //fails here
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${project.springBootVersion}")
}
}
install {
repositories.mavenInstaller {
pom.project {
parent {
groupId 'org.springframework.boot'
artifactId 'spring-boot-starter-parent'
version "${project.springBootVersion}" //this one works
}
}
}
}
Moving the ext block inside the buildscript block solves the problem for me. Not sure if this is officially supported though, as it's effectively configuring project.ext from the (very special) buildscript block.
Because the buildscript block is evaluated first, before springBootVersion has been defined. Therefore, the variable definition must go in the buildscript block before any other definitions:
Source Here
buildscript {
ext {
springBootVersion = '1.1.9.RELEASE'
}
print project.springBootVersion //Will succeed
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${project.springBootVersion}")
}
}
This will not work.
First of all buildscript block is evaluated at the very beginning, before any other part of groovy script. Hence, properties defined in ext block just does not exist at that time.
Secondly, I'm unsure about if exchanging properties between buildscript and other part of script is possible.

Resources