From 9c2b2337e4121a3a79d09a94a068a5a56761bbbc Mon Sep 17 00:00:00 2001 From: Yahor Urbanovich Date: Tue, 2 Jun 2026 14:56:25 +0300 Subject: [PATCH] Add CheckVersionCompatibility task to enforce Kotlin/Compose version --- .github/workflows/validation.yml | 3 ++ .../task/CheckVersionCompatibility.kt | 50 +++++++++++++++++++ gradle/libs.versions.toml | 7 ++- tools/idea-plugin/build.gradle.kts | 21 ++++++++ 4 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 build-logic/src/main/kotlin/io/github/composegears/valkyrie/task/CheckVersionCompatibility.kt diff --git a/.github/workflows/validation.yml b/.github/workflows/validation.yml index 333986404..f6f8afafe 100644 --- a/.github/workflows/validation.yml +++ b/.github/workflows/validation.yml @@ -39,5 +39,8 @@ jobs: with: cache-disabled: true + - name: Check version compatibility + run: ./gradlew :tools:idea-plugin:checkVersionCompatibility + - name: Run build run: ./gradlew build diff --git a/build-logic/src/main/kotlin/io/github/composegears/valkyrie/task/CheckVersionCompatibility.kt b/build-logic/src/main/kotlin/io/github/composegears/valkyrie/task/CheckVersionCompatibility.kt new file mode 100644 index 000000000..9bf78d156 --- /dev/null +++ b/build-logic/src/main/kotlin/io/github/composegears/valkyrie/task/CheckVersionCompatibility.kt @@ -0,0 +1,50 @@ +package io.github.composegears.valkyrie.task + +import net.swiftzer.semver.SemVer +import org.gradle.api.DefaultTask +import org.gradle.api.GradleException +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.TaskAction + +abstract class CheckVersionCompatibility : DefaultTask() { + + @get:Input + abstract val resolvedComponents: ListProperty + + @get:Input + abstract val maxKotlinVersion: Property + + @get:Input + abstract val maxComposeVersion: Property + + @TaskAction + fun check() { + val maxKotlin = SemVer.parse(maxKotlinVersion.get()) + val maxCompose = SemVer.parse(maxComposeVersion.get()) + + val violations = resolvedComponents.get() + .mapNotNull { coordinate -> + val (group, name, version) = coordinate.split(":") + when { + group == "org.jetbrains.kotlin" && SemVer.parse(version) > maxKotlin -> + "\t- $group:$name:$version (max supported: $maxKotlin)" + group.startsWith("org.jetbrains.compose") && SemVer.parse(version) > maxCompose -> + "\t- $group:$name:$version (max supported: $maxCompose)" + else -> null + } + } + .distinct() + + if (violations.isNotEmpty()) { + throw GradleException( + buildString { + appendLine("Incompatible dependency versions found:") + violations.forEach(::appendLine) + }, + ) + } + logger.lifecycle("✅ All dependencies are compatible (kotlin ≤ $maxKotlin, compose ≤ $maxCompose)") + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ae2d76a40..cd1be4c95 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,4 @@ [versions] -collection = "1.6.0" compose = "1.10.0" intellij = "2.13.1" jacoco = "0.8.13" @@ -12,7 +11,7 @@ leviathan = "3.1.0" ktor = "3.3.1" [libraries] -androidx-collection = { module = "androidx.collection:collection", version.ref = "collection" } +androidx-collection = "androidx.collection:collection:1.6.0" android-build-tools = "com.android.tools:sdk-common:32.2.1" compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", version.ref = "compose" } @@ -25,8 +24,8 @@ compose-ui-tooling-preview = { module = "org.jetbrains.compose.components:compon fonticons = "dev.tclement.fonticons:core:2.1.1" fuzzysearch = "com.github.android-password-store:sublime-fuzzy:2.3.4" highlights = "dev.snipme:highlights:1.1.0" -# Support Kotlin 2.2.20 https://github.com/square/kotlinpoet/releases/tag/2.1.0 -kotlinpoet = "com.squareup:kotlinpoet:2.1.0" +# Support Kotlin 2.2.20 https://github.com/square/kotlinpoet/releases/tag/2.2.0 +kotlinpoet = "com.squareup:kotlinpoet:2.2.0" kotlin-io = "org.jetbrains.kotlinx:kotlinx-io-core:0.8.2" kotlinx-browser = "org.jetbrains.kotlinx:kotlinx-browser:0.5.0" # Support Kotlin 2.2.20 https://github.com/Kotlin/kotlinx.serialization/releases/tag/v1.9.0 diff --git a/tools/idea-plugin/build.gradle.kts b/tools/idea-plugin/build.gradle.kts index 7f0da6871..801ebbe66 100644 --- a/tools/idea-plugin/build.gradle.kts +++ b/tools/idea-plugin/build.gradle.kts @@ -1,4 +1,5 @@ import io.github.composegears.valkyrie.excludeAndroidBuildTools +import io.github.composegears.valkyrie.task.CheckVersionCompatibility import org.jetbrains.changelog.Changelog import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType import org.jetbrains.intellij.platform.gradle.TestFrameworkType @@ -167,3 +168,23 @@ tasks { exclude { "coroutines" in it.name } } } + +tasks.register("checkVersionCompatibility") { + group = "verification" + description = "Ensures transitive deps don't exceed predefined Kotlin/Compose version" + // Use a separate configuration without kotlin/compose exclusions so transitive deps + // pulled by 3rd-party libs are visible even if they are bundled in IDEA and excluded + // from the actual runtimeClasspath. + val checkConfig = configurations.register("versionCompatibilityCheck") { + isCanBeResolved = true + isCanBeConsumed = false + dependencies.addAll(configurations.getByName("implementation").dependencies) + } + resolvedComponents = checkConfig.map { config -> + config.incoming.resolutionResult.allComponents + .mapNotNull { it.moduleVersion } + .map { "${it.group}:${it.name}:${it.version}" } + } + maxKotlinVersion = libs.versions.kotlin + maxComposeVersion = libs.versions.compose +}