Skip to content

Commit 9181926

Browse files
authored
Adjust Scala CLI nightly version resolution for the new Maven Central Snapshots repository (#3818)
* Adjust Scala CLI `nightly` version resolution for the new Maven Central Snapshots repository * NIT: refactor
1 parent 8ca6c96 commit 9181926

File tree

11 files changed

+85
-74
lines changed

11 files changed

+85
-74
lines changed

modules/build/src/main/scala/scala/build/Bloop.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package scala.build
33
import bloop.rifle.{BloopRifleConfig, BuildServer}
44
import ch.epfl.scala.bsp4j
55
import coursier.cache.FileCache
6-
import coursier.maven.MavenRepository
76
import coursier.util.Task
87
import dependency.parser.ModuleParser
98
import dependency.{AnyDependency, DependencyLike, ScalaParameters, ScalaVersion}
@@ -83,7 +82,7 @@ object Bloop {
8382
Seq(
8483
coursier.Repositories.sonatype("snapshots"),
8584
coursier.Repositories.sonatypeS01("snapshots"),
86-
MavenRepository("https://central.sonatype.com/repository/maven-snapshots")
85+
SonatypeUtils.snapshotsRepository
8786
),
8887
Some(params),
8988
logger,

modules/build/src/test/scala/scala/build/tests/BuildOptionsTests.scala

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@ import scala.build.options.{
2626
ScalacOpt,
2727
ShadowingSeq
2828
}
29-
import scala.build.{Build, BuildThreads, LocalRepo}
30-
import scala.build.Directories
31-
import scala.build.Positioned
29+
import scala.build.{Build, BuildThreads, Directories, LocalRepo, Positioned, SonatypeUtils}
3230
import scala.build.tests.util.BloopServer
3331
import scala.concurrent.duration.DurationInt
3432
import scala.build.internal.Regexes.scala3LtsRegex
@@ -449,9 +447,7 @@ class BuildOptionsTests extends TestUtil.ScalaCliBuildSuite {
449447
expect(repositories.contains(Repositories.sonatype("snapshots")))
450448
expect(repositories.contains(Repositories.sonatypeS01("snapshots")))
451449
expect(repositories.contains(Repositories.central))
452-
expect(repositories.contains(
453-
MavenRepository("https://central.sonatype.com/repository/maven-snapshots")
454-
))
450+
expect(repositories.contains(SonatypeUtils.snapshotsRepository))
455451
}
456452
}
457453

modules/cli/src/main/scala/scala/cli/commands/pgp/PgpExternalCommand.scala

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package scala.cli.commands.pgp
22

33
import coursier.Repositories
44
import coursier.cache.{ArchiveCache, FileCache}
5-
import coursier.maven.MavenRepository
65
import coursier.util.Task
76
import dependency.*
87

@@ -19,7 +18,7 @@ import scala.build.internal.{
1918
FetchExternalBinary,
2019
Runner
2120
}
22-
import scala.build.{Logger, Positioned, options as bo}
21+
import scala.build.{Logger, Positioned, SonatypeUtils, options as bo}
2322
import scala.cli.ScalaCli
2423
import scala.cli.commands.shared.{CoursierOptions, SharedJvmOptions}
2524
import scala.cli.commands.util.JvmUtils
@@ -185,13 +184,12 @@ object PgpExternalCommand {
185184

186185
if (signingCliOptions.forceJvm.getOrElse(false)) {
187186
val extraRepos =
188-
if (version.endsWith("SNAPSHOT"))
187+
if version.endsWith("SNAPSHOT") then
189188
Seq(
190189
Repositories.sonatype("snapshots"),
191-
MavenRepository("https://central.sonatype.com/repository/maven-snapshots")
190+
SonatypeUtils.snapshotsRepository
192191
)
193-
else
194-
Nil
192+
else Nil
195193

196194
val (_, signingRes) = value {
197195
scala.build.Artifacts.fetchCsDependencies(

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import java.net.URI
1010
import java.util.concurrent.ScheduledExecutorService
1111

1212
import scala.build.EitherCps.{either, value}
13-
import scala.build.Logger
1413
import scala.build.errors.BuildException
1514
import scala.build.internals.ConsoleUtils.ScalaCliConsole.warnPrefix
15+
import scala.build.{Logger, SonatypeUtils}
1616
import scala.cli.commands.util.ScalaCliSttpBackend
1717

1818
final case class RepoParams(
@@ -53,10 +53,10 @@ final case class RepoParams(
5353

5454
object RepoParams {
5555
private val sonatypeOssrhStagingApiBase = "https://ossrh-staging-api.central.sonatype.com"
56-
private val sonatypeSnapshotsBase = "https://central.sonatype.com/repository/maven-snapshots/"
57-
private val sonatypeLegacyBase = "https://oss.sonatype.org"
58-
private val sonatypeS01LegacyBase = "https://s01.oss.sonatype.org"
59-
private def sonatypeHosts: Seq[String] =
56+
private val sonatypeSnapshotsBase = s"${SonatypeUtils.snapshotsRepositoryUrl}/"
57+
private val sonatypeLegacyBase = "https://oss.sonatype.org"
58+
private val sonatypeS01LegacyBase = "https://s01.oss.sonatype.org"
59+
private def sonatypeHosts: Seq[String] =
6060
Seq(
6161
sonatypeLegacyBase,
6262
sonatypeSnapshotsBase,

modules/cli/src/main/scala/scala/cli/internal/ScalaJsLinker.scala

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package scala.cli.internal
22

33
import coursier.Repositories
44
import coursier.cache.{ArchiveCache, FileCache}
5-
import coursier.maven.MavenRepository
65
import coursier.util.Task
76
import dependency.*
87
import org.scalajs.testing.adapter.TestAdapterInitializer as TAI
@@ -14,7 +13,7 @@ import scala.build.errors.{BuildException, ScalaJsLinkingError}
1413
import scala.build.internal.Util.{DependencyOps, ModuleOps}
1514
import scala.build.internal.{ExternalBinaryParams, FetchExternalBinary, Runner, ScalaJsLinkerConfig}
1615
import scala.build.options.scalajs.ScalaJsLinkerOptions
17-
import scala.build.{Logger, Positioned}
16+
import scala.build.{Logger, Positioned, SonatypeUtils}
1817
import scala.io.Source
1918
import scala.util.Properties
2019

@@ -58,13 +57,13 @@ object ScalaJsLinker {
5857
)
5958

6059
val extraRepos =
61-
if (scalaJsVersion.endsWith("SNAPSHOT") || scalaJsCliVersion.endsWith("SNAPSHOT"))
60+
if scalaJsVersion.endsWith("SNAPSHOT") || scalaJsCliVersion.endsWith("SNAPSHOT")
61+
then
6262
Seq(
6363
Repositories.sonatype("snapshots"),
64-
MavenRepository("https://central.sonatype.com/repository/maven-snapshots")
64+
SonatypeUtils.snapshotsRepository
6565
)
66-
else
67-
Nil
66+
else Nil
6867

6968
options.finalUseJvm match {
7069
case Right(()) =>

modules/cli/src/main/scala/scala/cli/launcher/LauncherCli.scala

Lines changed: 34 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,44 +3,44 @@ package scala.cli.launcher
33
import coursier.Repositories
44
import coursier.cache.FileCache
55
import coursier.core.Version
6-
import coursier.maven.MavenRepository
76
import coursier.util.{Artifact, Task}
87
import dependency.*
98

109
import scala.build.internal.CsLoggerUtil.CsCacheExtensions
1110
import scala.build.internal.{Constants, OsLibc, Runner}
1211
import scala.build.options.ScalaVersionUtil.fileWithTtl0
1312
import scala.build.options.{BuildOptions, JavaOptions}
14-
import scala.build.{Artifacts, Os, Positioned}
13+
import scala.build.{Artifacts, Os, Positioned, SonatypeUtils}
1514
import scala.cli.ScalaCli
1615
import scala.cli.commands.shared.{CoursierOptions, LoggingOptions}
16+
import scala.xml.XML
1717

1818
object LauncherCli {
19-
2019
def runAndExit(version: String, options: LauncherOptions, remainingArgs: Seq[String]): Nothing = {
21-
2220
val logger = LoggingOptions().logger
2321
val cache = CoursierOptions().coursierCache(logger.coursierLogger(""))
2422
val scalaVersion = options.cliScalaVersion.getOrElse(scalaCliScalaVersion(version))
2523
val scalaParameters = ScalaParameters(scalaVersion)
2624
val snapshotsRepo = Seq(
2725
Repositories.central,
2826
Repositories.sonatype("snapshots"),
29-
MavenRepository("https://central.sonatype.com/repository/maven-snapshots")
27+
SonatypeUtils.snapshotsRepository
3028
)
3129

3230
val cliVersion: String =
33-
if (version == "nightly") resolveNightlyScalaCliVersion(cache, scalaParameters) else version
31+
if version == "nightly"
32+
then resolveNightlyScalaCliVersion(cache, scalaParameters.scalaBinaryVersion)
33+
else version
3434
val scalaCliDependency = Seq(dep"org.virtuslab.scala-cli::cli:$cliVersion")
3535

3636
val fetchedScalaCli =
3737
Artifacts.fetchAnyDependencies(
38-
scalaCliDependency.map(Positioned.none),
39-
snapshotsRepo,
40-
Some(scalaParameters),
41-
logger,
42-
cache.withMessage(s"Fetching ${ScalaCli.fullRunnerName} $cliVersion"),
43-
None
38+
dependencies = scalaCliDependency.map(Positioned.none),
39+
extraRepositories = snapshotsRepo,
40+
paramsOpt = Some(scalaParameters),
41+
logger = logger,
42+
cache = cache.withMessage(s"Fetching ${ScalaCli.fullRunnerName} $cliVersion"),
43+
classifiersOpt = None
4444
) match {
4545
case Right(value) => value
4646
case Left(value) =>
@@ -49,8 +49,7 @@ object LauncherCli {
4949
}
5050

5151
val scalaCli = fetchedScalaCli.fullDetailedArtifacts.collect {
52-
case (_, _, _, Some(f)) =>
53-
os.Path(f, os.pwd)
52+
case (_, _, _, Some(f)) => os.Path(f, os.pwd)
5453
}
5554

5655
val buildOptions = BuildOptions(
@@ -61,47 +60,43 @@ object LauncherCli {
6160

6261
val exitCode =
6362
Runner.runJvm(
64-
buildOptions.javaHome().value.javaCommand,
65-
buildOptions.javaOptions.javaOpts.toSeq.map(_.value.value),
66-
scalaCli,
67-
"scala.cli.ScalaCli",
68-
remainingArgs,
69-
logger,
63+
javaCommand = buildOptions.javaHome().value.javaCommand,
64+
javaArgs = buildOptions.javaOptions.javaOpts.toSeq.map(_.value.value),
65+
classPath = scalaCli,
66+
mainClass = "scala.cli.ScalaCli",
67+
args = remainingArgs,
68+
logger = logger,
7069
allowExecve = true
7170
).waitFor()
7271

7372
sys.exit(exitCode)
7473
}
7574

7675
def scalaCliScalaVersion(cliVersion: String): String =
77-
if (cliVersion == "nightly") Constants.defaultScalaVersion
78-
else if (Version(cliVersion) <= Version("0.1.2")) Constants.defaultScala212Version
79-
else if (Version(cliVersion) <= Version("0.1.4")) Constants.defaultScala213Version
76+
if cliVersion == "nightly" then Constants.defaultScalaVersion
77+
else if Version(cliVersion) <= Version("0.1.2") then Constants.defaultScala212Version
78+
else if Version(cliVersion) <= Version("0.1.4") then Constants.defaultScala213Version
8079
else Constants.defaultScalaVersion
8180

8281
def resolveNightlyScalaCliVersion(
8382
cache: FileCache[Task],
84-
scalaParameters: ScalaParameters
83+
scalaBinaryVersion: String
8584
): String = {
86-
87-
val snapshotRepoUrl =
88-
s"https://oss.sonatype.org/content/repositories/snapshots/org/virtuslab/scala-cli/cli_${scalaParameters.scalaBinaryVersion}/"
89-
val artifact = Artifact(snapshotRepoUrl).withChanging(true)
85+
val cliSubPath = s"org/virtuslab/scala-cli/cli_$scalaBinaryVersion"
86+
val mavenMetadataUrl = s"${SonatypeUtils.snapshotsRepositoryUrl}/$cliSubPath/maven-metadata.xml"
87+
val artifact = Artifact(mavenMetadataUrl).withChanging(true)
9088
cache.fileWithTtl0(artifact) match {
9189
case Left(_) =>
9290
System.err.println(s"Unable to find nightly ${ScalaCli.fullRunnerName} version")
9391
sys.exit(1)
94-
case Right(f) =>
95-
val snapshotRepoPage = os.read(os.Path(f, Os.pwd))
96-
val rawVersions = coursier.CoursierUtil.rawVersions(snapshotRepoUrl, snapshotRepoPage)
97-
val versions = rawVersions.map(Version(_))
98-
99-
if (versions.isEmpty)
100-
sys.error(s"No versions found in $snapshotRepoUrl (locally at $f)")
101-
else
102-
versions.max.repr
92+
case Right(mavenMetadataXml) =>
93+
val metadataXmlContent = os.read(os.Path(mavenMetadataXml, Os.pwd))
94+
val parsed = XML.loadString(metadataXmlContent)
95+
val rawVersions = (parsed \ "versioning" \ "versions" \ "version").map(_.text)
96+
val versions = rawVersions.map(Version(_))
97+
if versions.isEmpty
98+
then sys.error(s"No versions found in $mavenMetadataUrl (locally at $mavenMetadataXml)")
99+
else versions.max.repr
103100
}
104-
105101
}
106-
107102
}

modules/cli/src/test/scala/cli/tests/LauncherCliTest.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ class LauncherCliTest extends munit.FunSuite {
1515
val cache = CoursierOptions().coursierCache(logger.coursierLogger(""))
1616
val scalaParameters = ScalaParameters(Constants.defaultScalaVersion)
1717

18-
val nightlyCliVersion = LauncherCli.resolveNightlyScalaCliVersion(cache, scalaParameters)
18+
val nightlyCliVersion =
19+
LauncherCli.resolveNightlyScalaCliVersion(cache, scalaParameters.scalaBinaryVersion)
1920
expect(nightlyCliVersion.endsWith("-SNAPSHOT"))
2021
}
2122

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package scala.build
2+
3+
import coursier.maven.MavenRepository
4+
5+
object SonatypeUtils {
6+
lazy val snapshotsRepositoryUrl = "https://central.sonatype.com/repository/maven-snapshots"
7+
lazy val snapshotsRepository = MavenRepository(snapshotsRepositoryUrl)
8+
}

modules/integration/src/test/scala/scala/cli/integration/VersionTests.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,24 @@ class VersionTests extends ScalaCliSuite {
2727
}
2828
}
2929

30+
// given the 30 days snapshot retention, this may prove unreliable on the CI
31+
// but might still be valuable for local testing
32+
test("CLI nightly on new Maven Central Snapshots repo".flaky) {
33+
TestInputs.empty.fromRoot {
34+
root =>
35+
val res =
36+
os.proc(
37+
TestUtil.cli,
38+
"--cli-version",
39+
"nightly",
40+
"version",
41+
"--cli-version"
42+
)
43+
.call(cwd = root)
44+
expect(res.out.trim().coursierVersion >= "1.8.4".coursierVersion)
45+
}
46+
}
47+
3048
}
3149

3250
object VersionTests {

modules/options/src/main/scala/scala/build/Artifacts.scala

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package scala.build
33
import coursier.cache.FileCache
44
import coursier.core.{Classifier, Module, ModuleName, Organization, Repository, Version}
55
import coursier.error.ResolutionError
6-
import coursier.maven.MavenRepository
76
import coursier.util.Task
87
import coursier.{Dependency as CsDependency, Fetch, Resolution, core as csCore, util as csUtil}
98
import dependency.*
@@ -164,13 +163,12 @@ object Artifacts {
164163
val maybeSnapshotRepo = {
165164
val hasSnapshots = jvmTestRunnerDependencies.exists(_.version.endsWith("SNAPSHOT")) ||
166165
scalaArtifactsParamsOpt.flatMap(_.scalaNativeCliVersion).exists(_.endsWith("SNAPSHOT"))
167-
if (hasSnapshots)
166+
if hasSnapshots then
168167
Seq(
169168
coursier.Repositories.sonatype("snapshots"),
170-
MavenRepository("https://central.sonatype.com/repository/maven-snapshots")
169+
SonatypeUtils.snapshotsRepository
171170
)
172-
else
173-
Nil
171+
else Nil
174172
}
175173

176174
val allExtraRepositories =
@@ -433,7 +431,7 @@ object Artifacts {
433431
if runnerVersion.endsWith("SNAPSHOT") then
434432
Seq(
435433
coursier.Repositories.sonatype("snapshots"),
436-
MavenRepository("https://central.sonatype.com/repository/maven-snapshots")
434+
SonatypeUtils.snapshotsRepository
437435
)
438436
else Nil
439437
val runnerVersion0 =

0 commit comments

Comments
 (0)