From d7859cac48a777e9b4430b7299b9044c722eb3fa Mon Sep 17 00:00:00 2001 From: Lorenzo Gabriele Date: Tue, 7 Nov 2023 15:01:31 +0100 Subject: [PATCH] Support Play Framework 3.0 and 2.9 (#2772) - Update Play 2.8 to 2.8.20 - Add default `twirlVersion` for play based on `playVersion` - Add default `twirlScalaVersion` based on `twirlVersion` Pull request: https://github.com/com-lihaoyi/mill/pull/2772 --- build.sc | 22 ++- .../api/src/mill/playlib/api/Versions.java | 2 + contrib/playlib/readme.adoc | 45 +++-- .../playlib/src/mill/playlib/PlayModule.scala | 14 +- .../src/mill/playlib/RouterModule.scala | 9 +- .../playlib/src/mill/playlib/Version.scala | 8 +- .../resources/hello-world/core/routes/routes | 2 +- .../test/resources/invalid/core/routes/routes | 2 +- .../resources/invalidsub/core/routes/routes | 2 +- .../test/resources/playmulti/core/conf/routes | 2 +- .../test/resources/playsingle/conf/routes | 2 +- .../test/resources/playsingleapi/conf/routes | 2 +- .../src/mill/playlib/PlayModuleTests.scala | 75 +++++---- .../playlib/PlaySingleApiModuleTests.scala | 3 +- .../mill/playlib/PlaySingleModuleTests.scala | 5 +- .../test/src/mill/playlib/PlayTestSuite.scala | 19 ++- .../src/mill/playlib/RouterModuleTests.scala | 140 ++++++++-------- .../playlib/worker/RouteCompilerWorker.scala | 3 + .../playlib/worker/RouteCompilerWorker.scala | 3 + .../src/mill/twirllib/TwirlModule.scala | 22 ++- .../src/mill/twirllib/HelloWorldTests.scala | 156 ++++++++++-------- 21 files changed, 312 insertions(+), 226 deletions(-) create mode 100644 contrib/playlib/worker/2.9/src/mill/playlib/worker/RouteCompilerWorker.scala create mode 100644 contrib/playlib/worker/3.0/src/mill/playlib/worker/RouteCompilerWorker.scala diff --git a/build.sc b/build.sc index 34dd901eecd..f20ab37e308 100644 --- a/build.sc +++ b/build.sc @@ -61,6 +61,7 @@ object Deps { val testScala30Version = "3.0.2" val testScala31Version = "3.1.3" val testScala32Version = "3.2.0" + val testScala33Version = "3.3.1" object Scalajs_1 { val scalaJsVersion = "1.14.0" @@ -84,7 +85,11 @@ object Deps { trait Play { def playVersion: String def playBinVersion: String = playVersion.split("[.]").take(2).mkString(".") - def routesCompiler = ivy"com.typesafe.play::routes-compiler::$playVersion" + def routesCompiler = playBinVersion match { + case "2.6" | "2.7" | "2.8" => ivy"com.typesafe.play::routes-compiler::$playVersion" + case "2.9" => ivy"com.typesafe.play::play-routes-compiler::$playVersion" + case _ => ivy"org.playframework::play-routes-compiler::$playVersion" + } def scalaVersion: String = Deps.scalaVersion } object Play_2_6 extends Play { @@ -95,9 +100,15 @@ object Deps { val playVersion = "2.7.9" } object Play_2_8 extends Play { - val playVersion = "2.8.19" + val playVersion = "2.8.20" + } + object Play_2_9 extends Play { + val playVersion = "2.9.0" + } + object Play_3_0 extends Play { + val playVersion = "3.0.0" } - val play = Seq(Play_2_8, Play_2_7, Play_2_6).map(p => (p.playBinVersion, p)).toMap + val play = Seq(Play_3_0, Play_2_9, Play_2_8, Play_2_7, Play_2_6).map(p => (p.playBinVersion, p)).toMap val acyclic = ivy"com.lihaoyi:::acyclic:0.3.9" val ammoniteVersion = "3.0.0-M0-53-084f7f4e" @@ -352,6 +363,7 @@ trait MillBaseTestsModule extends MillJavaModule with TestModule { s"-DTEST_SCALA_3_0_VERSION=${Deps.testScala30Version}", s"-DTEST_SCALA_3_1_VERSION=${Deps.testScala31Version}", s"-DTEST_SCALA_3_2_VERSION=${Deps.testScala32Version}", + s"-DTEST_SCALA_3_3_VERSION=${Deps.testScala33Version}", s"-DTEST_SCALAJS_VERSION=${Deps.Scalajs_1.scalaJsVersion}", s"-DTEST_SCALANATIVE_VERSION=${Deps.Scalanative_0_4.scalanativeVersion}", s"-DTEST_UTEST_VERSION=${Deps.utest.dep.version}", @@ -739,7 +751,9 @@ object contrib extends Module { Seq( s"-DTEST_PLAY_VERSION_2_6=${Deps.Play_2_6.playVersion}", s"-DTEST_PLAY_VERSION_2_7=${Deps.Play_2_7.playVersion}", - s"-DTEST_PLAY_VERSION_2_8=${Deps.Play_2_8.playVersion}" + s"-DTEST_PLAY_VERSION_2_8=${Deps.Play_2_8.playVersion}", + s"-DTEST_PLAY_VERSION_2_9=${Deps.Play_2_9.playVersion}", + s"-DTEST_PLAY_VERSION_3_0=${Deps.Play_3_0.playVersion}" ) } diff --git a/contrib/playlib/api/src/mill/playlib/api/Versions.java b/contrib/playlib/api/src/mill/playlib/api/Versions.java index cf70aff9e94..9c31b143eba 100644 --- a/contrib/playlib/api/src/mill/playlib/api/Versions.java +++ b/contrib/playlib/api/src/mill/playlib/api/Versions.java @@ -4,4 +4,6 @@ public class Versions { public static final String PLAY_2_6 = "2.6"; public static final String PLAY_2_7 = "2.7"; public static final String PLAY_2_8 = "2.8"; + public static final String PLAY_2_9 = "2.9"; + public static final String PLAY_3_0 = "3.0"; } diff --git a/contrib/playlib/readme.adoc b/contrib/playlib/readme.adoc index 166fa3299ca..11275247940 100644 --- a/contrib/playlib/readme.adoc +++ b/contrib/playlib/readme.adoc @@ -47,10 +47,9 @@ import mill._ import $ivy.`com.lihaoyi::mill-contrib-playlib:`, mill.playlib._ object core extends PlayModule { - //config - override def scalaVersion= T{"2.13.8"} - override def playVersion= T{"2.8.16"} - override def twirlVersion= T{"1.5.1"} + // config + override def scalaVersion = T { "2.13.12" } + override def playVersion = T { "2.8.20" } object test extends PlayTests } @@ -108,18 +107,18 @@ ivy"com.typesafe.play::play-akka-http-server:${playVersion()}" === Using `PlayApiModule` The `PlayApiModule` trait behaves the same as the `PlayModule` trait but it won't process .scala -.html files and you don't need to define the `twirlVersion: +.html files: .`build.sc` [source,scala] ---- import mill._ -import $ivy.`com.lihaoyi::mill-contrib-playlib:$MILL_VERSION`, mill.playlib._ +import $ivy.`com.lihaoyi::mill-contrib-playlib:`, mill.playlib._ object core extends PlayApiModule { - //config - override def scalaVersion= T{"2.13.8"} - override def playVersion= T{"2.8.16"} + // config + override def scalaVersion = T { "2.13.12" } + override def playVersion = T { "2.8.20" } object test extends PlayTests } @@ -154,9 +153,9 @@ import mill._ import $ivy.`com.lihaoyi::mill-contrib-playlib:$MILL_VERSION`, mill.playlib._ object core extends PlayApiModule { - //config - override def scalaVersion= T{"2.13.8"} - override def playVersion= T{"2.8.16"} + // config + override def scalaVersion = T{ "2.13.12" } + override def playVersion = T{ "2.8.20" } object test extends PlayTests @@ -192,13 +191,12 @@ Looking back at the sample build definition in <<_using_playmodule>>: [source,scala] ---- import mill._ -import $ivy.`com.lihaoyi::mill-contrib-playlib:$MILL_VERSION`, mill.playlib._ +import $ivy.`com.lihaoyi::mill-contrib-playlib:`, mill.playlib._ object core extends PlayModule { - //config - override def scalaVersion= T{"2.13.8"} - override def playVersion= T{"2.8.16"} - override def twirlVersion= T{"1.5.1"} + // config + override def scalaVersion = T { "2.13.12" } + override def playVersion = T { "2.8.20" } object test extends PlayTests } @@ -236,10 +234,9 @@ import mill._ import $ivy.`com.lihaoyi::mill-contrib-playlib:`, mill.playlib._ object core extends PlayModule with SingleModule { - //config - override def scalaVersion= T{"2.13.8"} - override def playVersion= T{"2.8.16"} - override def twirlVersion= T{"1.5.1"} + // config + override def scalaVersion = T { "2.13.12" } + override def playVersion = T { "2.8.20" } object test extends PlayTests } @@ -281,8 +278,8 @@ import mill._ import $ivy.`com.lihaoyi::mill-contrib-playlib:`, mill.playlib._ object app extends ScalaModule with RouterModule { - def playVersion= T{"2.8.16"} - def scalaVersion= T{"2.13.8"} + def playVersion = T{ "2.8.20" } + def scalaVersion = T { "2.13.12" } } ---- @@ -336,7 +333,7 @@ import mill.scalalib._ import $ivy.`com.lihaoyi::mill-contrib-playlib:$MILL_VERSION`, mill.playlib._ object app extends ScalaModule with RouterModule { - def playVersion = "2.8.16" + def playVersion = "2.8.20" override def routesAdditionalImport = Seq("my.additional.stuff._", "my.other.stuff._") } ---- diff --git a/contrib/playlib/src/mill/playlib/PlayModule.scala b/contrib/playlib/src/mill/playlib/PlayModule.scala index eed15cec625..9984dde87c2 100644 --- a/contrib/playlib/src/mill/playlib/PlayModule.scala +++ b/contrib/playlib/src/mill/playlib/PlayModule.scala @@ -12,6 +12,8 @@ trait PlayApiModule extends Dependencies with Router with Server { case Versions.PLAY_2_6 => "3.1.3" case Versions.PLAY_2_7 => "4.0.3" case Versions.PLAY_2_8 => "5.1.0" + case Versions.PLAY_2_9 => "6.0.0" + case _ => "7.0.0" } Agg(ivy"org.scalatestplus.play::scalatestplus-play::${scalatestPlusPlayVersion}") } @@ -21,4 +23,14 @@ trait PlayApiModule extends Dependencies with Router with Server { def start(args: Task[Args] = T.task(Args())) = T.command { run(args) } } -trait PlayModule extends PlayApiModule with Static with Twirl +trait PlayModule extends PlayApiModule with Static with Twirl { + override def twirlVersion = T { + playMinorVersion() match { + case "2.6" => "1.3.16" + case "2.7" => "1.4.2" + case "2.8" => "1.5.1" + case "2.9" => "1.6.2" + case _ => "2.0.1" + } + } +} diff --git a/contrib/playlib/src/mill/playlib/RouterModule.scala b/contrib/playlib/src/mill/playlib/RouterModule.scala index 3b9ee6cc03c..07a20c05ac1 100644 --- a/contrib/playlib/src/mill/playlib/RouterModule.scala +++ b/contrib/playlib/src/mill/playlib/RouterModule.scala @@ -48,7 +48,14 @@ trait RouterModule extends ScalaModule with Version { def routerClasspath: T[Agg[PathRef]] = T { resolveDeps(T.task { val bind = bindDependency() - Agg(ivy"com.typesafe.play::routes-compiler:${playVersion()}").map(bind) + playMinorVersion() match { + case "2.6" | "2.7" | "2.8" => + Agg(ivy"com.typesafe.play::routes-compiler:${playVersion()}").map(bind) + case "2.9" => + Agg(ivy"com.typesafe.play::play-routes-compiler:${playVersion()}").map(bind) + case _ => + Agg(ivy"org.playframework::play-routes-compiler:${playVersion()}").map(bind) + } })() } diff --git a/contrib/playlib/src/mill/playlib/Version.scala b/contrib/playlib/src/mill/playlib/Version.scala index f5d7d9d32ee..d70ae9ae726 100644 --- a/contrib/playlib/src/mill/playlib/Version.scala +++ b/contrib/playlib/src/mill/playlib/Version.scala @@ -9,10 +9,14 @@ private[playlib] trait Version extends Module { def playVersion: T[String] private[playlib] def playMinorVersion: T[String] = T { - playVersion().split("\\.").take(2).mkString(".") + playVersion().split('.').take(2).mkString(".") + } + + private[playlib] def playOrganization: T[String] = T.task { + if (playVersion().startsWith("2.")) "com.typesafe.play" else "org.playframework" } private[playlib] def component(id: String) = T.task { - ivy"com.typesafe.play::$id::${playVersion()}" + ivy"${playOrganization()}::$id::${playVersion()}" } } diff --git a/contrib/playlib/test/resources/hello-world/core/routes/routes b/contrib/playlib/test/resources/hello-world/core/routes/routes index f71b0cdd826..230c627d528 100644 --- a/contrib/playlib/test/resources/hello-world/core/routes/routes +++ b/contrib/playlib/test/resources/hello-world/core/routes/routes @@ -1,3 +1,3 @@ -GET / controllers.HomeController.index +GET / controllers.HomeController.index() GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) -> /sub sub.Routes \ No newline at end of file diff --git a/contrib/playlib/test/resources/invalid/core/routes/routes b/contrib/playlib/test/resources/invalid/core/routes/routes index 5c946fc63b4..35ec45f9c84 100644 --- a/contrib/playlib/test/resources/invalid/core/routes/routes +++ b/contrib/playlib/test/resources/invalid/core/routes/routes @@ -1,4 +1,4 @@ -GET / controllers.HomeController.index +GET / controllers.HomeController.index() -> /sub sub.Routes GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) BOB =error controllers.HomeController.error(foo) \ No newline at end of file diff --git a/contrib/playlib/test/resources/invalidsub/core/routes/routes b/contrib/playlib/test/resources/invalidsub/core/routes/routes index 5c946fc63b4..35ec45f9c84 100644 --- a/contrib/playlib/test/resources/invalidsub/core/routes/routes +++ b/contrib/playlib/test/resources/invalidsub/core/routes/routes @@ -1,4 +1,4 @@ -GET / controllers.HomeController.index +GET / controllers.HomeController.index() -> /sub sub.Routes GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) BOB =error controllers.HomeController.error(foo) \ No newline at end of file diff --git a/contrib/playlib/test/resources/playmulti/core/conf/routes b/contrib/playlib/test/resources/playmulti/core/conf/routes index 2ac6b3366eb..60e8169b9c0 100644 --- a/contrib/playlib/test/resources/playmulti/core/conf/routes +++ b/contrib/playlib/test/resources/playmulti/core/conf/routes @@ -4,7 +4,7 @@ # ~~~~ # An example controller showing a sample home page -GET / controllers.HomeController.index +GET / controllers.HomeController.index() # Map static resources from the /public folder to the /assets URL path GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) diff --git a/contrib/playlib/test/resources/playsingle/conf/routes b/contrib/playlib/test/resources/playsingle/conf/routes index 2ac6b3366eb..60e8169b9c0 100644 --- a/contrib/playlib/test/resources/playsingle/conf/routes +++ b/contrib/playlib/test/resources/playsingle/conf/routes @@ -4,7 +4,7 @@ # ~~~~ # An example controller showing a sample home page -GET / controllers.HomeController.index +GET / controllers.HomeController.index() # Map static resources from the /public folder to the /assets URL path GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) diff --git a/contrib/playlib/test/resources/playsingleapi/conf/routes b/contrib/playlib/test/resources/playsingleapi/conf/routes index 2ac6b3366eb..60e8169b9c0 100644 --- a/contrib/playlib/test/resources/playsingleapi/conf/routes +++ b/contrib/playlib/test/resources/playsingleapi/conf/routes @@ -4,7 +4,7 @@ # ~~~~ # An example controller showing a sample home page -GET / controllers.HomeController.index +GET / controllers.HomeController.index() # Map static resources from the /public folder to the /assets URL path GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) diff --git a/contrib/playlib/test/src/mill/playlib/PlayModuleTests.scala b/contrib/playlib/test/src/mill/playlib/PlayModuleTests.scala index 03e505b9d87..138d6075c10 100644 --- a/contrib/playlib/test/src/mill/playlib/PlayModuleTests.scala +++ b/contrib/playlib/test/src/mill/playlib/PlayModuleTests.scala @@ -12,8 +12,6 @@ object PlayModuleTests extends TestSuite with PlayTestSuite { val (crossScalaVersion, crossPlayVersion) = (crossValue, crossValue2) override def playVersion = crossPlayVersion override def scalaVersion = crossScalaVersion - override def twirlVersion = "1.5.1" - override def twirlScalaVersion = sys.props.getOrElse("MILL_SCALA_2_13_VERSION", ???) object test extends PlayTests override def ivyDeps = T { super.ivyDeps() ++ Agg(ws()) } } @@ -77,41 +75,46 @@ object PlayModuleTests extends TestSuite with PlayTestSuite { } test("compile") { matrix.foreach { case (scalaVersion, playVersion) => - workspaceTest(playmulti) { eval => - val eitherResult = eval.apply(playmulti.core(scalaVersion, playVersion).compile) - val Right((result, evalCount)) = eitherResult - val outputFiles = os.walk(result.classes.path).filter(os.isFile) - val expectedClassfiles = Seq[os.RelPath]( - os.RelPath("controllers/HomeController.class"), - os.RelPath("controllers/ReverseAssets.class"), - os.RelPath("controllers/ReverseHomeController.class"), - os.RelPath("controllers/routes.class"), - os.RelPath("controllers/routes$javascript.class"), - os.RelPath("controllers/javascript/ReverseHomeController.class"), - os.RelPath("controllers/javascript/ReverseAssets.class"), - os.RelPath("router/Routes$$anonfun$routes$1.class"), - os.RelPath("router/Routes.class"), - os.RelPath("router/RoutesPrefix$.class"), - os.RelPath("router/RoutesPrefix.class"), - os.RelPath("views/html/index$.class"), - os.RelPath("views/html/index.class"), - os.RelPath("views/html/main$.class"), - os.RelPath("views/html/main.class") - ).map( - eval.outPath / "core" / scalaVersion / playVersion / "compile.dest" / "classes" / _ - ) - assert( - result.classes.path == eval.outPath / "core" / scalaVersion / playVersion / "compile.dest" / "classes", - outputFiles.nonEmpty, - outputFiles.forall(expectedClassfiles.contains), - outputFiles.size == 15, - evalCount > 0 - ) + skipUnsupportedVersions(playVersion) { + workspaceTest(playmulti) { eval => + val eitherResult = eval.apply(playmulti.core(scalaVersion, playVersion).compile) + val Right((result, evalCount)) = eitherResult + val outputClassFiles = + os.walk(result.classes.path).filter(f => os.isFile(f) && f.ext == "class") - // don't recompile if nothing changed - val Right((_, unchangedEvalCount)) = - eval.apply(playmulti.core(scalaVersion, playVersion).compile) - assert(unchangedEvalCount == 0) + val expectedClassfiles = Seq[os.RelPath]( + os.RelPath("controllers/HomeController.class"), + os.RelPath("controllers/ReverseAssets.class"), + os.RelPath("controllers/ReverseHomeController.class"), + os.RelPath("controllers/routes.class"), + os.RelPath("controllers/routes$javascript.class"), + os.RelPath("controllers/javascript/ReverseHomeController.class"), + os.RelPath("controllers/javascript/ReverseAssets.class"), + if (scalaVersion.startsWith("3.")) os.RelPath("router/Routes$$anon$1.class") + else os.RelPath("router/Routes$$anonfun$routes$1.class"), + os.RelPath("router/Routes.class"), + os.RelPath("router/RoutesPrefix$.class"), + os.RelPath("router/RoutesPrefix.class"), + os.RelPath("views/html/index$.class"), + os.RelPath("views/html/index.class"), + os.RelPath("views/html/main$.class"), + os.RelPath("views/html/main.class") + ).map( + eval.outPath / "core" / scalaVersion / playVersion / "compile.dest" / "classes" / _ + ) + assert( + result.classes.path == eval.outPath / "core" / scalaVersion / playVersion / "compile.dest" / "classes", + outputClassFiles.nonEmpty, + outputClassFiles.forall(expectedClassfiles.contains), + outputClassFiles.size == 15, + evalCount > 0 + ) + + // don't recompile if nothing changed + val Right((_, unchangedEvalCount)) = + eval.apply(playmulti.core(scalaVersion, playVersion).compile) + assert(unchangedEvalCount == 0) + } } } } diff --git a/contrib/playlib/test/src/mill/playlib/PlaySingleApiModuleTests.scala b/contrib/playlib/test/src/mill/playlib/PlaySingleApiModuleTests.scala index 865c550984d..a76becc7837 100644 --- a/contrib/playlib/test/src/mill/playlib/PlaySingleApiModuleTests.scala +++ b/contrib/playlib/test/src/mill/playlib/PlaySingleApiModuleTests.scala @@ -8,8 +8,7 @@ object PlaySingleApiModuleTests extends TestSuite with PlayTestSuite { object playsingleapi extends TestUtil.BaseModule with PlayApiModule with SingleModule { override def playVersion = T { testPlay28 } - def twirlVersion = T { "1.5.1" } - override def scalaVersion = T { "2.13.8" } + override def scalaVersion = T { "2.13.12" } object test extends PlayTests } diff --git a/contrib/playlib/test/src/mill/playlib/PlaySingleModuleTests.scala b/contrib/playlib/test/src/mill/playlib/PlaySingleModuleTests.scala index 8dc34e44ce7..5a413b6f896 100644 --- a/contrib/playlib/test/src/mill/playlib/PlaySingleModuleTests.scala +++ b/contrib/playlib/test/src/mill/playlib/PlaySingleModuleTests.scala @@ -8,10 +8,7 @@ object PlaySingleModuleTests extends TestSuite with PlayTestSuite { object playsingle extends TestUtil.BaseModule with PlayModule with SingleModule { override def playVersion = T { testPlay28 } - override def twirlVersion = T { "1.5.1" } - override def twirlScalaVersion: T[String] = - T { sys.props.getOrElse("MILL_SCALA_2_13_VERSION", ???) } - override def scalaVersion = T { sys.props.getOrElse("MILL_SCALA_2_13_VERSION", ???) } + override def scalaVersion = T { sys.props.getOrElse("TEST_SCALA_2_13_VERSION", ???) } object test extends PlayTests } diff --git a/contrib/playlib/test/src/mill/playlib/PlayTestSuite.scala b/contrib/playlib/test/src/mill/playlib/PlayTestSuite.scala index 450208746be..05ac0048cbc 100644 --- a/contrib/playlib/test/src/mill/playlib/PlayTestSuite.scala +++ b/contrib/playlib/test/src/mill/playlib/PlayTestSuite.scala @@ -5,20 +5,33 @@ import utest.framework.TestPath trait PlayTestSuite { - val testScala212 = sys.props.getOrElse("MILL_SCALA_2_12_VERSION", ???) - val testScala213 = sys.props.getOrElse("MILL_SCALA_2_13_VERSION", ???) + val testScala212 = sys.props.getOrElse("TEST_SCALA_2_12_VERSION", ???) + val testScala213 = sys.props.getOrElse("TEST_SCALA_2_13_VERSION", ???) + val testScala3 = sys.props.getOrElse("TEST_SCALA_3_3_VERSION", ???) val testPlay26 = sys.props.getOrElse("TEST_PLAY_VERSION_2_6", ???) val testPlay27 = sys.props.getOrElse("TEST_PLAY_VERSION_2_7", ???) val testPlay28 = sys.props.getOrElse("TEST_PLAY_VERSION_2_8", ???) + val testPlay29 = sys.props.getOrElse("TEST_PLAY_VERSION_2_9", ???) + val testPlay30 = sys.props.getOrElse("TEST_PLAY_VERSION_3_0", ???) val matrix = Seq( (testScala212, testPlay26), (testScala212, testPlay27), (testScala213, testPlay27), - (testScala213, testPlay28) + (testScala213, testPlay28), + (testScala213, testPlay29), + (testScala3, testPlay29), + (testScala213, testPlay30), + (testScala3, testPlay30) ) + def skipUnsupportedVersions(playVersion: String)(test: => Unit) = playVersion match { + case s"2.$minor.$_" if minor.toIntOption.exists(_ < 9) => test + case _ if scala.util.Properties.isJavaAtLeast(11) => test + case _ => System.err.println(s"Skipping since play $playVersion doesn't support Java 8") + } + def resourcePath: os.Path def workspaceTest[T, M <: TestUtil.BaseModule]( diff --git a/contrib/playlib/test/src/mill/playlib/RouterModuleTests.scala b/contrib/playlib/test/src/mill/playlib/RouterModuleTests.scala index 12687c6c19c..84b543c570a 100644 --- a/contrib/playlib/test/src/mill/playlib/RouterModuleTests.scala +++ b/contrib/playlib/test/src/mill/playlib/RouterModuleTests.scala @@ -34,85 +34,91 @@ object RouterModuleTests extends TestSuite with PlayTestSuite { def tests: Tests = Tests { test("compileRouter") { matrix.foreach { case (scalaVersion, playVersion) => - workspaceTest(HelloWorld) { eval => - val eitherResult = eval.apply(HelloWorld.core(scalaVersion, playVersion).compileRouter) - val Right((result, evalCount)) = eitherResult - val outputFiles = os.walk(result.classes.path).filter(os.isFile) - val expectedClassfiles = Seq[os.RelPath]( - os.RelPath("controllers/ReverseRoutes.scala"), - os.RelPath("controllers/routes.java"), - os.RelPath("router/Routes.scala"), - os.RelPath("router/RoutesPrefix.scala"), - os.RelPath("sub/Routes.scala"), - os.RelPath("sub/RoutesPrefix.scala"), - os.RelPath("controllers/javascript/JavaScriptReverseRoutes.scala") - ).map( - eval.outPath / "core" / scalaVersion / playVersion / "compileRouter.dest" / _ - ) - assert( - result.classes.path == eval.outPath / "core" / scalaVersion / playVersion / "compileRouter.dest", - outputFiles.nonEmpty, - outputFiles.forall(expectedClassfiles.contains), - outputFiles.size == 7, - evalCount > 0 - ) + skipUnsupportedVersions(playVersion) { + workspaceTest(HelloWorld) { eval => + val eitherResult = eval.apply(HelloWorld.core(scalaVersion, playVersion).compileRouter) + val Right((result, evalCount)) = eitherResult + val outputFiles = os.walk(result.classes.path).filter(os.isFile) + val expectedClassfiles = Seq[os.RelPath]( + os.RelPath("controllers/ReverseRoutes.scala"), + os.RelPath("controllers/routes.java"), + os.RelPath("router/Routes.scala"), + os.RelPath("router/RoutesPrefix.scala"), + os.RelPath("sub/Routes.scala"), + os.RelPath("sub/RoutesPrefix.scala"), + os.RelPath("controllers/javascript/JavaScriptReverseRoutes.scala") + ).map( + eval.outPath / "core" / scalaVersion / playVersion / "compileRouter.dest" / _ + ) + assert( + result.classes.path == eval.outPath / "core" / scalaVersion / playVersion / "compileRouter.dest", + outputFiles.nonEmpty, + outputFiles.forall(expectedClassfiles.contains), + outputFiles.size == 7, + evalCount > 0 + ) - // don't recompile if nothing changed - val Right((_, unchangedEvalCount)) = - eval.apply(HelloWorld.core(scalaVersion, playVersion).compileRouter) + // don't recompile if nothing changed + val Right((_, unchangedEvalCount)) = + eval.apply(HelloWorld.core(scalaVersion, playVersion).compileRouter) - assert(unchangedEvalCount == 0) + assert(unchangedEvalCount == 0) + } } } } test("compileRouterInvalidRoutes") { matrix.foreach { case (scalaVersion, playVersion) => - workspaceTest(HelloWorld, resourcePath = invalidResourcePath) { eval => - val project = HelloWorld.core(scalaVersion, playVersion) - val eitherResult = eval.apply(project.compileRouter) - val Left(Failure(message, x)) = eitherResult - val playExpectedMessage = - if (playVersion.startsWith("2.6.")) { - "HTTP Verb (GET, POST, ...), include (->), comment (#), or modifier line (+) expected" - } else { - "end of input expected" - } - val expectedMessage = "Unable to compile play routes, compilation error in " + - project.millSourcePath.toIO.getAbsolutePath.replace( - """\""", - "/" - ) + "/routes/routes at line 4, " + - "column" + " 1: " + playExpectedMessage - // fix windows paths - val normalizeMessage = message.replace("""\""", "/") - assert( - normalizeMessage == expectedMessage - ) + skipUnsupportedVersions(playVersion) { + workspaceTest(HelloWorld, resourcePath = invalidResourcePath) { eval => + val project = HelloWorld.core(scalaVersion, playVersion) + val eitherResult = eval.apply(project.compileRouter) + val Left(Failure(message, x)) = eitherResult + val playExpectedMessage = + if (playVersion.startsWith("2.6.")) { + "HTTP Verb (GET, POST, ...), include (->), comment (#), or modifier line (+) expected" + } else { + "end of input expected" + } + val expectedMessage = "Unable to compile play routes, compilation error in " + + project.millSourcePath.toIO.getAbsolutePath.replace( + """\""", + "/" + ) + "/routes/routes at line 4, " + + "column" + " 1: " + playExpectedMessage + // fix windows paths + val normalizeMessage = message.replace("""\""", "/") + assert( + normalizeMessage == expectedMessage + ) + } } } } test("compileRouterInvalidSubRoutes") { matrix.foreach { case (scalaVersion, playVersion) => - workspaceTest(HelloWorld, resourcePath = invalidSubResourcePath) { eval => - val eitherResult = eval.apply(HelloWorld.core(scalaVersion, playVersion).compileRouter) - val Left(Failure(message, x)) = eitherResult - val playExpectedMessage = - if (playVersion.startsWith("2.6.")) { - "HTTP Verb (GET, POST, ...), include (->), comment (#), or modifier line (+) expected" - } else { - "end of input expected" - } - val expectedMessage = "Unable to compile play routes, compilation error in " + - HelloWorld.core.millSourcePath.toIO.getAbsolutePath.replace( - """\""", - "/" - ) + "/routes/sub.routes at line 3, column" + - " 1: " + playExpectedMessage - // fix windows paths - val normalizeMessage = message.replace("""\""", "/") - assert( - normalizeMessage == expectedMessage - ) + skipUnsupportedVersions(playVersion) { + workspaceTest(HelloWorld, resourcePath = invalidSubResourcePath) { eval => + val eitherResult = eval.apply(HelloWorld.core(scalaVersion, playVersion).compileRouter) + val Left(Failure(message, x)) = eitherResult + val playExpectedMessage = + if (playVersion.startsWith("2.6.")) { + "HTTP Verb (GET, POST, ...), include (->), comment (#), or modifier line (+) expected" + } else { + "end of input expected" + } + val expectedMessage = "Unable to compile play routes, compilation error in " + + HelloWorld.core.millSourcePath.toIO.getAbsolutePath.replace( + """\""", + "/" + ) + "/routes/sub.routes at line 3, column" + + " 1: " + playExpectedMessage + // fix windows paths + val normalizeMessage = message.replace("""\""", "/") + assert( + normalizeMessage == expectedMessage + ) + } } } } diff --git a/contrib/playlib/worker/2.9/src/mill/playlib/worker/RouteCompilerWorker.scala b/contrib/playlib/worker/2.9/src/mill/playlib/worker/RouteCompilerWorker.scala new file mode 100644 index 00000000000..e24557b2651 --- /dev/null +++ b/contrib/playlib/worker/2.9/src/mill/playlib/worker/RouteCompilerWorker.scala @@ -0,0 +1,3 @@ +package mill.playlib.worker + +private[playlib] class RouteCompilerWorker extends RouteCompilerWorkerBase diff --git a/contrib/playlib/worker/3.0/src/mill/playlib/worker/RouteCompilerWorker.scala b/contrib/playlib/worker/3.0/src/mill/playlib/worker/RouteCompilerWorker.scala new file mode 100644 index 00000000000..e24557b2651 --- /dev/null +++ b/contrib/playlib/worker/3.0/src/mill/playlib/worker/RouteCompilerWorker.scala @@ -0,0 +1,3 @@ +package mill.playlib.worker + +private[playlib] class RouteCompilerWorker extends RouteCompilerWorkerBase diff --git a/contrib/twirllib/src/mill/twirllib/TwirlModule.scala b/contrib/twirllib/src/mill/twirllib/TwirlModule.scala index 7bd6a46e364..c00a3904dda 100644 --- a/contrib/twirllib/src/mill/twirllib/TwirlModule.scala +++ b/contrib/twirllib/src/mill/twirllib/TwirlModule.scala @@ -5,6 +5,7 @@ import coursier.{Dependency, Repository} import mill.api.PathRef import mill.scalalib._ import mill.api.Loose +import mill.main.BuildInfo import scala.io.Codec import scala.util.Properties @@ -17,7 +18,12 @@ trait TwirlModule extends mill.Module { twirlModule => * The Scala version matching the twirl version. * @since Mill after 0.10.5 */ - def twirlScalaVersion: T[String] + def twirlScalaVersion: T[String] = T { + twirlVersion() match { + case s"1.$minor.$_" if minor.toIntOption.exists(_ < 4) => BuildInfo.workerScalaVersion212 + case _ => BuildInfo.scalaVersion + } + } def twirlSources: T[Seq[PathRef]] = T.sources { millSourcePath / "views" @@ -25,11 +31,11 @@ trait TwirlModule extends mill.Module { twirlModule => /** * Replicate the logic from twirl build, - * see: https://github.com/playframework/twirl/blob/bdac9bb9470a7533a44b40c37fb3064737418768/build.sbt#L17-L22 + * see: https://github.com/playframework/twirl/blob/2.0.1/build.sbt#L12-L17 */ private def scalaParserCombinatorsVersion: T[String] = twirlScalaVersion.map { case v if v.startsWith("2.") => "1.1.2" - case _ => "2.1.0" + case _ => "2.3.0" } /** @@ -37,9 +43,13 @@ trait TwirlModule extends mill.Module { twirlModule => */ def twirlIvyDeps: T[Agg[Dep]] = T { Agg( - ivy"com.typesafe.play::twirl-compiler:${twirlVersion()}", - ivy"org.scala-lang.modules::scala-parser-combinators:${scalaParserCombinatorsVersion()}" - ) + if (twirlVersion().startsWith("1.")) + ivy"com.typesafe.play::twirl-compiler:${twirlVersion()}" + else ivy"org.playframework.twirl::twirl-compiler:${twirlVersion()}" + ) ++ + Agg( + ivy"org.scala-lang.modules::scala-parser-combinators:${scalaParserCombinatorsVersion()}" + ) } /** diff --git a/contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala b/contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala index a5f2b75236e..6bae2e57e54 100644 --- a/contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala +++ b/contrib/twirllib/test/src/mill/twirllib/HelloWorldTests.scala @@ -6,7 +6,6 @@ import utest.{TestSuite, Tests, assert, _} trait HelloWorldTests extends TestSuite { val testTwirlVersion: String - val testTwirlScalaVersion: String trait HelloBase extends TestUtil.BaseModule { override def millSourcePath: os.Path = @@ -15,7 +14,6 @@ trait HelloWorldTests extends TestSuite { trait HelloWorldModule extends mill.twirllib.TwirlModule { def twirlVersion = testTwirlVersion - val twirlScalaVersion = testTwirlScalaVersion } object HelloWorld extends HelloBase { @@ -78,6 +76,12 @@ trait HelloWorldTests extends TestSuite { "@something.else.Thing()" ) + def skipUnsupportedVersions(test: => Unit) = testTwirlVersion match { + case s"1.$minor.$_" if minor.toIntOption.exists(_ < 6) => test + case _ if scala.util.Properties.isJavaAtLeast(11) => test + case _ => System.err.println(s"Skipping since twirl $testTwirlVersion doesn't support Java 8") + } + def tests: Tests = Tests { "twirlVersion" - { @@ -91,83 +95,95 @@ trait HelloWorldTests extends TestSuite { ) } } - "compileTwirl" - workspaceTest(HelloWorld, "hello-world", debug = true) { eval => - val res = eval.apply(HelloWorld.core.compileTwirl) - assert(res.isRight) - val Right((result, evalCount)) = res - - val outputFiles = os.walk(result.classes.path).filter(_.last.endsWith(".scala")) - val expectedClassfiles = compileClassfiles.map( - eval.outPath / "core" / "compileTwirl.dest" / _ - ) - - assert( - result.classes.path == eval.outPath / "core" / "compileTwirl.dest", - outputFiles.nonEmpty, - outputFiles.forall(expectedClassfiles.contains), - outputFiles.size == 3, - evalCount > 0, - outputFiles.forall { p => - val lines = os.read.lines(p).map(_.trim) - (expectedDefaultImports ++ testAdditionalImports.map(s => s"import $s")).forall( - lines.contains + test("compileTwirl") { + skipUnsupportedVersions { + workspaceTest(HelloWorld, "hello-world", debug = true) { eval => + val res = eval.apply(HelloWorld.core.compileTwirl) + assert(res.isRight) + val Right((result, evalCount)) = res + + val outputFiles = os.walk(result.classes.path).filter(_.last.endsWith(".scala")) + val expectedClassfiles = compileClassfiles.map( + eval.outPath / "core" / "compileTwirl.dest" / _ + ) + + assert( + result.classes.path == eval.outPath / "core" / "compileTwirl.dest", + outputFiles.nonEmpty, + outputFiles.forall(expectedClassfiles.contains), + outputFiles.size == 3, + evalCount > 0, + outputFiles.forall { p => + val lines = os.read.lines(p).map(_.trim) + (expectedDefaultImports ++ testAdditionalImports.map(s => s"import $s")).forall( + lines.contains + ) + }, + outputFiles.filter(_.toString().contains("hello.template.scala")).forall { p => + val lines = os.read.lines(p).map(_.trim) + val expectedClassDeclaration = s"class hello ${testConstructorAnnotations.mkString}" + lines.exists(_.startsWith(expectedClassDeclaration)) + } ) - }, - outputFiles.filter(_.toString().contains("hello.template.scala")).forall { p => - val lines = os.read.lines(p).map(_.trim) - val expectedClassDeclaration = s"class hello ${testConstructorAnnotations.mkString}" - lines.exists(_.startsWith(expectedClassDeclaration)) - } - ) - // don't recompile if nothing changed - val Right((_, unchangedEvalCount)) = - eval.apply(HelloWorld.core.compileTwirl) + // don't recompile if nothing changed + val Right((_, unchangedEvalCount)) = + eval.apply(HelloWorld.core.compileTwirl) - assert(unchangedEvalCount == 0) - } - "compileTwirlInclusiveDot" - workspaceTest( - HelloWorldWithInclusiveDot, - "hello-world-inclusive-dot" - ) { eval => - val Right((result, evalCount)) = eval.apply(HelloWorldWithInclusiveDot.core.compileTwirl) - - val outputFiles = os.walk(result.classes.path).filter(_.last.endsWith(".scala")) - val expectedClassfiles = compileClassfiles.map(name => - eval.outPath / "core" / "compileTwirl.dest" / name / os.RelPath.up / name.last.replace( - ".template.scala", - "$$TwirlInclusiveDot.template.scala" - ) - ) - - println(s"outputFiles: $outputFiles") - - assert( - result.classes.path == eval.outPath / "core" / "compileTwirl.dest", - outputFiles.nonEmpty, - outputFiles.forall(expectedClassfiles.contains), - outputFiles.size == 3, - evalCount > 0, - outputFiles.filter(_.toString().contains("hello.template.scala")).forall { p => - val lines = os.read.lines(p).map(_.trim) - lines.exists(_.contains("$$TwirlInclusiveDot")) + assert(unchangedEvalCount == 0) } - ) + } + } + test("compileTwirlInclusiveDot") { + skipUnsupportedVersions { + workspaceTest( + HelloWorldWithInclusiveDot, + "hello-world-inclusive-dot" + ) { eval => + val Right((result, evalCount)) = eval.apply(HelloWorldWithInclusiveDot.core.compileTwirl) + + val outputFiles = os.walk(result.classes.path).filter(_.last.endsWith(".scala")) + val expectedClassfiles = compileClassfiles.map(name => + eval.outPath / "core" / "compileTwirl.dest" / name / os.RelPath.up / name.last.replace( + ".template.scala", + "$$TwirlInclusiveDot.template.scala" + ) + ) + + println(s"outputFiles: $outputFiles") + + assert( + result.classes.path == eval.outPath / "core" / "compileTwirl.dest", + outputFiles.nonEmpty, + outputFiles.forall(expectedClassfiles.contains), + outputFiles.size == 3, + evalCount > 0, + outputFiles.filter(_.toString().contains("hello.template.scala")).forall { p => + val lines = os.read.lines(p).map(_.trim) + lines.exists(_.contains("$$TwirlInclusiveDot")) + } + ) - // don't recompile if nothing changed - val Right((_, unchangedEvalCount)) = - eval.apply(HelloWorld.core.compileTwirl) + // don't recompile if nothing changed + val Right((_, unchangedEvalCount)) = + eval.apply(HelloWorld.core.compileTwirl) - assert(unchangedEvalCount == 0) + assert(unchangedEvalCount == 0) + } + } } } } -object HelloWorldTests2_12 extends HelloWorldTests { - override val testTwirlVersion = "1.3.15" - override val testTwirlScalaVersion = sys.props.getOrElse("MILL_SCALA_2_12_VERSION", ???) +object HelloWorldTests1_3 extends HelloWorldTests { + override val testTwirlVersion = "1.3.16" +} +object HelloWorldTests1_5 extends HelloWorldTests { + override val testTwirlVersion = "1.5.2" +} +object HelloWorldTests1_6 extends HelloWorldTests { + override val testTwirlVersion = "1.6.2" } -object HelloWorldTests2_13 extends HelloWorldTests { - override val testTwirlVersion = "1.5.1" - override val testTwirlScalaVersion = sys.props.getOrElse("MILL_SCALA_2_13_VERSION", ???) +object HelloWorldTests2_0 extends HelloWorldTests { + override val testTwirlVersion = "2.0.1" }