diff --git a/uploadSonatypePublication.main.kts b/uploadSonatypePublication.main.kts index f6517cfa3ab..6dfc047128d 100755 --- a/uploadSonatypePublication.main.kts +++ b/uploadSonatypePublication.main.kts @@ -1,58 +1,120 @@ #!/usr/bin/env kotlin +@file:Repository("https://repo.maven.apache.org/maven2/") +@file:DependsOn("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1") + +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive import java.net.http.HttpRequest.BodyPublisher -import java.nio.charset.StandardCharsets import java.net.http.HttpClient import java.net.http.HttpRequest import java.net.http.HttpResponse import java.net.URI -import kotlin.io.encoding.Base64 -@OptIn(kotlin.io.encoding.ExperimentalEncodingApi::class) -fun uploadSonatypePublication (repos_state: String, publishing_type: String) { - val bearer = let { - val username = System.getenv("SONATYPE_USER") - val password = System.getenv("SONATYPE_PASSWORD") - Base64.encodeToByteArray("$username:$password".encodeToByteArray()) - } - val baseUrl = "https://ossrh-staging-api.central.sonatype.com/manual" - val client = HttpClient.newHttpClient() - val makeRequest: (String, BodyPublisher, String) -> HttpResponse = { method, bodyPublisher, suffix -> +class CentralSonatypeOSSRHApi( + private val bearer: String, +) { + data class SonatypeOSSRHRepository( + val key: String, + val portalDeploymentId: String?, + val state: String, + ) + + private val baseUrl = "https://ossrh-staging-api.central.sonatype.com/manual" + private val client = HttpClient.newHttpClient() + private fun makeRequest( + method: String, + suffix: String, + bodyPublisher: BodyPublisher = HttpRequest.BodyPublishers.ofString("") + ): JsonObject? { val request = HttpRequest.newBuilder() .uri(URI.create("$baseUrl/$suffix")) .method(method, bodyPublisher) .header("Content-Type", "application/json") .header("Authorization", "Bearer $bearer") .build() - client.send(request, HttpResponse.BodyHandlers.ofString()) + val response = client.send(request, HttpResponse.BodyHandlers.ofString()) + println(response) + val responseBody = response.body() + println(responseBody) + return when { + response.statusCode() == 200 && responseBody.isNotEmpty() -> { + return Json.decodeFromString(JsonObject.serializer(), responseBody) + } + response.statusCode() == 200 -> { + return JsonObject(emptyMap()) + } + else -> null + } } - val response = makeRequest( + fun repositories( + profileId: String? = null, + state: String? = null, + ip: String? = null, + ): List? { + val repositories = makeRequest( "GET", - HttpRequest.BodyPublishers.ofString(""), - "/search/repositories?state=$repos_state" - ) - val keys = mutableListOf() - Regex("\"key\"[\\s]*:[\\s]*\"[^\"]+\"").findAll( - response.body() - ).forEach { - val key = Regex("[^\"]+").find(Regex("[^\"]+\"\$").find(it.value) ?.value ?: return@forEach) ?.value ?: return@forEach - keys.add(key) - } - keys.forEach { - println("Start uploading $it") - val uploadResponse = makeRequest( - "POST", - HttpRequest.BodyPublishers.ofString(""), - "upload/repository/$it?publishing_type=$publishing_type" - ) - if (uploadResponse.statusCode() != 200) { - println("Faced error of uploading for repo with key $it. Response: $uploadResponse") + "search/repositories?${state ?.let { "state=$it" } ?: ""}${profileId ?.let { "&profile_id=$it" } ?: ""}${ip ?.let { "&ip=$it" } ?: ""}" + ) ?.get("repositories") as? JsonArray + + return repositories ?.mapNotNull { + val asObject = it as? JsonObject ?:return@mapNotNull null + SonatypeOSSRHRepository( + (asObject["key"] as JsonPrimitive).content, + (asObject["portal_deployment_id"] as? JsonPrimitive) ?.content, + (asObject["state"] as JsonPrimitive).content, + ) } } + + fun drop(repositoryKey: String, ): Boolean { + val dropped = makeRequest( + "DELETE", + "drop/repository/$repositoryKey" + ) + + return dropped != null + } + + fun uploadDefault(requestedNamespace: String, publishingType: String? = null): Boolean { + val uploaded = makeRequest( + "POST", + "upload/defaultRepository/$requestedNamespace?${publishingType ?.let { "publishing_type=$publishingType" } ?: ""}" + ) + + return uploaded != null + } + + fun upload(repositoryKey: String, publishingType: String? = null): Boolean { + val uploaded = makeRequest( + "POST", + "upload/repository/$repositoryKey?${publishingType ?.let { "publishing_type=$publishingType" } ?: ""}" + ) + + return uploaded != null + } } val repos_state = runCatching { System.getenv("repos_state").takeIf { it.isNotEmpty() } }.getOrNull() ?: "open" val publishing_type = runCatching { System.getenv("publishing_type").takeIf { it.isNotEmpty() } }.getOrNull() ?: "user_managed" +val api = CentralSonatypeOSSRHApi( + let { + val username = System.getenv("SONATYPE_USER") + val password = System.getenv("SONATYPE_PASSWORD") + java.util.Base64.getEncoder().encodeToString("$username:$password".encodeToByteArray()) + } +) -uploadSonatypePublication(repos_state, publishing_type) +api.repositories() ?.forEach { + if (it.state == "open") { + api.upload(it.key, "user_managed") + } +} +api.repositories() ?.forEach { + if (it.state == "closed") { + api.upload(it.key, "automatic") + } +}