Gradle 6 migration settings.gradle.kts - gradle

I've got the following code in the settings.gradle.kts, which is works fine in gradle 5
rootProject.name = "server"
val pluginsRepoUrl: String by settings
val repoUsername: String by settings
val repoPassword: String by settings
pluginManagement {
repositories {
maven {
url = uri(pluginsRepoUrl)
credentials {
username = repoUsername
password = repoPassword
}
}
}
}
I want to upgrade to gradle 6 but this code is not works and gives me a following error:
e: .../settings.gradle.kts:10:23: Unresolved reference: pluginsRepoUrl
The values comes from the gradle.properties file.

In Gradle 6, the behavior of the pluginManagement {} block was changed:
Previously, any pluginManagement {} blocks inside a settings script were executed during the normal execution of the script.
Now, they are executed earlier in a similar manner to buildscript {} or plugins {}. This means that code inside such a block cannot reference anything declared elsewhere in the script.
(emphasis mine)
This means that you cannot reference the variables declared outside of that block. To fix this, move those declarations inside the pluginManagement {} block:
pluginManagement {
val pluginsRepoUrl: String by settings
val repoUsername: String by settings
val repoPassword: String by settings
repositories {
...

Related

Gradle 6 settings.gradle.kts properties problem

please help me understand what was changed in Gradle 6 so the following code doesn't work anymore (worked well in Gradle 5):
val artifactoryUser: String by settings
val artifactoryPassword: String by settings
pluginManagement {
repositories {
mavenLocal()
maven {
url = uri("https://internal-artifactory")
credentials {
username = artifactoryUser
password = artifactoryPassword
}
}
}
}
Now I have an error: "Unresolved reference: artifactoryUser".
This problem can be solved by moving properties declaration inside the pluginManagement block
pluginManagement {
val artifactoryUser: String by settings
val artifactoryPassword: String by settings
repositories {
mavenLocal()
maven {
url = uri("https://internal-artifactory")
credentials {
username = artifactoryUser
password = artifactoryPassword
}
}
}
}
But I don't understand why.
The reason for it is mentioned in the Grade 6 upgrade notes :
The pluginManagement block in settings scripts is now isolated
Previously, any pluginManagement {} blocks inside a settings script
were executed during the normal execution of the script.
Now, they are executed earlier in a similar manner to buildscript {}
or plugins {}. This means that code inside such a block cannot
reference anything declared elsewhere in the script.
This change has been made so that pluginManagement configuration can
also be applied when resolving plugins for the settings script itself.
Indeed, moving the val inside the pluginManagement block does the trick, when migrating from Gradle 5.x to Gradle 6.x.
val kotlinVersion: String by settings
pluginManagement {
...
}
to:
pluginManagement {
val kotlinVersion: String by settings
...
}

Define an artifact to be used as a dependency in another project

TL;DR
I'm trying to configure two Gradle projects in a way that one project uses files built by the other one.
The first project is added to the second one by includeBuild and the file is defined in the second project as a dependency.
Project testA
settings.gradle:
rootProject.name = 'testA'
build.gradle:
group = 'org.test'
version = '0.0.0.1_test'
task someZip (type: Zip) {
from './settings.gradle'
archiveName = 'xxx.zip'
destinationDir = file("${buildDir}/test")
}
artifacts {
//TODO add something here?
}
Project testB
settings.gradle:
rootProject.name = 'testB'
if (System.getenv('LOCAL_COMPILATION') == 'true') {
includeBuild '../testA'
}
build.gradle:
if (System.getenv('LOCAL_COMPILATION') != 'true') {
repositories {
maven { url '192.168.1.100' }
}
}
configurations {
magic
}
dependencies {
magic 'org.test:xxx:0.0.0.+#zip'
}
task ultimateZip (type: Zip) {
from configurations.magic
archiveName = 'ultimate.zip'
destinationDir = file("${buildDir}/ultimate-test")
}
Description
You may noticed that the example has an option use a maven repository. I wanted to highlight that eventually there will be a possibility to do that.
Using Maven repository is not the point of this question, though, other than the solution should not interfere with that.
(In other words you can assume that System.getenv('LOCAL_COMPILATION') == 'true'.)
The question is how to define the artifact in a way that the other project is able to recognize it.
The preferred solution should be similar to what the Java plugin does because I'm using jar dependencies in my projects and they are working both through includeBuild and through a repository.
The following setup should work (tested with Gradle 5.5.1). It mostly corresponds to your original setup with the exception of the changes indicated by XXX.
Project testA
settings.gradle:
rootProject.name = 'testA'
build.gradle:
group = 'org.test'
version = '0.0.0.1_test'
task someZip (type: Zip) {
from './settings.gradle'
archiveName = 'xxx.zip'
destinationDir = file("${buildDir}/test")
}
// XXX (replaced your empty "artifacts" block)
configurations.create('default')
def myArtifact = artifacts.add('default', someZip) {
name = 'xxx'
}
// XXX (only added to show that publishing works)
apply plugin: 'maven-publish'
publishing {
repositories {
maven { url = 'file:///tmp/my-repo' }
}
publications {
myPub(MavenPublication) {
artifactId myArtifact.name
artifact myArtifact
}
}
}
Project testB
settings.gradle:
rootProject.name = 'testB'
if (System.getenv('LOCAL_COMPILATION') == 'true') {
// XXX (added a dependency substitution to let Gradle know that
// "org.test:xxx" corresponds to the testA project)
includeBuild('../testA') {
dependencySubstitution {
substitute module('org.test:xxx') with project(':')
}
}
}
build.gradle:
if (System.getenv('LOCAL_COMPILATION') != 'true') {
repositories {
// XXX (only changed to show that resolution still works after
// publishing)
maven { url = 'file:///tmp/my-repo' }
}
}
configurations {
magic
}
dependencies {
magic 'org.test:xxx:0.0.0.+#zip'
}
task ultimateZip (type: Zip) {
from configurations.magic
archiveName = 'ultimate.zip'
destinationDir = file("${buildDir}/ultimate-test")
}
As requested in the comments, here’s some more explanation on the created default configuration and the added artifact in project testA.
Composite builds in Gradle currently have the limitation that substituted project dependencies “will always point to the default configuration of the target project”. In your example this means that testA needs to publish in the default configuration. We thus first create the default configuration. Note that some plugins (like java) already create this configuration; you don’t need to create it yourself when using such plugins.
It doesn’t seem to be mentioned explicitly anywhere but as you seem to have found out yourself already, the PublishedArtifacts of a project (as declared with project.artifacts) are important for Gradle to figure out the dependency wiring in composite builds. Hence, we make sure to declare such a PublishedArtifact in testA using this API. The artifact (e.g., its extension) is configured based on the properties of the someZip task. The name seems to not be taken from the someZip task in your example because you manually set archiveName; hence we need to explicitly declare it. If you use archiveBaseName = 'xxx' in someZip instead, then you don’t need the closure when adding the artifact.

How do I add a private repo in the pluginManagement block in gradle.settings?

I am trying to setup a gradle 5 project which uses a custom plugin someone developed and is available in my company internal repository.
Until now, we have been importing it using the following approach:
buildscript {
ext {
usr = System.env.usr != null ? System.env.usr : project.ext.properties.usr
pass = System.env.pass != null ? System.env.pass : project.ext.properties.pass
privateRepo = {
name "privateRepo"
url <url>
credentials {
username usr
password pass
}
}
}
repositories {
maven (privateRepo)
}
dependencies {
// various dependencies
classpath "org.something:some-plugin:1.0"
...
}
apply plugin: "someplugin"
Just like this question.
As far as I understood, this is a deprecated approach, so I would like to use the pluginManagement block gradle.settings (again, as suggested in this answer)
The problem is that my repository is private, so I would need to define the user and pass variables.
I tried similar approached inside the pluginManagement block in gradle.settings, but I could not get it to work: the pluginManagement does not support the ext block and the pluginManagement has to be the first block in the script, limiting my alternatives.
Is there anyway I can define the variables so it can be used in the pluginManagement block?
Disclaimer: my question is not a duplicated of the linked one because my problem is related to the credentials part, that I am having issues defining the variables and values.
Well I just added the def inside the block, not ideal but at least works:
pluginManagement {
def artifactoryUrl = "www.my.artifactory.url"
def artifactoryUser= "myUser"
def artifactoryPass= "myPass"
repositories {
maven {
name = "A-MavenGoogle"
url = uri(
"https://$artifactoryUrl/list/maven-google-remote/"
)
credentials {
username = artifactoryUser
password = artifactoryPass
}
}
maven {
name = "A-MavenCentral"
url = uri(
"https://$artifactoryUrl/list/maven-central-remote/"
)
credentials {
username = artifactoryUser
password = artifactoryPass
}
}
}
}

ant.propertyFile updates comment everytime

In my build.gradle file I have the following variable to indicate which environment I'm building to:
buildscript {
ext {
springBootVersion = '1.5.15.RELEASE'
kotlinVersion = '1.2.70'
queryDslVersion = '4.1.4'
env = 'local'
}
// ...
}
And on my application.properties I have the following line for spring to use the correct application-{env}.properties:
spring.profiles.active=local
I have created a gradle task to update this value on my application.properties as follow:
task setEnv {
doFirst {
ant.propertyfile(file: "$projectDir/src/main/resources/application.properties") {
entry( key: "spring.profiles.active", value: "$env")
}
println "Building with env = $env"
}
}
The task works just fine except it adds one comment line with the timestamp of the update. So my application.properties now looks like:
#Fri, 14 Dec 2018 11:22:04 -0200
spring.profiles.active=local
This is a problem because everytime someone builds the project it changes this file, causing conflicts when commiting and pushing to git.
Any ideas on how I could get rid of that comment? Or even a better approach to set spring profile?
Thanks!
I don't think it's possible with ant, because it's implemented with the java.util.Properties class and it's said in the javadoc that:
...a comment line is always written, consisting of an ASCII #
character, the current date and time (as if produced by the toString
method of Date for the current time), and a line separator as
generated by the Writer.
So, to avoid it, you have to change a value in your properties file in some other way. For example, by configurion the ProcessResources Gradle task as follows:
processResources {
filesMatching('**/*.properties') {
filter {
it.replace('#ENV#', "$env")
}
}
}
And the value should be set to #ENV# inside the application.properties

Android gradle build: how to set global variables

How can I set a global variable that can be accessed from build.gradle and tasks?
To set a global variable
project.ext.set("variableName", value)
To access it from anywhere in the project:
project.variableName
For instance:
project.ext.set("newVersionName", versionString)
and then...
println project.newVersionName
For more information see: http://www.gradle.org/docs/current/dsl/org.gradle.api.plugins.ExtraPropertiesExtension.html
EDIT:
As commented by Dmitry, In new versions you can use the following shorthand:
project.ext.variableName = value
The answer from Guy is excellent. I just want to add the practical code.
Example:
Put something like this in the Project build.gradle:
project.ext {
minSdkVersion = 21
targetSdkVersion = 23
}
And put something like this in the Module build.gradle to access it:
defaultConfig {
minSdkVersion.apiLevel project.minSdkVersion
targetSdkVersion.apiLevel project.targetSdkVersion
}
You can also do this. Let's say you want to add appcompat with the version 25.3.1, you can add a variable version_name in your project level build.gradle.
buildscript{
ext.version_name = '25.3.1'
}
Now you can add this to your application level build gradle and avoid any conflicts.
compile "com.android.support:appcompat-v7:$version_name"
compile "com.android.support:recyclerview-v7:$version_name"
compile "com.android.support:design:$version_name"
You cant create a Gradle file in the project's root directory and put all variables there, like this:
lib-versions.gradle
ext {
kt_core = '1.6.0'
app_compat = '1.3.1'
material = '1.4.0'
constraintlayout = '2.1.1'
nav_version = '2.3.5'
junit = '4.13.2'
junit_ext = '1.1.3'
escpresso = '3.4.0'
}
Then in the project build.gradle file on the bottom you should apply the Gradle file like this:
buildscript {
...
}
task clean(type: Delete) {
delete rootProject.buildDir
}
apply from: 'lib-versions.gradle' //apply it like this
Then you are able to use the variables in any module-level build Gradle file (app/build.gradle) like this:
implementation "androidx.core:core-ktx:$rootProject.ext.kt_core"
implementation "androidx.appcompat:appcompat:$rootProject.ext.app_compat"
implementation "com.google.android.material:material:$rootProject.ext.material"
implementation "androidx.constraintlayout:constraintlayout:$rootProject.ext.constraintlayout"
...
Additional, for dynamic global variables you can define global functions in the master build.gradle file:
First, define your function, for example for git branch:
def getGitBranch = { ->
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-parse', '--abbrev-ref', 'HEAD'
standardOutput = stdout
}
return stdout.toString().trim()
}
In allProjects section set the variable:
allprojects {
repositories {
google()
jcenter()
}
project.ext {
gitBranch="\"${getGitBranch()}\""
}
}
In your build.gradle files of your sub projects or android modules, get this variable like this:
android {
compileSdkVersion project.mCompileSdkVersion.toInteger()
defaultConfig {
minSdkVersion project.mMinSdkVersion.toInteger()
...
buildConfigField "String", "GitBranch", project.gitBranch
}
...
}
Finally, you can use it in your code like this:
public static String getGitBranch() {
return BuildConfig.GitBranch;
}
This is for Kotlin DSL (build.gradle.kts).
Root (top-level) build file:
val myVariable by extra("watermelon")
// Alternative notations:
// extra.set("myVariable", "watermelon")
// extra["myVariable"] = "watermelon"
Extra properties on a project object are visible from its subprojects. Note that extra. is equivalent to project.extra.; in other words the project object is implicit.
A sub-project build file:
val myVariable: String by rootProject.extra
// Alternative notations:
// val myVariable: String by rootProject
// val myVariable: String = rootProject.extra["myVariable"] as String
// val myVariable: String = rootProject.extra.get("myVariable") as String
Note that when using Kotlin delegation (by keyword) the name of the variables should be the same in both build files.
See Gradle Docs: Extra properties for more information.

Resources