Skip to content

Commit

Permalink
Switching to Kotlin Multiplatform for JVM use (#1654)
Browse files Browse the repository at this point in the history
* Transition to Kotlin Multiplatform for JVM use

* Use jvmTest task instead of test task

* Apply KMP plugin only to the kotlinpoet module

* Fix setup check task

* Fix targetExclude folder as the source set name change

* Move Java code to jvmMain directory

* Apply dokka workaround

* Use js(IR) as phantom target

* Update kotlinpoet/build.gradle.kts

* Update kotlinpoet/build.gradle.kts

* Update kotlinpoet/build.gradle.kts

* Update gradle/libs.versions.toml

* Update kotlinpoet/build.gradle.kts

---------

Co-authored-by: Jake Wharton <[email protected]>
  • Loading branch information
takahirom and JakeWharton authored Oct 18, 2023
1 parent 26b5a71 commit 69c8b38
Show file tree
Hide file tree
Showing 79 changed files with 180 additions and 101 deletions.
73 changes: 46 additions & 27 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ import com.diffplug.gradle.spotless.SpotlessExtension
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.jetbrains.dokka.gradle.DokkaTask
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
alias(libs.plugins.kotlin.multiplatform) apply false
alias(libs.plugins.kotlin.jvm) apply false
alias(libs.plugins.ksp) apply false
alias(libs.plugins.dokka) apply false
Expand Down Expand Up @@ -53,12 +55,18 @@ subprojects {
options.release.set(8)
}

apply(plugin = "org.jetbrains.kotlin.jvm")
if ("test" !in name && buildFile.exists()) {
apply(plugin = "org.jetbrains.dokka")
apply(plugin = "com.vanniktech.maven.publish")
configure<KotlinProjectExtension> {
explicitApi()
pluginManager.withPlugin("org.jetbrains.kotlin.multiplatform") {
configure<KotlinMultiplatformExtension> {
explicitApi()
}
}
pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
configure<KotlinProjectExtension> {
explicitApi()
}
}
afterEvaluate {
tasks.named<DokkaTask>("dokkaHtml") {
Expand All @@ -70,7 +78,6 @@ subprojects {
}
}
}

apply(plugin = "com.diffplug.spotless")
configure<SpotlessExtension> {
kotlin {
Expand Down Expand Up @@ -98,40 +105,52 @@ subprojects {
| * See the License for the specific language governing permissions and
| * limitations under the License.
| */
""".trimMargin()
""".trimMargin(),
)
}
}

// Only enable the extra toolchain tests on CI. Otherwise local development is broken on Apple Silicon macs
// because there are no matching toolchains for several older JDK versions.
if ("CI" in System.getenv()) {
// Copied from https://github.com/square/retrofit/blob/master/retrofit/build.gradle#L28.
// Create a test task for each supported JDK. We check every "LTS" + current version.
val versionsToTest = listOf(8, 11, 17, 19)
for (majorVersion in versionsToTest) {
val jdkTest = tasks.register<Test>("testJdk$majorVersion") {
val javaToolchains = project.extensions.getByType(JavaToolchainService::class)
javaLauncher.set(javaToolchains.launcherFor {
languageVersion.set(JavaLanguageVersion.of(majorVersion))
vendor.set(JvmVendorSpec.AZUL)
})
fun Project.setupCheckTask(testTaskName: String) {
// Copied from https://github.com/square/retrofit/blob/master/retrofit/build.gradle#L28.
// Create a test task for each supported JDK. We check every "LTS" + current version.
val versionsToTest = listOf(8, 11, 17, 19)
for (majorVersion in versionsToTest) {
val jdkTest = tasks.register<Test>("testJdk$majorVersion") {
val javaToolchains = project.extensions.getByType(JavaToolchainService::class)
javaLauncher.set(
javaToolchains.launcherFor {
languageVersion.set(JavaLanguageVersion.of(majorVersion))
vendor.set(JvmVendorSpec.AZUL)
},
)

description = "Runs the test suite on JDK $majorVersion"
group = LifecycleBasePlugin.VERIFICATION_GROUP

description = "Runs the test suite on JDK $majorVersion"
group = LifecycleBasePlugin.VERIFICATION_GROUP
// Copy inputs from normal Test task.
val testTask =
tasks.getByName<Test>(testTaskName)

// Copy inputs from normal Test task.
val testTask = tasks.getByName<Test>("test")
classpath = testTask.classpath
testClassesDirs = testTask.testClassesDirs
classpath = testTask.classpath
testClassesDirs = testTask.testClassesDirs

testLogging {
exceptionFormat = TestExceptionFormat.FULL
testLogging {
exceptionFormat = TestExceptionFormat.FULL
}
}
tasks.named("check").configure {
dependsOn(jdkTest)
}
}
tasks.named("check").configure {
dependsOn(jdkTest)
}
}
pluginManager.withPlugin("org.jetbrains.kotlin.multiplatform") {
setupCheckTask("jvmTest")
}
pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
setupCheckTask("test")
}
}
}
Expand All @@ -140,6 +159,6 @@ apiValidation {
nonPublicMarkers += "com.squareup.kotlinpoet.ExperimentalKotlinPoetApi"
ignoredProjects += listOf(
"interop", // Empty middle package
"test-processor" // Test only
"test-processor", // Test only
)
}
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ ksp = "1.9.10-1.0.13"
ktlint = "0.48.2"

[plugins]
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
dokka = { id = "org.jetbrains.dokka", version = "1.9.10" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
Expand Down
3 changes: 3 additions & 0 deletions interop/javapoet/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
kotlin("jvm")
}

tasks.jar {
manifest {
Expand Down
3 changes: 3 additions & 0 deletions interop/kotlinx-metadata/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
kotlin("jvm")
}

tasks.jar {
manifest {
Expand Down
3 changes: 3 additions & 0 deletions interop/ksp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
kotlin("jvm")
}

tasks.jar {
manifest {
Expand Down
1 change: 1 addition & 0 deletions interop/ksp/test-processor/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
plugins {
id("com.google.devtools.ksp")
kotlin("jvm")
}

tasks.compileTestKotlin {
Expand Down
71 changes: 45 additions & 26 deletions kotlinpoet/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,59 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
tasks.jar {
manifest {
attributes("Automatic-Module-Name" to "com.squareup.kotlinpoet")
}
}

tasks.compileTestKotlin {
compilerOptions {
freeCompilerArgs.add("-opt-in=com.squareup.kotlinpoet.DelicateKotlinPoetApi")
}
plugins {
kotlin("multiplatform")
}

spotless {
kotlin {
targetExclude(
// Non-Square licensed files
"src/main/java/com/squareup/kotlinpoet/ClassName.kt",
"src/test/java/com/squareup/kotlinpoet/AbstractTypesTest.kt",
"src/test/java/com/squareup/kotlinpoet/ClassNameTest.kt",
"src/test/java/com/squareup/kotlinpoet/TypesEclipseTest.kt",
"src/test/java/com/squareup/kotlinpoet/TypesTest.kt",
"src/commonMain/kotlin/com/squareup/kotlinpoet/ClassName.kt",
"src/commonTest/kotlin/com/squareup/kotlinpoet/AbstractTypesTest.kt",
"src/commonTest/kotlin/com/squareup/kotlinpoet/ClassNameTest.kt",
"src/commonTest/kotlin/com/squareup/kotlinpoet/TypesEclipseTest.kt",
"src/commonTest/kotlin/com/squareup/kotlinpoet/TypesTest.kt",
)
}
}

dependencies {
implementation(libs.kotlin.reflect)
testImplementation(libs.kotlin.junit)
testImplementation(libs.truth)
testImplementation(libs.guava)
testImplementation(libs.compileTesting)
testImplementation(libs.jimfs)
testImplementation(libs.ecj)
testImplementation(libs.kotlinCompileTesting)
testImplementation(libs.kotlin.annotationProcessingEmbeddable)
testImplementation(libs.kotlin.compilerEmbeddable)
kotlin {
jvm {
withJava()
}

sourceSets {
val commonMain by getting {
dependencies {
implementation(libs.kotlin.reflect)
}
}
val commonTest by getting {
dependencies {
implementation(libs.kotlin.junit)
implementation(libs.truth)
implementation(libs.guava)
implementation(libs.compileTesting)
implementation(libs.jimfs)
implementation(libs.ecj)
implementation(libs.kotlinCompileTesting)
implementation(libs.kotlin.annotationProcessingEmbeddable)
implementation(libs.kotlin.compilerEmbeddable)
}
}
}
}

tasks.withType(org.gradle.jvm.tasks.Jar::class.java) {
manifest {
attributes("Automatic-Module-Name" to "com.squareup.kotlinpoet")
}
}

tasks.named<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>("compileTestKotlinJvm") {
compilerOptions {
freeCompilerArgs.add("-opt-in=com.squareup.kotlinpoet.DelicateKotlinPoetApi")
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -345,32 +345,6 @@ class AnnotationSpecTest {
)
}

@Test fun getOnValueArrayTypeMirrorShouldNameValueArg() {
val myClazz = compilation.elements
.getTypeElement(JavaClassWithArrayValueAnnotation::class.java.canonicalName)
val classBuilder = TypeSpec.classBuilder("Result")

myClazz.annotationMirrors.map { AnnotationSpec.get(it) }
.forEach {
classBuilder.addAnnotation(it)
}

assertThat(toString(classBuilder.build())).isEqualTo(
"""
|package com.squareup.tacos
|
|import com.squareup.kotlinpoet.JavaClassWithArrayValueAnnotation
|import java.lang.Boolean
|import java.lang.Object
|
|@JavaClassWithArrayValueAnnotation.AnnotationWithArrayValue(value = arrayOf(Object::class,
| Boolean::class))
|public class Result
|
""".trimMargin(),
)
}

@Test fun getOnVarargMirrorShouldNameValueArg() {
val myClazz = compilation.elements
.getTypeElement(KotlinClassWithVarargAnnotation::class.java.canonicalName)
Expand Down Expand Up @@ -399,28 +373,6 @@ class AnnotationSpecTest {
)
}

@Test fun getOnValueArrayTypeAnnotationShouldNameValueArg() {
val annotation = JavaClassWithArrayValueAnnotation::class.java.getAnnotation(
JavaClassWithArrayValueAnnotation.AnnotationWithArrayValue::class.java,
)
val classBuilder = TypeSpec.classBuilder("Result")
.addAnnotation(AnnotationSpec.get(annotation))

assertThat(toString(classBuilder.build()).trim()).isEqualTo(
"""
|package com.squareup.tacos
|
|import com.squareup.kotlinpoet.JavaClassWithArrayValueAnnotation
|import java.lang.Boolean
|import java.lang.Object
|
|@JavaClassWithArrayValueAnnotation.AnnotationWithArrayValue(value = arrayOf(Object::class,
| Boolean::class))
|public class Result
""".trimMargin(),
)
}

@Test fun getOnVarargAnnotationShouldNameValueArg() {
val annotation = KotlinClassWithVarargAnnotation::class.java
.getAnnotation(AnnotationWithArrayValue::class.java)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2015 Square, 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
*
* https://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.squareup.kotlinpoet

import com.google.common.truth.Truth.assertThat
import com.google.testing.compile.CompilationRule
import kotlin.test.Test
import org.junit.Rule

class JavaAnnotationSpecTest {

@Rule @JvmField
val compilation = CompilationRule()

@Test fun getOnValueArrayTypeMirrorShouldNameValueArg() {
val myClazz = compilation.elements
.getTypeElement(JavaClassWithArrayValueAnnotation::class.java.canonicalName)
val classBuilder = TypeSpec.classBuilder("Result")

myClazz.annotationMirrors.map { AnnotationSpec.get(it) }
.forEach {
classBuilder.addAnnotation(it)
}

assertThat(toString(classBuilder.build())).isEqualTo(
"""
|package com.squareup.tacos
|
|import com.squareup.kotlinpoet.JavaClassWithArrayValueAnnotation
|import java.lang.Boolean
|import java.lang.Object
|
|@JavaClassWithArrayValueAnnotation.AnnotationWithArrayValue(value = arrayOf(Object::class,
| Boolean::class))
|public class Result
|
""".trimMargin(),
)
}

@Test fun getOnValueArrayTypeAnnotationShouldNameValueArg() {
val annotation = JavaClassWithArrayValueAnnotation::class.java.getAnnotation(
JavaClassWithArrayValueAnnotation.AnnotationWithArrayValue::class.java,
)
val classBuilder = TypeSpec.classBuilder("Result")
.addAnnotation(AnnotationSpec.get(annotation))

assertThat(toString(classBuilder.build()).trim()).isEqualTo(
"""
|package com.squareup.tacos
|
|import com.squareup.kotlinpoet.JavaClassWithArrayValueAnnotation
|import java.lang.Boolean
|import java.lang.Object
|
|@JavaClassWithArrayValueAnnotation.AnnotationWithArrayValue(value = arrayOf(Object::class,
| Boolean::class))
|public class Result
""".trimMargin(),
)
}

private fun toString(typeSpec: TypeSpec) =
FileSpec.get("com.squareup.tacos", typeSpec).toString()
}

0 comments on commit 69c8b38

Please sign in to comment.