diff --git a/main-actions/src/main/scala/sbt/internal/sona/Sona.scala b/main-actions/src/main/scala/sbt/internal/sona/Sona.scala index 63d6e6591..65369ce87 100644 --- a/main-actions/src/main/scala/sbt/internal/sona/Sona.scala +++ b/main-actions/src/main/scala/sbt/internal/sona/Sona.scala @@ -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) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index afe752b21..79001b1b3 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -3108,6 +3108,7 @@ object Classpaths { val uuid = UUID.randomUUID().toString().take(8) s"$o:$v:$uuid" }, + sonaRequestTimeout := 2.minutes, ) @nowarn("cat=deprecation") diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index 661199c84..a509d856d 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -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) diff --git a/main/src/main/scala/sbt/internal/librarymanagement/Publishing.scala b/main/src/main/scala/sbt/internal/librarymanagement/Publishing.scala index eca6e2219..99221e98a 100644 --- a/main/src/main/scala/sbt/internal/librarymanagement/Publishing.scala +++ b/main/src/main/scala/sbt/internal/librarymanagement/Publishing.scala @@ -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) } }