Skip to content

Commit

Permalink
add release Android target by default for KMP (#736)
Browse files Browse the repository at this point in the history
* add release Android target by default for KMP

* ktlint
  • Loading branch information
gabrielittner authored Mar 10, 2024
1 parent 2ccf77c commit c5019ea
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 10 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

- Added support for publishing through the new [Central Portal](https://central.sonatype.com). To use
this use the `CENTRAL_PORTAL` option when specifying the Sonatype host.
- For Kotlin Multiplatform the main plugin will now automatically publish the
`release` variant if the project has an Android target.
- Support specifying the Android variants to publish in `KotlinMultiplatform(...)`.
- Updated minimum supported Gradle, Android Gradle Plugin and Kotlin versions.
- Removed support for the deprecated Kotlin/JS plugin.
- Removed the deprecated `closeAndReleaseRepository` task. Use `releaseRepository`, which
Expand Down
11 changes: 9 additions & 2 deletions docs/what.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,10 @@ For projects using the `org.jetbrains.kotlin.multiplatform` plugin.
// - `JavadocJar.None()` don't publish this artifact
// - `JavadocJar.Empty()` publish an emprt jar
// - `JavadocJar.Dokka("dokkaHtml")` when using Kotlin with Dokka, where `dokkaHtml` is the name of the Dokka task that should be used as input
// sources publishing is always enabled by the Kotlin Multiplatform plugin
configure(new KotlinMultiplatform(new JavadocJar.Dokka("dokkaHtml")))
// the second whether to publish a sources jar
// the third parameters configures which Android library variants to publish if this project has an Android target
// defaults to "release" when using the main plugin and nothing for the base plugin
configure(new KotlinMultiplatform(new JavadocJar.Dokka("dokkaHtml"), true, ["debug", "release"]))
}
```

Expand All @@ -215,6 +217,11 @@ For projects using the `org.jetbrains.kotlin.multiplatform` plugin.
// - `JavadocJar.Empty()` publish an emprt jar
// - `JavadocJar.Dokka("dokkaHtml")` when using Kotlin with Dokka, where `dokkaHtml` is the name of the Dokka task that should be used as input
javadocJar = JavadocJar.Dokka("dokkaHtml"),
// whether to publish a sources jar
sourcesJar = true,
// configure which Android library variants to publish if this project has an Android target
// defaults to "release" when using the main plugin and nothing for the base plugin
androidVariantsToPublish = listOf("debug", release"),
))
}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,112 @@ class MavenPublishPluginPlatformTest {
assertThat(androidReleaseResult).javadocJar().exists()
assertThat(androidReleaseResult).javadocJar().isSigned()

val androidDebugResult = result.withArtifactIdSuffix("android-debug")
assertThat(androidDebugResult).outcome().succeeded()
assertThat(androidDebugResult).artifact("aar").doesNotExist()
assertThat(androidDebugResult).pom().doesNotExist()
assertThat(androidDebugResult).module().doesNotExist()
assertThat(androidDebugResult).sourcesJar().doesNotExist()
assertThat(androidDebugResult).javadocJar().doesNotExist()
}

@TestParameterInjectorTest
fun kotlinMultiplatformWithAndroidLibraryAndSpecifiedVariantsProject(
@TestParameter(valuesProvider = AgpVersionProvider::class) agpVersion: AgpVersion,
@TestParameter(valuesProvider = KotlinVersionProvider::class) kotlinVersion: KotlinVersion,
) {
agpVersion.assumeSupportedJdkAndGradleVersion(gradleVersion)
kotlinVersion.assumeSupportedJdkAndGradleVersion(gradleVersion)

val project = kotlinMultiplatformWithAndroidLibraryAndSpecifiedVariantsProjectSpec(agpVersion, kotlinVersion)
val result = project.run(fixtures, testProjectDir, testOptions)

assertThat(result).outcome().succeeded()
assertThat(result).artifact("jar").exists()
assertThat(result).artifact("jar").isSigned()
assertThat(result).pom().exists()
assertThat(result).pom().isSigned()
assertThat(result).pom().matchesExpectedPom(
kotlinStdlibCommon(kotlinVersion).copy(scope = "runtime"),
)
assertThat(result).module().exists()
assertThat(result).module().isSigned()
assertThat(result).sourcesJar().exists()
assertThat(result).sourcesJar().isSigned()
assertThat(result).sourcesJar().containsSourceSetFiles("commonMain")
assertThat(result).javadocJar().exists()
assertThat(result).javadocJar().isSigned()

val jvmResult = result.withArtifactIdSuffix("jvm")
assertThat(jvmResult).outcome().succeeded()
assertThat(jvmResult).artifact("jar").exists()
assertThat(jvmResult).artifact("jar").isSigned()
assertThat(jvmResult).pom().exists()
assertThat(jvmResult).pom().isSigned()
assertThat(jvmResult).pom().matchesExpectedPom(
kotlinStdlibJdk(kotlinVersion),
kotlinStdlibCommon(kotlinVersion),
)
assertThat(jvmResult).module().exists()
assertThat(jvmResult).module().isSigned()
assertThat(jvmResult).sourcesJar().exists()
assertThat(jvmResult).sourcesJar().isSigned()
assertThat(jvmResult).sourcesJar().containsSourceSetFiles("commonMain", "jvmMain")
assertThat(jvmResult).javadocJar().exists()
assertThat(jvmResult).javadocJar().isSigned()

val linuxResult = result.withArtifactIdSuffix("linux")
assertThat(linuxResult).outcome().succeeded()
assertThat(linuxResult).artifact("klib").exists()
assertThat(linuxResult).artifact("klib").isSigned()
assertThat(linuxResult).pom().exists()
assertThat(linuxResult).pom().isSigned()
assertThat(linuxResult).pom().matchesExpectedPom(
"klib",
kotlinStdlibCommon(kotlinVersion),
)
assertThat(linuxResult).module().exists()
assertThat(linuxResult).module().isSigned()
assertThat(linuxResult).sourcesJar().exists()
assertThat(linuxResult).sourcesJar().isSigned()
assertThat(linuxResult).sourcesJar().containsSourceSetFiles("commonMain", "linuxMain")
assertThat(linuxResult).javadocJar().exists()
assertThat(linuxResult).javadocJar().isSigned()

val nodejsResult = result.withArtifactIdSuffix("nodejs")
assertThat(nodejsResult).outcome().succeeded()
assertThat(nodejsResult).artifact("klib").exists()
assertThat(nodejsResult).artifact("klib").isSigned()
assertThat(nodejsResult).pom().exists()
assertThat(nodejsResult).pom().isSigned()
assertThat(nodejsResult).pom().matchesExpectedPom("klib", kotlinStdlibJs(kotlinVersion), kotlinDomApi(kotlinVersion))
assertThat(nodejsResult).module().exists()
assertThat(nodejsResult).module().isSigned()
assertThat(nodejsResult).sourcesJar().exists()
assertThat(nodejsResult).sourcesJar().isSigned()
assertThat(nodejsResult).sourcesJar().containsSourceSetFiles("commonMain", "nodeJsMain")
assertThat(nodejsResult).javadocJar().exists()
assertThat(nodejsResult).javadocJar().isSigned()

val androidReleaseResult = result.withArtifactIdSuffix("android")
assertThat(androidReleaseResult).outcome().succeeded()
assertThat(androidReleaseResult).artifact("aar").exists()
assertThat(androidReleaseResult).artifact("aar").isSigned()
assertThat(androidReleaseResult).pom().exists()
assertThat(androidReleaseResult).pom().isSigned()
assertThat(androidReleaseResult).pom().matchesExpectedPom(
"aar",
kotlinStdlibJdk(kotlinVersion),
kotlinStdlibCommon(kotlinVersion),
)
assertThat(androidReleaseResult).module().exists()
assertThat(androidReleaseResult).module().isSigned()
assertThat(androidReleaseResult).sourcesJar().exists()
assertThat(androidReleaseResult).sourcesJar().isSigned()
assertThat(androidReleaseResult).sourcesJar().containsSourceSetFiles("commonMain", "androidMain", "androidRelease")
assertThat(androidReleaseResult).javadocJar().exists()
assertThat(androidReleaseResult).javadocJar().isSigned()

val androidDebugResult = result.withArtifactIdSuffix("android-debug")
assertThat(androidDebugResult).outcome().succeeded()
assertThat(androidDebugResult).artifact("aar").exists()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ fun kotlinMultiplatformWithAndroidLibraryProjectSpec(agpVersion: AgpVersion, kot
SourceFile("androidDebug", "kotlin", "com/vanniktech/maven/publish/test/ExpectedTestClass.kt"),
SourceFile("androidRelease", "kotlin", "com/vanniktech/maven/publish/test/ExpectedTestClass.kt"),
),
// needs to explicitly specify release to match the main plugin default behavior
basePluginConfig = "configure(new KotlinMultiplatform(new JavadocJar.Empty(), true, [\"release\"]))",
buildFileExtra = baseProject.buildFileExtra + """
android {
Expand All @@ -187,9 +189,7 @@ fun kotlinMultiplatformWithAndroidLibraryProjectSpec(agpVersion: AgpVersion, kot
}
kotlin {
android {
publishLibraryVariants("release", "debug")
}
androidTarget {}
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of("8"))
Expand All @@ -199,6 +199,24 @@ fun kotlinMultiplatformWithAndroidLibraryProjectSpec(agpVersion: AgpVersion, kot
)
}

fun kotlinMultiplatformWithAndroidLibraryAndSpecifiedVariantsProjectSpec(
agpVersion: AgpVersion,
kotlinVersion: KotlinVersion,
): ProjectSpec {
val baseProject = kotlinMultiplatformWithAndroidLibraryProjectSpec(agpVersion, kotlinVersion)
return baseProject.copy(
basePluginConfig = "configure(new KotlinMultiplatform(new JavadocJar.Empty()))",
buildFileExtra = baseProject.buildFileExtra + """
kotlin {
androidTarget {
publishLibraryVariants("release", "debug")
}
}
""".trimIndent(),
)
}

fun androidLibraryProjectSpec(version: AgpVersion) = ProjectSpec(
plugins = listOf(
androidLibraryPlugin.copy(version = version.value),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ open class ArtifactSubject internal constructor(
}
}

fun doesNotExist() {
if (artifact.exists()) {
val files = result.repo.toFile().walkTopDown().filter { it.isFile }.toList()
failWithActual(fact("expected not to exist", artifact), fact("but repo contained", files))
}
}

fun isSigned() {
val signedArtifact = artifact.resolveSibling("${artifact.name}.asc")
if (!signedArtifact.exists()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,8 +368,17 @@ abstract class MavenPublishBaseExtension(
}

when {
project.plugins.hasPlugin("org.jetbrains.kotlin.multiplatform") ->
configure(KotlinMultiplatform(defaultJavaDocOption(plainJavadocSupported = false)))
project.plugins.hasPlugin("org.jetbrains.kotlin.multiplatform") -> {
val variant = project.findOptionalProperty("ANDROID_VARIANT_TO_PUBLISH") ?: "release"
configure(
KotlinMultiplatform(
javadocJar = defaultJavaDocOption(plainJavadocSupported = false),
sourcesJar = true,
androidVariantsToPublish = listOf(variant),
forceAndroidVariantsIfNotEmpty = false,
),
)
}
project.plugins.hasPlugin("com.android.library") -> {
val variant = project.findOptionalProperty("ANDROID_VARIANT_TO_PUBLISH") ?: "release"
configure(AndroidSingleVariantLibrary(variant))
Expand Down
25 changes: 22 additions & 3 deletions plugin/src/main/kotlin/com/vanniktech/maven/publish/Platform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import org.gradle.jvm.component.internal.DefaultJvmSoftwareComponent
import org.gradle.jvm.tasks.Jar
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget

/**
* Represents a platform that the plugin supports to publish. For example [JavaLibrary], [AndroidMultiVariantLibrary] or
Expand Down Expand Up @@ -269,10 +270,18 @@ data class AndroidMultiVariantLibrary @JvmOverloads constructor(
*
* This does not include javadoc jars because there are no APIs for that available.
*/
data class KotlinMultiplatform @JvmOverloads constructor(
override val javadocJar: JavadocJar = JavadocJar.Empty(),
override val sourcesJar: Boolean = true,
data class KotlinMultiplatform internal constructor(
override val javadocJar: JavadocJar,
override val sourcesJar: Boolean,
val androidVariantsToPublish: List<String>,
val forceAndroidVariantsIfNotEmpty: Boolean,
) : Platform() {
@JvmOverloads constructor(
javadocJar: JavadocJar = JavadocJar.Empty(),
sourcesJar: Boolean = true,
androidVariantsToPublish: List<String> = emptyList(),
) : this(javadocJar, sourcesJar, androidVariantsToPublish, forceAndroidVariantsIfNotEmpty = true)

override fun configure(project: Project) {
check(project.plugins.hasPlugin("org.jetbrains.kotlin.multiplatform")) {
"Calling configure(KotlinMultiplatform(...)) requires the org.jetbrains.kotlin.multiplatform plugin to be applied"
Expand All @@ -286,6 +295,16 @@ data class KotlinMultiplatform @JvmOverloads constructor(

project.extensions.configure(KotlinMultiplatformExtension::class.java) {
it.withSourcesJar(sourcesJar)

if (androidVariantsToPublish.isNotEmpty()) {
it.targets.configureEach { target ->
if (target is KotlinAndroidTarget) {
if (forceAndroidVariantsIfNotEmpty || target.publishLibraryVariants.isNullOrEmpty()) {
target.publishLibraryVariants = androidVariantsToPublish
}
}
}
}
}
}
}
Expand Down

0 comments on commit c5019ea

Please sign in to comment.