From 3de98ff7c9847db0a378e3166290228d6698eeb8 Mon Sep 17 00:00:00 2001 From: Sergey Shanshin Date: Mon, 24 Jun 2024 16:38:56 +0300 Subject: [PATCH] Fixed HOCON publication (#2723) Fixes #2717 --- build.gradle.kts | 17 +- .../publishing-check-conventions.gradle.kts | 65 +++++++ .../kotlin/publishing-conventions.gradle.kts | 73 ++++++-- gradle/artifacts.txt | 177 ++++++++++++++++++ integration-test/build.gradle.kts | 1 + 5 files changed, 310 insertions(+), 23 deletions(-) create mode 100644 buildSrc/src/main/kotlin/publishing-check-conventions.gradle.kts create mode 100644 gradle/artifacts.txt diff --git a/build.gradle.kts b/build.gradle.kts index b19a6f1f60..6c56120499 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,6 +11,7 @@ plugins { id("org.jetbrains.kotlinx.binary-compatibility-validator") id("org.jetbrains.dokka") id("benchmark-conventions") + id("publishing-check-conventions") alias(libs.plugins.serialization) apply false } @@ -111,23 +112,33 @@ subprojects { apply(plugin = "publishing-conventions") } +// == publishing setup == + +val mergeProject = project + +subprojects { + if (name in unpublishedProjects) return@subprojects + apply(plugin = "publishing-conventions") + mergeProject.dependencies.add(Publishing_check_conventions_gradle.TestPublishing.configurationName, this) +} + // == animalsniffer setup == subprojects { // Can't be applied to BOM - if (excludedFromBomProjects.contains(project.name)) return@subprojects + if (project.name in excludedFromBomProjects) return@subprojects apply(plugin = "animalsniffer-conventions") } // == BOM setup == subprojects { // Can't be applied to BOM - if (excludedFromBomProjects.contains(project.name)) return@subprojects + if (project.name in excludedFromBomProjects) return@subprojects apply(plugin = "bom-conventions") } // == Kover setup == subprojects { - if (uncoveredProjects.contains(project.name)) return@subprojects + if (project.name in uncoveredProjects) return@subprojects apply(plugin = "kover-conventions") } diff --git a/buildSrc/src/main/kotlin/publishing-check-conventions.gradle.kts b/buildSrc/src/main/kotlin/publishing-check-conventions.gradle.kts new file mode 100644 index 0000000000..04021a4bb5 --- /dev/null +++ b/buildSrc/src/main/kotlin/publishing-check-conventions.gradle.kts @@ -0,0 +1,65 @@ +object TestPublishing { + const val configurationName = "testRepository" +} + +val testRepositoryDependency = configurations.create(TestPublishing.configurationName) { + isVisible = true + isCanBeResolved = false + isCanBeConsumed = false +} + + +val testRepositories = configurations.create("testRepositories") { + isVisible = false + isCanBeResolved = true + // this config consumes modules from OTHER projects, and cannot be consumed by other projects + isCanBeConsumed = false + + attributes { + attribute(Attribute.of("kotlinx.serialization.repository", String::class.java), "test") + } + extendsFrom(testRepositoryDependency) +} + +tasks.register("checkArtifacts") { + repositories.from(testRepositories) +} + +abstract class ArtifactsCheckTask: DefaultTask() { + + @get:InputFiles + @get:PathSensitive(PathSensitivity.RELATIVE) + abstract val repositories: ConfigurableFileCollection + + @TaskAction + fun check() { + val artifactsFile = project.rootDir.resolve("gradle/artifacts.txt") + + val actualArtifacts = repositories.files.flatMap { file -> + file.resolve("org/jetbrains/kotlinx").list()?.toSet() ?: emptySet() + }.toSortedSet() + + if (project.hasProperty("dumpArtifacts")) { + artifactsFile.bufferedWriter().use { writer -> + actualArtifacts.forEach { artifact -> writer.appendLine(artifact) } + } + return + } + + val expectedArtifacts = artifactsFile.readLines().toSet() + + if (expectedArtifacts == actualArtifacts) { + logger.lifecycle("All artifacts are published") + } else { + val missedArtifacts = expectedArtifacts - actualArtifacts + val unknownArtifacts = actualArtifacts - expectedArtifacts + val message = "The published artifacts differ from the expected ones." + + (if (missedArtifacts.isNotEmpty()) missedArtifacts.joinToString(prefix = "\n\tMissing artifacts: ") else "") + + (if (unknownArtifacts.isNotEmpty()) unknownArtifacts.joinToString(prefix = "\n\tUnknown artifacts: ") else "") + + "\nTo save current list of artifacts as expecting, call 'checkArtifacts -PdumpArtifacts'" + + logger.error(message) + throw GradleException("The published artifacts differ from the expected ones") + } + } +} diff --git a/buildSrc/src/main/kotlin/publishing-conventions.gradle.kts b/buildSrc/src/main/kotlin/publishing-conventions.gradle.kts index 6cfe041171..7f2a72a627 100644 --- a/buildSrc/src/main/kotlin/publishing-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/publishing-conventions.gradle.kts @@ -51,7 +51,7 @@ afterEvaluate { publishing { if (!isMultiplatform && !isBom) { - publications.withType().all { + publications.register("maven") { artifactId = project.name from(components["java"]) artifact(mainSourcesJar) @@ -59,7 +59,7 @@ afterEvaluate { } } else { // Rename artifacts for backward compatibility - publications.withType(MavenPublication::class).all { + publications.withType().configureEach { val type = name logger.info("Configuring $type") when (type) { @@ -81,16 +81,49 @@ afterEvaluate { } } - publications.withType(MavenPublication::class).all { - pom.configureMavenCentralMetadata(project) - signPublicationIfKeyPresent(project, this) + publications.withType().configureEach { + pom.configureMavenCentralMetadata() + signPublicationIfKeyPresent() } } } +val testRepositoryDir = project.layout.buildDirectory.dir("testRepository") + publishing { repositories { - configureMavenPublication(this, project) + addSonatypeRepository() + + /** + * Maven repository in build directory to check published artifacts. + */ + maven { + setUrl(testRepositoryDir) + name = "test" + } + } +} + +interface LocalArtifactAttr : Named { + companion object { + val ATTRIBUTE = Attribute.of( + "kotlinx.kover.gradle-plugin", + LocalArtifactAttr::class.java + ) + } +} + +val testPublicationTask: TaskCollection<*> = tasks.named { name -> name == "publishAllPublicationsToTestRepository" } +configurations.register("testPublication") { + isVisible = false + isCanBeResolved = false + // this configuration produces modules that can be consumed by other projects + isCanBeConsumed = true + attributes { + attribute(Attribute.of("kotlinx.serialization.repository", String::class.java), "test") + } + outgoing.artifact(testRepositoryDir) { + builtBy(testPublicationTask) } } @@ -119,7 +152,7 @@ tasks.register("bintrayUpload") { dependsOn(tasks.publishToMavenLocal) } -fun MavenPom.configureMavenCentralMetadata(project: Project) { +fun MavenPom.configureMavenCentralMetadata() { name = project.name description = "Kotlin multiplatform serialization runtime library" url = "https://github.com/Kotlin/kotlinx.serialization" @@ -158,7 +191,7 @@ fun MavenPom.configureMavenCentralMetadata(project: Project) { */ public fun Project.reconfigureMultiplatformPublication(jvmPublication: MavenPublication) { val mavenPublications = - extensions.getByType(PublishingExtension::class.java).publications.withType() + extensions.getByType().publications.withType() val kmpPublication = mavenPublications.getByName("kotlinMultiplatform") var jvmPublicationXml: XmlProvider? = null @@ -194,24 +227,24 @@ public fun Project.reconfigureMultiplatformPublication(jvmPublication: MavenPubl } } -fun signPublicationIfKeyPresent(project: Project, publication: MavenPublication) { - val keyId = project.getSensitiveProperty("libs.sign.key.id") - val signingKey = project.getSensitiveProperty("libs.sign.key.private") - val signingKeyPassphrase = project.getSensitiveProperty("libs.sign.passphrase") +fun MavenPublication.signPublicationIfKeyPresent() { + val keyId = getSensitiveProperty("libs.sign.key.id") + val signingKey = getSensitiveProperty("libs.sign.key.private") + val signingKeyPassphrase = getSensitiveProperty("libs.sign.passphrase") if (!signingKey.isNullOrBlank()) { - project.extensions.configure("signing") { + extensions.configure("signing") { useInMemoryPgpKeys(keyId, signingKey, signingKeyPassphrase) - sign(publication) + sign(this@signPublicationIfKeyPresent) } } } -fun configureMavenPublication(rh: RepositoryHandler, project: Project) { - rh.maven { +fun RepositoryHandler.addSonatypeRepository() { + maven { url = mavenRepositoryUri() credentials { - username = project.getSensitiveProperty("libs.sonatype.user") - password = project.getSensitiveProperty("libs.sonatype.password") + username = getSensitiveProperty("libs.sonatype.user") + password = getSensitiveProperty("libs.sonatype.password") } } } @@ -226,6 +259,6 @@ fun mavenRepositoryUri(): URI { } } -fun Project.getSensitiveProperty(name: String): String? { - return project.findProperty(name) as? String ?: System.getenv(name) +fun getSensitiveProperty(name: String): String? { + return findProperty(name) as? String ?: System.getenv(name) } diff --git a/gradle/artifacts.txt b/gradle/artifacts.txt new file mode 100644 index 0000000000..409938254f --- /dev/null +++ b/gradle/artifacts.txt @@ -0,0 +1,177 @@ +kotlinx-serialization-bom +kotlinx-serialization-cbor +kotlinx-serialization-cbor-androidnativearm32 +kotlinx-serialization-cbor-androidnativearm64 +kotlinx-serialization-cbor-androidnativex64 +kotlinx-serialization-cbor-androidnativex86 +kotlinx-serialization-cbor-iosarm64 +kotlinx-serialization-cbor-iossimulatorarm64 +kotlinx-serialization-cbor-iosx64 +kotlinx-serialization-cbor-js +kotlinx-serialization-cbor-jvm +kotlinx-serialization-cbor-linuxarm32hfp +kotlinx-serialization-cbor-linuxarm64 +kotlinx-serialization-cbor-linuxx64 +kotlinx-serialization-cbor-macosarm64 +kotlinx-serialization-cbor-macosx64 +kotlinx-serialization-cbor-mingwx64 +kotlinx-serialization-cbor-tvosarm64 +kotlinx-serialization-cbor-tvossimulatorarm64 +kotlinx-serialization-cbor-tvosx64 +kotlinx-serialization-cbor-wasm-js +kotlinx-serialization-cbor-wasm-wasi +kotlinx-serialization-cbor-watchosarm32 +kotlinx-serialization-cbor-watchosarm64 +kotlinx-serialization-cbor-watchosdevicearm64 +kotlinx-serialization-cbor-watchossimulatorarm64 +kotlinx-serialization-cbor-watchosx64 +kotlinx-serialization-core +kotlinx-serialization-core-androidnativearm32 +kotlinx-serialization-core-androidnativearm64 +kotlinx-serialization-core-androidnativex64 +kotlinx-serialization-core-androidnativex86 +kotlinx-serialization-core-iosarm64 +kotlinx-serialization-core-iossimulatorarm64 +kotlinx-serialization-core-iosx64 +kotlinx-serialization-core-js +kotlinx-serialization-core-jvm +kotlinx-serialization-core-linuxarm32hfp +kotlinx-serialization-core-linuxarm64 +kotlinx-serialization-core-linuxx64 +kotlinx-serialization-core-macosarm64 +kotlinx-serialization-core-macosx64 +kotlinx-serialization-core-mingwx64 +kotlinx-serialization-core-tvosarm64 +kotlinx-serialization-core-tvossimulatorarm64 +kotlinx-serialization-core-tvosx64 +kotlinx-serialization-core-wasm-js +kotlinx-serialization-core-wasm-wasi +kotlinx-serialization-core-watchosarm32 +kotlinx-serialization-core-watchosarm64 +kotlinx-serialization-core-watchosdevicearm64 +kotlinx-serialization-core-watchossimulatorarm64 +kotlinx-serialization-core-watchosx64 +kotlinx-serialization-hocon +kotlinx-serialization-json +kotlinx-serialization-json-androidnativearm32 +kotlinx-serialization-json-androidnativearm64 +kotlinx-serialization-json-androidnativex64 +kotlinx-serialization-json-androidnativex86 +kotlinx-serialization-json-io +kotlinx-serialization-json-io-androidnativearm32 +kotlinx-serialization-json-io-androidnativearm64 +kotlinx-serialization-json-io-androidnativex64 +kotlinx-serialization-json-io-androidnativex86 +kotlinx-serialization-json-io-iosarm64 +kotlinx-serialization-json-io-iossimulatorarm64 +kotlinx-serialization-json-io-iosx64 +kotlinx-serialization-json-io-js +kotlinx-serialization-json-io-jvm +kotlinx-serialization-json-io-linuxarm32hfp +kotlinx-serialization-json-io-linuxarm64 +kotlinx-serialization-json-io-linuxx64 +kotlinx-serialization-json-io-macosarm64 +kotlinx-serialization-json-io-macosx64 +kotlinx-serialization-json-io-mingwx64 +kotlinx-serialization-json-io-tvosarm64 +kotlinx-serialization-json-io-tvossimulatorarm64 +kotlinx-serialization-json-io-tvosx64 +kotlinx-serialization-json-io-wasm-js +kotlinx-serialization-json-io-wasm-wasi +kotlinx-serialization-json-io-watchosarm32 +kotlinx-serialization-json-io-watchosarm64 +kotlinx-serialization-json-io-watchosdevicearm64 +kotlinx-serialization-json-io-watchossimulatorarm64 +kotlinx-serialization-json-io-watchosx64 +kotlinx-serialization-json-iosarm64 +kotlinx-serialization-json-iossimulatorarm64 +kotlinx-serialization-json-iosx64 +kotlinx-serialization-json-js +kotlinx-serialization-json-jvm +kotlinx-serialization-json-linuxarm32hfp +kotlinx-serialization-json-linuxarm64 +kotlinx-serialization-json-linuxx64 +kotlinx-serialization-json-macosarm64 +kotlinx-serialization-json-macosx64 +kotlinx-serialization-json-mingwx64 +kotlinx-serialization-json-okio +kotlinx-serialization-json-okio-iosarm64 +kotlinx-serialization-json-okio-iossimulatorarm64 +kotlinx-serialization-json-okio-iosx64 +kotlinx-serialization-json-okio-js +kotlinx-serialization-json-okio-jvm +kotlinx-serialization-json-okio-linuxarm64 +kotlinx-serialization-json-okio-linuxx64 +kotlinx-serialization-json-okio-macosarm64 +kotlinx-serialization-json-okio-macosx64 +kotlinx-serialization-json-okio-mingwx64 +kotlinx-serialization-json-okio-tvosarm64 +kotlinx-serialization-json-okio-tvossimulatorarm64 +kotlinx-serialization-json-okio-tvosx64 +kotlinx-serialization-json-okio-wasm-js +kotlinx-serialization-json-okio-watchosarm32 +kotlinx-serialization-json-okio-watchosarm64 +kotlinx-serialization-json-okio-watchossimulatorarm64 +kotlinx-serialization-json-okio-watchosx64 +kotlinx-serialization-json-tvosarm64 +kotlinx-serialization-json-tvossimulatorarm64 +kotlinx-serialization-json-tvosx64 +kotlinx-serialization-json-wasm-js +kotlinx-serialization-json-wasm-wasi +kotlinx-serialization-json-watchosarm32 +kotlinx-serialization-json-watchosarm64 +kotlinx-serialization-json-watchosdevicearm64 +kotlinx-serialization-json-watchossimulatorarm64 +kotlinx-serialization-json-watchosx64 +kotlinx-serialization-properties +kotlinx-serialization-properties-androidnativearm32 +kotlinx-serialization-properties-androidnativearm64 +kotlinx-serialization-properties-androidnativex64 +kotlinx-serialization-properties-androidnativex86 +kotlinx-serialization-properties-iosarm64 +kotlinx-serialization-properties-iossimulatorarm64 +kotlinx-serialization-properties-iosx64 +kotlinx-serialization-properties-js +kotlinx-serialization-properties-jvm +kotlinx-serialization-properties-linuxarm32hfp +kotlinx-serialization-properties-linuxarm64 +kotlinx-serialization-properties-linuxx64 +kotlinx-serialization-properties-macosarm64 +kotlinx-serialization-properties-macosx64 +kotlinx-serialization-properties-mingwx64 +kotlinx-serialization-properties-tvosarm64 +kotlinx-serialization-properties-tvossimulatorarm64 +kotlinx-serialization-properties-tvosx64 +kotlinx-serialization-properties-wasm-js +kotlinx-serialization-properties-wasm-wasi +kotlinx-serialization-properties-watchosarm32 +kotlinx-serialization-properties-watchosarm64 +kotlinx-serialization-properties-watchosdevicearm64 +kotlinx-serialization-properties-watchossimulatorarm64 +kotlinx-serialization-properties-watchosx64 +kotlinx-serialization-protobuf +kotlinx-serialization-protobuf-androidnativearm32 +kotlinx-serialization-protobuf-androidnativearm64 +kotlinx-serialization-protobuf-androidnativex64 +kotlinx-serialization-protobuf-androidnativex86 +kotlinx-serialization-protobuf-iosarm64 +kotlinx-serialization-protobuf-iossimulatorarm64 +kotlinx-serialization-protobuf-iosx64 +kotlinx-serialization-protobuf-js +kotlinx-serialization-protobuf-jvm +kotlinx-serialization-protobuf-linuxarm32hfp +kotlinx-serialization-protobuf-linuxarm64 +kotlinx-serialization-protobuf-linuxx64 +kotlinx-serialization-protobuf-macosarm64 +kotlinx-serialization-protobuf-macosx64 +kotlinx-serialization-protobuf-mingwx64 +kotlinx-serialization-protobuf-tvosarm64 +kotlinx-serialization-protobuf-tvossimulatorarm64 +kotlinx-serialization-protobuf-tvosx64 +kotlinx-serialization-protobuf-wasm-js +kotlinx-serialization-protobuf-wasm-wasi +kotlinx-serialization-protobuf-watchosarm32 +kotlinx-serialization-protobuf-watchosarm64 +kotlinx-serialization-protobuf-watchosdevicearm64 +kotlinx-serialization-protobuf-watchossimulatorarm64 +kotlinx-serialization-protobuf-watchosx64 diff --git a/integration-test/build.gradle.kts b/integration-test/build.gradle.kts index 103676372d..d723c2d680 100644 --- a/integration-test/build.gradle.kts +++ b/integration-test/build.gradle.kts @@ -80,6 +80,7 @@ kotlin { dependencies { implementation(kotlin("stdlib-jdk8")) implementation("com.google.dagger:dagger:2.13") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-hocon:$serialization_version") } } jvmTest {