From abb22519eb4b5bbeb6577f84855571d1601b0bca Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Fri, 16 May 2025 00:48:43 +0600 Subject: [PATCH] update to support central sonatype --- .../export/CentralSonatypeUploadingPart.kt | 48 +++++++++++++++++++ .../core/export/GpgSignMavenConfig.kt | 6 +-- .../core/export/js_only/MavenTemplater.kt | 4 ++ .../core/export/jvm_only/MavenTemplater.kt | 4 ++ .../core/export/mpp/MavenTemplater.kt | 31 ++++++------ .../core/models/MavenConfig.kt | 8 ++-- .../core/ui/MavenInfoView.kt | 46 ++++++++++++++---- 7 files changed, 114 insertions(+), 33 deletions(-) create mode 100644 core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/CentralSonatypeUploadingPart.kt diff --git a/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/CentralSonatypeUploadingPart.kt b/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/CentralSonatypeUploadingPart.kt new file mode 100644 index 0000000..b40e2f4 --- /dev/null +++ b/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/CentralSonatypeUploadingPart.kt @@ -0,0 +1,48 @@ +package dev.inmo.kmppscriptbuilder.core.export + +import dev.inmo.kmppscriptbuilder.core.models.MavenConfig + +const val generateCentralSonatypeUploadingPartImports = """import java.nio.charset.StandardCharsets +import java.net.http.HttpClient +import java.net.http.HttpRequest +import java.net.http.HttpResponse""" +const val generateCentralSonatypeUploadingPart = """if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) { + def taskName = "uploadSonatypePublication" + if (rootProject.tasks.names.contains(taskName) == false) { + rootProject.tasks.register(taskName) { + doLast { + def username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER') + def password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD') + def bearer = Base64.getEncoder().encodeToString("${"$"}username:${"$"}password".getBytes(StandardCharsets.UTF_8)) + + def client = HttpClient.newHttpClient() + def request = HttpRequest.newBuilder() + .uri(URI.create("https://ossrh-staging-api.central.sonatype.com/manual/search/repositories?state=open")) + .GET() + .header("Content-Type", "application/json") + .header("Authorization", "Bearer ${"$"}bearer") + .build() + + def response = client.send(request, HttpResponse.BodyHandlers.ofString()) + def keys = new ArrayList() + response.body().findAll("\"key\"[\\s]*:[\\s]*\"[^\"]+\"").forEach { + def key = it.find("[^\"]+\"\$").find("[^\"]+") + keys.add(key) + } + keys.forEach { + println("Start uploading ${"$"}it") + def uploadRequest = HttpRequest.newBuilder() + .uri(URI.create("https://ossrh-staging-api.central.sonatype.com/manual/upload/repository/${"$"}it?publishing_type=user_managed")) + .POST(HttpRequest.BodyPublishers.ofString("")) + .header("Content-Type", "application/json") + .header("Authorization", "Bearer ${"$"}bearer") + .build() + def uploadResponse = client.send(uploadRequest, HttpResponse.BodyHandlers.ofString()) + if (uploadResponse.statusCode() != 200) { + throw IllegalStateException("Faced error of uploading for repo with key ${"$"}it. Response: ${"$"}uploadResponse") + } + } + } + } + } +}""" diff --git a/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/GpgSignMavenConfig.kt b/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/GpgSignMavenConfig.kt index 7622dbf..afc6c15 100644 --- a/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/GpgSignMavenConfig.kt +++ b/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/GpgSignMavenConfig.kt @@ -8,13 +8,13 @@ fun GpgSigning.generateMavenConfig() = when (this) { """ if (project.hasProperty("signing.gnupg.keyName")) { apply plugin: 'signing' - + signing { useGpgCmd() - + sign publishing.publications } - + task signAll { tasks.withType(Sign).forEach { dependsOn(it) diff --git a/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/js_only/MavenTemplater.kt b/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/js_only/MavenTemplater.kt index 800cc1a..6ad8f67 100644 --- a/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/js_only/MavenTemplater.kt +++ b/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/js_only/MavenTemplater.kt @@ -1,10 +1,14 @@ package dev.inmo.kmppscriptbuilder.core.export.js_only +import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPart +import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPartImports import dev.inmo.kmppscriptbuilder.core.export.generateMavenConfig import dev.inmo.kmppscriptbuilder.core.models.* fun MavenConfig.buildJsOnlyMavenConfig(licenses: List): String = """ +${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPartImports\n" else ""} apply plugin: 'maven-publish' +${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPart\n" else ""} task javadocJar(type: Jar) { archiveClassifier = 'javadoc' diff --git a/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/jvm_only/MavenTemplater.kt b/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/jvm_only/MavenTemplater.kt index b5c313e..6d3402c 100644 --- a/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/jvm_only/MavenTemplater.kt +++ b/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/jvm_only/MavenTemplater.kt @@ -1,10 +1,14 @@ package dev.inmo.kmppscriptbuilder.core.export.jvm_only +import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPart +import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPartImports import dev.inmo.kmppscriptbuilder.core.export.generateMavenConfig import dev.inmo.kmppscriptbuilder.core.models.* fun MavenConfig.buildJvmOnlyMavenConfig(licenses: List): String = """ +${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPartImports\n" else ""} apply plugin: 'maven-publish' +${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPart\n" else ""} task javadocJar(type: Jar) { from javadoc diff --git a/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/mpp/MavenTemplater.kt b/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/mpp/MavenTemplater.kt index 1f460e5..05aead3 100644 --- a/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/mpp/MavenTemplater.kt +++ b/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/export/mpp/MavenTemplater.kt @@ -1,11 +1,14 @@ package dev.inmo.kmppscriptbuilder.core.export.mpp +import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPart +import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPartImports import dev.inmo.kmppscriptbuilder.core.export.generateMavenConfig import dev.inmo.kmppscriptbuilder.core.models.* fun MavenConfig.buildMultiplatformMavenConfig(licenses: List): String = """ +${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPartImports\n" else ""} apply plugin: 'maven-publish' - +${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPart\n" else ""} task javadocsJar(type: Jar) { archiveClassifier = 'javadoc' } @@ -24,23 +27,19 @@ publishing { url = "$vcsUrl" } - developers { - ${developers.joinToString("\n") { """ - developer { - id = "${it.id}" - name = "${it.name}" - email = "${it.eMail}" - } - """ }} + developers {${developers.joinToString("\n") { """ + developer { + id = "${it.id}" + name = "${it.name}" + email = "${it.eMail}" + }""" }} } - licenses { - ${licenses.joinToString("\n") { """ - license { - name = "${it.title}" - url = "${it.url}" - } - """ }} + licenses {${licenses.joinToString("\n") { """ + license { + name = "${it.title}" + url = "${it.url}" + }""" }} } } repositories { diff --git a/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/models/MavenConfig.kt b/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/models/MavenConfig.kt index 4bbfa00..c9ac6e0 100644 --- a/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/models/MavenConfig.kt +++ b/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/models/MavenConfig.kt @@ -26,6 +26,7 @@ data class MavenConfig( val gpgSigning: GpgSigning = GpgSigning.Disabled, @Deprecated("Replaced with gpgSigning") val includeGpgSigning: Boolean = false, + val includeCentralSonatypeUploadingScript: Boolean = false, ) @Serializable @@ -61,8 +62,7 @@ return """ credentials { username = project.hasProperty('${usernameProperty}') ? project.property('${usernameProperty}') : System.getenv('${usernameProperty}') password = project.hasProperty('${passwordProperty}') ? project.property('${passwordProperty}') : System.getenv('${passwordProperty}') - } -""" + }""" } companion object { @@ -89,8 +89,7 @@ return """ authentication { header(HttpHeaderAuthentication) - } -""" + }""" } companion object { @@ -119,3 +118,4 @@ ${credsType.buildCredsPart()} } val SonatypeRepository = MavenPublishingRepository("sonatype", "https://oss.sonatype.org/service/local/staging/deploy/maven2/") +val CentralSonatypeRepository = MavenPublishingRepository("sonatype", "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/") diff --git a/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/ui/MavenInfoView.kt b/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/ui/MavenInfoView.kt index e15679b..7b2167c 100644 --- a/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/ui/MavenInfoView.kt +++ b/core/src/commonMain/kotlin/dev/inmo/kmppscriptbuilder/core/ui/MavenInfoView.kt @@ -1,6 +1,7 @@ package dev.inmo.kmppscriptbuilder.core.ui import androidx.compose.runtime.* +import dev.inmo.kmppscriptbuilder.core.models.CentralSonatypeRepository import dev.inmo.kmppscriptbuilder.core.models.GpgSigning import dev.inmo.kmppscriptbuilder.core.models.MavenConfig import dev.inmo.kmppscriptbuilder.core.models.SonatypeRepository @@ -23,22 +24,31 @@ class MavenInfoView : VerticalView("Project information") { internal var projectVcsUrlProperty by mutableStateOf("") internal var gpgSignProperty by mutableStateOf(GpgSigning.Disabled) internal var publishToMavenCentralProperty by mutableStateOf(false) + internal var publishToCentralSonatypeProperty by mutableStateOf(false) + internal var includeCentralSonatypeUploadingScriptProperty by mutableStateOf(false) internal val developersView = DevelopersView() internal val repositoriesView = RepositoriesView() var mavenConfig: MavenConfig get() = MavenConfig( - projectNameProperty.ifBlank { defaultProjectName }, - projectDescriptionProperty.ifBlank { defaultProjectDescription }, - projectUrlProperty, - projectVcsUrlProperty, - developersView.developers, - repositoriesView.repositories + if (publishToMavenCentralProperty) { - listOf(SonatypeRepository) + name = projectNameProperty.ifBlank { defaultProjectName }, + description = projectDescriptionProperty.ifBlank { defaultProjectDescription }, + url = projectUrlProperty, + vcsUrl = projectVcsUrlProperty, + developers = developersView.developers, + repositories = repositoriesView.repositories + if (publishToMavenCentralProperty) { + listOf( + if (publishToCentralSonatypeProperty) { + CentralSonatypeRepository + } else { + SonatypeRepository + } + ) } else { emptyList() }, - gpgSignProperty + gpgSigning = gpgSignProperty, + includeCentralSonatypeUploadingScript = includeCentralSonatypeUploadingScriptProperty ) set(value) { projectNameProperty = value.name @@ -50,9 +60,11 @@ class MavenInfoView : VerticalView("Project information") { } else { value.gpgSigning } - publishToMavenCentralProperty = value.repositories.any { it == SonatypeRepository } + publishToMavenCentralProperty = value.repositories.any { it == SonatypeRepository || it == CentralSonatypeRepository } developersView.developers = value.developers - repositoriesView.repositories = value.repositories.filter { it != SonatypeRepository } + repositoriesView.repositories = value.repositories.filter { it != SonatypeRepository && it != CentralSonatypeRepository } + publishToCentralSonatypeProperty = value.repositories.any { it == CentralSonatypeRepository } + includeCentralSonatypeUploadingScriptProperty = value.includeCentralSonatypeUploadingScript } private val gpgSigningDrawer = GpgSigningOptionDrawerWithView(this) @@ -100,6 +112,20 @@ class MavenInfoView : VerticalView("Project information") { publishToMavenCentralProperty, placeSwitchAtTheStart = true ) { publishToMavenCentralProperty = it } + if (publishToMavenCentralProperty) { + SwitchWithLabel( + "Use Central Sonatype instead of OSSRH (OSSRH has been deprecated)", + publishToCentralSonatypeProperty, + placeSwitchAtTheStart = true + ) { publishToCentralSonatypeProperty = it } + if (publishToCentralSonatypeProperty) { + SwitchWithLabel( + "Add 'uploadSonatypePublication' root project task (required for Central Sonatype publishing)", + includeCentralSonatypeUploadingScriptProperty, + placeSwitchAtTheStart = true + ) { includeCentralSonatypeUploadingScriptProperty = it } + } + } developersView.build() repositoriesView.build() }