From db3278c088d8c90c9373e9f44f563700a8eea553 Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Sun, 23 Apr 2023 17:26:26 +0200 Subject: [PATCH] fix: fix bugged source jar management in kotlin-js projects (#619) * fix: sources jar management in kotlin-js projects * style: stile improvements * fix: ensure hacks are confined to Kotlin/JS projects --------- Co-authored-by: Giovanni Ciatto --- .../gradle/mavencentral/ProjectExtensions.kt | 47 +++++++++++++++- .../gradle/mavencentral/PublishOnCentral.kt | 55 ++++++++++++++++--- .../gradle/test/ktjs/build.gradle.kts | 5 ++ .../danilopianini/gradle/test/ktjs/test.yaml | 29 ++++++++-- 4 files changed, 122 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/org/danilopianini/gradle/mavencentral/ProjectExtensions.kt b/src/main/kotlin/org/danilopianini/gradle/mavencentral/ProjectExtensions.kt index b8deb674..f88282e1 100644 --- a/src/main/kotlin/org/danilopianini/gradle/mavencentral/ProjectExtensions.kt +++ b/src/main/kotlin/org/danilopianini/gradle/mavencentral/ProjectExtensions.kt @@ -2,7 +2,9 @@ package org.danilopianini.gradle.mavencentral import io.github.gradlenexus.publishplugin.internal.StagingRepository.State.CLOSED import org.danilopianini.gradle.mavencentral.MavenPublicationExtensions.signingTasks +import org.gradle.api.Action import org.gradle.api.DefaultTask +import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.provider.Property @@ -10,6 +12,7 @@ import org.gradle.api.publish.PublishingExtension import org.gradle.api.publish.maven.MavenPublication import org.gradle.api.publish.maven.tasks.PublishToMavenRepository import org.gradle.api.publish.plugins.PublishingPlugin +import org.gradle.jvm.tasks.Jar import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.create import org.gradle.kotlin.dsl.property @@ -23,13 +26,51 @@ import kotlin.reflect.KClass internal object ProjectExtensions { + /** + * The id of the Kotlin/JS plugin. + */ + private const val KOTLIN_JS_PLUGIN = "org.jetbrains.kotlin.js" + + /** + * The `jsSourcesJar` [Task] of a Kotlin/JS project. + */ + internal val Project.jsSourcesJar: Jar? get() = tasks.withType().findByName("jsSourcesJar") + + /** + * The `kotlinSourcesJar` [Task] of a Kotlin/JS or Kotlin/JVM project. + */ + private val Project.kotlinSourcesJar: Jar? get() = tasks.withType().findByName("kotlinSourcesJar") + + /** + * The list of default sources Jar [Task]s: it may include [kotlinSourcesJar] and [jsSourcesJar], + * if they are non-null. + */ + internal val Project.sourcesJarTasks: List get() = listOfNotNull(jsSourcesJar, kotlinSourcesJar) + + /** + * Executes an action on Kotlin/JS projects only. + */ + internal fun Project.ifKotlinJsProject(action: Action>) { + plugins.withId(KOTLIN_JS_PLUGIN, action) + } + + /** + * Configures the provided task to include the `main` source set of a Kotlin/JS project. + * The configuration does nothing if the provided task not of type [SourceJar]. + */ fun Project.configureJavadocJarTaskForKtJs(sourcesJarTask: Task) { - plugins.withId("org.jetbrains.kotlin.js") { _ -> + ifKotlinJsProject { _ -> configure { js { sourceSets.getByName("main") { - (sourcesJarTask as SourceJar).sourceSet(it.kotlin) - sourcesJarTask.sourceSet(it.resources) + (sourcesJarTask as? SourceJar)?.run { + sourceSet(it.kotlin) + sourceSet(it.resources) + } ?: logger.warn( + "source sets of task {} not configured because it is not of type {}", + sourcesJarTask.name, + SourceJar::class.java.name, + ) } } } diff --git a/src/main/kotlin/org/danilopianini/gradle/mavencentral/PublishOnCentral.kt b/src/main/kotlin/org/danilopianini/gradle/mavencentral/PublishOnCentral.kt index b4198cc4..66f59e78 100644 --- a/src/main/kotlin/org/danilopianini/gradle/mavencentral/PublishOnCentral.kt +++ b/src/main/kotlin/org/danilopianini/gradle/mavencentral/PublishOnCentral.kt @@ -4,9 +4,13 @@ import org.danilopianini.gradle.mavencentral.MavenPublicationExtensions.configur import org.danilopianini.gradle.mavencentral.MavenPublicationExtensions.signingTasks import org.danilopianini.gradle.mavencentral.ProjectExtensions.configureJavadocJarTaskForKtJs import org.danilopianini.gradle.mavencentral.ProjectExtensions.configureRepository +import org.danilopianini.gradle.mavencentral.ProjectExtensions.ifKotlinJsProject +import org.danilopianini.gradle.mavencentral.ProjectExtensions.jsSourcesJar import org.danilopianini.gradle.mavencentral.ProjectExtensions.registerTaskIfNeeded +import org.danilopianini.gradle.mavencentral.ProjectExtensions.sourcesJarTasks import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.Task import org.gradle.api.plugins.JavaPlugin import org.gradle.api.publish.PublishingExtension import org.gradle.api.publish.maven.MavenPublication @@ -29,6 +33,48 @@ class PublishOnCentral : Plugin { private const val publicationName = "OSSRH" } + private fun addSourcesArtifactIfNeeded(project: Project, publication: MavenPublication, sourcesJarTask: Task) { + if (sourcesJarTask is SourceJar) { + if (project.jsSourcesJar == null) { + publication.artifact(sourcesJarTask) + project.logger.info( + "add sources jar artifact to publication {} from task {}", + publication.name, + sourcesJarTask.name, + ) + } else { + /* + * This is a hack for Kotlin/JS projects. + * These projects already contain tasks named "jsSourcesJar" and "kotlinSourcesJar", generating the + * same jar "-js--sources.jar". + * In particular, task kotlinSourcesJar is automatically registered as an artifact to Maven publications + * when they are created. So, adding further sources-jar-generating tasks it troublesome in this + * situation. The following code simply removes the "-js" appendix from the jar file name, + * hence making the jar compliant with Maven Central. + */ + project.ifKotlinJsProject { _ -> + project.sourcesJarTasks.forEach { + it.archiveAppendix.set("") + // Better to tell the user the plugin is changing the behaviour of default tasks + project.logger.lifecycle( + "remove '-js' appendix from sources jar generated by task {}", + it.name, + ) + } + } + } + } + } + + private fun addJavadocArtifactIfNeeded(project: Project, publication: MavenPublication, javadocJarTask: Task) { + if (javadocJarTask is JavadocJar) { + publication.artifact(javadocJarTask) + project.logger.info( + "add javadoc jar artifact to publication ${publication.name} from task ${javadocJarTask.name}", + ) + } + } + override fun apply(project: Project) { project.plugins.apply(MavenPublishPlugin::class.java) project.plugins.apply(SigningPlugin::class.java) @@ -48,13 +94,8 @@ class PublishOnCentral : Plugin { publications.create(name, MavenPublication::class.java) { publication -> createdPublications += publication publication.from(component) - // Add artifacts selectively, only if this plugin created the publication - if (sourcesJarTask is SourceJar) { - publication.artifact(sourcesJarTask) - } - if (javadocJarTask is JavadocJar) { - publication.artifact(javadocJarTask) - } + addSourcesArtifactIfNeeded(project, publication, sourcesJarTask) + addJavadocArtifactIfNeeded(project, publication, javadocJarTask) publication.configurePomForMavenCentral(extension) publication.pom.packaging = "jar" project.configure { diff --git a/src/test/resources/org/danilopianini/gradle/test/ktjs/build.gradle.kts b/src/test/resources/org/danilopianini/gradle/test/ktjs/build.gradle.kts index 2c804737..30ee1f38 100644 --- a/src/test/resources/org/danilopianini/gradle/test/ktjs/build.gradle.kts +++ b/src/test/resources/org/danilopianini/gradle/test/ktjs/build.gradle.kts @@ -1,6 +1,7 @@ @file:Suppress("UnstableApiUsage") import org.danilopianini.gradle.mavencentral.DocStyle +import org.gradle.kotlin.dsl.repositories @Suppress("DSL_SCOPE_VIOLATION") plugins { @@ -11,6 +12,10 @@ plugins { group = "org.danilopianini" version = "1.0.0" +repositories { + mavenCentral() +} + kotlin { js { browser() diff --git a/src/test/resources/org/danilopianini/gradle/test/ktjs/test.yaml b/src/test/resources/org/danilopianini/gradle/test/ktjs/test.yaml index 82c5583c..4e07ce1b 100644 --- a/src/test/resources/org/danilopianini/gradle/test/ktjs/test.yaml +++ b/src/test/resources/org/danilopianini/gradle/test/ktjs/test.yaml @@ -7,9 +7,9 @@ tests: - '--stacktrace' expectation: success: *tasks1 - file_exists: + file_exists: &exists - name: /build/libs/ktjs-1.0.0-sources.jar - - description: "Task :jsSourcesJar should generate sources Jar with -js specifier for Kotlin Js projects" + - description: "Task :jsSourcesJar should generate sources Jar with for Kotlin Js projects" configuration: tasks: &tasks2 - 'jsSourcesJar' @@ -17,5 +17,26 @@ tests: - '--stacktrace' expectation: success: *tasks2 - file_exists: - - name: /build/libs/ktjs-js-1.0.0-sources.jar \ No newline at end of file + file_exists: *exists + - description: "Task :kotlinSourcesJar should generate sources Jar with for Kotlin Js projects" + configuration: + tasks: &tasks3 + - 'kotlinSourcesJar' + options: + - '--stacktrace' + expectation: + success: *tasks3 + file_exists: *exists + - description: "Publishing should only use :jsSourcesJar to create sources Jars" + configuration: + tasks: + - 'publishToMavenLocal' + options: + - '--dry-run' + - '--stacktrace' + expectation: + output_contains: + - ":kotlinSourcesJar SKIPPED" + output_doesnt_contain: + - ":sourcesJar" + - ":jsSourcesJar" \ No newline at end of file