Skip to content

Commit

Permalink
BCV Gradle rework (#134)
Browse files Browse the repository at this point in the history
* Annotate file paths with `@Language("file-reference")` (#126)
* Update to Gradle 8 (#122)
* bump Gradle Plugin Publish Plugin version
* build script updates & improvements
* use Java Toolchains to set the Java version
* use jvm-test-fixtures plugin for functionalTest sources
* update build config, remove redundant Maven publication

* Initial Gradle convention plugins (#123)
* Apply BCV, commit API dump (#131)
* The ABI shape will be reduced in the future, this is a technical change
* java-diff-utils
* Update Gradle to 8.5

---------

Co-authored-by: aSemy <897017+aSemy@users.noreply.github.com>
  • Loading branch information
qwwdfsad and aSemy authored Jan 12, 2024
1 parent 24cdd4e commit 60098a3
Show file tree
Hide file tree
Showing 29 changed files with 962 additions and 478 deletions.
286 changes: 286 additions & 0 deletions api/binary-compatibility-validator.api

Large diffs are not rendered by default.

190 changes: 111 additions & 79 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import com.gradle.publish.*
import kotlinx.validation.build.*
import org.jetbrains.kotlin.gradle.tasks.*
import kotlinx.validation.build.mavenCentralMetadata
import kotlinx.validation.build.mavenRepositoryPublishing
import kotlinx.validation.build.signPublicationIfKeyPresent
import org.gradle.api.attributes.TestSuiteType.FUNCTIONAL_TEST
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion

plugins {
kotlin("jvm")
`java-gradle-plugin`
id("com.gradle.plugin-publish") apply false
id("com.gradle.plugin-publish")
kotlinx.validation.build.conventions.`java-base`
signing
`maven-publish`
`jvm-test-suite`
id("org.jetbrains.kotlinx.binary-compatibility-validator")
}

repositories {
mavenCentral()
gradlePluginPortal()
google()
group = "org.jetbrains.kotlinx"
providers.gradleProperty("DeployVersion").orNull?.let {
version = it
}

sourceSets {
Expand All @@ -22,29 +27,18 @@ sourceSets {
}
}

sourceSets {
create("functionalTest") {
withConvention(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::class) {
}
compileClasspath += sourceSets.main.get().output + configurations.testRuntimeClasspath
runtimeClasspath += output + compileClasspath
}
}

tasks.register<Test>("functionalTest") {
testClassesDirs = sourceSets["functionalTest"].output.classesDirs
classpath = sourceSets["functionalTest"].runtimeClasspath
}
tasks.check { dependsOn(tasks["functionalTest"]) }

// While gradle testkit supports injection of the plugin classpath it doesn't allow using dependency notation
// to determine the actual runtime classpath for the plugin. It uses isolation, so plugins applied by the build
// script are not visible in the plugin classloader. This means optional dependencies (dependent on applied plugins -
// for example kotlin multiplatform) are not visible even if they are in regular gradle use. This hack will allow
// extending the classpath. It is based upon: https://docs.gradle.org/6.0/userguide/test_kit.html#sub:test-kit-classpath-injection

// Create a configuration to register the dependencies against
val testPluginRuntimeConfiguration = configurations.register("testPluginRuntime")
val testPluginRuntimeConfiguration = configurations.create("testPluginRuntime") {
isCanBeConsumed = false
isCanBeResolved = true
isVisible = false
}

// The task that will create a file that stores the classpath needed for the plugin to have additional runtime dependencies
// This file is then used in to tell TestKit which classpath to use.
Expand All @@ -58,106 +52,144 @@ val createClasspathManifest = tasks.register("createClasspathManifest") {
.withPropertyName("outputDir")

doLast {
outputDir.mkdirs()
file(outputDir.resolve("plugin-classpath.txt")).writeText(testPluginRuntimeConfiguration.get().joinToString("\n"))
file(outputDir.resolve("plugin-classpath.txt"))
.writeText(testPluginRuntimeConfiguration.joinToString("\n"))
}
}

val kotlinVersion: String by project
val androidGradlePluginVersion: String = "7.2.2"

dependencies {
implementation(gradleApi())
implementation("org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.6.2")
implementation("org.ow2.asm:asm:9.2")
implementation("org.ow2.asm:asm-tree:9.2")
implementation("com.googlecode.java-diff-utils:diffutils:1.3.0")
compileOnly("org.jetbrains.kotlin.multiplatform:org.jetbrains.kotlin.multiplatform.gradle.plugin:1.8.10")
// compileOnly("com.android.tools.build:gradle:${androidGradlePluginVersion}")
implementation(libs.kotlinx.metadata)
implementation(libs.ow2.asm)
implementation(libs.ow2.asmTree)
implementation(libs.javaDiffUtils)
compileOnly(libs.gradlePlugin.kotlin)

// Android support is not yet implemented https://github.com/Kotlin/binary-compatibility-validator/issues/94
//compileOnly(libs.gradlePlugin.android)

// The test needs the full kotlin multiplatform plugin loaded as it has no visibility of previously loaded plugins,
// unlike the regular way gradle loads plugins.
add(testPluginRuntimeConfiguration.name, "org.jetbrains.kotlin.multiplatform:org.jetbrains.kotlin.multiplatform.gradle.plugin:$kotlinVersion")
add(testPluginRuntimeConfiguration.name, "com.android.tools.build:gradle:${androidGradlePluginVersion}")

testImplementation(kotlin("test-junit"))
"functionalTestImplementation"(files(createClasspathManifest))

"functionalTestImplementation"("org.assertj:assertj-core:3.18.1")
"functionalTestImplementation"(gradleTestKit())
"functionalTestImplementation"(kotlin("test-junit"))
testPluginRuntimeConfiguration(libs.gradlePlugin.android)
testPluginRuntimeConfiguration(libs.gradlePlugin.kotlin)
}

tasks.compileKotlin {
kotlinOptions.apply {
allWarningsAsErrors = true

languageVersion = "1.4"
apiVersion = "1.4"
jvmTarget = "1.8"

compilerOptions {
allWarningsAsErrors.set(true)
@Suppress("DEPRECATION") // Compatibility with Gradle 7 requires Kotlin 1.4
languageVersion.set(KotlinVersion.KOTLIN_1_4)
apiVersion.set(languageVersion)
jvmTarget.set(JvmTarget.JVM_1_8)
// Suppressing "w: Language version 1.4 is deprecated and its support will be removed" message
// because LV=1.4 in practice is mandatory as it is a default language version in Gradle 7.0+ for users' kts scripts.
freeCompilerArgs += "-Xsuppress-version-warnings"
freeCompilerArgs.addAll(
"-Xsuppress-version-warnings"
)
}
}

java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
withJavadocJar()
withSourcesJar()
toolchain {
languageVersion.set(JavaLanguageVersion.of(8))
}
}

tasks {
compileTestKotlin {
kotlinOptions {
languageVersion = "1.9"
freeCompilerArgs += "-Xsuppress-version-warnings"
}
}
test {
systemProperty("overwrite.output", System.getProperty("overwrite.output", "false"))
systemProperty("testCasesClassesDirs", sourceSets.test.get().output.classesDirs.asPath)
jvmArgs("-ea")
tasks.compileTestKotlin {
compilerOptions {
languageVersion.set(KotlinVersion.KOTLIN_1_9)
}
}

properties["DeployVersion"]?.let { version = it }
tasks.withType<Test>().configureEach {
systemProperty("overwrite.output", System.getProperty("overwrite.output", "false"))
systemProperty("testCasesClassesDirs", sourceSets.test.get().output.classesDirs.asPath)
jvmArgs("-ea")
}

publishing {
publications {
create<MavenPublication>("maven") {
from(components["java"])
mavenCentralMetadata()
mavenCentralArtifacts(project, project.sourceSets.main.get().allSource)
artifact(tasks.javadocJar)
artifact(tasks.sourcesJar)
}

mavenRepositoryPublishing(project)
mavenCentralMetadata()
}

publications.withType(MavenPublication::class).all {
publications.withType<MavenPublication>().all {
signPublicationIfKeyPresent(this)
}
}

apply(plugin = "org.gradle.java-gradle-plugin")
apply(plugin = "com.gradle.plugin-publish")

extensions.getByType(PluginBundleExtension::class).apply {
website = "https://github.com/Kotlin/binary-compatibility-validator"
vcsUrl = "https://github.com/Kotlin/binary-compatibility-validator"
tags = listOf("kotlin", "api-management", "binary-compatibility")
// a publication will be created automatically by com.gradle.plugin-publish
}

@Suppress("UnstableApiUsage")
gradlePlugin {
testSourceSets(sourceSets["functionalTest"])
website.set("https://github.com/Kotlin/binary-compatibility-validator")
vcsUrl.set("https://github.com/Kotlin/binary-compatibility-validator")

plugins.configureEach {
tags.addAll("kotlin", "api-management", "binary-compatibility")
}

plugins {
create("binary-compatibility-validator") {
id = "org.jetbrains.kotlinx.binary-compatibility-validator"
implementationClass = "kotlinx.validation.BinaryCompatibilityValidatorPlugin"
displayName = "Binary compatibility validator"
description = "Produces binary API dumps and compares them in order to verify that binary API is preserved"
description =
"Produces binary API dumps and compares them in order to verify that binary API is preserved"
}
}
}

@Suppress("UnstableApiUsage")
testing {
suites {
withType<JvmTestSuite>().configureEach {
useJUnit()
dependencies {
implementation(project())
implementation(libs.assertJ.core)
implementation(libs.kotlin.test)
}
}

val test by getting(JvmTestSuite::class) {
description = "Regular unit tests"
}

val functionalTest by creating(JvmTestSuite::class) {
testType.set(FUNCTIONAL_TEST)
description = "Functional Plugin tests using Gradle TestKit"

dependencies {
implementation(files(createClasspathManifest))

implementation(gradleApi())
implementation(gradleTestKit())
}

targets.configureEach {
testTask.configure {
shouldRunAfter(test)
}
}
}

gradlePlugin.testSourceSets(functionalTest.sources)

tasks.check {
dependsOn(functionalTest)
}
}
}

tasks.withType<Sign>().configureEach {
onlyIf("only sign if signatory is present") { signatory?.keyId != null }
}
34 changes: 5 additions & 29 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,21 @@
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/

import org.jetbrains.kotlin.gradle.plugin.*
import java.util.Properties
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.util.*

plugins {
`kotlin-dsl`
}

repositories {
jcenter()
}

val props = Properties().apply {
project.file("../gradle.properties").inputStream().use { load(it) }
}

val kotlinVersion: String = props.getProperty("kotlinVersion")

dependencies {
implementation(kotlin("gradle-plugin-api", kotlinVersion))
}

sourceSets["main"].withConvention(KotlinSourceSet::class) { kotlin.srcDirs("src") }

kotlinDslPluginOptions {
experimentalWarning.set(false)
implementation(libs.gradlePlugin.kotlin)
implementation(libs.gradlePlugin.pluginPublishing)
implementation(libs.gradlePlugin.bcv)
}

tasks.withType<KotlinCompile>().configureEach {
kotlinOptions.apply {
kotlinOptions {
allWarningsAsErrors = true
apiVersion = "1.3"
freeCompilerArgs += "-Xskip-runtime-version-check"
}
}

// Silence the following warning:
// 'compileJava' task (current target is 17) and 'compileKotlin' task (current target is 1.8) jvm target compatibility should be set to the same Java version.
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
31 changes: 31 additions & 0 deletions buildSrc/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2016-2023 JetBrains s.r.o.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/
import org.gradle.api.initialization.resolve.RepositoriesMode.PREFER_SETTINGS

rootProject.name = "buildSrc"

pluginManagement {
repositories {
gradlePluginPortal()
mavenCentral()
}
}

@Suppress("UnstableApiUsage")
dependencyResolutionManagement {

repositoriesMode.set(PREFER_SETTINGS)

repositories {
mavenCentral()
gradlePluginPortal()
}

versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
/*
* Copyright 2016-2020 JetBrains s.r.o.
* Copyright 2016-2023 JetBrains s.r.o.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/

package kotlinx.validation.build

import org.gradle.api.*
import org.gradle.api.file.*
import org.gradle.api.publish.*
import org.gradle.api.publish.maven.*
import org.gradle.jvm.tasks.*
import org.gradle.kotlin.dsl.*
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.kotlin.dsl.withType

fun PublishingExtension.mavenCentralMetadata() {
publications.withType(MavenPublication::class) {
Expand Down Expand Up @@ -41,16 +37,3 @@ fun PublishingExtension.mavenCentralMetadata() {
}
}
}

fun MavenPublication.mavenCentralArtifacts(project: Project, sources: SourceDirectorySet) {
val sourcesJar by project.tasks.creating(Jar::class) {
archiveClassifier.set("sources")
from(sources)
}
val javadocJar by project.tasks.creating(Jar::class) {
archiveClassifier.set("javadoc")
// contents are deliberately left empty
}
artifact(sourcesJar)
artifact(javadocJar)
}
File renamed without changes.
Loading

0 comments on commit 60098a3

Please sign in to comment.