Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion build.sc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import $ivy.`com.lihaoyi::mill-contrib-bloop:$MILL_VERSION`
import $ivy.`io.get-coursier::coursier-launcher:2.1.24`
import $ivy.`io.github.alexarchambault.mill::mill-native-image-upload:0.1.29`
import $file.project.deps, deps.{Deps, Docker, InternalDeps, Java, Scala, TestDeps}
import $file.project.deps, deps.{Cli, Deps, Docker, InternalDeps, Java, Scala, TestDeps}
import $file.project.publish, publish.{ghOrg, ghName, ScalaCliPublishModule, organization}
import $file.project.settings, settings.{
CliLaunchers,
Expand Down Expand Up @@ -454,6 +454,7 @@ trait Core extends ScalaCliCrossSbtModule
| def runnerOrganization = "${runner(Scala.runnerScala3).pomSettings().organization}"
| def runnerModuleName = "${runner(Scala.runnerScala3).artifactName()}"
| def runnerVersion = "${runner(Scala.runnerScala3).publishVersion()}"
| def runnerLegacyVersion = "${Cli.runnerLegacyVersion}"
| def runnerMainClass = "$runnerMainClass"
|
| def semanticDbPluginOrganization = "${Deps.semanticDbScalac.dep.module.organization
Expand Down Expand Up @@ -1060,6 +1061,9 @@ trait CliIntegration extends SbtModule with ScalaCliPublishModule with HasTests
| def maxAmmoniteScala213Version = "${Scala.maxAmmoniteScala213Version}"
| def maxAmmoniteScala3Version = "${Scala.maxAmmoniteScala3Version}"
| def maxAmmoniteScala3LtsVersion = "${Scala.maxAmmoniteScala3LtsVersion}"
| def legacyScala3Versions = Seq(${Scala.legacyScala3Versions.map(p =>
s"\"$p\""
).mkString(", ")})
| def scalaJsVersion = "${Scala.scalaJs}"
| def scalaJsCliVersion = "${Scala.scalaJsCli}"
| def scalaNativeVersion = "${Deps.Versions.scalaNative}"
Expand All @@ -1069,6 +1073,7 @@ trait CliIntegration extends SbtModule with ScalaCliPublishModule with HasTests
| def ammoniteVersion = "${Deps.ammonite.dep.version}"
| def defaultGraalVMJavaVersion = "${deps.graalVmJavaVersion}"
| def defaultGraalVMVersion = "${deps.graalVmVersion}"
| def runnerLegacyVersion = "${Cli.runnerLegacyVersion}"
| def scalaPyVersion = "${Deps.scalaPy.dep.version}"
| def scalaPyMaxScalaNative = "${Deps.Versions.maxScalaNativeForScalaPy}"
| def bloopVersion = "${Deps.bloopRifle.dep.version}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import caseapp.*
import coursier.core.Version

import scala.build.EitherCps.{either, value}
import scala.build.coursierVersion
import scala.build.errors.BuildException
import scala.build.internal.FetchExternalBinary
import scala.build.options.BuildOptions
Expand All @@ -16,7 +17,6 @@ import scala.cli.commands.shared.{
SharedOptions
}
import scala.cli.commands.{Constants, tags}
import scala.cli.coursierVersion
import scala.util.Properties

// format: off
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import scala.cli.config.{ConfigDb, Keys}
import scala.cli.packaging.Library
import scala.cli.util.ArgHelpers.*
import scala.cli.util.ConfigDbUtils
import scala.cli.{CurrentParams, ScalaCli, coursierVersion}
import scala.cli.{CurrentParams, ScalaCli}
import scala.jdk.CollectionConverters.*
import scala.util.Properties

Expand Down
2 changes: 2 additions & 0 deletions modules/cli/src/main/scala/scala/cli/commands/run/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import scala.build.errors.{BuildException, CompositeBuildException}
import scala.build.input.{Inputs, ScalaCliInvokeData, SubCommand}
import scala.build.internal.{Constants, Runner, ScalaJsLinkerConfig}
import scala.build.internals.ConsoleUtils.ScalaCliConsole
import scala.build.internals.ConsoleUtils.ScalaCliConsole.warnPrefix
import scala.build.internals.EnvVar
import scala.build.options.{BuildOptions, JavaOpt, PackageType, Platform, ScalacOpt, Scope}
import scala.cli.CurrentParams
Expand Down Expand Up @@ -103,6 +104,7 @@ object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers {
addRunnerDependencyOpt = baseOptions.notForBloopOptions.addRunnerDependencyOpt.orElse {
runMode(options) match {
case _: RunMode.Spark | RunMode.HadoopJar =>
logger.debug(s"$warnPrefix Skipping the runner dependency when running Spark/Hadoop.")
Some(false)
case RunMode.Default => None
}
Expand Down
7 changes: 0 additions & 7 deletions modules/cli/src/main/scala/scala/cli/package.scala

This file was deleted.

5 changes: 5 additions & 0 deletions modules/core/src/main/scala/scala/build/CsUtils.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package scala.build

import coursier.core.Version

extension (s: String) def coursierVersion: Version = Version(s)
Original file line number Diff line number Diff line change
Expand Up @@ -2400,4 +2400,18 @@ abstract class RunTestDefinitions
expect(res.out.trim() == expectedOutput)
}
}

test(
s"run a simple hello world with the runner module on the classpath and Scala $actualScalaVersion"
) {
val expectedMessage = "Hello, world!"
val legacyRunnerWarning = "Defaulting to a legacy runner module version"
TestInputs(os.rel / "script.sc" -> s"""println("$expectedMessage")""")
.fromRoot { root =>
val res = os.proc(TestUtil.cli, "run", ".", "--runner", extraOptions)
.call(cwd = root, stderr = os.Pipe)
expect(res.out.trim() == expectedMessage)
expect(!res.err.trim().contains(legacyRunnerWarning))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,4 +187,22 @@ class RunTestsDefault extends RunTestDefinitions
}
}
}

for {
scalaVersion <- TestUtil.legacyScalaVersionsOnePerMinor
expectedMessage = "Hello, world!"
expectedWarning =
s"Defaulting to a legacy runner module version: ${Constants.runnerLegacyVersion}"
}
test(
s"run a simple hello world with the runner module on the classpath and Scala $scalaVersion (legacy)"
) {
TestInputs(os.rel / "script.sc" -> s"""println("$expectedMessage")""").fromRoot { root =>
val res =
os.proc(TestUtil.cli, "run", ".", "-S", scalaVersion, TestUtil.extraOptions, "--runner")
.call(cwd = root, stderr = os.Pipe)
expect(res.out.trim() == expectedMessage)
expect(res.err.trim().contains(expectedWarning))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.eed3si9n.expecty.Expecty.expect
import java.io.File

import scala.cli.integration.Constants.munitVersion
import scala.cli.integration.TestUtil.StringOps

class TestTestsDefault extends TestTestDefinitions with TestDefault {
test("Pure Java with Scala tests") {
Expand Down Expand Up @@ -62,11 +63,39 @@ class TestTestsDefault extends TestTestDefinitions with TestDefault {
).fromRoot { root =>
val output = os.proc(TestUtil.cli, "test", extraOptions, ".", "--cross", "--power")
.call(cwd = root).out.text()
def countOccurrences(a: String, b: String): Int =
if (b.isEmpty) 0 // Avoid infinite splitting
else a.sliding(b.length).count(_ == b)
expect(output.contains(expectedMessage))
expect(countOccurrences(output, expectedMessage) == crossVersions.length)
expect(output.countOccurrences(expectedMessage) == crossVersions.length)
}
}

for {
scalaVersion <- TestUtil.legacyScalaVersionsOnePerMinor
expectedMessage = "Hello, world!"
expectedWarning =
s"Defaulting to a legacy test-runner module version: ${Constants.runnerLegacyVersion}"
}
test(s"run a simple test with Scala $scalaVersion (legacy)") {
TestInputs(os.rel / "example.test.scala" ->
// using JUnit to work around TASTy and macro incompatibilities
s"""//> using dep com.novocode:junit-interface:0.11
|import org.junit.Test
|
|class MyTests {
| @Test
| def foo(): Unit = {
| assert(2 + 2 == 4)
| println("$expectedMessage")
| }
|}
|""".stripMargin).fromRoot { root =>
val res =
os.proc(TestUtil.cli, "test", ".", "-S", scalaVersion, TestUtil.extraOptions)
.call(cwd = root, stderr = os.Pipe)
val out = res.out.trim()
expect(out.contains(expectedMessage))
val err = res.err.trim()
expect(err.contains(expectedWarning))
expect(err.countOccurrences(expectedWarning) == 1)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ object TestUtil {
val cli: Seq[String] = cliCommand(cliPath)
val ltsEqualsNext: Boolean = Constants.scala3Lts equals Constants.scala3Next

lazy val legacyScalaVersionsOnePerMinor: Seq[String] =
Constants.legacyScala3Versions.sorted.reverse.distinctBy(_.split('.').take(2).mkString("."))

def cliCommand(cliPath: String): Seq[String] =
if (isNativeCli)
Seq(cliPath)
Expand Down Expand Up @@ -367,4 +370,10 @@ object TestUtil {
Thread.sleep(200L)
if (proc.isAlive()) proc.destroyForcibly()
}

implicit class StringOps(a: String) {
def countOccurrences(b: String): Int =
if (b.isEmpty) 0 // Avoid infinite splitting
else a.sliding(b.length).count(_ == b)
}
}
49 changes: 41 additions & 8 deletions modules/options/src/main/scala/scala/build/Artifacts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import scala.build.internal.Constants
import scala.build.internal.Constants.*
import scala.build.internal.CsLoggerUtil.*
import scala.build.internal.Util.{PositionedScalaDependencyOps, ScalaModuleOps}
import scala.build.internals.ConsoleUtils.ScalaCliConsole.warnPrefix
import scala.collection.mutable

final case class Artifacts(
Expand Down Expand Up @@ -129,11 +130,32 @@ object Artifacts {
): Either[BuildException, Artifacts] = either {
val dependencies = defaultDependencies ++ extraDependencies

val scalaVersion = (for {
scalaArtifactsParams <- scalaArtifactsParamsOpt
scalaParams = scalaArtifactsParams.params
scalaVersion = scalaParams.scalaVersion
} yield scalaVersion).getOrElse(defaultScalaVersion)

val shouldUseLegacyRunners =
scalaVersion.startsWith("3") &&
scalaVersion.coursierVersion < s"$scala3LtsPrefix.0".coursierVersion

val jvmTestRunnerDependencies =
if (addJvmTestRunner)
Seq(dep"$testRunnerOrganization::$testRunnerModuleName:$testRunnerVersion")
else
Nil
if addJvmTestRunner then {
val testRunnerVersion0 =
if shouldUseLegacyRunners then {
logger.message(
s"""$warnPrefix Scala $scalaVersion is no longer supported by the test-runner module.
|$warnPrefix Defaulting to a legacy test-runner module version: $runnerLegacyVersion.
|$warnPrefix To use the latest test-runner, upgrade Scala to at least $scala3LtsPrefix."""
.stripMargin
)
runnerLegacyVersion
}
else testRunnerVersion
Seq(dep"$testRunnerOrganization::$testRunnerModuleName:$testRunnerVersion0")
}
else Nil

val jmhDependencies = addJmhDependencies.toSeq
.map(version => dep"${Constants.jmhOrg}:${Constants.jmhGeneratorBytecodeModule}:$version")
Expand Down Expand Up @@ -399,18 +421,29 @@ object Artifacts {
}

val (hasRunner, extraRunnerJars) =
if (scalaOpt.nonEmpty) {
if scalaOpt.nonEmpty then {
val addJvmRunner0 = addJvmRunner.getOrElse(false)
val runnerJars =
if (addJvmRunner0) {
if addJvmRunner0 then {
val maybeSnapshotRepo =
if (runnerVersion.endsWith("SNAPSHOT"))
if runnerVersion.endsWith("SNAPSHOT") then
Seq(coursier.Repositories.sonatype("snapshots"))
else Nil
val runnerVersion0 =
if shouldUseLegacyRunners then {
logger.message(
s"""$warnPrefix Scala $scalaVersion is no longer supported by the runner module.
|$warnPrefix Defaulting to a legacy runner module version: $runnerLegacyVersion.
|$warnPrefix To use the latest runner, upgrade Scala to at least $scala3LtsPrefix."""
.stripMargin
)
runnerLegacyVersion
}
else runnerVersion
value {
artifacts(
Seq(Positioned.none(
dep"$runnerOrganization::$runnerModuleName:$runnerVersion,intransitive"
dep"$runnerOrganization::$runnerModuleName:$runnerVersion0,intransitive"
)),
extraRepositories ++ maybeSnapshotRepo,
scalaArtifactsParamsOpt.map(_.params),
Expand Down
28 changes: 21 additions & 7 deletions project/deps.sc
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ import Deps.Versions
import mill._
import scalalib._

object Cli {
def runnerLegacyVersion = "1.7.1" // last runner version to support pre-LTS Scala 3 versions
}

object Scala {
def scala212 = "2.12.20"
def scala213 = "2.13.16"
def runnerScala3 = "3.0.2" // the newest version that is compatible with all Scala 3.x versions
def scala3LtsPrefix = "3.3" // used for the LTS version tags
def scala212 = "2.12.20"
def scala213 = "2.13.16"
def scala3LtsPrefix = "3.3" // used for the LTS version tags
def scala3Lts = s"$scala3LtsPrefix.5" // the LTS version currently used in the build
def runnerScala3 = scala3Lts
def scala3NextPrefix = "3.7"
def scala3Next = s"$scala3NextPrefix.0" // the newest/next version of Scala
def scala3NextAnnounced = "3.6.4" // the newest/next version of Scala that's been announced
Expand All @@ -27,14 +31,18 @@ object Scala {
val scala3MainVersions = (defaults ++ allScala3).distinct
val mainVersions = (Seq(scala213) ++ scala3MainVersions).distinct
val runnerScalaVersions = runnerScala3 +: allScala2
val testRunnerScalaVersions = runnerScalaVersions ++ allScala3
val testRunnerScalaVersions = (runnerScalaVersions ++ allScala3).distinct

def scalaJs = "1.19.0"
def scalaJsCli = scalaJs // this must be compatible with the Scala.js version

private def patchVer(sv: String): Int =
sv.split('.').drop(2).head.takeWhile(_.isDigit).toInt

private def minorVer(sv: String): Int =
sv.split('.').drop(1).head.takeWhile(_.isDigit).toInt

def listAll: Seq[String] = {
def patchVer(sv: String): Int =
sv.split('.').drop(2).head.takeWhile(_.isDigit).toInt
val max212 = patchVer(scala212)
val max213 = patchVer(scala213)
val max30 = 2
Expand All @@ -57,6 +65,12 @@ object Scala {
(0 until max37).map(i => s"3.7.$i") ++ Seq(scala3Next)
}

def legacyScala3Versions =
listAll
.filter(_.startsWith("3"))
.distinct
.filter(minorVer(_) < minorVer(scala3Lts))

def maxAmmoniteScala212Version = scala212
def maxAmmoniteScala213Version = scala213
def maxAmmoniteScala3Version = "3.6.3"
Expand Down