diff options
author | Xavier Ducrohet <xav@google.com> | 2024-02-14 15:40:43 -0800 |
---|---|---|
committer | Xavier Ducrohet <xav@google.com> | 2024-02-16 09:38:25 -0800 |
commit | db75ddbd29f572a24ab23c0b71b0e0378af86bae (patch) | |
tree | 68bf6fc8999af247e77966ec129a9666daf5fee2 | |
parent | bac9e498c8a07fec36d422d45fa5a3bba8f15ef6 (diff) | |
download | gradle-recipes-db75ddbd29f572a24ab23c0b71b0e0378af86bae.tar.gz |
Replace SemVer with a custom version
Bug: N/A
Test: existing tests
Change-Id: Ib9ca588319bc3ae480a1f462d5b6aee17339341a
10 files changed, 262 insertions, 101 deletions
diff --git a/convert-tool/app/build.gradle.kts b/convert-tool/app/build.gradle.kts index d65fa17..c774ee0 100644 --- a/convert-tool/app/build.gradle.kts +++ b/convert-tool/app/build.gradle.kts @@ -29,7 +29,6 @@ dependencies { implementation(libs.guava) implementation(libs.kotlinx.cli) implementation(libs.tomlj) - implementation(libs.semver) implementation(libs.gradle.api) implementation(libs.okhttp) runtimeOnly(libs.slf4j) diff --git a/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/LatestVersionFinder.kt b/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/LatestVersionFinder.kt index 75b8a80..f909702 100644 --- a/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/LatestVersionFinder.kt +++ b/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/LatestVersionFinder.kt @@ -16,7 +16,7 @@ package com.google.android.gradle_recipe.converter -import com.github.rising3.semver.SemVer +import com.google.android.gradle_recipe.converter.converters.FullAgpVersion import java.io.File import java.io.FileInputStream import java.io.InputStream @@ -49,7 +49,7 @@ fun findLatestVersion(mavenMetadataFile: File, majorMinorVersion: String): Strin FileInputStream(mavenMetadataFile).use { stream -> val map = findLatestVersion(stream, listOf(majorMinorVersion)) - return map[majorMinorVersion] + return map[majorMinorVersion]?.toString() } } @@ -57,9 +57,11 @@ fun findLatestVersion(mavenMetadataFile: File, majorMinorVersion: String): Strin * Parse [mavenMetadataContent] and return the latest version of AGP for all short-versions (x.y) provided * * [mavenMetadataContent] is assumed to be a xml file in the expected maven metadata format. + * + * It is possible that the map does not contains values for all provided versions. This can happen if a version + * of AGP is not yet published. */ -internal fun findLatestVersion(mavenMetadataContent: InputStream, shortAgpVersions: List<String>): Map<String, String> { - val maxMap = mutableMapOf<String, String>() +internal fun findLatestVersion(mavenMetadataContent: InputStream, shortAgpVersions: List<String>): Map<String, FullAgpVersion> { shortAgpVersions.forEach(::validateMajorMinorVersion) val versionNodeList = @@ -68,15 +70,18 @@ internal fun findLatestVersion(mavenMetadataContent: InputStream, shortAgpVersio .parse(mavenMetadataContent) .getElementsByTagName("version") + val maxMap = mutableMapOf<String, FullAgpVersion>() + for (i in 0 until versionNodeList.length) { val version = versionNodeList.item(i).textContent for (agpVersion in shortAgpVersions) { if (version.startsWith("$agpVersion.")) { + val fullAgpVersion = FullAgpVersion.of(version) when (val max = maxMap[agpVersion]) { - null -> maxMap[agpVersion] = version - else -> if (SemVer.parse(version) > SemVer.parse(max)) { - maxMap[agpVersion] = version + null -> maxMap[agpVersion] = fullAgpVersion + else -> if (fullAgpVersion > max) { + maxMap[agpVersion] = fullAgpVersion } } } diff --git a/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/converters/AgpVersions.kt b/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/converters/AgpVersions.kt index 8818806..79fddab 100644 --- a/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/converters/AgpVersions.kt +++ b/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/converters/AgpVersions.kt @@ -16,10 +16,7 @@ package com.google.android.gradle_recipe.converter.converters -import com.github.rising3.semver.SemVer -import com.google.android.gradle_recipe.converter.converters.ShortAgpVersion.Companion.isShortVersion -import com.google.android.gradle_recipe.converter.printErrorAndTerminate -import com.google.android.gradle_recipe.converter.recipe.toMajorMinor +import java.util.regex.Pattern // in order to make it clearer what versions of AGP the code expect, we are creating String wrapper to // use type-safety @@ -30,31 +27,23 @@ interface AgpVersion * * Example: 8.3.0, 8.4.0-alpha01 */ -data class FullAgpVersion(val value: String): AgpVersion, Comparable<FullAgpVersion> { +data class FullAgpVersion(val version: AndroidPluginVersion): AgpVersion, Comparable<FullAgpVersion> { + companion object { /** * Wraps the given string with a [FullAgpVersion]. The value must be a properly * formatted full version that is published */ - fun of(value: String) = FullAgpVersion(value) - - /** - * From the given version, attempts to find a matching published AGP version - */ - fun String.toPublishedAgp(): FullAgpVersion = if (isShortVersion()) { - val version = ShortAgpVersion.of(this) - getVersionsFromAgp(version)?.agp ?: printErrorAndTerminate("AGP version '$this' does not match a published AGP version") - } else { - of(this) - } + fun of(value: String) = FullAgpVersion(AndroidPluginVersion.parse(value)) } - fun toShort() = ShortAgpVersion.of(value.toMajorMinor()) + fun toShort(): ShortAgpVersion = ShortAgpVersion(version.major, version.minor) + override fun compareTo(other: FullAgpVersion): Int { - return SemVer.parse(value).compareTo(SemVer.parse(other.value)) + return this.version.compareTo(other.version) } - override fun toString(): String = value + override fun toString(): String = version.version } /** @@ -62,26 +51,27 @@ data class FullAgpVersion(val value: String): AgpVersion, Comparable<FullAgpVers * * Example: 8.3, 8.4 */ -data class ShortAgpVersion(val value: String): AgpVersion, Comparable<ShortAgpVersion> { +data class ShortAgpVersion(val major: Int, val minor: Int): AgpVersion, Comparable<ShortAgpVersion> { companion object { - fun of(value: String) = ShortAgpVersion(value) + private val VERSION_REGEX: Pattern = Pattern.compile("^(\\d+)\\.(\\d+)$") - fun String.isShortVersion(): Boolean { - return this.matches(Regex("^\\d+\\.\\d+$")) - } + fun ofOrNull(value: String): ShortAgpVersion? { + val matcher = VERSION_REGEX.matcher(value) + if (matcher.matches()) { + return ShortAgpVersion(matcher.group(1).toInt(), matcher.group(2).toInt()) + } - fun String.convertIfMatch(): ShortAgpVersion? { - return if (this.isShortVersion()) { - of(this) - } else null + return null } + + private val comparator: Comparator<ShortAgpVersion> = + Comparator.comparingInt<ShortAgpVersion> { it.major } + .thenComparingInt { it.minor } } override fun compareTo(other: ShortAgpVersion): Int { - // in order to be able to parse with SemVer, we need x.y.z but this class only deals with - // x.y, so we add a .0 - return SemVer.parse(value + ".0").compareTo(SemVer.parse(other.value + ".0")) + return comparator.compare(this, other) } - override fun toString(): String = value + override fun toString(): String = "$major.$minor" } diff --git a/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/converters/AndroidPluginVersion.kt b/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/converters/AndroidPluginVersion.kt new file mode 100644 index 0000000..2abb39f --- /dev/null +++ b/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/converters/AndroidPluginVersion.kt @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.gradle_recipe.converter.converters + +import com.google.android.gradle_recipe.converter.converters.AndroidPluginVersion.PreviewType +import java.util.Locale +import java.util.regex.Pattern + +/** + * Represents a version of the Android Gradle Plugin + */ +data class AndroidPluginVersion( + /** + * The major version. + * + * e.g. 7 for Android Gradle Plugin Version 7.0.1 + */ + val major: Int, + /** + * The minor version. + * + * e.g. 0 for Android Gradle Plugin Version 7.0.1 + */ + val minor: Int, + /** + * The micro, or patch version. + * + * e.g. 1 for Android Gradle Plugin Version 7.0.1 + */ + val micro: Int, + val previewType: PreviewType = PreviewType.FINAL, + + /** + * The preview version. + * + * e.g. 5 for Android Gradle Plugin Version 7.0.0-alpha05. 0 if [PreviewType.FINAL] or [PreviewType.DEV] + */ + val preview: Int = 0, +) : Comparable<AndroidPluginVersion> { + + enum class PreviewType(val publicName: String?) { + ALPHA("alpha"), + BETA("beta"), + RC("rc"), + DEV("dev"), // dev is always the latest in the branch, and therefore is higher than all published previews + FINAL(null); + + companion object { + fun from(value: String): PreviewType { + return valueOf(value.uppercase(Locale.getDefault())) + } + } + } + + override fun compareTo(other: AndroidPluginVersion): Int { + return comparator.compare(this, other) + } + + override fun toString(): String { + return version + } + + /** + * Returns the string representing this AGP version in maven version form. + * + * This corresponds exactly to the format of the version of the Android Gradle plugin artifacts + * published in the Google maven repository. + */ + val version: String = buildString { + append(major).append('.').append(minor).append('.').append(micro) + // This duplicates encoding the same special cases as in AgpVersion. Sadly it's challenging + // to share code as gradle-api should have as few dependencies as possible. + // See AndroidPluginVersionTest + when (previewType) { + PreviewType.FINAL -> {} + PreviewType.DEV -> append("-dev") + else -> { + append('-').append(previewType.publicName) + val isTwoDigitPreviewFormat = major > 3 || + major == 3 && minor > 1 || + major == 3 && minor == 1 && micro == 0 && previewType != PreviewType.BETA + if (isTwoDigitPreviewFormat && preview < 10) append('0') + append(preview) + } + } + } + + companion object { + private val comparator: Comparator<AndroidPluginVersion> = + Comparator.comparingInt<AndroidPluginVersion> { it.major } + .thenComparingInt { it.minor } + .thenComparingInt { it.micro } + .thenComparingInt { it.previewType.ordinal } + .thenComparingInt { it.preview } + + private val VERSION_REGEX: Pattern = Pattern.compile("^(\\d+)\\.(\\d+)\\.(\\d+)(-.+)?$") + private val PREVIEW_REGEX: Pattern = Pattern.compile("^([a-z]+)(\\d+)$") + + fun parse(versionString: String): AndroidPluginVersion { + val matcher = VERSION_REGEX.matcher(versionString) + if (matcher.matches()) { + val previewTag= matcher.group(4)?.substring(1) + val (previewType, preview) = previewTag?.let { + if (previewTag == "dev") { + (PreviewType.DEV to 0) + } else { + val matcher2 = PREVIEW_REGEX.matcher(it) + if (matcher2.matches()) { + PreviewType.from(matcher2.group(1)) to matcher2.group(2).toInt() + } else throw RuntimeException("Unable to parse AGP version '$versionString'. Preview type is malformed") + } + } ?: (PreviewType.FINAL to 0) + + return AndroidPluginVersion( + matcher.group(1).toInt(), + matcher.group(2).toInt(), + matcher.group(3)?.toInt() ?: 0, + previewType, + preview + ) + } + throw RuntimeException("Unable to parse AGP version '$versionString'") + } + } +} diff --git a/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/converters/RecipeConverter.kt b/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/converters/RecipeConverter.kt index a3acb4d..5c3ceba 100644 --- a/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/converters/RecipeConverter.kt +++ b/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/converters/RecipeConverter.kt @@ -84,14 +84,18 @@ private fun initAgpToGradleMap() { val map = mutableMapOf<ShortAgpVersion, VersionInfo>() for (versions in versionList) { + val shortAgpVersion = ShortAgpVersion.ofOrNull(versions[0]) + ?: throw RuntimeException("unable to parse short AGP version ${versions[0]}") + val versionInfo = VersionInfo( - // TODO handle the case where there is no published version (e.g. new API in yet unpublished AGP) - agp = FullAgpVersion.of(publishedAgpMap[versions[0]] ?: versions[0]), + // if there is not published version, convert the short version to a dev version and parse it. + agp = publishedAgpMap[versions[0]] ?: FullAgpVersion.of("${versions[0]}.0-dev"), gradle = versions[1], kotlin = versions[2] ) + lastVersionInfo = versionInfo - map[ShortAgpVersion.of(versions[0])] = versionInfo + map[shortAgpVersion] = versionInfo } // max is the last lime read diff --git a/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/recipe/RecipeData.kt b/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/recipe/RecipeData.kt index f4c1882..5ca5fb2 100644 --- a/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/recipe/RecipeData.kt +++ b/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/recipe/RecipeData.kt @@ -16,12 +16,9 @@ package com.google.android.gradle_recipe.converter.recipe -import com.github.rising3.semver.SemVer -import com.google.android.gradle_recipe.converter.converters.AgpVersion import com.google.android.gradle_recipe.converter.converters.FullAgpVersion import com.google.android.gradle_recipe.converter.converters.RecipeConverter import com.google.android.gradle_recipe.converter.converters.ShortAgpVersion -import com.google.android.gradle_recipe.converter.converters.ShortAgpVersion.Companion.isShortVersion import com.google.android.gradle_recipe.converter.converters.getVersionsFromAgp import com.google.android.gradle_recipe.converter.printErrorAndTerminate import org.tomlj.Toml @@ -98,18 +95,22 @@ class RecipeData private constructor( val minAgpString = parseResult.getString("agpVersion.min") ?: printErrorAndTerminate("Did not find mandatory 'agpVersion.min' in $toml") - val minAgpVersion = if (minAgpString.isShortVersion()) { - getVersionsFromAgp(ShortAgpVersion.of(minAgpString))?.agp + val minAgpVersion = ShortAgpVersion.ofOrNull(minAgpString)?.let { + getVersionsFromAgp(it)?.agp ?: printErrorAndTerminate("Unable to get published AGP version from '$minAgpString'") - } else { - FullAgpVersion.of(minAgpString) - } + } ?: FullAgpVersion.of(minAgpString) + + val maxAgpString = parseResult.getString("agpVersion.max") + val maxAgpVersion = if (maxAgpString != null) { + ShortAgpVersion.ofOrNull(maxAgpString) + ?: printErrorAndTerminate("unable to parse 'agpVersion.max' with value '$maxAgpString'") + } else null return RecipeData( indexName = indexName, destinationFolder = destinationFolder, minAgpVersion = minAgpVersion, - maxAgpVersion = parseResult.getString("agpVersion.max")?.let { ShortAgpVersion.of(it) }, + maxAgpVersion = maxAgpVersion, tasks = parseResult.getArray("gradleTasks.tasks")?.toList()?.map { it as String } ?: emptyList(), validationTasks = parseResult.getArray("gradleTasks.validationTasks")?.toList()?.map { it as String }, keywords = parseResult.getArray("indexMetadata.index")?.toList()?.map { it as String } ?: emptyList() @@ -118,6 +119,4 @@ class RecipeData private constructor( } } -fun String.toMajorMinor(): String = SemVer.parse(this).run { "${this.major}.${this.minor}" } - fun isRecipeFolder(folder: Path) = File(folder.toFile(), RECIPE_METADATA_FILE).exists() diff --git a/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/validators/GradleTasksExecutor.kt b/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/validators/GradleTasksExecutor.kt index e7a4940..ec08fab 100644 --- a/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/validators/GradleTasksExecutor.kt +++ b/convert-tool/app/src/main/kotlin/com/google/android/gradle_recipe/converter/validators/GradleTasksExecutor.kt @@ -17,13 +17,8 @@ package com.google.android.gradle_recipe.converter.validators import org.gradle.tooling.BuildException -import org.gradle.tooling.GradleConnectionException import org.gradle.tooling.GradleConnector -import org.gradle.tooling.ProjectConnection -import org.gradle.tooling.ResultHandler -import java.lang.System.err import java.nio.file.Path -import java.util.concurrent.CountDownLatch /** Executes Gradle tasks via GradleConnector API */ diff --git a/convert-tool/app/src/test/kotlin/com/google/android/gradle_recipe/converter/AGPVersionsTest.kt b/convert-tool/app/src/test/kotlin/com/google/android/gradle_recipe/converter/AGPVersionsTest.kt deleted file mode 100644 index 5b11302..0000000 --- a/convert-tool/app/src/test/kotlin/com/google/android/gradle_recipe/converter/AGPVersionsTest.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2022 Google, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.gradle_recipe.converter - -import com.github.rising3.semver.SemVer -import com.google.common.truth.Truth.assertThat -import org.junit.Test - -internal class AGPVersionsTest { - @Test - fun alphaBeta() = - assertThat(SemVer.parse("7.1.0-alpha") < SemVer.parse("7.1.0-beta5")).isTrue() - - @Test - fun betaRc() = assertThat(SemVer.parse("7.1.0-beta") < SemVer.parse("7.1.0-rc5")).isTrue() - - @Test - fun rc1Rc2() = - assertThat(SemVer.parse("7.1.0-rc1") < SemVer.parse("7.1.0-rc2")).isTrue() - - @Test - fun rcFinal() = assertThat(SemVer.parse("7.1.0-rc1") < SemVer.parse("7.1.0")).isTrue() - - @Test - fun finalFinal() = assertThat(SemVer.parse("7.1.0") < SemVer.parse("8.1.0")).isTrue() -}
\ No newline at end of file diff --git a/convert-tool/app/src/test/kotlin/com/google/android/gradle_recipe/converter/converters/AndroidPluginVersionTest.kt b/convert-tool/app/src/test/kotlin/com/google/android/gradle_recipe/converter/converters/AndroidPluginVersionTest.kt new file mode 100644 index 0000000..436b4b9 --- /dev/null +++ b/convert-tool/app/src/test/kotlin/com/google/android/gradle_recipe/converter/converters/AndroidPluginVersionTest.kt @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.gradle_recipe.converter.converters + +import com.google.common.truth.Truth +import org.junit.Test + +class AndroidPluginVersionTest { + @Test + fun testParse() { + Truth.assertThat("1.2.3".parse()).isEqualTo(AndroidPluginVersion(1,2,3)) + Truth.assertThat("1.2.3-beta01".parse()).isEqualTo(AndroidPluginVersion(1,2,3, AndroidPluginVersion.PreviewType.BETA, 1)) + Truth.assertThat("1.2.3-rc12".parse()).isEqualTo(AndroidPluginVersion(1,2,3, AndroidPluginVersion.PreviewType.RC, 12)) + } + + @Test + fun finalToFina() { + Truth.assertThat("7.3.0".parse()).isLessThan("8.4.5".parse()) + } + + @Test + fun previewToPreview() { + Truth.assertThat("7.1.0-alpha01".parse()).isLessThan("7.1.0-alpha02".parse()) + Truth.assertThat("7.1.0-beta01".parse()).isLessThan("7.1.0-beta02".parse()) + Truth.assertThat("7.1.0-rc01".parse()).isLessThan("7.1.0-rc02".parse()) + } + + @Test + fun alphaToBeta() { + Truth.assertThat("7.1.0-alpha05".parse()).isLessThan("7.1.0-beta01".parse()) + Truth.assertThat("7.1.0-beta01".parse()).isLessThan("7.2.0-alpha01".parse()) + } + + @Test + fun betaToRc(): Unit { + Truth.assertThat("7.1.0-beta01".parse()).isLessThan("7.1.0-rc01".parse()) + Truth.assertThat("7.1.0-rc01".parse()).isLessThan("7.2.0-beta01".parse()) + } + + @Test + fun rcToFinal() { + Truth.assertThat("7.1.0-rc01".parse()).isLessThan("7.1.0".parse()) + Truth.assertThat("7.1.0".parse()).isLessThan("7.2.0-rc01".parse()) + } + + @Test + fun devToPreviews() { + Truth.assertThat("7.1.0-dev".parse()).isGreaterThan("7.1.0-alpha01".parse()) + Truth.assertThat("7.1.0-dev".parse()).isGreaterThan("7.1.0-beta01".parse()) + Truth.assertThat("7.1.0-dev".parse()).isGreaterThan("7.1.0-rc01".parse()) + + Truth.assertThat("7.1.0-dev".parse()).isLessThan("7.1.0".parse()) + } + + private fun String.parse(): AndroidPluginVersion? { + return AndroidPluginVersion.parse(this) + } +}
\ No newline at end of file diff --git a/convert-tool/gradle/libs.versions.toml b/convert-tool/gradle/libs.versions.toml index 2e23eea..07a2414 100644 --- a/convert-tool/gradle/libs.versions.toml +++ b/convert-tool/gradle/libs.versions.toml @@ -3,7 +3,6 @@ kotlin = "1.9.21" guava = "30.1.1-jre" kotlinx-cli = "0.3.4" tomlj = "1.0.0" -semver = "0.3.1" gradle-api = "8.4" slf4j = "1.7.10" truth = "1.1.3" @@ -15,7 +14,6 @@ kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.re guava = { module = "com.google.guava:guava", version.ref = "guava" } kotlinx-cli = { module = "org.jetbrains.kotlinx:kotlinx-cli", version.ref = "kotlinx-cli" } tomlj = { module = "org.tomlj:tomlj", version.ref = "tomlj" } -semver = { module = "com.github.rising3:semver", version.ref = "semver" } gradle-api = { module = "org.gradle:gradle-tooling-api", version.ref = "gradle-api" } slf4j = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" } kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } |