Gradle Kotlin DSL: Определите версию Kotlin в уникальном месте

Для описания скриптов сборки Gradle мы можем использовать Kotlin через build.gradle.kts файлы. Общей проблемой для глобально определить версию Kotlin, которая будет использоваться, как в dependencies, так и в разделе build plugin (довольно необычно использовать разные версии для данного случая).

Рассмотрим следующий код (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
}

Как вы можете видеть, kotlin version (1.2.30 в этом случае) определяется дважды: dependencyVersion и pluginVersion, что очень часто не отличается. Из-за ограничений DSL невозможно получить доступ к pluginVersion извне блока plugins или получить доступ к dependencyVersion из блока plugins.

Как строка версии "1.2.30" может быть извлечена в одно место?

Ответ 1

В более поздних версиях Gradle вам больше не нужно указывать версию зависимостей kotlin(stdlib|reflect|test), плагин Kotlin автоматически настроит их для вас.

Как для извлечения зависимости к одному месту, существуют два основных шаблона:

  • определите константы, которые вы хотите использовать в объекте в buildSrc/src/main/kotlin/, и используйте этот объект в своей сборке script, код из buildSrc доступен для всего script, включая блок plugins
  • используйте системное свойство, вы можете определить системное свойство в gradle.properties, указав его имя на systemProp., и вы можете получить доступ к свойствам системы через System.getProperties(), например:

    // build.gradle.kts
    plugins {
      val kotlinVersion by System.getProperties()
      println("Kotlin version is $kotlinVersion")
    }
    
    // gradle.properties
    systemProp.kotlinVersion=1.2.20
    

Ответ 2

Вы можете извлечь версию из класса плагина:

import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper

plugins {
    kotlin("jvm") version "1.2.0"
}

val kotlinVersion = plugins.getPlugin(KotlinPluginWrapper::class.java).kotlinPluginVersion

Ответ 3

Доступно обходное решение, которое ищет версию, определенную для плагина kotlin, и присваивает это внешней переменной. Это демонстрирует следующее:

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
}

Теперь переменная kotlinVersion может быть использована в dependencies без дополнительных проблем.

Ответ 4

Я только что наткнулся на использование классов Kotlin в моем build.gradle.kts.

Я должен был:

  • создайте модуль с именем buildSrc с src/main/kotlin и build.gradle.kts в его корне.
  • include("buildSrc") в settings.gradle.kts

buildSrc/build.gradle.kts очень минимальный:

plugins {
    'kotlin-dsl'
}

repositories {
    jcenter()
}

В buildSrc/src/main/kotlin я добавил 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]"

И 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"
}

Так что я мог бы использовать его в своем корне build.gradle.kts как

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)
                }
            }
        }
    }
}

Я вполне доволен этим, но когда все сводится к автоматическому увеличению version, я могу отступить, чтобы сохранить его в gradle.properties.