How to use plugin version from gradle.properties in Gradle Kotlin DSL? - gradle

Now I use this way:
plugins {
val kotlinVersion: String by project
val springBootPluginVersion: String by project
val springDependencyManagementPluginVersion: String by project
id("org.jetbrains.kotlin.plugin.allopen") version kotlinVersion
id("org.jetbrains.kotlin.jvm") version kotlinVersion
id("org.springframework.boot") version springBootPluginVersion
id("io.spring.dependency-management") version springDependencyManagementPluginVersion
}
This variant compiles and works, but I don't know is this way right and why IntelliJ IDEA shows error on lines where placed versions definitions:
'val Build_gradle.project: Project' can't be called in this context by implicit receiver. Use the explicit one if necessary

(Cross-post: source)
Apparently this has become possible recently, if it wasn't possible in the past. (Almost) from the docs:
gradle.properties:
helloPluginVersion=1.0.0
settings.gradle.kts:
pluginManagement {
val helloPluginVersion: String by settings
plugins {
id("com.example.hello") version helloPluginVersion
}
}
And now the docs say that build.gradle.kts should be empty but my testing shows that you still need this in build.gradle.kts:
plugins {
id("com.example.hello")
}
The version is now determined by settings.gradle.kts and hence by gradle.properties which is what we want...

There are a couple issues that have some details around this:
gradle/kotlin-dsl#480
gradle/gradle#1697
The way to do this in the most recent verions of Gradle is to use settings.gradle or settings.gradle.kts and the pluginManagement {} block.
In your case, it could look like:
pluginManagement {
resolutionStrategy {
eachPlugin {
when (requested.id.id) {
"org.jetbrains.kotlin.plugin.allopen" -> {
val kotlinVersion: String by settings
useVersion(kotlinVersion)
}
"org.jetbrains.kotlin.jvm" -> {
val kotlinVersion: String by settings
useVersion(kotlinVersion)
}
"org.springframework.boot" -> {
val springBootPluginVersion: String by settings
useVersion(springBootPluginVersion)
}
"io.spring.dependency-management" -> {
val springDependencyManagementPluginVersion: String by settings
useVersion(springDependencyManagementPluginVersion)
}
}
}
}
}

Related

Gradle single-project pluginManagement block not working (Kotlin DSL)

I need to change a multi-project build to a single-project build, as there is and only ever will be one project in this repo. Currently, in settings.gradle, I have a custom plugin repo that currently uses a pluginManagement block with resolutionStrategy and my list of repo's:
pluginManagement {
resolutionStrategy {
eachPlugin {
if (requested.id.namespace == 'com.meanwhileinhell.plugin') {
useModule('com.meanwhileinhell:gradle-plugin:1.0.0-SNAPSHOT')
}
}
}
repositories {
mavenLocal()
maven { url "https://repo.spring.io/milestone" }
maven { url "https://plugins.gradle.org/m2/" }
// Meanwhileinhell repo
maven {
url "s3://mvn.meanwhileinhell.com/releases"
credentials(AwsCredentials) {
accessKey s3_access_key
secretKey s3_access_secret
}
}
}
plugins {
...
...
}
}
However, deleting settings.gradle and moving this block into my build.gradle.kts (Kotlin DSL) seems to do nothing. I've tried wrapping in a
configurations {
all {
resolutionStrategy {
eachPlugin {
...
}
}
}
}
and also
settings {
pluginManagement {
resolutionStrategy {
eachPlugin {
...
}
}
}
}
I found a SO answer that used settingsEvaluated in order to get the settings object, but again this was a no go.
Currently my build.gradle.kts looks like this, without pulling any plugin in from my repo:
val springBootVersion: String by project
group = "com.meanwhileinhell.myapp"
version = "$version"
repositories {
mavenCentral()
mavenLocal()
maven ("https://repo.spring.io/snapshot")
maven ("https://repo.spring.io/milestone")
maven ("https://plugins.gradle.org/m2/")
maven {
url = uri("s3://mvn.meanwhileinhell.com/releases")
credentials(AwsCredentials::class) {
accessKey = (project.property("s3_access_key") as String)
secretKey = (project.property("s3_access_secret") as String)
}
}
}
plugins {
base
eclipse
idea
java
id("io.spring.dependency-management") version "1.0.9.RELEASE"
// Load but don't apply to root project
id("org.springframework.boot") version "1.5.14.RELEASE" apply false
}
dependencies {
...
}
Whenever I try to add a plugin id like id("com.meanwhileinhell.plugin.hell2java") version "1.0.0-SNAPSHOT" I get an error that looks like it isn't even looking in my S3 location:
* What went wrong:
Plugin [id: 'com.meanwhileinhell.plugin.hell2java', version: '1.0.0-SNAPSHOT'] was not found in any of the following sources:
- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Plugin Repositories (could not resolve plugin artifact 'com.meanwhileinhell.plugin.hell2java:com.meanwhileinhell.plugin.hell2java.gradle.plugin:1.0.0-SNAPSHOT')
Searched in the following repositories:
Gradle Central Plugin Repository
Any help on this would be appreciated!
EDIT !!!! -----------------------
I've just found this in the Gradle docs:
https://docs.gradle.org/current/userguide/plugins.html#sec:plugin_management
The pluginManagement {} block may only appear in either the settings.gradle file....
Looks like I'm going down the wrong way entirely, so will look into the initialisation script route.
I think you may have missed something about the file structure.
In the Groovy DSL, you have the following files:
build.gradle
settings.gradle
init.gradle
In the Kotlin DSL, you have the same files but with the .kts extension:
build.gradle.kts
settings.gradle.kts
init.gradle.kts
The Kotlin DSL doesn't differ to the Groovy DSL in where to put things. pluginManagement need to go in to the settings file, so for Kotlin that would be settings.gradle.kts. If you are in doubt, look at the documentation. For almost all code examples, you can switch between Groovy and Kotlin DSL to see how to do it (and which files they are supposed go to into).

How to define dependency version only once for whole Gradle multi-module project?

I made a decision to migrate from Dependency Management Plugin to Gradle built-in BOM import support. Since Gradle built-in BOM import support has better performance But
I run into the issue:
I cannot find alternatives for dependency and dependencySet in native Gradle:
dependencyManagement {
dependencies {
dependency("org.springframework:spring-core:4.0.3.RELEASE")
}
}
//or
dependencyManagement {
dependencies {
dependencySet(group:'org.slf4j', version: '1.7.7') {
entry 'slf4j-api'
entry 'slf4j-simple'
}
}
}
and then I could use dependency without version
dependencies {
compile 'org.springframework:spring-core'
}
How can I get the same behavior in naive Gradle? I mean: I'd like to define a version once as I did it when using Dependency Management Plugin
Solution below helps to avoid versions copy-paste. However it isn't the same with Dependency Management plugin.
For Gradle Kotlin Dsl:
You can create buildSrc with you own code, when you can place any constants.
Algorithm:
Create folder buildSrc/src/main/kotlin
Create file buildSrc/src/main/kotlin/Versions.kt with content:
object Versions {
const val junitVersion = "5.5.5" // just example
}
Create file buildSrc/build.gradle.kts with content:
plugins {
`kotlin-dsl`
}
Use the following syntax in your gradle.kts files:
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:${Versions.junitVersion}")
}
For Gradle Groovy:
Create file gradle.properties
Put versions there with syntax like okhttp_version=4.2.0
Use the following syntax in your gradle files:
dependencies {
compile group: 'com.squareup.okhttp3', name: 'okhttp', version: okhttp_version
}
You can do so on the gradle.properties file. I.e.:
# APPLICATION PROPERTIES
name=projectName
group=com.domain
version=1.0.0
description=A brief description
gradleScripts=https://raw.githubusercontent.com/hexagonkt/hexagon/1.2.0/gradle
# DEPENDENCIES VERSIONS
kotlinVersion=1.3.61
kotlinCoroutinesVersion=1.3.2
Or in settings.gradle if you don't want to create another file:
rootProject.name = "hexagon-contact-application"
gradle.rootProject {
allprojects {
version = "1.0.0"
group = "org.hexagonkt"
description = "Contact application backend api"
}
extensions.gradleScripts = "https://raw.githubusercontent.com/hexagonkt/hexagon/1.0.18/gradle"
extensions.kotlinVersion = "1.3.50"
extensions.kotlinCoroutinesVersion = "1.3.2"
extensions.hexagonVersion = "1.0.21"
extensions.logbackVersion = "1.2.3"
extensions.bcryptVersion="0.8.0"
extensions.javaJwtVersion="3.8.2"
}
And if you want to avoid adding the version variable to all related dependencies, you can create a method in the build file:
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.50'
}
apply from: "$gradleScripts/kotlin.gradle"
apply from: "$gradleScripts/service.gradle"
apply from: "$gradleScripts/junit.gradle"
defaultTasks("test")
mainClassName = 'com.hexagonkt.contact.ApplicationKt'
applicationDefaultJvmArgs = ["-Xms64M", "-Xmx2G", "-XX:+UseNUMA", "-XX:+UseParallelGC"]
dependencies {
httpkt(it, "http_server_jetty")
httpkt(it, "store_mongodb")
httpkt(it, "hexagon_web")
implementation("at.favre.lib:bcrypt:$bcryptVersion")
implementation("com.auth0:java-jwt:$javaJwtVersion")
testImplementation("com.hexagonkt:port_http_client:$hexagonVersion")
}
private void httpkt(final def dependencies, final String artifact) {
dependencies.implementation("com.hexagonkt:$artifact:$hexagonVersion")
}

How to Make Kotlin Gradle Plugin not Manage Version

When I use Kotlin Gradle Plugin and consume Kotlin BOM at the same time it seems that the plugin version takes in priority for kotlin-stdlib, how do I make the plugin not manage my dependency?
plugins {
kotlin("jvm") version "1.2.50"
}
dependencies {
implementation(platform("some-bom:0.3")) // this has API dependency to kotlin-bom 1.3.50
implementation(kotlin("stdlib")) // this resolves to 1.2.50 (plugin version) instead of 1.3.50 (BOM version)
}
Project is using Gradle 5.2.1
I can't reproduce it, it looks like a bug. As a workaround you can enforce a particular version by specify isForce = true:
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.2.50") {
isForce = true
}
implementation("org.jetbrains.kotlin:kotlin-stdlib-common:1.3.10"){
isForce = true
}
isForce is not transitive, so you have to specify all the transitive kotlin dependencies explicitly with isForce flag true or create a virtual platform:
open class KotlinAlignmentRule : ComponentMetadataRule {
override fun execute(ctx: ComponentMetadataContext) {
ctx.details.run {
if (id.group == "org.jetbrains.kotlin") {
belongsTo("org.jetbrains.kotlin:kotlin-platform:${id.version}")
}
}
}
}
And add it to your dependencies block:
dependencies {
components.all(KotlinAlignmentRule::class.java)
implementation(platform("some-bom:0.3"))
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.2.50") {
isForce = true
}
}
This last solution is the best imo.

Gradle: manage dependency/plugin versions in multi-project builds

I was working with Maven before Gradle and Maven has such things like dependencyManagement and pluginManagement what allows to keep all versions "DRY" in one place with help of "properties".
Gradle supports project properties, so I can declare versions like:
buildscript {
ext.kotlin_version = '1.1.61'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
But this approach cannot be applied to plugins {} DSL. I cannot write something like this:
plugins {
id 'org.jetbrains.kotlin:kotlin-gradle-plugin' version $kotlin_version
}
As according to docs:
values must be literal (e.g. constant strings, not variables)
Is there a way to workaround this limitation?
The latest versions of Gradle allows you to define your versions in a property file, map that version in a pluginManagement block, and then omit the version from all downstream plugin blocks. The pluginManagement block does not have the only-constant restriction.
In fact, once you use this approach, it is a compile time error to even try to declare a version downstream.
After using this approach, there is a good chance you can completely omit your buildscript.
gradle.properties
kotlinVersion=1.3.50
settings.gradle
pluginManagement {
resolutionStrategy {
eachPlugin {
if (requested.id.id == "org.jetbrains.kotlin.jvm") {
useVersion(kotlinVersion)
}
}
}
}
build.gradle
plugins {
id("org.jetbrains.kotlin.jvm")
}
If you are into kotlinscript, get your version from a delegate:
settings.gradle.kts
val kotlinVersion: String by settings
pluginManagement {
resolutionStrategy {
eachPlugin {
if (requested.id.id == "org.jetbrains.kotlin.jvm") {
useVersion(kotlinVersion)
}
}
}
}
Of course, you do not need the properties file. You can just hard code the version in your gradle.settings. But by having the property, you can then declare dependencies to the stdlib using it.
I think you can put the ext closure in a separate properties.gradle, and then reference the properties twice in buildscript as well as project build (buildscript block is evaluated at the very beginning, before any other part of groovy script).
For example, in $projectRoot/gradle/properties.gradle as below:
ext {
kotlinVersion = '1.1.61' // NOTE, the naming convention is better with kotlinVersion instead of kotlin_version
}
And your $projectRoot/build.gradle would look like this:
buildscript {
apply from: "gradle/properties.gradle"
repositories {
jcenter()
}
dependencies {
println "In buildscript, kotlinVersion is $kotlinVersion"
}
}
apply plugin: 'java'
apply from: "gradle/properties.gradle"
repositories {
jcenter()
}
dependencies {
println "In project, kotlinVersion is $kotlinVersion"
}
When you run ./gradlew dependencies, it would show you the populated versions:
> Configure project :
In buildscript, kotlinVersion is 1.1.61
In project, kotlinVersion is 1.1.61

ext in buildscript can not be recognised by Gradle Kotlin DSL

In these days, I am trying to write some codes to experience the Spring reactive features and kotlin extension in Spring 5, and I also prepared a gradle Kotlin DSL build.gradle.kt to configure the gradle build.
The build.gradle.kt is converted from Spring Boot template codes generated by http://start.spring.io.
But the ext in the buildscript can not be detected by Gradle.
buildscript {
ext { }
}
The ext will cause Gradle build error.
To make the variables in classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") and compile("org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlinVersion") work, I added the variables in the hard way.
val kotlinVersion = "1.1.4"
val springBootVersion = "2.0.0.M3"
But I have to declare them in global top location and duplicate them in the buildscript.
Code: https://github.com/hantsy/spring-reactive-sample/blob/master/kotlin-gradle/build.gradle.kts
Is there a graceful approach to make ext work?
Update: There are some ugly approaches:
From Gradle Kotlin DSL example, https://github.com/gradle/kotlin-dsl/tree/master/samples/project-properties, declares the properties in gradel.properties.
kotlinVersion = 1.1.4
springBootVersion = 2.0.0.M3
And use it in build.gradle.kts.
buildScript{
val kotlinVersion by project
}
val kotlinVersion by project //another declare out of buildscript block.
Similar with above declare them in buildScript block:
buildScript{
extra["kotlinVersion"] = "1.1.4"
extra["springBootVersion"] = "2.0.0.M3"
val kotlinVersion: String by extra
}
val kotlinVersion: String by extra//another declare out of buildscript block.
How can I avoid the duplication of val kotlinVersion: String by extra?
With Kotlin DSL ext has been changed to extra and it can be used under buildscript.
Eg :-
buildscript {
// Define versions in a single place
extra.apply{
set("minSdkVersion", 26)
set("targetSdkVersion", 27)
}
}
It is possible to use constants defined in .kt file in .gradle.kts files.
create buildSrc folder in root folder of your project
create buildSrc/build.gradle.kts file with the following content
plugins {
`kotlin-dsl`
}
repositories {
mavenCentral()
}
create file buildSrc/src/main/kotlin/Constants.kt with the following content
object Constants {
const val kotlinVersion = "1.3.70"
const val targetSdkVersion = 28
}
Synchronize. Now you may reference created constants in various .gradle.kts files like this
...
classpath(kotlin("gradle-plugin", version = Constants.kotlinVersion))
...
...
targetSdkVersion(Constants.targetSdkVersion)
...
What is working for me is using ext in allprojects instead of buildscript, so in your top-level build.gradle.kts
allprojects {
ext {
set("supportLibraryVersion", "26.0.1")
}
}
then you can use it in build.gradle.kts files in modules like this:
val supportLibraryVersion = ext.get("supportLibraryVersion") as String
None of these answers felt clear to me.
So here's my explanation:
/build.gradle.kts:
buildscript {
extra.apply {
set("compose_version", "1.0.3")
}
...
}
/app/build.gradle.kts:
val composeVersion = rootProject.extra["compose_version"]
implementation("androidx.compose.ui:ui:$composeVersion")
implementation("androidx.compose.material:material:$composeVersion")
There is a new possibility with Kotlin we can use:
object DependencyVersions {
const val JETTY_VERSION = "9.4.12.v20180830"
}
dependencies{
implementation("org.eclipse.jetty:jettyserver:${DependencyVersions.JETTY_VERSION}")
}
Here, DependencyVersions is a name I chose. You can choose another name,
like "MyProjectVariables". This is a way to avoid using the extra or ext properties.
Global properties in kotlin-gradle-dsl:
https://stackoverflow.com/a/53594357/3557894
Kotlin version is embedded into kotlin-gradle-dsl.
You can use dependecies with embedded version as follows:
implementation(embeddedKotlin("stdlib-jdk7"))
classpath(embeddedKotlin("gradle-plugin"))
val junitVersion by extra("4.13.2")
testImplementation("junit:junit:$junitVersion")
In Kotlin, the way to do this is with by extra or an ext block.
With by extra:
val kotlinVersion = "95" by extra
val kotlinCompiler = true by extra
With ext:
ext {
set("kotlinVersion", "95")
set("kotlinCompiler", true)
}
Set it like this:
val kotlinVersion by extra("1.1.4")
Use it like this:
val kotlinVersion: String by rootProject.extra
It's a possibility to define global properties within gradle.properties:
xyzVersion=1.0.0
And then use them in your module's build.gradle.kts:
val xyzVersion: String by project

Resources