Allow users to configure the timeout when publishing to the Maven Central repo

This commit is contained in:
Jules Ivanic 2025-07-02 13:53:50 +04:00
parent f37aea07b2
commit 084ca08f34
No known key found for this signature in database
GPG Key ID: D9698C4AC764198B
4 changed files with 27 additions and 20 deletions

View File

@ -36,13 +36,16 @@ class Sona(client: SonaClient) extends AutoCloseable {
def close(): Unit = client.close()
}
class SonaClient(reqTransform: Request => Request) extends AutoCloseable {
class SonaClient(reqTransform: Request => Request, requestTimeout: FiniteDuration)
extends AutoCloseable {
import SonaClient.baseUrl
val gigahorseConfig = Gigahorse.config
.withRequestTimeout(2.minute)
.withReadTimeout(2.minute)
val http = Gigahorse.http(gigahorseConfig)
private val gigahorseConfig = Gigahorse.config
.withRequestTimeout(requestTimeout)
.withReadTimeout(requestTimeout)
private val http = Gigahorse.http(gigahorseConfig)
def uploadBundle(
bundleZipPath: Path,
deploymentName: String,
@ -66,7 +69,6 @@ class SonaClient(reqTransform: Request => Request) extends AutoCloseable {
FormPart("bundle", bundleZipPath.toFile())
)
)
.withRequestTimeout(600.second)
http.run(reqTransform(req), Gigahorse.asString)
}
awaitWithMessage(res, "uploading...", log)
@ -155,7 +157,7 @@ class SonaClient(reqTransform: Request => Request) extends AutoCloseable {
}.foreach(_ => loop(attempt + 1))
} else ()
loop(0)
Await.result(f, 600.seconds)
Await.result(f, requestTimeout + 5.seconds)
}
def close(): Unit = http.close()
@ -163,8 +165,8 @@ class SonaClient(reqTransform: Request => Request) extends AutoCloseable {
object Sona {
def host: String = SonaClient.host
def oauthClient(userName: String, userToken: String): Sona =
new Sona(SonaClient.oauthClient(userName, userToken))
def oauthClient(userName: String, userToken: String, requestTimeout: FiniteDuration): Sona =
new Sona(SonaClient.oauthClient(userName, userToken, requestTimeout))
}
object SonaClient {
@ -175,8 +177,8 @@ object SonaClient {
Parser.parseFromByteBuffer(r.bodyAsByteBuffer).get
def as[A1: JsonFormat]: FullResponse => A1 = asJson.andThen(Converter.fromJsonUnsafe[A1])
val asPublisherStatus: FullResponse => PublisherStatus = as[PublisherStatus]
def oauthClient(userName: String, userToken: String): SonaClient =
new SonaClient(OAuthClient(userName, userToken))
def oauthClient(userName: String, userToken: String, requestTimeout: FiniteDuration): SonaClient =
new SonaClient(OAuthClient(userName, userToken), requestTimeout)
}
private case class OAuthClient(userName: String, userToken: String)

View File

@ -3108,6 +3108,7 @@ object Classpaths {
val uuid = UUID.randomUUID().toString().take(8)
s"$o:$v:$uuid"
},
sonaRequestTimeout := 2.minutes,
)
@nowarn("cat=deprecation")

View File

@ -571,6 +571,7 @@ object Keys {
val sonaBundle = taskKey[File]("Local bundle for Sonatype publishing").withRank(DTask)
val localStaging = settingKey[Option[Resolver]]("Local staging resolver for Sonatype publishing").withRank(CSetting)
val sonaDeploymentName = settingKey[String]("The name used for deployment").withRank(DSetting)
val sonaRequestTimeout = settingKey[FiniteDuration]("Request timeout for Sonatype publishing").withRank(DSetting)
val classifiersModule = taskKey[GetClassifiersModule]("classifiers-module").withRank(CTask)
val compatibilityWarningOptions = settingKey[CompatibilityWarningOptions]("Configures warnings around Maven incompatibility.").withRank(CSetting)

View File

@ -15,7 +15,9 @@ import sbt.internal.util.MessageOnlyException
import sbt.io.IO
import sbt.io.Path.contentOf
import sbt.librarymanagement.ivy.Credentials
import sona.{ Sona, PublishingType }
import sona.{ PublishingType, Sona }
import scala.concurrent.duration.FiniteDuration
object Publishing {
val sonaRelease: Command =
@ -36,22 +38,23 @@ object Publishing {
bundlePath
}
private def sonatypeReleaseAction(pt: PublishingType)(s0: State): State = {
private def sonatypeReleaseAction(publishingType: PublishingType)(s0: State): State = {
val extracted = Project.extract(s0)
val log = extracted.get(Keys.sLog)
val dn = extracted.get(Keys.sonaDeploymentName)
val v = extracted.get(Keys.version)
if (v.endsWith("-SNAPSHOT")) {
val version = extracted.get(Keys.version)
if (version.endsWith("-SNAPSHOT")) {
log.error("""SNAPSHOTs are not supported on the Central Portal;
configure ThisBuild / publishTo to publish directly to the central-snapshots.
see https://www.scala-sbt.org/1.x/docs/Using-Sonatype.html for details.""")
s0.fail
} else {
val deploymentName = extracted.get(Keys.sonaDeploymentName)
val requestTimeout = extracted.get(Keys.sonaRequestTimeout)
val (s1, bundle) = extracted.runTask(Keys.sonaBundle, s0)
val (s2, creds) = extracted.runTask(Keys.credentials, s1)
val client = fromCreds(creds)
val client = fromCreds(creds, requestTimeout)
try {
client.uploadBundle(bundle.toPath(), dn, pt, log)
client.uploadBundle(bundle.toPath(), deploymentName, publishingType, log)
s2
} finally {
client.close()
@ -59,10 +62,10 @@ see https://www.scala-sbt.org/1.x/docs/Using-Sonatype.html for details.""")
}
}
private def fromCreds(creds: Seq[Credentials]): Sona = {
private def fromCreds(creds: Seq[Credentials], requestTimeout: FiniteDuration): Sona = {
val cred = Credentials
.forHost(creds, Sona.host)
.getOrElse(throw new MessageOnlyException(s"no credentials are found for ${Sona.host}"))
Sona.oauthClient(cred.userName, cred.passwd)
Sona.oauthClient(cred.userName, cred.passwd, requestTimeout)
}
}