Skip to content

Commit

Permalink
build rule & downstream modules with both Scala 3 LTS and Next
Browse files Browse the repository at this point in the history
This changes the cross-publishing strategy for rules from binary to full, in
order to have different artifacts for Scala 3. This will allow
ExplicitResultTypes to bring in a different presentation compiler since there
is no guarantee that LTS supports recent source syntax, nor that Next supports
old one.
  • Loading branch information
bjaglin committed Aug 22, 2024
1 parent 94abea2 commit 1498200
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 54 deletions.
20 changes: 10 additions & 10 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,24 @@ Start the SBT shell with `$ sbt`. The commands below assume you have a running
sbt shell.

```sh
# Fast unit tests for rules, cli, core.
> unit2_13 / test
# Fast unit tests for core, rules, reflect, cli & testkit.
> unit3_3_4 / test

# Integration tests for rules, cli, core. Contains a lot
# of different test suites, so it's recommended to use testOnly
# and/or testQuick.
> integration2_13 / test
# Integration tests for core, rules, reflect, cli & testkit.
# Contains a lot of different test suites, so it's recommended
# to use testOnly and/or testQuick.
> integration3_3_4 / test

# Use testWindows to exclude tests that are not expected to succeed
# on that OS.
> unit2_13 / testWindows
> integration2_13 / testWindows
> unit3_3_4 / testWindows
> integration3_3_4 / testWindows

# Only run tests for built-in rules, using scalafix-testkit.
> expect2_13Target2_13_10 / test
> expect3_3_4Target2_13_14 / test

# Only run ProcedureSyntax unit tests.
> expect2_13Target2_13_10 / testOnly -- -z ProcedureSyntax
> expect3_3_4Target2_13_14 / testOnly -- -z ProcedureSyntax
```

[sbt-projectmatrix](https://github.com/sbt/sbt-projectmatrix) is used to
Expand Down
26 changes: 19 additions & 7 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ lazy val interfaces = project
props.put("scala213", scala213)
props.put("scala212", scala212)
props.put("scala3LTS", scala3LTS)
props.put("scala3Next", scala3Next)
val out =
(Compile / managedResourceDirectories).value.head /
"scalafix-interfaces.properties"
Expand Down Expand Up @@ -104,6 +105,7 @@ lazy val rules = projectMatrix
.settings(
moduleName := "scalafix-rules",
description := "Built-in Scalafix rules",
isFullCrossVersion,
buildInfoSettingsForRules,
libraryDependencies ++= {
if (!isScala3.value)
Expand Down Expand Up @@ -131,7 +133,7 @@ lazy val rules = projectMatrix
}
)
.defaultAxes(VirtualAxis.jvm)
.jvmPlatform(cliScalaVersions)
.jvmPlatformFull(cliScalaVersions)
.dependsOn(`compat-metaconfig-macros` % "provided")
.dependsOn(core)
.enablePlugins(BuildInfoPlugin)
Expand Down Expand Up @@ -214,7 +216,7 @@ lazy val cli = projectMatrix
}.value
)
.defaultAxes(VirtualAxis.jvm)
.jvmPlatform(cliScalaVersions)
.jvmPlatformFull(cliScalaVersions)
.dependsOn(interfaces)
.dependsOn(`compat-metaconfig-macros` % "provided")
.dependsOn(reflect, rules)
Expand All @@ -230,7 +232,7 @@ lazy val testkit = projectMatrix
)
)
.defaultAxes(VirtualAxis.jvm)
.jvmPlatform(cliScalaVersions)
.jvmPlatformFull(cliScalaVersions)
.dependsOn(cli)

lazy val shared = projectMatrix
Expand Down Expand Up @@ -308,7 +310,7 @@ lazy val unit = projectMatrix
)
)
.defaultAxes(VirtualAxis.jvm)
.jvmPlatform(cliScalaVersions)
.jvmPlatformFull(cliScalaVersions)
.enablePlugins(BuildInfoPlugin)
.dependsOn(testkit % Test)

Expand Down Expand Up @@ -362,14 +364,24 @@ lazy val integration = projectMatrix
resolve(output, Compile / sourceDirectory).value
),
Test / test := (Test / test)
.dependsOn(resolve(cli, publishLocalTransitive))
.dependsOn(
(resolve(cli, publishLocalTransitive) +: cli.projectRefs
// always publish Scala 3 artifacts to test Scala 3 minor version fallbacks
.collect { case p @ LocalProject(n) if n.startsWith("cli3") => p }
.map(_ / publishLocalTransitive)): _*
)
.value,
Test / testWindows := (Test / testWindows)
.dependsOn(resolve(cli, publishLocalTransitive))
.dependsOn(
(resolve(cli, publishLocalTransitive) +: cli.projectRefs
// always publish Scala 3 artifacts to test Scala 3 minor version fallbacks
.collect { case p @ LocalProject(n) if n.startsWith("cli3") => p }
.map(_ / publishLocalTransitive)): _*
)
.value
)
.defaultAxes(VirtualAxis.jvm)
.jvmPlatform(cliScalaVersions)
.jvmPlatformFull(cliScalaVersions)
.enablePlugins(BuildInfoPlugin)
.dependsOn(unit % "compile->test")

Expand Down
12 changes: 6 additions & 6 deletions project/ScalafixBuild.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ object ScalafixBuild extends AutoPlugin with GhpagesKeys {

// https://github.com/scalameta/scalameta/issues/2485
lazy val coreScalaVersions = Seq(scala212, scala213)
lazy val cliScalaVersions = Seq(scala212, scala213, scala3LTS)
lazy val cliScalaVersions = Seq(scala212, scala213, scala3LTS, scala3Next)
lazy val cliScalaVersionsWithTargets: Seq[(String, TargetAxis)] =
cliScalaVersions.map(sv => (sv, TargetAxis(sv))) ++
Seq(scala213, scala212).flatMap { sv =>
Expand Down Expand Up @@ -62,10 +62,7 @@ object ScalafixBuild extends AutoPlugin with GhpagesKeys {
val xsource3 = TargetAxis(sv, xsource3 = true)

(prevVersions :+ xsource3).map((sv, _))
} ++ Seq(
(scala3LTS, TargetAxis(scala3Next)),
(scala3LTS, TargetAxis(scala213))
)
} :+ (scala3Next, TargetAxis(scala213))

lazy val publishLocalTransitive =
taskKey[Unit]("Run publishLocal on this project and its dependencies")
Expand Down Expand Up @@ -143,6 +140,7 @@ object ScalafixBuild extends AutoPlugin with GhpagesKeys {
"scala212" -> scala212,
"scala213" -> scala213,
"scala3LTS" -> scala3LTS,
"scala3Next" -> scala3Next,
sbtVersion
),
buildInfoPackage := "scalafix",
Expand Down Expand Up @@ -211,7 +209,9 @@ object ScalafixBuild extends AutoPlugin with GhpagesKeys {
.get(extracted.structure.data)
.get

s"all cli2_12/publishLocalTransitive cli2_13/publishLocalTransitive interfaces/publishLocal" ::
def asSuffix(scalaVersion: String) = scalaVersion.replace(".", "_")

s"all cli${asSuffix(scala212)}/publishLocalTransitive cli${asSuffix(scala213)}/publishLocalTransitive interfaces/publishLocal" ::
"reload plugins" ::
s"""set dependencyOverrides += "ch.epfl.scala" % "scalafix-interfaces" % "$v"""" :: // as documented in installation.md
"session save" ::
Expand Down
26 changes: 22 additions & 4 deletions project/TargetAxis.scala
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,20 @@ object TargetAxis {

implicit class TargetProjectMatrix(projectMatrix: ProjectMatrix) {

/** Like jvmPlatform but with the full Scala 3 version as suffix */
def jvmPlatformFull(scalaVersions: Seq[String]): ProjectMatrix = {
scalaVersions.foldLeft(projectMatrix) { (acc, scalaVersion) =>
acc.customRow(
autoScalaLibrary = true,
axisValues = Seq(
VirtualAxis.jvm,
VirtualAxis.scalaVersionAxis(scalaVersion, scalaVersion)
),
process = p => p
)
}
}

/**
* Create one JVM project for each target, tagged and configured with the
* requests of that target
Expand All @@ -132,10 +146,14 @@ object TargetAxis {
): ProjectMatrix = {
scalaVersionAgainstTarget.foldLeft(projectMatrix) {
case (acc, (scalaVersion, target)) =>
acc.jvmPlatform(
scalaVersions = Seq(scalaVersion),
axisValues = Seq(target),
settings = Seq()
acc.customRow(
autoScalaLibrary = true,
axisValues = Seq(
VirtualAxis.jvm,
VirtualAxis.scalaVersionAxis(scalaVersion, scalaVersion),
target
),
process = p => p
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package scalafix.internal.interfaces

import buildinfo.RulesBuildInfo
import scalafix.Versions
import scalafix.interfaces.Scalafix
import scalafix.interfaces.ScalafixArguments
Expand All @@ -17,6 +18,8 @@ final class ScalafixImpl extends Scalafix {
MainOps.helpMessage(screenWidth)
}

override def scalaVersion(): String =
RulesBuildInfo.scalaVersion
override def scalafixVersion(): String =
Versions.version
override def scalametaVersion(): String =
Expand All @@ -33,5 +36,7 @@ final class ScalafixImpl extends Scalafix {
Versions.scala213
override def scala3LTS(): String =
Versions.scala3LTS
override def scala3Next(): String =
Versions.scala3Next

}
57 changes: 34 additions & 23 deletions scalafix-interfaces/src/main/java/scalafix/interfaces/Scalafix.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ public interface Scalafix {
*/
String mainHelp(int screenWidth);

/**
* The exact Scala versions used
*/
String scalaVersion();

/**
* The release version of the current Scalafix API instance.
*/
Expand Down Expand Up @@ -70,6 +75,11 @@ public interface Scalafix {
*/
String scala3LTS();

/**
* The Scala 3 Next version in {@link #supportedScalaVersions()}
*/
String scala3Next();

/**
* Fetch JARs containing an implementation of {@link Scalafix} using Coursier and classload an instance of it via
* runtime reflection.
Expand All @@ -78,11 +88,11 @@ public interface Scalafix {
* classload external rules must have the classloader of the returned instance as ancestor to share a common
* loaded instance of `scalafix-core`, and therefore have been compiled against the requested Scala binary version.
*
* @param scalaBinaryVersion The Scala binary version ("2.13" for example) available in the classloader of the
* returned instance. To be able to run advanced semantic rules using the Scala
* Presentation Compiler such as ExplicitResultTypes, this must match the binary
* version that the target classpath was built with, as provided with
* {@link ScalafixArguments#withScalaVersion}.
* @param requestedScalaVersion The Scala version ("3.3.4" for example) available in the classloader of the
* returned instance. To be able to run advanced semantic rules using the Scala
* Presentation Compiler such as ExplicitResultTypes, this must match the version
* that the target classpath was built with, as provided with
* {@link ScalafixArguments#withScalaVersion}.
* @return An implementation of the {@link Scalafix} interface.
* @throws ScalafixException in case of errors during artifact resolution/fetching.
*/
Expand All @@ -98,31 +108,32 @@ static Scalafix fetchAndClassloadInstance(String scalaBinaryVersion) throws Scal
* classload external rules must have the classloader of the returned instance as ancestor to share a common
* loaded instance of `scalafix-core`, and therefore have been compiled against the requested Scala binary version.
*
* @param scalaBinaryVersion The Scala binary version ("2.13" for example) available in the classloader of the
* returned instance. To be able to run advanced semantic rules using the Scala
* Presentation Compiler such as ExplicitResultTypes, this must match the binary
* version that the target classpath was built with, as provided with
* {@link ScalafixArguments#withScalaVersion}.
* @param requestedScalaVersion The Scala version ("3.3.4" for example) available in the classloader of the
* returned instance. To be able to run advanced semantic rules using the Scala
* Presentation Compiler such as ExplicitResultTypes, this must match the version
* that the target classpath was built with, as provided with
* {@link ScalafixArguments#withScalaVersion}.
* @param repositories Maven/Ivy repositories to fetch the JARs from.
* @return An implementation of the {@link Scalafix} interface.
* @throws ScalafixException in case of errors during artifact resolution/fetching.
*/
static Scalafix fetchAndClassloadInstance(String scalaBinaryVersion, List<Repository> repositories)
static Scalafix fetchAndClassloadInstance(String requestedScalaVersion, List<Repository> repositories)
throws ScalafixException {

String scalaVersionKey;
switch (scalaBinaryVersion) {
case "2.12":
scalaVersionKey = "scala212";
break;
case "2.13":
scalaVersionKey = "scala213";
break;
case "3":
scalaVersionKey = "scala3LTS";
break;
default:
throw new IllegalArgumentException("Unsupported scala version " + scalaBinaryVersion);
if (requestedScalaVersion.startsWith("2.12")) {
scalaVersionKey = "scala212";
} else if (requestedScalaVersion.startsWith("2.13")) {
scalaVersionKey = "scala213";
} else if (requestedScalaVersion.startsWith("3.0") ||
requestedScalaVersion.startsWith("3.1") ||
requestedScalaVersion.startsWith("3.2") ||
requestedScalaVersion.startsWith("3.3")) {
scalaVersionKey = "scala3LTS";
} else if (requestedScalaVersion.startsWith("3")) {
scalaVersionKey = "scala3Next";
} else {
throw new IllegalArgumentException("Unsupported scala version " + requestedScalaVersion);
}

Properties properties = new Properties();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import scalafix.interfaces.Scalafix
import scalafix.interfaces.ScalafixDiagnostic
import scalafix.interfaces.ScalafixException
import scalafix.interfaces.ScalafixMainCallback
import scalafix.internal.config.ScalaVersion
import scalafix.tests.BuildInfo

/**
Expand All @@ -25,16 +24,17 @@ import scalafix.tests.BuildInfo
*/
class ScalafixSuite extends AnyFunSuite {

val scalaVersion: String =
ScalaVersion.from(BuildInfo.scalaVersion).get.binary.get.value
val scalaVersion: String = BuildInfo.scalaVersion

test("versions") {
val api = Scalafix.classloadInstance(this.getClass.getClassLoader)
assert(api.scalafixVersion() == Versions.version)
assert(api.scalaVersion() == scalaVersion)
assert(api.scalametaVersion() == Versions.scalameta)
assert(api.scala212() == Versions.scala212)
assert(api.scala213() == Versions.scala213)
assert(api.scala3LTS() == Versions.scala3LTS)
assert(api.scala3Next() == Versions.scala3Next)
assert(
api
.supportedScalaVersions()
Expand All @@ -44,7 +44,17 @@ class ScalafixSuite extends AnyFunSuite {
assert(help.contains("Usage: scalafix"))
}

test("error") {
test("classload Scala 3 LTS as a fallback for pre-LTS versions") {
val scalafixAPI = Scalafix.fetchAndClassloadInstance("3.0.0")
assert(scalafixAPI.scalaVersion() == Versions.scala3LTS)
}

test("classload Scala 3 Next as a fallback for post-LTS versions") {
val scalafixAPI = Scalafix.fetchAndClassloadInstance("3.4.0")
assert(scalafixAPI.scalaVersion() == Versions.scala3Next)
}

test("invalid class loader") {
val cl = new URLClassLoader(Array(), null)
val ex = intercept[ScalafixException] {
Scalafix.classloadInstance(cl)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ class InterfacesPropertiesSuite extends AnyFunSuite with BeforeAndAfterAll {
check("scala212", Versions.scala212)
check("scala213", Versions.scala213)
check("scala3LTS", Versions.scala3LTS)
check("scala3Next", Versions.scala3Next)

}

0 comments on commit 1498200

Please sign in to comment.