Gradle Kotlin DSL: Define Kotlin version in unique place
Solution 1
In later versions of Gradle you no longer need to specify the version of your kotlin(stdlib|reflect|test)
dependencies, the Kotlin plugin will automatically configure them for you.
As for extracting the dependency to a single place, there are two main patterns:
- define the constants you want to share in an object within
buildSrc/src/main/kotlin/
and use that object in your build script, code frombuildSrc
is available to the whole script including theplugins
block use a system property, you can define a system property in
gradle.properties
by prefixing its name withsystemProp.
and you can access system properties viaSystem.getProperties()
, for example:// build.gradle.kts plugins { val kotlinVersion by System.getProperties() println("Kotlin version is $kotlinVersion") } // gradle.properties systemProp.kotlinVersion=1.2.20
Solution 2
What I just stumbled upon was using Kotlin classes ins my build.gradle.kts
.
I had to:
- create a module called
buildSrc
withsrc/main/kotlin
and abuild.gradle.kts
in its root. - (obsolete)
include("buildSrc")
insettings.gradle.kts
The buildSrc/build.gradle.kts
is very minimal:
plugins {
`kotlin-dsl`
}
repositories {
jcenter()
}
In buildSrc/src/main/kotlin
I've added a Config.kt
const val GROUP_ID = "my-company"
const val VERSION = "0.1.0-SNAPSHOT"
const val POM_NAME = "my-library-name"
const val POM_DESCRIPTION = "A library doing stuff."
const val POM_URL = "https://github.com/${GROUP_ID}/${POM_NAME}/"
const val POM_SCM_URL = POM_URL
const val POM_SCM_CONNECTION = "scm:git:git://github.com/${GROUP_ID}/${POM_NAME}.git"
const val POM_SCM_DEV_CONNECTION = "scm:git:ssh://[email protected]/${GROUP_ID}/${POM_NAME}.git"
const val POM_LICENCE_NAME = "The Apache Software License, Version 2.0"
const val POM_LICENCE_URL = "http://www.apache.org/licenses/LICENSE-2.0.txt"
const val POM_LICENCE_DIST = "repo"
const val POM_DEVELOPER_ID = "me"
const val POM_DEVELOPER_NAME = "meeee"
const val POM_DEVELOPER_EMAIL = "[email protected]"
And a Dependencies.kt
@file:Suppress("MemberVisibilityCanBePrivate")
object Jvm {
const val version = "1.8"
}
object Kotlin {
const val version = "1.3.50"
const val stdlibJdk8 = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$version"
const val jvmId = "jvm"
const val kaptId = "kapt"
}
object MavenPublish {
const val id = "maven-publish"
}
object Arrow {
const val version = "0.10.1"
const val core = "io.arrow-kt:arrow-core:$version"
const val syntax = "io.arrow-kt:arrow-syntax:$version"
const val optics = "io.arrow-kt:arrow-optics:$version"
const val fx = "io.arrow-kt:arrow-fx:$version"
const val meta = "io.arrow-kt:arrow-meta:$version"
}
object Versions {
const val version = "0.27.0"
const val versions = "com.github.ben-manes:gradle-versions-plugin:$version"
const val id = "com.github.ben-manes.versions"
}
So I could use it in my root build.gradle.kts
like
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin(Kotlin.jvmId) version Kotlin.version
kotlin(Kotlin.kaptId) version Kotlin.version
id(Versions.id) version Versions.version
id(MavenPublish.id)
}
group = GROUP_ID
version = VERSION
repositories {
mavenCentral()
jcenter()
}
dependencies {
implementation(Kotlin.stdlibJdk8)
implementation(Arrow.core)
implementation(Arrow.syntax)
kapt(Arrow.meta)
}
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = Jvm.version
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
@Suppress("UnstableApiUsage")
pom {
name.set(POM_NAME)
description.set(POM_DESCRIPTION)
url.set(POM_URL)
licenses {
license {
name.set(POM_LICENCE_NAME)
url.set(POM_LICENCE_URL)
distribution.set(POM_LICENCE_DIST)
}
}
developers {
developer {
id.set(POM_DEVELOPER_ID)
name.set(POM_DEVELOPER_NAME)
email.set(POM_DEVELOPER_EMAIL)
}
}
scm {
connection.set(POM_SCM_CONNECTION)
developerConnection.set(POM_SCM_DEV_CONNECTION)
url.set(POM_SCM_URL)
}
}
}
}
}
I am quite happy with this, but when it comes down to automatically increment the version
I may fall back to maintain it in the gradle.properties
.
Edit:
It is no longer necessary (and allowed) to add buildSrc
to the settings.gradle.kts
, instead it will automatically get picked up if present.
Solution 3
You can extract the version from the plugin class:
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper
plugins {
kotlin("jvm") version "1.2.0"
}
val kotlinVersion = plugins.getPlugin(KotlinPluginWrapper::class.java).kotlinPluginVersion
Solution 4
There's a workaround available, which searches the version defined for the kotlin plugin and assignes this one to the outer variable. The following demonstrates this:
val kotlinVersion: String? by extra {
buildscript.configurations["classpath"]
.resolvedConfiguration.firstLevelModuleDependencies
.find { it.moduleName == "kotlin-gradle-plugin" }?.moduleVersion
}
plugins {
kotlin("jvm").version("1.2.30")
//more
}
The variable kotlinVersion
can then be used in the dependencies
without further trouble.
Solution 5
Answer for @s1m0nw1 comment (too long for comment): No you can't use buildSrc/src stuff in buildSrc/build.gradle. I had exactly this problem as I wrote android-based plugin and I need android gradle plugin dependency in buildsSrc but I also declare this dependency in project. So I had two different places and two versions to maintain.
I resolved this by creating gradle.properties file in buildSrc directory.
In it I've created prop androidGradlePluginVersion=3.6.0-rc02
buildSrc/build.gradle:
val androidGradlePluginVersion: String by project
dependencies {
implementation("com.android.tools.build:gradle:$androidGradlePluginVersion")
buildSrc/src/.../Versions.kt:
var ANDROID_PLUGIN = loadAndroidGradlePluginVersion()
Util for props:
val GRADLE_PROPERTIES = "buildSrc/gradle.properties"
val ANDROID_PLUGIN_VERSION_PROP = "androidGradlePluginVersion"
fun loadAndroidGradlePluginVersion(): String {
Properties().apply { load(FileInputStream(GRADLE_PROPERTIES)) }.let {
return it.getProperty(ANDROID_PLUGIN_VERSION_PROP)
}
error("Provide $ANDROID_PLUGIN_VERSION_PROP in $GRADLE_PROPERTIES")
}
s1m0nw1
I'm a Software Engineer working on distributed systems and integrations at BRYTER. I'm an Oracle Certified Java Professional, a Kotlin Enthusiast and also a Google Developer Expert for Kotlin. Read about my Kotlin stories on this blog: https://kotlinexpertise.com I'm currently learning to like Go. If you want to say thank you for just anything, feel free to buy me a coffee ☕️ on https://ko-fi.com/s1m0nw1 Other profiles around the web: GitHub Twitter Kotlin Blog LinkedIn
Updated on June 06, 2022Comments
-
s1m0nw1 almost 2 years
For describing Gradle build scripts, we can use Kotlin via
build.gradle.kts
files. It's a common problem to globally define the Kotlin version to be used, both in thedependencies
and also in the buildplugin
section (It's rather uncommon to have different versions in use for the given case).Consider the following code (Gradle 4.3.1):
plugins { var pluginVersion = "1.2.30" kotlin("jvm").version(kotlinVersion) // more } var dependencyVersion = "1.2.30" dependencies { compile(kotlin("stdlib", kotlinVersion)) compile(kotlin("reflect", kotlinVersion)) testCompile(kotlin("test", kotlinVersion)) // more }
As you can see, the kotlin
version
(1.2.30 in this case) is defined twice:dependencyVersion
andpluginVersion
, which very often does not differ. Due to DSL restrictions, it is impossible to access thepluginVersion
from outside theplugins
block or access thedependencyVersion
from within theplugins
block.How can the version string,
"1.2.30"
be extracted to a single place?-
nuamehas over 5 yearskotlin version constant is part of gradle-kotlin-DSL. Usage samples:
implementation(embeddedKotlin("stdlib-jdk7"))
orclasspath(embeddedKotlin("gradle-plugin"))
-
-
s1m0nw1 over 5 yearsWhen defining constants in
buildSrc
, can I also use them in the build.gradle.kts ofbuildSrc
itself? -
nuamehas over 5 yearsNote: kotlin version constant is part of gradle-kotlin-DSL. Usage samples:
implementation(embeddedKotlin("stdlib-jdk7"))
orclasspath(embeddedKotlin("gradle-plugin"))
-
peacepassion about 5 yearsbuildSrc is really a good place and Gradle support such way officially.
-
Kamil Seweryn about 4 yearsYou can get the version from KotlinCompilerVersion.VERSION
-
Shenk almost 4 yearsDoing this, I still had to duplicate the property definitions in both buildSrc/gradle.properties and rootProject/gradle.properties. Otherwise, when trying to use the property, such as in buildSrc/src/main/kotlin/Versions.kt, it doesn't find the property. For some reason, it tries to search for the property in the rootProject's buildSrc, skipping the buildSrc's. I've tried for hours to find a solution yet to no avail.
-
Shenk almost 4 yearsOkay, so I was eventually able to get around the issue by using this
val gradlePropertiesFile: File = File("${System.getProperty("user.dir")}${if (project.name == "buildSrc") "" else "/buildSrc"}/$GRADLE_PROPERTIES")
as the file from which to load the input stream. (using Kotlin DSL) -
Kostek almost 4 yearsI guess it make sense as it is resolved in runtime instead of compile time. My bad, I forgot to add my consts:
GRADLE_PROPERTIES = "buildSrc/gradle.properties" ANDROID_PLUGIN_VERSION_PROP = "androidGradlePluginVersion"
-
user3681304 almost 4 years
'buildSrc' cannot be used as a project name as it is a reserved name
insettings.gradle
-
sschrass almost 4 yearsYes, this is true for recent versions. BuildSrc also gets automatically picked up if present.