Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .idea/dictionaries/project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,32 @@
# 0.4.0
_date_

## Add `TapmocExtension.gradle(String)` (#35)

`TapmocExtension.gradle(String)` makes it easy to configure compatibility for your Gradle plugins:

```kotlin
tapmoc {
// Sets Java and Kotlin flags according to
// https://docs.gradle.org/current/userguide/compatibility.html
gradle("8.14")
}
```

## `checkDependencies()` does not check the `kotlin-stdlib` version by default anymore (#74).

`kotlin-stdlib` can be safely upgraded in most cases (Gradle plugins is the exception) and calling `checkDependencies()` does not enable it any more.

## add `checkJavaClassFiles()`, `checkKotlinMetadata()` and `checkKotlinStdlibs()` (#74).

You may now enable/disable check individually. `checkDependencies()` calls `checkJavaClassFiles()`
and `checkKotlinMetadata()`.

## All changes

* [NEW] Add `TapmocExtension.gradle()` for configuring Gradle plugins (#35)
* [NEW] Checking for `kotlin-stdlib` versions in dependencies is now a separate check (#74)

# 0.3.2
_2025-12-16_

Expand Down
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ nmcp-tasks = { module = "com.gradleup.nmcp:nmcp-tasks", version.ref = "nmcp" }
kgp-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kgp-latest" }
kgp-android = { id = "org.jetbrains.kotlin.android", version.ref = "kgp-latest" }
kgp-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kgp-latest" }
#noinspection SimilarGradleDependency
agp8 = { id = "com.android.library", version = "8.13.0" }
#noinspection SimilarGradleDependency, NewerVersionAvailable
agp8 = { id = "com.android.library", version = "8.12.0" }
agp9-kmp = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp9" }
#noinspection SimilarGradleDependency
agp9-library = { id = "com.android.library", version.ref = "agp9" }
Expand Down
3 changes: 3 additions & 0 deletions tapmoc-gradle-plugin/api/tapmoc-gradle-plugin.api
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public abstract interface class tapmoc/TapmocExtension {
public abstract fun checkApiDependencies (Ltapmoc/Severity;)V
public abstract fun checkDependencies ()V
public abstract fun checkDependencies (Ltapmoc/Severity;)V
public abstract fun checkJavaClassFiles (Ltapmoc/Severity;)V
public abstract fun checkKotlinMetadata (Ltapmoc/Severity;)V
public abstract fun checkKotlinStdlibs (Ltapmoc/Severity;)V
public abstract fun checkRuntimeDependencies (Ltapmoc/Severity;)V
public abstract fun gradle (Ljava/lang/String;)V
public abstract fun java (I)V
Expand Down
29 changes: 19 additions & 10 deletions tapmoc-gradle-plugin/src/kgp/kotlin/tapmoc/internal/KgpImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tapmoc.internal

import java.lang.reflect.Method
import org.gradle.api.Project
import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.api.provider.ProviderFactory
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
Expand Down Expand Up @@ -36,7 +37,7 @@ private fun compilerOptionsMethod(): Method? {
return method
}

private class KgpImpl(extension: Any, private val providers: ProviderFactory, private val kgpVersion: String) : Kgp {
private class KgpImpl(private val dependencyHandler: DependencyHandler, extension: Any, private val providers: ProviderFactory, private val kgpVersion: String) : Kgp {
private val kotlinProjectExtension: KotlinProjectExtension = extension as KotlinProjectExtension

override fun javaCompatibility(version: Int) {
Expand Down Expand Up @@ -119,17 +120,25 @@ private class KgpImpl(extension: Any, private val providers: ProviderFactory, pr
*
* See https://github.com/Jetbrains/kotlin/blob/7fa1c5fdc7077e52d29505c6fa10a82a43665d7c/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/stdlibDependencyManagement.kt#L97
*/
kotlinProjectExtension.forEachTarget { target ->
target.compilations.filter { it.name != "test" }.forEach { compilation ->
compilation.defaultSourceSet.dependencies {
if (target.platformType in setOf(KotlinPlatformType.jvm, KotlinPlatformType.androidJvm, KotlinPlatformType.common)) {
api("org.jetbrains.kotlin:kotlin-stdlib:${version}")
} else {
// Non-JVM targets do not support compatibility flags and require the latest version of kotlin-stdlib
api("org.jetbrains.kotlin:kotlin-stdlib:${kgpVersion}")
if (kotlinProjectExtension is KotlinMultiplatformExtension) {
kotlinProjectExtension.targets.configureEach { target ->
target.compilations.matching { it.name != "test" }.configureEach { compilation ->
compilation.defaultSourceSet.dependencies {
if (target.platformType in setOf(KotlinPlatformType.jvm, KotlinPlatformType.androidJvm, KotlinPlatformType.common)) {
api("org.jetbrains.kotlin:kotlin-stdlib:${version}")
} else {
// Non-JVM targets do not support compatibility flags and require the latest version of kotlin-stdlib
api("org.jetbrains.kotlin:kotlin-stdlib:${kgpVersion}")
}
}
}
}
} else {
/**
* Android/JVM: adding the stdlib through the compilations does not seem to work,
* just add to the `api` configuration
*/
dependencyHandler.add("api", "org.jetbrains.kotlin:kotlin-stdlib:${version}")
}
}
}
Expand Down Expand Up @@ -192,7 +201,7 @@ internal fun Project.onKgp(block: (Kgp) -> Unit) {
plugins.withType(KotlinBasePlugin::class.java).configureEach {
if(!hasKgp) {
hasKgp = true
block(KgpImpl(extensions.getByName("kotlin"), providers, getKotlinPluginVersion()))
block(KgpImpl(this.dependencies, extensions.getByName("kotlin"), providers, getKotlinPluginVersion()))
}
}
}
68 changes: 51 additions & 17 deletions tapmoc-gradle-plugin/src/main/kotlin/tapmoc/TapmocExtension.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,24 @@ interface TapmocExtension {
fun kotlin(version: String)

/**
* Configures the minimal Gradle version supported.
* Configures compatibility flags for the minimal Gradle version supported.
*
* This method:
* - Calls [kotlin] with the compatible Kotlin version as described in the [Gradle compatibility matrix](https://docs.gradle.org/current/userguide/compatibility.html#kotlin).
* - Calls [java] with the compatible Java version as described in the [Gradle compatibility matrix](https://docs.gradle.org/current/userguide/compatibility.html#java_runtime).
*
* It is equivalent to the following code:
* ```kotlin
* kotlin(kotlinVersionForGradle(gradleVersion))
* java(javaVersionForGradle(gradleVersion))
* ```
*
* Note: When building a Gradle plugin, calling `checkDependencies(Severity.ERROR)` and `checkKotlinStdlibs(Severity.ERROR)` is strongly recommended.
*
* @param gradleVersion the Gradle version to target, specified as a string. Example: "8.14".
*
* @see checkDependencies
* @see checkKotlinStdlibs
*/
fun gradle(gradleVersion: String)

Expand All @@ -56,33 +67,56 @@ interface TapmocExtension {
*/
fun kotlinVersionForGradle(gradleVersion: String): String

@Deprecated("Use checkDependencies instead.", ReplaceWith("checkDependencies(severity)"))
fun checkApiDependencies(severity: Severity)
/**
* Checks that the api and runtime dependencies are compatible with the target Java version.
*
* This checks the [class file version](https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-4.html#jvms-4.1).
*
* @param severity The severity level for the check. Defaults to `Severity.IGNORE`.
*/
fun checkJavaClassFiles(severity: Severity)

@Deprecated("Use checkDependencies instead.", ReplaceWith("checkDependencies(severity)"))
fun checkRuntimeDependencies(severity: Severity)
/**
* Checks that the api dependencies Kotlin metadata is compatible with the target Kotlin version.
*
* Thanks to Kotlin [best effort n + 1 forward compatibility guarantee](https://kotlinlang.org/docs/kotlin-evolution-principles.html#evolving-the-binary-format),
* dependencies may contain `kotlinTarget + 1` metadata.
*
* @param severity The severity level for the check. Defaults to `Severity.IGNORE`.
*/
fun checkKotlinMetadata(severity: Severity)

/**
* Walks the consumable configurations exposing a `java-api` or `java-runtime` [usage attribute](https://docs.gradle.org/9.2.1/javadoc/org/gradle/api/attributes/Usage.html)
* and checks that dependencies are compatible with the target [java] and [kotlin] values:
* Checks that the runtime dependencies do not contain a version of `kotlin-stdlib` higher than the target Kotlin version.
*
* In most cases, `kotlin-stdlib` can be safely upgraded and this check is disabled by default.
*
* Enable it if your runtime forces a given version of `kotlin-stdlib`. This is the notably case for Gradle plugins.
*
* - checks that `kotlin-stdlib` is always <= targetKotlinVersion (`java-runtime` only)
* - checks that Kotlin metadata is always <= targetKotlinVersion + 1 (`java-api` only).
* Note: it is `targetKotlinVersion + 1` because Kotlin has a [best effort n + 1 forward compatibility guarantee](https://kotlinlang.org/docs/kotlin-evolution-principles.html#evolving-the-binary-format).
* - checks that the Java class files version is always <= targetJavaVersion
* @param severity The severity level for the check. Defaults to `Severity.IGNORE`.
*/
fun checkKotlinStdlibs(severity: Severity)

/**
* This is equivalent to calling `checkJavaClassFiles(severity)` and `checkKotlinMetadata(severity)`.
*
* @see checkJavaClassFiles
* @see checkKotlinMetadata
*/
fun checkDependencies(severity: Severity)

/**
* Walks the consumable configurations exposing a `java-api` or `java-runtime` [usage attribute](https://docs.gradle.org/9.2.1/javadoc/org/gradle/api/attributes/Usage.html)
* and checks that dependencies are compatible with the target [java] and [kotlin] values:
* This is equivalent to calling `checkDependencies(Severity.ERROR)`.
*
* - checks that `kotlin-stdlib` is always <= targetKotlinVersion (`java-runtime` only)
* - checks that Kotlin metadata is always <= targetKotlinVersion + 1 (`java-api` only).
* Note: it is `targetKotlinVersion + 1` because Kotlin has a [best effort n + 1 forward compatibility guarantee](https://kotlinlang.org/docs/kotlin-evolution-principles.html#evolving-the-binary-format).
* - checks that the Java class files version is always <= targetJavaVersion
* @see checkDependencies
*/
fun checkDependencies()

@Deprecated("Use checkDependencies instead.", ReplaceWith("checkDependencies(severity)"), level = DeprecationLevel.ERROR)
fun checkApiDependencies(severity: Severity)

@Deprecated("Use checkDependencies instead.", ReplaceWith("checkDependencies(severity)"), level = DeprecationLevel.ERROR)
fun checkRuntimeDependencies(severity: Severity)
}

enum class Severity {
Expand Down
Loading