Home > Back-end >  Kotlin multiplatform publish with dokka and sources
Kotlin multiplatform publish with dokka and sources

Time:06-27

I am struggling to publish a Kotlin multiplatform project properly to maven (for now mavenLocal). I can add the dependency to another multiplatform project and use the code but I don't get any documentation and I am not sure if I am doing something wrong or if that is simply not possible at the moment.

From what I understand you cannot use the normal javadoc because it is bound to Java which does not make sense in a multiplatform environment. I read somewhere that in that case you should use the html version of dokka. I can see that I get a "javadoc.jar" with content to my mavenLocal but still in the IDE in an example project where I add my KMP library as a dependency, I don't see any documentation. Also, the code decompiling seems to be weird. I guess somehow the sources are also not properly resolved.

According to the documentation everything should automatically and perfectly work by simply adding the maven-publish and the dokka plugin. But it seems like this is not the case and actually nothing is working as I'd expect it :D

Does anyone know, how to properly set that up?

My gradle file looks like this:

plugins {
    kotlin("multiplatform") version "1.6.21"
    id("org.jetbrains.kotlinx.benchmark") version "0.4.2"
    id("org.jetbrains.dokka") version "1.6.21"
    `maven-publish`
    signing
}

group = "io.github.quillraven.fleks"
version = "1.4-KMP-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_1_8

repositories {
    mavenCentral()
}

kotlin {
    targets {
        jvm {
            compilations {
                all {
                    kotlinOptions {
                        jvmTarget = "1.8"
                    }
                }
                val main by getting { }
                // custom benchmark compilation
                val benchmarks by compilations.creating {
                    defaultSourceSet {
                        dependencies {
                            // Compile against the main compilation's compile classpath and outputs:
                            implementation(main.compileDependencyFiles   main.output.classesDirs)
                        }
                    }
                }
            }
            withJava()
            testRuns["test"].executionTask.configure {
                useJUnitPlatform()
            }
        }
    }
    js(BOTH) {
        browser { }
    }
    val hostOs = System.getProperty("os.name")
    val isMingwX64 = hostOs.startsWith("Windows")
    val nativeTarget = when {
        hostOs == "Mac OS X" -> macosX64("native")
        hostOs == "Linux" -> linuxX64("native")
        isMingwX64 -> mingwX64("native")
        else -> throw GradleException("Host OS is not supported in Kotlin/Native.")
    }

    sourceSets {
        val commonMain by getting { }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test"))
            }
        }
        val jvmMain by getting
        val jvmTest by getting
        val jvmBenchmarks by getting {
            dependsOn(commonMain)
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.4.2")
                implementation("com.badlogicgames.ashley:ashley:1.7.4")
                implementation("net.onedaybeard.artemis:artemis-odb:2.3.0")
            }
        }
        val jsMain by getting
        val jsTest by getting
        val nativeMain by getting
        val nativeTest by getting
    }
}

benchmark {
    targets {
        register("jvmBenchmarks")
    }
}

val javadocJar by tasks.registering(Jar::class) {
    archiveClassifier.set("javadoc")
    from(tasks.dokkaHtml)
}

publishing {
    repositories {
        maven {
            url = if (project.version.toString().endsWith("SNAPSHOT")) {
                uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")
            } else {
                uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
            }

            credentials {
                username = System.getenv("OSSRH_USERNAME")
                password = System.getenv("OSSRH_TOKEN")
            }
        }
    }

    publications {
        val kotlinMultiplatform by getting(MavenPublication::class) {
            version = project.version.toString()
            groupId = project.group.toString()
            artifactId = "Fleks"
            artifact(javadocJar)

            pom {
                name.set("Fleks")
                description.set("A lightweight entity component system written in Kotlin.")
                url.set("https://github.com/Quillraven/Fleks")

                scm {
                    connection.set("scm:git:[email protected]:quillraven/fleks.git")
                    developerConnection.set("scm:git:[email protected]:quillraven/fleks.git")
                    url.set("https://github.com/quillraven/fleks/")
                }


                licenses {
                    license {
                        name.set("MIT License")
                        url.set("https://opensource.org/licenses/MIT")
                    }
                }

                developers {
                    developer {
                        id.set("Quillraven")
                        name.set("Simon Klausner")
                        email.set("[email protected]")
                    }
                }
            }
        }

        signing {
            useInMemoryPgpKeys(System.getenv("SIGNING_KEY"), System.getenv("SIGNING_PASSWORD"))
            sign(kotlinMultiplatform)
        }
    }
}

// only sign if version is not a SNAPSHOT release.
// this makes it easier to publish to mavenLocal and test the packed version.
tasks.withType<Sign>().configureEach {
    onlyIf { !project.version.toString().endsWith("SNAPSHOT") }
}

When I run the publishToMavenLocal gradle task then I get following directories in my .m2 folder: enter image description here enter image description here enter image description here enter image description here enter image description here

When I then create an example project and add it as a dependency, then I don't see any quick documentation and also the decompiling is not working properly:

enter image description here enter image description here

CodePudding user response:

I am trying to publish a Kotlin/Multiplatform project to MavenCentral myself. Just curious, are you using a Gradle multi-project setup?

CodePudding user response:

I was finally able to publish to mavenCentral. Not sure if this is the best way and correct way to do it, but it seems to work. Here is my build.gradle.kts. The important part is in the publications sections. For whatever reason it is not sufficient to have the "root" folder setup properly. I also had to adjust the pom, javadoc and signing of every single publication, too.

@file:Suppress("UNUSED_VARIABLE")

plugins {
    kotlin("multiplatform") version "1.6.21"
    id("org.jetbrains.kotlinx.benchmark") version "0.4.2"
    id("org.jetbrains.dokka") version "1.6.21"
    `maven-publish`
    signing
}

group = "io.github.quillraven.fleks"
version = "1.4-KMP-RC1"
java.sourceCompatibility = JavaVersion.VERSION_1_8

repositories {
    mavenCentral()
}

kotlin {
    targets {
        jvm {
            compilations {
                all {
                    kotlinOptions {
                        jvmTarget = "1.8"
                    }
                }
                val main by getting { }
                // custom benchmark compilation
                val benchmarks by compilations.creating {
                    defaultSourceSet {
                        dependencies {
                            // Compile against the main compilation's compile classpath and outputs:
                            implementation(main.compileDependencyFiles   main.output.classesDirs)
                        }
                    }
                }
            }
            withJava()
            testRuns["test"].executionTask.configure {
                useJUnitPlatform()
            }
        }
    }
    js(BOTH) {
        browser { }
    }
    val hostOs = System.getProperty("os.name")
    val isMingwX64 = hostOs.startsWith("Windows")
    val nativeTarget = when {
        hostOs == "Mac OS X" -> macosX64("native")
        hostOs == "Linux" -> linuxX64("native")
        isMingwX64 -> mingwX64("native")
        else -> throw GradleException("Host OS is not supported in Kotlin/Native.")
    }

    sourceSets {
        val commonMain by getting { }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test"))
            }
        }
        val jvmMain by getting
        val jvmTest by getting
        val jvmBenchmarks by getting {
            dependsOn(commonMain)
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.4.2")
                implementation("com.badlogicgames.ashley:ashley:1.7.4")
                implementation("net.onedaybeard.artemis:artemis-odb:2.3.0")
            }
        }
        val jsMain by getting
        val jsTest by getting
        val nativeMain by getting
        val nativeTest by getting
    }
}

benchmark {
    targets {
        register("jvmBenchmarks")
    }
}

val javadocJar by tasks.registering(Jar::class) {
    archiveClassifier.set("javadoc")
    from(tasks.dokkaHtml)
}

publishing {
    repositories {
        maven {
            url = if (project.version.toString().endsWith("SNAPSHOT")) {
                uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")
            } else {
                uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
            }

            credentials {
                username = System.getenv("OSSRH_USERNAME")
                password = System.getenv("OSSRH_TOKEN")
            }
        }
    }

    publications {
        val kotlinMultiplatform by getting(MavenPublication::class) {
            // we need to keep this block up here because
            // otherwise the different target folders like js/jvm/native are not created
            version = project.version.toString()
            groupId = project.group.toString()
            artifactId = "Fleks"
        }
    }

    publications.forEach {
        if (it !is MavenPublication) {
            return@forEach
        }

        // We need to add the javadocJar to every publication
        // because otherwise maven is complaining.
        // It is not sufficient to only have it in the "root" folder.
        it.artifact(javadocJar)

        // pom information needs to be specified per publication
        // because otherwise maven will complain again that
        // information like license, developer or url are missing.
        it.pom {
            name.set("Fleks")
            description.set("A lightweight entity component system written in Kotlin.")
            url.set("https://github.com/Quillraven/Fleks")

            scm {
                connection.set("scm:git:[email protected]:quillraven/fleks.git")
                developerConnection.set("scm:git:[email protected]:quillraven/fleks.git")
                url.set("https://github.com/quillraven/fleks/")
            }

            licenses {
                license {
                    name.set("MIT License")
                    url.set("https://opensource.org/licenses/MIT")
                }
            }

            developers {
                developer {
                    id.set("Quillraven")
                    name.set("Simon Klausner")
                    email.set("[email protected]")
                }
            }
        }

        signing {
            useInMemoryPgpKeys(System.getenv("SIGNING_KEY"), System.getenv("SIGNING_PASSWORD"))
            sign(it)
        }
    }
}

// only sign if version is not a SNAPSHOT release.
// this makes it easier to publish to mavenLocal and test the packed version.
tasks.withType<Sign>().configureEach {
    onlyIf { !project.version.toString().endsWith("SNAPSHOT") }
}
  • Related