From 3e1413336843957e1adb9f97a65ed13cc615d755 Mon Sep 17 00:00:00 2001 From: Ben Carter Date: Tue, 3 May 2022 10:04:22 +0100 Subject: [PATCH] Crossbuild for Scala3 (#105) --- .scalafix3.conf | 19 ++++++++++ .scalafmt.conf | 2 +- .travis.yml | 4 +-- build.sbt | 35 +++++++++++++++---- project/Dependencies.scala | 15 +++++--- src/test/scala/base/IntegrationSpecBase.scala | 6 ++-- .../DeprecatedMethodsIntSpec.scala | 4 +-- src/test/scala/utils/RandomPort.scala | 9 +++-- 8 files changed, 69 insertions(+), 25 deletions(-) create mode 100644 .scalafix3.conf diff --git a/.scalafix3.conf b/.scalafix3.conf new file mode 100644 index 00000000..63f168af --- /dev/null +++ b/.scalafix3.conf @@ -0,0 +1,19 @@ +rules = [ + NoAutoTupling, + DisableSyntax, + LeakingImplicitClassVal, + NoValInForComprehension +] + +OrganizeImports { + coalesceToWildcardImportThreshold = 8 + expandRelative = true + groupedImports = Merge + importSelectorsOrder = SymbolsFirst + removeUnused = false + groups = [ + "java." + "*" + "scala." + ] +} diff --git a/.scalafmt.conf b/.scalafmt.conf index d6dc8006..4dad02ea 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -6,6 +6,6 @@ maxColumn = 120 newlines.sometimesBeforeColonInMethodReturnType = false project.git = true rewrite.rules = [SortImports, RedundantBraces, RedundantParens, PreferCurlyFors] -runner.dialect = scala213 +runner.dialect = scala3 spaces.beforeContextBoundColon = Always style = defaultWithAlign diff --git a/.travis.yml b/.travis.yml index e9fe4bc8..e1026afa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,9 @@ language: scala scala: - - 2.13.7 + - 3.1.1 jdk: - - openjdk12 + - openjdk17 # Avoid triggering a duplicate build for PRs branches: diff --git a/build.sbt b/build.sbt index 0fb825a9..49b3b860 100644 --- a/build.sbt +++ b/build.sbt @@ -1,8 +1,7 @@ -import Dependencies.all - +lazy val scala3 = "3.1.1" lazy val scala213 = "2.13.8" lazy val scala212 = "2.12.15" -lazy val supportedScalaVersions = List(scala213, scala212) +lazy val supportedScalaVersions = List(scala3, scala213, scala212) lazy val scmUrl = "https://github.com/sky-uk/kafka-topic-loader" name := "kafka-topic-loader" @@ -21,7 +20,7 @@ developers := List( ) ) -scalaVersion := scala213 +scalaVersion := scala3 crossScalaVersions := supportedScalaVersions semanticdbEnabled := true semanticdbVersion := scalafixSemanticdb.revision @@ -30,19 +29,41 @@ tpolecatScalacOptions ++= Set(ScalacOptions.source3) ThisBuild / scalacOptions ++= Seq("-explaintypes") ++ { CrossVersion.partialVersion(scalaVersion.value) match { - case Some((2, 13)) => Seq("-Wconf:msg=annotation:silent") - case _ => Nil + case Some((3, _)) | Some((2, 13)) => Seq("-Wconf:msg=annotation:silent") + case _ => Nil } } ThisBuild / scalafixDependencies += Dependencies.Plugins.organizeImports +/** Scala 3 doesn't support two rules yet - RemoveUnused and ProcedureSyntax. So we require a different scalafix config + * for Scala 3 + * + * RemoveUnused relies on -warn-unused which isn't available in scala 3 yet - + * https://scalacenter.github.io/scalafix/docs/rules/RemoveUnused.html + * + * ProcedureSyntax doesn't exist in Scala 3 - https://scalacenter.github.io/scalafix/docs/rules/ProcedureSyntax.html + */ +scalafixConfig := { + CrossVersion.partialVersion(scalaVersion.value) match { + case Some((3, _)) => Some((ThisBuild / baseDirectory).value / ".scalafix3.conf") + case _ => None + } +} + Test / parallelExecution := false Test / fork := true Global / onChangedBuildSource := ReloadOnSourceChanges -libraryDependencies ++= all +libraryDependencies ++= Dependencies.all + +excludeDependencies ++= { + CrossVersion.partialVersion(scalaVersion.value) match { + case Some((3, _)) => Dependencies.scala3Exclusions + case _ => Seq.empty + } +} addCommandAlias("checkFix", "scalafixAll --check OrganizeImports; scalafixAll --check") addCommandAlias("runFix", "scalafixAll OrganizeImports; scalafixAll") diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 46b7a4f6..0d67ce52 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -8,10 +8,10 @@ object Dependencies { object Akka { private val version = "2.6.19" - val stream = "com.typesafe.akka" %% "akka-stream" % version - val streamKafka = "com.typesafe.akka" %% "akka-stream-kafka" % "2.1.1" - val streamTestkit = "com.typesafe.akka" %% "akka-stream-testkit" % version % Test - val testkit = "com.typesafe.akka" %% "akka-testkit" % version % Test + val stream = "com.typesafe.akka" %% "akka-stream" % version cross CrossVersion.for3Use2_13 + val streamKafka = "com.typesafe.akka" %% "akka-stream-kafka" % "2.1.1" cross CrossVersion.for3Use2_13 + val streamTestkit = "com.typesafe.akka" %% "akka-stream-testkit" % version % Test cross CrossVersion.for3Use2_13 + val testkit = "com.typesafe.akka" %% "akka-testkit" % version % Test cross CrossVersion.for3Use2_13 val base = Seq(stream, streamKafka) val test = Seq(streamTestkit, testkit) } @@ -28,9 +28,14 @@ object Dependencies { val logbackClassic = "ch.qos.logback" % "logback-classic" % "1.2.11" % Runtime val scalaCollectionCompat = "org.scala-lang.modules" %% "scala-collection-compat" % "2.7.0" - val embeddedKafka = "io.github.embeddedkafka" %% "embedded-kafka" % "3.1.0" % Test + val embeddedKafka = "io.github.embeddedkafka" %% "embedded-kafka" % "3.1.0" % Test cross CrossVersion.for3Use2_13 val scalaTest = "org.scalatest" %% "scalatest" % "3.2.12" % Test + val scala3Exclusions = Seq( + "com.typesafe.scala-logging" % "scala-logging_2.13", + "org.scala-lang.modules" % "scala-collection-compat_2.13" + ) + val core = Akka.base ++ Cats.all ++ Seq( kafkaClients, scalaLogging, diff --git a/src/test/scala/base/IntegrationSpecBase.scala b/src/test/scala/base/IntegrationSpecBase.scala index 861bb9a4..19d2681b 100644 --- a/src/test/scala/base/IntegrationSpecBase.scala +++ b/src/test/scala/base/IntegrationSpecBase.scala @@ -25,13 +25,13 @@ import scala.jdk.CollectionConverters._ abstract class IntegrationSpecBase extends WordSpecBase with Eventually { - override implicit val patienceConfig = PatienceConfig(20.seconds, 200.millis) + override implicit val patienceConfig: PatienceConfig = PatienceConfig(20.seconds, 200.millis) - implicit val timeout = Timeout(5.seconds) + implicit val timeout: Timeout = Timeout(5.seconds) trait TestContext extends AkkaSpecBase with EmbeddedKafka { - implicit lazy val kafkaConfig = + implicit lazy val kafkaConfig: EmbeddedKafkaConfig = EmbeddedKafkaConfig(kafkaPort = RandomPort(), zooKeeperPort = RandomPort(), Map("log.roll.ms" -> "10")) override implicit lazy val system: ActorSystem = ActorSystem( diff --git a/src/test/scala/integration/DeprecatedMethodsIntSpec.scala b/src/test/scala/integration/DeprecatedMethodsIntSpec.scala index 64a0d247..be6b4573 100644 --- a/src/test/scala/integration/DeprecatedMethodsIntSpec.scala +++ b/src/test/scala/integration/DeprecatedMethodsIntSpec.scala @@ -109,13 +109,13 @@ class DeprecatedMethodsIntSpec extends IntegrationSpecBase { .runWith(Sink.ignore) .futureValue shouldBe Done - store.getRecords.futureValue.map(_.partition) should contain only (partitionsToRead.toList: _*) + store.getRecords.futureValue.map(_.partition).toSet should contain theSameElementsAs partitionsToRead.toList } } } class RecordStore()(implicit system: ActorSystem) { - private val storeActor = system.actorOf(Props(classOf[Store], RecordStore.this)) + private val storeActor = system.actorOf(Props(new Store)) def storeRecord(rec: ConsumerRecord[String, String])(implicit timeout: Timeout): Future[Int] = (storeActor ? rec).mapTo[Int] diff --git a/src/test/scala/utils/RandomPort.scala b/src/test/scala/utils/RandomPort.scala index 04fc0719..f3d14f1d 100644 --- a/src/test/scala/utils/RandomPort.scala +++ b/src/test/scala/utils/RandomPort.scala @@ -2,12 +2,11 @@ package utils import java.net.ServerSocket +import scala.util.Using + object RandomPort { - def apply(): Int = { - val socket = new ServerSocket(0) + def apply(): Int = Using.resource(new ServerSocket(0)) { socket => socket.setReuseAddress(true) - val port = socket.getLocalPort - socket.close() - port + socket.getLocalPort } }