Skip to content

Commit 619ba91

Browse files
authored
Merge pull request #712 from mkurz/sbt2
sbt 2 cross build
2 parents 5d17c2b + 89cd5d6 commit 619ba91

4 files changed

Lines changed: 112 additions & 32 deletions

File tree

.github/workflows/build-test.yml

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,29 @@ jobs:
5252
- "check-docs"
5353
uses: playframework/.github/.github/workflows/cmd.yml@v4
5454
with:
55-
java: 21, 17
56-
scala: 2.13.18, 3.3.6
55+
matrix: |
56+
java:
57+
- '21'
58+
- '17'
59+
include:
60+
- plugin_scala: 2.12.x
61+
app_scala: 2.13.x
62+
- plugin_scala: 2.12.x
63+
app_scala: 3.x
64+
- plugin_scala: 3.x
65+
app_scala: 2.13.x
66+
- plugin_scala: 3.x
67+
app_scala: 3.x
5768
cmd: >-
5869
sbt "
59-
+publishLocal;
60-
set plugin/scriptedLaunchOpts += \"-Dscala.version=$MATRIX_SCALA\";
70+
++ $MATRIX_PLUGIN_SCALA;
71+
set plugin/scriptedLaunchOpts += \"-Dscripted.scala.version=$MATRIX_APP_SCALA\";
6172
show scriptedSbt;
6273
show scriptedLaunchOpts;
6374
plugin/scripted;
6475
"
76+
# Alternative:
77+
# sbt -Dscripted.scala.version=$MATRIX_APP_SCALA "++ $MATRIX_PLUGIN_SCALA" plugin/scripted
6578

6679
finish:
6780
name: Finish

build.sbt

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
import Dependencies.ScalaVersions.scala212
44
import Dependencies.ScalaVersions.scala213
5-
import Dependencies.ScalaVersions.scala3
5+
import Dependencies.ScalaVersions.scala3App
6+
import Dependencies.ScalaVersions.scala3Plugin
67
import Dependencies.Versions
78
import com.typesafe.tools.mima.core._
89
import sbt.Append.appendSeq
@@ -32,7 +33,7 @@ lazy val root = project
3233
.aggregate(core, plugin)
3334
.disablePlugins(MimaPlugin)
3435
.settings(
35-
scalaVersion := scala3,
36+
scalaVersion := scala3App,
3637
name := "play-ebean-root",
3738
crossScalaVersions := Nil,
3839
publish / skip := true,
@@ -52,7 +53,7 @@ lazy val core = project
5253
.settings(
5354
name := "play-ebean",
5455
scalaVersion := scala213,
55-
crossScalaVersions := Seq(scala213, scala3),
56+
crossScalaVersions := Seq(scala213, scala3App),
5657
Dependencies.ebean,
5758
mimaSettings,
5859
Compile / compile := enhanceEbeanClasses(
@@ -71,21 +72,53 @@ lazy val plugin = project
7172
organization := "org.playframework",
7273
Dependencies.plugin,
7374
addSbtPlugin("org.playframework" % "sbt-plugin" % Versions.play),
74-
scalaVersion := scala212,
75-
crossScalaVersions := Seq(scala212),
75+
scalaVersion := scala212,
76+
crossScalaVersions := Seq(scala212, scala3Plugin),
77+
pluginCrossBuild / sbtVersion := {
78+
scalaBinaryVersion.value match {
79+
case "2.12" => "1.12.9"
80+
case _ => "2.0.0-RC11"
81+
}
82+
},
83+
scalacOptions ++= {
84+
CrossVersion.partialVersion(scalaVersion.value) match {
85+
case Some((2, _)) => Seq("-Xsource:3")
86+
case _ => Seq.empty
87+
}
88+
},
7689
mimaPreviousArtifacts := Set.empty,
7790
Compile / resourceGenerators += generateVersionFile.taskValue,
91+
// Use the current lane-based app Scala as a fallback for local runs without scripted.scala.version.
7892
scriptedLaunchOpts ++= Seq(
7993
s"-Dproject.version=${version.value}",
94+
s"-Dscala.version=${resolveScriptedScala(
95+
sys.props.getOrElse(
96+
"scripted.scala.version",
97+
if (scalaBinaryVersion.value == "2.12") scala213 else scala3App
98+
)
99+
)}",
80100
),
81101
scriptedBufferLog := false,
82-
scriptedDependencies := ((): Unit),
102+
scriptedDependencies := Def
103+
.sequential(
104+
core / publishLocal,
105+
publishLocal
106+
)
107+
.value,
83108
)
84109
.settings(
85110
(Compile / headerSources) ++=
86111
(sourceDirectory.value / "sbt-test" ** ("*.java" || "*.sbt")).get
87112
)
88113

114+
def resolveScriptedScala(version: String): String =
115+
version match {
116+
case "scala212" | "2.12.x" => scala212
117+
case "scala213" | "2.13.x" => scala213
118+
case "scala3" | "3.x" => scala3App
119+
case exact => exact
120+
}
121+
89122
def sbtPluginDep(moduleId: ModuleID, sbtVersion: String, scalaVersion: String) = {
90123
Defaults.sbtPluginExtra(
91124
moduleId,

project/Dependencies.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ import sbt._
99
object Dependencies {
1010

1111
object ScalaVersions {
12-
val scala212 = "2.12.21"
13-
val scala213 = "2.13.18"
14-
val scala3 = "3.3.7"
12+
val scala212 = "2.12.21"
13+
val scala213 = "2.13.18"
14+
val scala3App = "3.8.3"
15+
val scala3Plugin = scala3App
1516
}
1617

1718
object Versions {
18-
val play: String = "3.1.0-M4"
19+
val play: String = "3.1.0-M8"
1920
val ebean = "17.3.0"
2021
val typesafeConfig = "1.4.6"
2122
}

sbt-play-ebean/src/main/scala/play/ebean/sbt/PlayEbean.scala

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ package play.ebean.sbt
77
import java.net.URLClassLoader
88
import io.ebean.enhance.Transformer
99
import io.ebean.enhance.ant.OfflineFileTransform
10+
import play.sbt.PluginCompat
1011
import sbt.Keys._
1112
import sbt.internal.inc.FarmHash
1213
import sbt.internal.inc.LastModified
13-
import sbt.internal.inc.PlainVirtualFileConverter
1414
import sbt.internal.inc.Stamper
1515
import sbt.AutoPlugin
1616
import sbt.Compile
@@ -19,41 +19,71 @@ import sbt.Task
1919
import sbt.inConfig
2020
import sbt.settingKey
2121
import sbt.taskKey
22+
import xsbti.FileConverter
23+
import xsbti.VirtualFileRef
2224
import xsbti.compile.CompileResult
2325
import xsbti.compile.analysis.Stamp
2426
import sbt._
25-
import xsbti.VirtualFileRef
26-
import scala.util.control.NonFatal
2727

2828
object PlayEbean extends AutoPlugin {
2929

3030
object autoImport {
31+
@transient
3132
val playEbeanModels = taskKey[Seq[String]]("The packages that should be searched for ebean models to enhance.")
3233
val playEbeanVersion =
3334
settingKey[String]("The version of Play ebean that should be added to the library dependencies.")
3435
val playEbeanDebugLevel = settingKey[Int](
3536
"The debug level to use for the ebean agent. The higher, the more debug is output, with 9 being the most. -1 turns debugging off."
3637
)
38+
@transient
3739
val playEbeanAgentArgs = taskKey[Map[String, String]]("The arguments to pass to the agent.")
3840
}
3941

4042
import autoImport._
4143

4244
override def trigger = noTrigger
4345

44-
override def projectSettings: Seq[Def.Setting[_]] = inConfig(Compile)(scopedSettings) ++ unscopedSettings
46+
override def projectSettings: Seq[Def.Setting[?]] = inConfig(Compile)(scopedSettings) ++ unscopedSettings
4547

46-
def scopedSettings: Seq[Def.Setting[_]] =
48+
def scopedSettings: Seq[Def.Setting[?]] =
4749
Seq(
48-
playEbeanModels := configuredEbeanModels.value,
49-
manipulateBytecode := ebeanEnhance.value
50+
playEbeanModels := PluginCompat.uncached { configuredEbeanModels.value },
51+
manipulateBytecode := PluginCompat.uncached { ebeanEnhance.value },
52+
// sbt 2 / Play can reach compiled classes through these tasks without running compile first,
53+
// so make them trigger enhancement too.
54+
products := {
55+
manipulateBytecode.value
56+
products.value
57+
},
58+
productDirectories := {
59+
manipulateBytecode.value
60+
productDirectories.value
61+
},
62+
exportedProducts := PluginCompat.uncached {
63+
manipulateBytecode.value
64+
exportedProducts.value
65+
},
66+
fullClasspath := PluginCompat.uncached {
67+
manipulateBytecode.value
68+
fullClasspath.value
69+
}
5070
)
5171

52-
def unscopedSettings: Seq[Def.Setting[_]] =
72+
def unscopedSettings: Seq[Def.Setting[?]] =
5373
Seq(
5474
playEbeanDebugLevel := -1,
5575
playEbeanAgentArgs := Map("debug" -> playEbeanDebugLevel.value.toString),
5676
playEbeanVersion := readResourceProperty("play-ebean.version.properties", "play-ebean.version"),
77+
// Test tasks need the already-enhanced main classes on their classpath, otherwise sbt 2
78+
// can run tests against non-enhanced entities even though Compile / manipulateBytecode exists.
79+
Test / dependencyClasspath := PluginCompat.uncached {
80+
(Compile / manipulateBytecode).value
81+
(Test / dependencyClasspath).value
82+
},
83+
Test / fullClasspath := PluginCompat.uncached {
84+
(Compile / manipulateBytecode).value
85+
(Test / fullClasspath).value
86+
},
5787
libraryDependencies ++=
5888
Seq(
5989
"org.playframework" %% "play-ebean" % playEbeanVersion.value,
@@ -73,30 +103,30 @@ object PlayEbean extends AutoPlugin {
73103
val agentArgs = playEbeanAgentArgs.value
74104
val analysis = result.analysis.asInstanceOf[sbt.internal.inc.Analysis]
75105
val agentArgsString = agentArgs.map { case (key, value) => s"$key=$value" }.mkString(";")
106+
val converter = fileConverter.value
107+
val models = playEbeanModels.value
76108

77109
val originalContextClassLoader = Thread.currentThread.getContextClassLoader
78110

79111
try {
80-
val classpath = deps.map(_.data.toURI.toURL).toArray :+ classes.toURI.toURL
112+
implicit val fileConverterCompat: FileConverter = converter
113+
val classpath =
114+
(deps.map(dep => PluginCompat.toNioPath(dep.data).toUri.toURL).toVector :+ classes.toURI.toURL)
115+
.toArray[java.net.URL]
81116
val classLoader = new URLClassLoader(classpath, null)
82117

83118
Thread.currentThread.setContextClassLoader(classLoader)
84119

85120
val transformer = new Transformer(classLoader, agentArgsString)
86121
val fileTransform = new OfflineFileTransform(transformer, classLoader, classes.getAbsolutePath)
87122

88-
try {
89-
fileTransform.process(playEbeanModels.value.mkString(","))
90-
} catch {
91-
case NonFatal(_) =>
92-
}
123+
fileTransform.process(models.mkString(","))
93124

94125
} finally {
95126
Thread.currentThread.setContextClassLoader(originalContextClassLoader)
96127
}
97128

98129
val allProducts = analysis.relations.allProducts
99-
val converter = new PlainVirtualFileConverter()
100130

101131
/**
102132
* Updates stamp of product (class file) by preserving the type of a passed stamp. This way any stamp incremental
@@ -136,9 +166,12 @@ object PlayEbean extends AutoPlugin {
136166
// Creates a classloader with all the dependencies and all the resources, from there we can use the play ebean
137167
// code to load the config as it would be loaded in production
138168
def withClassLoader[T](block: ClassLoader => T): T = {
139-
val classpath =
140-
unmanagedResourceDirectories.value.map(_.toURI.toURL) ++ dependencyClasspath.value.map(_.data.toURI.toURL)
141-
val classLoader = new URLClassLoader(classpath.toArray, null)
169+
val converter = fileConverter.value
170+
implicit val fileConverterCompat: FileConverter = converter
171+
val classpath =
172+
unmanagedResourceDirectories.value.map(_.toURI.toURL) ++
173+
dependencyClasspath.value.map(dep => PluginCompat.toNioPath(dep.data).toUri.toURL)
174+
val classLoader = new URLClassLoader(classpath.toArray[java.net.URL], null)
142175
try {
143176
block(classLoader)
144177
} catch {

0 commit comments

Comments
 (0)