From 8c91f16db4fcc037e95738be38395e5ad45b5696 Mon Sep 17 00:00:00 2001 From: Fuxiang Luo Date: Tue, 17 Mar 2026 22:09:27 +0800 Subject: [PATCH 1/4] Replace plugin upload with custom HttpClient upload task Use Java HttpClient for Maven Central Portal upload instead of the publish-on-central plugin's releaseMavenCentralPortalPublication task to address request timeout issues. - 15-minute default upload timeout (configurable via property) - 5-minute connect timeout - Plugin still generates the zip bundle --- build.gradle | 2 +- .../groovy/local-s3.central-portal.gradle | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b993e5b..75596fd 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ project.subprojects.each { if (it.plugins.hasPlugin('local-s3.publish')) { rootProject.tasks.release.dependsOn(it.tasks['publishAllPublicationsToProjectLocalRepository']) rootProject.tasks.release.dependsOn(it.tasks['zipMavenCentralPortalPublication']) - rootProject.tasks.release.dependsOn(it.tasks['releaseMavenCentralPortalPublication']) + rootProject.tasks.release.dependsOn(it.tasks['uploadMavenCentralPortal']) } } } \ No newline at end of file diff --git a/buildSrc/src/main/groovy/local-s3.central-portal.gradle b/buildSrc/src/main/groovy/local-s3.central-portal.gradle index f8e72fb..939d948 100644 --- a/buildSrc/src/main/groovy/local-s3.central-portal.gradle +++ b/buildSrc/src/main/groovy/local-s3.central-portal.gradle @@ -31,4 +31,65 @@ publishing { } } } +} + +tasks.register('uploadMavenCentralPortal') { + description = 'Uploads the Maven Central Portal zip bundle with configurable timeout' + group = 'publishing' + dependsOn tasks.named('zipMavenCentralPortalPublication') + + // Configurable timeout in minutes (default: 15 minutes) + def uploadTimeoutMinutes = (project.findProperty("MAVEN_CENTRAL_PORTAL_UPLOAD_TIMEOUT_MINUTES") ?: "15") as int + + doLast { + def zipTask = tasks.named('zipMavenCentralPortalPublication').get() + def zipFile = zipTask.archiveFile.get().asFile + if (!zipFile.exists()) { + throw new GradleException("Zip file not found: ${zipFile.absolutePath}") + } + + def username = project.findProperty("MAVEN_CENTRAL_PORTAL_USERNAME") ?: System.getenv("MAVEN_CENTRAL_PORTAL_USERNAME") + def password = project.findProperty("MAVEN_CENTRAL_PORTAL_PASSWORD") ?: System.getenv("MAVEN_CENTRAL_PORTAL_PASSWORD") + if (!username || !password) { + throw new GradleException("MAVEN_CENTRAL_PORTAL_USERNAME and MAVEN_CENTRAL_PORTAL_PASSWORD must be set") + } + def token = Base64.getEncoder().encodeToString("${username}:${password}".getBytes("UTF-8")) + def publishingType = project.findProperty("MAVEN_CENTRAL_PORTAL_PUBLISHING_TYPE") ?: "USER_MANAGED" + + def boundary = UUID.randomUUID().toString() + def CRLF = "\r\n" + def baos = new ByteArrayOutputStream() + baos.write("--${boundary}${CRLF}".getBytes("UTF-8")) + baos.write("Content-Disposition: form-data; name=\"bundle\"; filename=\"${zipFile.name}\"${CRLF}".getBytes("UTF-8")) + baos.write("Content-Type: application/octet-stream${CRLF}".getBytes("UTF-8")) + baos.write(CRLF.getBytes("UTF-8")) + baos.write(zipFile.bytes) + baos.write("${CRLF}--${boundary}--${CRLF}".getBytes("UTF-8")) + + def encodedName = URLEncoder.encode(zipFile.name, "UTF-8") + def uploadUrl = "https://central.sonatype.com/api/v1/publisher/upload?name=${encodedName}&publishingType=${publishingType}" + + logger.lifecycle("Uploading ${zipFile.name} (${zipFile.length()} bytes) to Maven Central Portal...") + logger.lifecycle("Publishing type: ${publishingType}, timeout: ${uploadTimeoutMinutes} minutes") + + def client = java.net.http.HttpClient.newBuilder() + .connectTimeout(java.time.Duration.ofMinutes(5)) + .build() + + def request = java.net.http.HttpRequest.newBuilder() + .uri(URI.create(uploadUrl)) + .header("Authorization", "Bearer ${token}") + .header("Content-Type", "multipart/form-data; boundary=${boundary}") + .timeout(java.time.Duration.ofMinutes(uploadTimeoutMinutes)) + .POST(java.net.http.HttpRequest.BodyPublishers.ofByteArray(baos.toByteArray())) + .build() + + def response = client.send(request, java.net.http.HttpResponse.BodyHandlers.ofString()) + + if (response.statusCode() == 201) { + logger.lifecycle("Upload successful! Deployment ID: ${response.body()}") + } else { + throw new GradleException("Upload to Maven Central Portal failed with status ${response.statusCode()}: ${response.body()}") + } + } } \ No newline at end of file From 6206ed726e73995800cf9a6ce54fef0718f5d7fc Mon Sep 17 00:00:00 2001 From: Fuxiang Luo Date: Wed, 18 Mar 2026 09:11:06 +0800 Subject: [PATCH 2/4] use new version. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 8683a4e..728dbe9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -version=2.3-SNAPSHOT +version=2.3.1-SNAPSHOT org.gradle.parallel=false From 71d3c722ff9b63ac5fc2b02dfa1340ced99b1376 Mon Sep 17 00:00:00 2001 From: Github Release Plugin Date: Wed, 18 Mar 2026 01:23:19 +0000 Subject: [PATCH 3/4] local-s3 2.3.1 released. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 728dbe9..3311000 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -version=2.3.1-SNAPSHOT +version=2.3.2-SNAPSHOT org.gradle.parallel=false From d6b209e4fce2544788eb3a3edb6840608e24d62b Mon Sep 17 00:00:00 2001 From: Luo Date: Wed, 18 Mar 2026 10:27:32 +0800 Subject: [PATCH 4/4] Update Gradle version to 2.4-SNAPSHOT --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 3311000..d08bd0f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -version=2.3.2-SNAPSHOT +version=2.4-SNAPSHOT org.gradle.parallel=false