From 4d6ddd50a6b41f6a8e0cc855740078b663c1c3a1 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Tue, 16 Dec 2025 00:49:19 -0500 Subject: [PATCH] [2.x] projectMatrix crossVerson support **Problem** crossVersion is missing from projectMatrix in sbt 2.x. **Solution** Port it from sbt-projectmatrix. --- build.sbt | 1 + main/src/main/scala/sbt/ProjectMatrix.scala | 271 +++++++++++++----- .../sbt-test/project-matrix/full/build.sbt | 49 ++++ sbt-app/src/sbt-test/project-matrix/full/test | 4 + 4 files changed, 251 insertions(+), 74 deletions(-) create mode 100644 sbt-app/src/sbt-test/project-matrix/full/build.sbt create mode 100644 sbt-app/src/sbt-test/project-matrix/full/test diff --git a/build.sbt b/build.sbt index 06847bf6b..3205b07d5 100644 --- a/build.sbt +++ b/build.sbt @@ -710,6 +710,7 @@ lazy val mainProj = (project in file("main")) Compile / doc / sources := Nil, mimaSettings, mimaBinaryIssueFilters ++= Vector( + exclude[ReversedMissingMethodProblem]("sbt.ProjectMatrix.*"), ), ) .dependsOn(lmCore, lmIvy, lmCoursierShadedPublishing) diff --git a/main/src/main/scala/sbt/ProjectMatrix.scala b/main/src/main/scala/sbt/ProjectMatrix.scala index 86a59a0f3..8582f6db4 100644 --- a/main/src/main/scala/sbt/ProjectMatrix.scala +++ b/main/src/main/scala/sbt/ProjectMatrix.scala @@ -81,6 +81,17 @@ sealed trait ProjectMatrix extends CompositeProject { */ def configure(transforms: (Project => Project)*): ProjectMatrix + /** + * If autoScalaLibrary is false, add non-Scala row. + * Otherwise, add custom rows for each scalaVersions. + */ + def customRow( + autoScalaLibrary: Boolean, + crossVersion: Option[CrossVersion], + scalaVersions: Seq[String], + axisValues: Seq[VirtualAxis] + )(process: Project => Project): ProjectMatrix + /** * If autoScalaLibrary is false, add non-Scala row. * Otherwise, add custom rows for each scalaVersions. @@ -116,8 +127,17 @@ sealed trait ProjectMatrix extends CompositeProject { settings: Seq[Def.Setting[?]] ): ProjectMatrix + def jvmPlatform( + autoScalaLibrary: Boolean, + crossVersion: CrossVersion, + scalaVersions: Seq[String], + axisValues: Seq[VirtualAxis], + settings: Seq[Def.Setting[?]] + ): ProjectMatrix + def jvmPlatform(crossVersion: CrossVersion, scalaVersions: Seq[String]): ProjectMatrix def jvmPlatform(scalaVersions: Seq[String]): ProjectMatrix def jvmPlatform(autoScalaLibrary: Boolean): ProjectMatrix + def jvmPlatform(autoScalaLibrary: Boolean, crossVersion: CrossVersion): ProjectMatrix def jvmPlatform(scalaVersions: Seq[String], settings: Seq[Def.Setting[?]]): ProjectMatrix def jvmPlatform( scalaVersions: Seq[String], @@ -136,6 +156,14 @@ sealed trait ProjectMatrix extends CompositeProject { ): ProjectMatrix def jvm: ProjectFinder + def jsPlatform( + autoScalaLibrary: Boolean, + crossVersion: CrossVersion, + scalaVersions: Seq[String], + axisValues: Seq[VirtualAxis], + settings: Seq[Def.Setting[?]] + ): ProjectMatrix + def jsPlatform(crossVersion: CrossVersion, scalaVersions: Seq[String]): ProjectMatrix def jsPlatform(scalaVersions: Seq[String]): ProjectMatrix def jsPlatform(scalaVersions: Seq[String], settings: Seq[Def.Setting[?]]): ProjectMatrix def jsPlatform( @@ -150,6 +178,14 @@ sealed trait ProjectMatrix extends CompositeProject { ): ProjectMatrix def js: ProjectFinder + def nativePlatform( + autoScalaLibrary: Boolean, + crossVersion: CrossVersion, + scalaVersions: Seq[String], + axisValues: Seq[VirtualAxis], + settings: Seq[Def.Setting[?]] + ): ProjectMatrix + def nativePlatform(crossVersion: CrossVersion, scalaVersions: Seq[String]): ProjectMatrix def nativePlatform(scalaVersions: Seq[String]): ProjectMatrix def nativePlatform(scalaVersions: Seq[String], settings: Seq[Def.Setting[?]]): ProjectMatrix def nativePlatform( @@ -223,6 +259,17 @@ object ProjectMatrix { def isSecondaryMatch(that: ProjectRow): Boolean = VirtualAxis.isSecondaryMatch(this.axisValues, that.axisValues) + /** Calculate the idSuffix for this row */ + def idSuffix(defAxes: Seq[VirtualAxis]): String = axisValues + .sortBy(_.suffixOrder) + .filterNot(isSortOfDefaultAxis(defAxes)) + .map(_.idSuffix) + .mkString("") + + private def isSortOfDefaultAxis(defAxes: Seq[VirtualAxis])(a: VirtualAxis): Boolean = + defAxes.exists: da => + VirtualAxis.isPartialVersionEquals(da, a) + override def toString: String = s"ProjectRow($autoScalaLibrary, $axisValues)" } @@ -259,19 +306,9 @@ object ProjectMatrix { private def resolveProjectIds: Map[ProjectRow, String] = { Map((for { r <- rows - } yield { - val axes = r.axisValues - .sortBy(_.suffixOrder) - .filterNot(isSortOfDefaultAxis) - val idSuffix = axes.map(_.idSuffix).mkString("") - val childId = self.id + idSuffix - r -> childId - })*) + } yield r -> (self.id + r.idSuffix(defAxes)))*) } - private def isSortOfDefaultAxis(a: VirtualAxis): Boolean = - defAxes exists { da => VirtualAxis.isPartialVersionEquals(da, a) } - private def resolveMappings: ListMap[ProjectRow, Project] = { val projectIds = resolveProjectIds val projects = @@ -428,41 +465,72 @@ object ProjectMatrix { def setPlugins(ns: Plugins): ProjectMatrix = copy(plugins = ns) - override def jvmPlatform(scalaVersions: Seq[String]): ProjectMatrix = - jvmPlatform(scalaVersions, Nil) - override def jvmPlatform(autoScalaLibrary: Boolean): ProjectMatrix = - jvmPlatform(autoScalaLibrary, Nil, Nil) override def jvmPlatform( + autoScalaLibrary: Boolean, + crossVersion: CrossVersion, scalaVersions: Seq[String], + axisValues: Seq[VirtualAxis], settings: Seq[Def.Setting[?]] ): ProjectMatrix = - jvmPlatform(true, scalaVersions, settings) + customRow(autoScalaLibrary, Some(crossVersion), scalaVersions, VirtualAxis.jvm +: axisValues): + p => p.settings(settings) + override def jvmPlatform( autoScalaLibrary: Boolean, scalaVersions: Seq[String], settings: Seq[Def.Setting[?]] ): ProjectMatrix = - customRow(autoScalaLibrary, scalaVersions, Seq(VirtualAxis.jvm), { _.settings(settings) }) + customRow(autoScalaLibrary, crossVersion = None, scalaVersions, Seq(VirtualAxis.jvm)): p => + p.settings(settings) + + override def jvmPlatform( + crossVersion: CrossVersion, + scalaVersions: Seq[String] + ): ProjectMatrix = + jvmPlatform(autoScalaLibrary = true, crossVersion, scalaVersions, Nil, Nil) override def jvmPlatform( scalaVersions: Seq[String], axisValues: Seq[VirtualAxis], settings: Seq[Def.Setting[?]] ): ProjectMatrix = - customRow(true, scalaVersions, VirtualAxis.jvm +: axisValues, { _.settings(settings) }) + customRow( + autoScalaLibrary = true, + crossVersion = None, + scalaVersions, + VirtualAxis.jvm +: axisValues + ): p => + p.settings(settings) override def jvmPlatform( scalaVersions: Seq[String], axisValues: Seq[VirtualAxis], configure: Project => Project ): ProjectMatrix = - customRow(true, scalaVersions, VirtualAxis.jvm +: axisValues, configure) + customRow( + autoScalaLibrary = true, + crossVersion = None, + scalaVersions, + VirtualAxis.jvm +: axisValues + )(configure) + + override def jvmPlatform(scalaVersions: Seq[String]): ProjectMatrix = + jvmPlatform(autoScalaLibrary = true, scalaVersions, Nil) + + override def jvmPlatform(autoScalaLibrary: Boolean): ProjectMatrix = + jvmPlatform(autoScalaLibrary, Nil, Nil) + + override def jvmPlatform(autoScalaLibrary: Boolean, crossVersion: CrossVersion): ProjectMatrix = + jvmPlatform(autoScalaLibrary, crossVersion, Nil, Nil, Nil) + + override def jvmPlatform( + scalaVersions: Seq[String], + settings: Seq[Def.Setting[?]] + ): ProjectMatrix = + jvmPlatform(autoScalaLibrary = true, scalaVersions, settings) override def jvm: ProjectFinder = new AxisBaseProjectFinder(Seq(VirtualAxis.jvm)) - override def jsPlatform(scalaVersions: Seq[String]): ProjectMatrix = - jsPlatform(scalaVersions, Nil) - private def enableScalaJSPlugin(project: Project): Project = project.enablePlugins( scalajsPlugin.getOrElse( @@ -474,16 +542,25 @@ object ProjectMatrix { ) ) + override def jsPlatform( + autoScalaLibrary: Boolean, + crossVersion: CrossVersion, + scalaVersions: Seq[String], + axisValues: Seq[VirtualAxis], + settings: Seq[Def.Setting[?]] + ): ProjectMatrix = + customRow(autoScalaLibrary, Some(crossVersion), scalaVersions, VirtualAxis.js +: axisValues): + p => enableScalaJSPlugin(p).settings(settings) + override def jsPlatform( scalaVersions: Seq[String], settings: Seq[Def.Setting[?]] ): ProjectMatrix = - customRow( - true, - scalaVersions, - Seq(VirtualAxis.js), - project => enableScalaJSPlugin(project).settings(settings) - ) + customRow(autoScalaLibrary = true, crossVersion = None, scalaVersions, Seq(VirtualAxis.js)): + p => enableScalaJSPlugin(p).settings(settings) + + override def jsPlatform(crossVersion: CrossVersion, scalaVersions: Seq[String]): ProjectMatrix = + jsPlatform(autoScalaLibrary = true, crossVersion, scalaVersions, Nil, Nil) override def jsPlatform( scalaVersions: Seq[String], @@ -491,11 +568,12 @@ object ProjectMatrix { settings: Seq[Def.Setting[?]] ): ProjectMatrix = customRow( - true, + autoScalaLibrary = true, + crossVersion = None, scalaVersions, - VirtualAxis.js +: axisValues, - project => enableScalaJSPlugin(project).settings(settings) - ) + VirtualAxis.js +: axisValues + ): p => + enableScalaJSPlugin(p).settings(settings) override def jsPlatform( scalaVersions: Seq[String], @@ -503,11 +581,15 @@ object ProjectMatrix { configure: Project => Project ): ProjectMatrix = customRow( - true, + autoScalaLibrary = true, + crossVersion = None, scalaVersions, - VirtualAxis.js +: axisValues, - project => configure(enableScalaJSPlugin(project)) - ) + VirtualAxis.js +: axisValues + ): p => + configure(enableScalaJSPlugin(p)) + + override def jsPlatform(scalaVersions: Seq[String]): ProjectMatrix = + jsPlatform(scalaVersions, Nil) override def defaultAxes(axes: VirtualAxis*): ProjectMatrix = copy(defAxes = axes.toSeq) @@ -523,9 +605,6 @@ object ProjectMatrix { override def native: ProjectFinder = new AxisBaseProjectFinder(Seq(VirtualAxis.native)) - override def nativePlatform(scalaVersions: Seq[String]): ProjectMatrix = - nativePlatform(scalaVersions, Nil) - private def enableScalaNativePlugin(project: Project): Project = project.enablePlugins( nativePlugin.getOrElse( @@ -537,16 +616,38 @@ object ProjectMatrix { ) ) + override def nativePlatform( + autoScalaLibrary: Boolean, + crossVersion: CrossVersion, + scalaVersions: Seq[String], + axisValues: Seq[VirtualAxis], + settings: Seq[Def.Setting[?]] + ): ProjectMatrix = + customRow( + autoScalaLibrary, + Some(crossVersion), + scalaVersions, + VirtualAxis.native +: axisValues + ): p => + enableScalaNativePlugin(p).settings(settings) + override def nativePlatform( scalaVersions: Seq[String], settings: Seq[Def.Setting[?]] ): ProjectMatrix = customRow( - true, + autoScalaLibrary = true, + crossVersion = None, scalaVersions, - Seq(VirtualAxis.native), - project => enableScalaNativePlugin(project).settings(settings) - ) + Seq(VirtualAxis.native) + ): p => + enableScalaNativePlugin(p).settings(settings) + + override def nativePlatform( + crossVersion: CrossVersion, + scalaVersions: Seq[String] + ): ProjectMatrix = + nativePlatform(autoScalaLibrary = true, crossVersion, scalaVersions, Nil, Nil) override def nativePlatform( scalaVersions: Seq[String], @@ -554,11 +655,12 @@ object ProjectMatrix { settings: Seq[Def.Setting[?]] ): ProjectMatrix = customRow( - true, + autoScalaLibrary = true, + crossVersion = None, scalaVersions, - VirtualAxis.native +: axisValues, - project => enableScalaNativePlugin(project).settings(settings) - ) + VirtualAxis.native +: axisValues + ): p => + enableScalaNativePlugin(p).settings(settings) override def nativePlatform( scalaVersions: Seq[String], @@ -566,11 +668,15 @@ object ProjectMatrix { configure: Project => Project ): ProjectMatrix = customRow( - true, + autoScalaLibrary = true, + crossVersion = None, scalaVersions, - VirtualAxis.native +: axisValues, - project => configure(enableScalaNativePlugin(project)) - ) + VirtualAxis.native +: axisValues + ): p => + configure(enableScalaNativePlugin(p)) + + override def nativePlatform(scalaVersions: Seq[String]): ProjectMatrix = + nativePlatform(scalaVersions, Nil) def nativePlugin: Try[AutoPlugin] = { import ReflectionUtil.* @@ -606,23 +712,59 @@ object ProjectMatrix { .getOrElse(sys.error(s"project matching $axisValues and $autoScalaLibrary was not found")) } + /** + * If autoScalaLibrary is false, add non-Scala row. + * Otherwise, add custom rows for each scalaVersions. + */ + override def customRow( + autoScalaLibrary: Boolean, + crossVersion: Option[CrossVersion], + scalaVersions: Seq[String], + axisValues: Seq[VirtualAxis] + )( + process: Project => Project + ): ProjectMatrix = + val process1 = crossVersion match + case Some(cv) => (p: Project) => process(p.settings(Keys.crossVersion := cv)) + case None => process + if autoScalaLibrary then + scalaVersions.foldLeft(this: ProjectMatrix): (acc, sv) => + val scalaAxis = + if crossVersion == Some(CrossVersion.full) then VirtualAxis.scalaVersionAxis(sv, sv) + else VirtualAxis.scalaABIVersion(sv) + acc.customRow(autoScalaLibrary, axisValues ++ Seq(scalaAxis), process1) + else customRow(autoScalaLibrary, axisValues ++ Seq(VirtualAxis.jvm), process1) + + override def customRow( + autoScalaLibrary: Boolean, + axisValues: Seq[VirtualAxis], + process: Project => Project + ): ProjectMatrix = + val newRow: ProjectRow = ProjectRow(autoScalaLibrary, axisValues, process) + copy(rows = this.rows :+ newRow) + override def customRow( scalaVersions: Seq[String], axisValues: Seq[VirtualAxis], settings: Seq[Def.Setting[?]] - ): ProjectMatrix = customRow(true, scalaVersions, axisValues, { _.settings(settings) }) + ): ProjectMatrix = + customRow(autoScalaLibrary = true, crossVersion = None, scalaVersions, axisValues): p => + p.settings(settings) override def customRow( autoScalaLibrary: Boolean, axisValues: Seq[VirtualAxis], settings: Seq[Def.Setting[?]] - ): ProjectMatrix = customRow(autoScalaLibrary, Nil, axisValues, { _.settings(settings) }) + ): ProjectMatrix = + customRow(autoScalaLibrary, crossVersion = None, Nil, axisValues): (p) => + p.settings(settings) override def customRow( scalaVersions: Seq[String], axisValues: Seq[VirtualAxis], process: Project => Project - ): ProjectMatrix = customRow(true, scalaVersions, axisValues, process) + ): ProjectMatrix = + customRow(autoScalaLibrary = true, crossVersion = None, scalaVersions, axisValues)(process) override def customRow( autoScalaLibrary: Boolean, @@ -630,26 +772,7 @@ object ProjectMatrix { axisValues: Seq[VirtualAxis], process: Project => Project ): ProjectMatrix = - if (autoScalaLibrary) { - scalaVersions.foldLeft(this: ProjectMatrix) { (acc, sv) => - acc.customRow( - autoScalaLibrary, - axisValues ++ Seq(VirtualAxis.scalaABIVersion(sv)), - process - ) - } - } else { - customRow(autoScalaLibrary, axisValues ++ Seq(VirtualAxis.jvm), process) - } - - override def customRow( - autoScalaLibrary: Boolean, - axisValues: Seq[VirtualAxis], - process: Project => Project - ): ProjectMatrix = { - val newRow: ProjectRow = new ProjectRow(autoScalaLibrary, axisValues, process) - copy(rows = this.rows :+ newRow) - } + customRow(autoScalaLibrary, crossVersion = None, scalaVersions, axisValues)(process) override def finder(axisValues: VirtualAxis*): ProjectFinder = new AxisBaseProjectFinder(axisValues.toSeq) diff --git a/sbt-app/src/sbt-test/project-matrix/full/build.sbt b/sbt-app/src/sbt-test/project-matrix/full/build.sbt new file mode 100644 index 000000000..804759a5b --- /dev/null +++ b/sbt-app/src/sbt-test/project-matrix/full/build.sbt @@ -0,0 +1,49 @@ +lazy val scala3_LTS = "3.3.5" +lazy val scala3_current = "3.7.4" +lazy val check = taskKey[Unit]("") + +organization := "com.example" +version := "0.1.0-SNAPSHOT" + +lazy val root = (project in file(".")) + .aggregate((core.projectRefs ++ app.projectRefs)*) + .settings( + ) + +lazy val app = (projectMatrix in file("app")) + .aggregate(core, intf) + .dependsOn(core, intf) + .settings( + name := "app", + ) + .jvmPlatform( + crossVersion = CrossVersion.full, + scalaVersions = Seq(scala3_LTS, scala3_current), + ) + +lazy val core = (projectMatrix in file("core")) + .settings( + check := { + assert(moduleName.value == "core", s"moduleName is ${moduleName.value}") + assert(projectMatrixBaseDirectory.value == file("core")) + assert(projectID.value.crossVersion == CrossVersion.full, s"crossVersion is ${projectID.value.crossVersion}") + }, + ) + .jvmPlatform( + crossVersion = CrossVersion.full, + scalaVersions = Seq(scala3_LTS, scala3_current) + ) + +lazy val intf = (projectMatrix in file("intf")) + .settings( + check := { + assert(moduleName.value == "intf", s"moduleName is ${moduleName.value}") + assert(projectMatrixBaseDirectory.value == file("intf")) + }, + ) + .jvmPlatform( + autoScalaLibrary = false, + crossVersion = CrossVersion.disabled, + ) + +lazy val core_3_LTS = core.jvm(scala3_LTS) diff --git a/sbt-app/src/sbt-test/project-matrix/full/test b/sbt-app/src/sbt-test/project-matrix/full/test new file mode 100644 index 000000000..687e928db --- /dev/null +++ b/sbt-app/src/sbt-test/project-matrix/full/test @@ -0,0 +1,4 @@ +> packageBin +$ exists target/**/app_3.3.5-0.1.0-SNAPSHOT.jar +$ exists target/**/app_3.7.4-0.1.0-SNAPSHOT.jar +> core3_7_4/check