diff --git a/build.sc b/build.sc index 4ce480692c..a7cad2ac28 100644 --- a/build.sc +++ b/build.sc @@ -451,6 +451,7 @@ trait Core extends ScalaCliSbtModule with ScalaCliPublishModule with HasTests | def defaultScalaVersion = "${Scala.defaultUser}" | def defaultScala212Version = "${Scala.scala212}" | def defaultScala213Version = "${Scala.scala213}" + | def scala3Lts = "${Scala.scala3Lts}" | | def workspaceDirName = "$workspaceDirName" | def projectFileName = "$projectFileName" diff --git a/modules/build/src/test/scala/scala/build/tests/BuildOptionsTests.scala b/modules/build/src/test/scala/scala/build/tests/BuildOptionsTests.scala index c7151876ba..71bf67f1d3 100644 --- a/modules/build/src/test/scala/scala/build/tests/BuildOptionsTests.scala +++ b/modules/build/src/test/scala/scala/build/tests/BuildOptionsTests.scala @@ -29,6 +29,8 @@ import scala.build.Directories import scala.build.Positioned import scala.build.tests.util.BloopServer import scala.concurrent.duration.DurationInt +import scala.build.internal.Regexes.scala3LtsRegex +import scala.build.errors.ScalaVersionError class BuildOptionsTests extends TestUtil.ScalaCliBuildSuite { @@ -95,6 +97,21 @@ class BuildOptionsTests extends TestUtil.ScalaCliBuildSuite { ) } + test(s"Scala 2.lts shows Scala Version Error") { + + val options = BuildOptions( + scalaOptions = ScalaOptions( + scalaVersion = Some(MaybeScalaVersion(s"3.${Int.MaxValue}")) + ) + ) + assert( + options.projectParams.swap.exists { + case _: ScalaVersionError => true; case _ => false + }, + s"specifying 2.lts scala version does not lead to Scala Version Error" + ) + } + test("Scala 2.11.2 shows Unupported Scala Version Error") { val options = BuildOptions( @@ -226,6 +243,19 @@ class BuildOptionsTests extends TestUtil.ScalaCliBuildSuite { ) } + test("-S 3.lts option works") { + val options = BuildOptions( + scalaOptions = ScalaOptions( + scalaVersion = Some(MaybeScalaVersion("3.lts")) + ) + ) + val scalaParams = options.scalaParams.orThrow.getOrElse(???) + assert( + scala3LtsRegex.unapplySeq(scalaParams.scalaVersion).isDefined, + "-S 3.lts argument does not lead to scala3 LTS" + ) + } + test("-S 2.12.nightly option works") { val options = BuildOptions( scalaOptions = ScalaOptions( diff --git a/modules/core/src/main/scala/scala/build/errors/ScalaVersionError.scala b/modules/core/src/main/scala/scala/build/errors/ScalaVersionError.scala index ec71c0e618..04c36e95e3 100644 --- a/modules/core/src/main/scala/scala/build/errors/ScalaVersionError.scala +++ b/modules/core/src/main/scala/scala/build/errors/ScalaVersionError.scala @@ -20,5 +20,6 @@ object ScalaVersionError { |In addition, you can request compilation with the last nightly versions of Scala, |by passing the 2.nightly, 2.12.nightly, 2.13.nightly, or 3.nightly arguments. |Specific Scala 2 or Scala 3 nightly versions are also accepted. + |You can also request the latest Scala 3 LTS by passing lts or 3.lts. |""".stripMargin } diff --git a/modules/core/src/main/scala/scala/build/internals/Regexes.scala b/modules/core/src/main/scala/scala/build/internals/Regexes.scala index 10033c4c9a..3a24315feb 100644 --- a/modules/core/src/main/scala/scala/build/internals/Regexes.scala +++ b/modules/core/src/main/scala/scala/build/internals/Regexes.scala @@ -3,4 +3,5 @@ package scala.build.internal object Regexes { val scala2NightlyRegex = raw"""2\.(\d+)\.(\d+)-bin-[a-f0-9]*""".r val scala3NightlyNicknameRegex = raw"""3\.([0-9]*)\.nightly""".r + val scala3LtsRegex = raw"""3\.3\.[0-9]+""".r } diff --git a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala index 8ef01d65d8..a80416570c 100644 --- a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala @@ -330,6 +330,14 @@ final case class BuildOptions( case Some(MaybeScalaVersion(Some(svInput))) => val sv = value { svInput match { + case sv if ScalaVersionUtil.scala3Lts.contains(sv) => + ScalaVersionUtil.validateStable( + Constants.scala3Lts, + cache, + repositories + ) + case sv if ScalaVersionUtil.scala2Lts.contains(sv) => + Left(new ScalaVersionError(s"Invalid Scala version: ${sv}. There is no official LTS version for Scala 2.")) case sv if sv == ScalaVersionUtil.scala3Nightly => ScalaVersionUtil.GetNightly.scala3(cache) case scala3NightlyNicknameRegex(threeSubBinaryNum) => diff --git a/modules/options/src/main/scala/scala/build/options/ScalaVersionUtil.scala b/modules/options/src/main/scala/scala/build/options/ScalaVersionUtil.scala index bd97fbd79c..26e333ccc6 100644 --- a/modules/options/src/main/scala/scala/build/options/ScalaVersionUtil.scala +++ b/modules/options/src/main/scala/scala/build/options/ScalaVersionUtil.scala @@ -31,6 +31,9 @@ object ScalaVersionUtil { def scala212Nightly = "2.12.nightly" def scala213Nightly = List("2.13.nightly", "2.nightly") def scala3Nightly = "3.nightly" + def scala3Lts = List("3.lts", "lts") + // not valid versions, defined only for informative error messages + def scala2Lts = List("2.13.lts", "2.12.lts", "2.lts") extension (cache: FileCache[Task]) { def fileWithTtl0(artifact: Artifact): Either[ArtifactError, File] = cache.logger.use { diff --git a/project/deps.sc b/project/deps.sc index 99fba989e4..e570b5fb3d 100644 --- a/project/deps.sc +++ b/project/deps.sc @@ -5,6 +5,7 @@ object Scala { def scala213 = "2.13.12" def runnerScala3 = "3.0.2" // the newest version that is compatible with all Scala 3.x versions def scala3 = "3.3.1" + def scala3Lts = "3.3" //the full version should be resolved later // The Scala version used to build the CLI itself. def defaultInternal = sys.props.get("scala.version.internal").getOrElse(scala3)