Skip to content

Commit 7eafb3d

Browse files
committed
Switch publish command to point Sonatype publishing to Sonatype Central Portal OSSRH Staging API
1 parent 0770a32 commit 7eafb3d

File tree

1 file changed

+100
-70
lines changed

1 file changed

+100
-70
lines changed

modules/cli/src/main/scala/scala/cli/commands/publish/RepoParams.scala

Lines changed: 100 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import java.util.concurrent.ScheduledExecutorService
1212
import scala.build.EitherCps.{either, value}
1313
import scala.build.Logger
1414
import scala.build.errors.BuildException
15+
import scala.build.internals.ConsoleUtils.ScalaCliConsole.warnPrefix
1516
import scala.cli.commands.util.ScalaCliSttpBackend
1617

1718
final case class RepoParams(
@@ -49,7 +50,6 @@ final case class RepoParams(
4950
}
5051

5152
object RepoParams {
52-
5353
def apply(
5454
repo: String,
5555
vcsUrlOpt: Option[String],
@@ -67,24 +67,45 @@ object RepoParams {
6767
case "ivy2-local" =>
6868
RepoParams.ivy2Local(ivy2HomeOpt)
6969
case "sonatype" | "central" | "maven-central" | "mvn-central" =>
70+
val ossrhStagingApiBase = "https://ossrh-staging-api.central.sonatype.com"
71+
logger.message(s"Using Portal OSSRH Staging API: $ossrhStagingApiBase")
72+
RepoParams.centralRepo(
73+
base = ossrhStagingApiBase,
74+
useLegacySnapshots = false,
75+
connectionTimeoutRetries = connectionTimeoutRetries,
76+
connectionTimeoutSeconds = connectionTimeoutSeconds,
77+
stagingRepoRetries = stagingRepoRetries,
78+
stagingRepoWaitTimeMilis = stagingRepoWaitTimeMilis,
79+
es = es,
80+
logger = logger
81+
)
82+
case "sonatype-legacy" | "central-legacy" | "maven-central-legacy" | "mvn-central-legacy" =>
83+
val legacyBase = "https://oss.sonatype.org"
84+
logger.message(s"$warnPrefix $legacyBase is EOL since 2025-06-30.")
85+
logger.message(s"$warnPrefix $legacyBase publishing is expected to fail.")
7086
RepoParams.centralRepo(
71-
"https://oss.sonatype.org",
72-
connectionTimeoutRetries,
73-
connectionTimeoutSeconds,
74-
stagingRepoRetries,
75-
stagingRepoWaitTimeMilis,
76-
es,
77-
logger
87+
base = legacyBase,
88+
useLegacySnapshots = true,
89+
connectionTimeoutRetries = connectionTimeoutRetries,
90+
connectionTimeoutSeconds = connectionTimeoutSeconds,
91+
stagingRepoRetries = stagingRepoRetries,
92+
stagingRepoWaitTimeMilis = stagingRepoWaitTimeMilis,
93+
es = es,
94+
logger = logger
7895
)
7996
case "sonatype-s01" | "central-s01" | "maven-central-s01" | "mvn-central-s01" =>
97+
val s01SonatypeLegacyBase = "https://s01.oss.sonatype.org"
98+
logger.message(s"$warnPrefix $s01SonatypeLegacyBase is EOL since 2025-06-30.")
99+
logger.message(s"$warnPrefix it's expected publishing will fail.")
80100
RepoParams.centralRepo(
81-
"https://s01.oss.sonatype.org",
82-
connectionTimeoutRetries,
83-
connectionTimeoutSeconds,
84-
stagingRepoRetries,
85-
stagingRepoWaitTimeMilis,
86-
es,
87-
logger
101+
base = s01SonatypeLegacyBase,
102+
useLegacySnapshots = true,
103+
connectionTimeoutRetries = connectionTimeoutRetries,
104+
connectionTimeoutSeconds = connectionTimeoutSeconds,
105+
stagingRepoRetries = stagingRepoRetries,
106+
stagingRepoWaitTimeMilis = stagingRepoWaitTimeMilis,
107+
es = es,
108+
logger = logger
88109
)
89110
case "github" =>
90111
value(RepoParams.gitHubRepo(vcsUrlOpt, workspace, logger))
@@ -103,77 +124,86 @@ object RepoParams {
103124
}
104125

105126
RepoParams(
106-
PublishRepository.Simple(repo0),
107-
None,
108-
Hooks.dummy,
109-
isIvy2LocalLike,
110-
true,
111-
true,
112-
true,
113-
false,
114-
false
127+
repo = PublishRepository.Simple(repo0),
128+
targetRepoOpt = None,
129+
hooks = Hooks.dummy,
130+
isIvy2LocalLike = isIvy2LocalLike,
131+
defaultParallelUpload = true,
132+
supportsSig = true,
133+
acceptsChecksums = true,
134+
shouldSign = false,
135+
shouldAuthenticate = false
115136
)
116137
}
117138
}
118139

119140
def centralRepo(
120141
base: String,
142+
useLegacySnapshots: Boolean,
121143
connectionTimeoutRetries: Option[Int],
122144
connectionTimeoutSeconds: Option[Int],
123145
stagingRepoRetries: Option[Int],
124146
stagingRepoWaitTimeMilis: Option[Int],
125147
es: ScheduledExecutorService,
126148
logger: Logger
127-
) = {
128-
val repo0 = PublishRepository.Sonatype(MavenRepository(base))
149+
): RepoParams = {
150+
val repo0 = PublishRepository.Sonatype(
151+
base = MavenRepository(base),
152+
useLegacySnapshots = useLegacySnapshots
153+
)
129154
val backend = ScalaCliSttpBackend.httpURLConnection(logger, connectionTimeoutSeconds)
130155
val api = SonatypeApi(
131-
backend,
132-
base + "/service/local",
133-
None,
134-
logger.verbosity,
156+
backend = backend,
157+
base = base + "/service/local",
158+
authentication = None,
159+
verbosity = logger.verbosity,
135160
retryOnTimeout = connectionTimeoutRetries.getOrElse(3),
136-
stagingRepoRetryParams = EmaRetryParams(
137-
stagingRepoRetries.getOrElse(3),
138-
stagingRepoWaitTimeMilis.getOrElse(10 * 1000),
139-
2.0f
140-
)
161+
stagingRepoRetryParams =
162+
EmaRetryParams(
163+
attempts = stagingRepoRetries.getOrElse(3),
164+
initialWaitDurationMs = stagingRepoWaitTimeMilis.getOrElse(10 * 1000),
165+
factor = 2.0f
166+
)
141167
)
142168
val hooks0 = Hooks.sonatype(
143-
repo0,
144-
api,
145-
logger.compilerOutputStream, // meh
146-
logger.verbosity,
169+
repo = repo0,
170+
api = api,
171+
out = logger.compilerOutputStream, // meh
172+
verbosity = logger.verbosity,
147173
batch = coursier.paths.Util.useAnsiOutput(), // FIXME Get via logger
148-
es
174+
es = es
149175
)
150176
RepoParams(
151-
repo0,
152-
Some("https://repo1.maven.org/maven2"),
153-
hooks0,
154-
false,
155-
true,
156-
true,
157-
true,
158-
true,
159-
true
177+
repo = repo0,
178+
targetRepoOpt = Some("https://repo1.maven.org/maven2"),
179+
hooks = hooks0,
180+
isIvy2LocalLike = false,
181+
defaultParallelUpload = true,
182+
supportsSig = true,
183+
acceptsChecksums = true,
184+
shouldSign = true,
185+
shouldAuthenticate = true
160186
)
161187
}
162188

163-
def gitHubRepoFor(org: String, name: String) =
189+
def gitHubRepoFor(org: String, name: String): RepoParams =
164190
RepoParams(
165-
PublishRepository.Simple(MavenRepository(s"https://maven.pkg.github.com/$org/$name")),
166-
None,
167-
Hooks.dummy,
168-
false,
169-
false,
170-
false,
171-
false,
172-
false,
173-
true
191+
repo = PublishRepository.Simple(MavenRepository(s"https://maven.pkg.github.com/$org/$name")),
192+
targetRepoOpt = None,
193+
hooks = Hooks.dummy,
194+
isIvy2LocalLike = false,
195+
defaultParallelUpload = false,
196+
supportsSig = false,
197+
acceptsChecksums = false,
198+
shouldSign = false,
199+
shouldAuthenticate = true
174200
)
175201

176-
def gitHubRepo(vcsUrlOpt: Option[String], workspace: os.Path, logger: Logger) = either {
202+
def gitHubRepo(
203+
vcsUrlOpt: Option[String],
204+
workspace: os.Path,
205+
logger: Logger
206+
): Either[BuildException, RepoParams] = either {
177207
val orgNameFromVcsOpt = vcsUrlOpt.flatMap(GitRepo.maybeGhOrgName)
178208

179209
val (org, name) = orgNameFromVcsOpt match {
@@ -184,23 +214,23 @@ object RepoParams {
184214
gitHubRepoFor(org, name)
185215
}
186216

187-
def ivy2Local(ivy2HomeOpt: Option[os.Path]) = {
217+
def ivy2Local(ivy2HomeOpt: Option[os.Path]): RepoParams = {
188218
val home = ivy2HomeOpt
189219
.orElse(sys.props.get("ivy.home").map(prop => os.Path(prop)))
190220
.orElse(sys.props.get("user.home").map(prop => os.Path(prop) / ".ivy2"))
191221
.getOrElse(os.home / ".ivy2")
192222
val base = home / "local"
193223
// not really a Maven repo…
194224
RepoParams(
195-
PublishRepository.Simple(MavenRepository(base.toNIO.toUri.toASCIIString)),
196-
None,
197-
Hooks.dummy,
198-
true,
199-
true,
200-
true,
201-
true,
202-
false,
203-
false
225+
repo = PublishRepository.Simple(MavenRepository(base.toNIO.toUri.toASCIIString)),
226+
targetRepoOpt = None,
227+
hooks = Hooks.dummy,
228+
isIvy2LocalLike = true,
229+
defaultParallelUpload = true,
230+
supportsSig = true,
231+
acceptsChecksums = true,
232+
shouldSign = false,
233+
shouldAuthenticate = false
204234
)
205235
}
206236

0 commit comments

Comments
 (0)