From 27c2eb134a0f6f99bfbc3ca4d7d6bc7bc3d13595 Mon Sep 17 00:00:00 2001 From: Michel Davit Date: Mon, 12 Feb 2024 19:15:24 +0100 Subject: [PATCH] Add scalafix 0.7 migration rule --- .github/workflows/scalafix.yaml | 42 ++++++++ scalafix/.sbtopts | 7 ++ scalafix/build.sbt | 98 +++++++++++++++++++ .../main/scala/fix/MapBasedConverters.scala | 19 ++++ .../main/scala/fix/MapBasedConverters.scala | 16 +++ .../META-INF/services/scalafix.v1.Rule | 2 + .../main/scala/fix/MapBasedConverters.scala | 31 ++++++ .../tests/src/test/scala/fix/RuleSuite.scala | 8 ++ 8 files changed, 223 insertions(+) create mode 100644 .github/workflows/scalafix.yaml create mode 100644 scalafix/.sbtopts create mode 100644 scalafix/build.sbt create mode 100644 scalafix/input-0_7/src/main/scala/fix/MapBasedConverters.scala create mode 100644 scalafix/output-0_7/src/main/scala/fix/MapBasedConverters.scala create mode 100644 scalafix/rules/src/main/resources/META-INF/services/scalafix.v1.Rule create mode 100644 scalafix/rules/src/main/scala/fix/MapBasedConverters.scala create mode 100644 scalafix/tests/src/test/scala/fix/RuleSuite.scala diff --git a/.github/workflows/scalafix.yaml b/.github/workflows/scalafix.yaml new file mode 100644 index 00000000..8738681e --- /dev/null +++ b/.github/workflows/scalafix.yaml @@ -0,0 +1,42 @@ +name: Scalafix Migration Rules + +on: + pull_request: + branches: [main] + paths: + - 'scalafix/**' + + push: + branches: [main] + paths: + - 'scalafix/**' + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + scalafix: + name: Test + runs-on: ubuntu-latest + timeout-minutes: 60 + steps: + - name: Checkout current branch (full) + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Java (corretto@11) + id: setup-java-corretto-11 + uses: actions/setup-java@v3 + with: + distribution: corretto + java-version: 11 + cache: sbt + + - name: sbt update + if: steps.setup-java-corretto-11.outputs.cache-hit == 'false' + run: sbt scalafix/update + + - name: Test + run: sbt test + working-directory: scalafix diff --git a/scalafix/.sbtopts b/scalafix/.sbtopts new file mode 100644 index 00000000..162e0a33 --- /dev/null +++ b/scalafix/.sbtopts @@ -0,0 +1,7 @@ +-J-Xms2G +-J-Xmx8G +-J-XX:ReservedCodeCacheSize=512m +-J-XX:+TieredCompilation +-J-XX:+UseParallelGC +-Dfile.encoding=UTF8 + diff --git a/scalafix/build.sbt b/scalafix/build.sbt new file mode 100644 index 00000000..d163fb6a --- /dev/null +++ b/scalafix/build.sbt @@ -0,0 +1,98 @@ +lazy val V = _root_.scalafix.sbt.BuildInfo + +inThisBuild( + List( + resolvers ++= Resolver.sonatypeOssRepos("snapshots"), + organization := "com.spotify", + scalaVersion := V.scala212, + scalacOptions ++= List("-Yrangepos"), + publish / skip := true, + semanticdbEnabled := true, + semanticdbVersion := scalafixSemanticdb.revision, + semanticdbIncludeInJar := true, + scalafmtOnCompile := false, + scalafmtConfig := baseDirectory.value / ".." / ".scalafmt.conf", + ) +) + +lazy val root = project + .in(file(".")) + .aggregate( + tests.projectRefs ++ Seq[sbt.ProjectReference]( + // 0.7 + `input-0_7`, + `output-0_7`, + // scalafix + rules + ): _* + ) + +lazy val rules = project + .settings( + moduleName := "scalafix", + libraryDependencies ++= Seq( + "ch.epfl.scala" %% "scalafix-core" % V.scalafixVersion + ) + ) + +def magnolify(version: String): List[ModuleID] = { + val modules = List( + "magnolify-avro", + "magnolify-bigquery", + "magnolify-bigtable", + "magnolify-cats", + "magnolify-datastore", + "magnolify-guava", + "magnolify-neo4j", + "magnolify-parquet", + "magnolify-protobuf", + "magnolify-refined", + "magnolify-shared", + "magnolify-scalacheck", + "magnolify-tensorflow" + ) + + val libs = List ( + "org.apache.avro" % "avro" % "1.11.2", + "com.google.apis" % "google-api-services-bigquery" % "v2-rev20231111-2.0.0", + "com.google.api.grpc" % "proto-google-cloud-bigtable-v2" % "2.32.0", + "org.typelevel" %% "cats-core" % "2.10.0", + "com.google.cloud.datastore" % "datastore-v1-proto-client" % "2.18.2", + "com.google.guava" % "guava" % "33.0.0-jre", + "org.neo4j.driver" % "neo4j-java-driver" % "4.4.12", + "org.apache.parquet" % "parquet-hadoop" % "1.13.1", + "com.google.protobuf" % "protobuf-java" % "3.25.2", + "eu.timepit" %% "refined" % "0.11.1", + "org.scalacheck" %% "scalacheck" % "1.17.0", + "org.tensorflow" % "tensorflow-core-api" % "0.5.0" + ) + + modules.map("com.spotify" %% _ % version) ++ libs +} + +lazy val `input-0_7` = project + .settings( + libraryDependencies ++= magnolify("0.6.0") + ) + +lazy val `output-0_7` = project + .settings( + libraryDependencies ++= magnolify("0.7.0") + ) + + +lazy val magnolify0_7 = ConfigAxis("-magnolify-0_7", "-0_7-") + +lazy val tests = projectMatrix + .in(file("tests")) + .enablePlugins(ScalafixTestkitPlugin) + .customRow( + scalaVersions = Seq(V.scala212), + axisValues = Seq(magnolify0_7, VirtualAxis.jvm), + _.settings( + moduleName := name.value + magnolify0_7.idSuffix, + scalafixTestkitOutputSourceDirectories := (`output-0_7` / Compile / unmanagedSourceDirectories).value, + scalafixTestkitInputSourceDirectories := (`input-0_7` / Compile / unmanagedSourceDirectories).value, + scalafixTestkitInputClasspath := (`input-0_7` / Compile / fullClasspath).value + ).dependsOn(rules) + ) diff --git a/scalafix/input-0_7/src/main/scala/fix/MapBasedConverters.scala b/scalafix/input-0_7/src/main/scala/fix/MapBasedConverters.scala new file mode 100644 index 00000000..848164c0 --- /dev/null +++ b/scalafix/input-0_7/src/main/scala/fix/MapBasedConverters.scala @@ -0,0 +1,19 @@ +/* +rule = MapBasedConverters + */ +package fix + +import magnolify.tensorflow._ +import org.tensorflow.proto.example.Example + +object MapBasedConverters { + + final case class Person(name: String, age: Int) + + // ExampleType + val etPerson: ExampleType[Person] = ??? + val e: Example = ??? + val p: Person = ??? + etPerson.from(e) + etPerson.to(p) +} diff --git a/scalafix/output-0_7/src/main/scala/fix/MapBasedConverters.scala b/scalafix/output-0_7/src/main/scala/fix/MapBasedConverters.scala new file mode 100644 index 00000000..8098d428 --- /dev/null +++ b/scalafix/output-0_7/src/main/scala/fix/MapBasedConverters.scala @@ -0,0 +1,16 @@ +package fix + +import magnolify.tensorflow._ +import org.tensorflow.proto.example.Example + +object MapBasedConverters { + + final case class Person(name: String, age: Int) + + // ExampleType + val etPerson: ExampleType[Person] = ??? + val e: Example = ??? + val p: Person = ??? + etPerson(e) + etPerson(p) +} diff --git a/scalafix/rules/src/main/resources/META-INF/services/scalafix.v1.Rule b/scalafix/rules/src/main/resources/META-INF/services/scalafix.v1.Rule new file mode 100644 index 00000000..9e615557 --- /dev/null +++ b/scalafix/rules/src/main/resources/META-INF/services/scalafix.v1.Rule @@ -0,0 +1,2 @@ +fix.v0_7_0.MapBasedConverters + diff --git a/scalafix/rules/src/main/scala/fix/MapBasedConverters.scala b/scalafix/rules/src/main/scala/fix/MapBasedConverters.scala new file mode 100644 index 00000000..5dda8fd5 --- /dev/null +++ b/scalafix/rules/src/main/scala/fix/MapBasedConverters.scala @@ -0,0 +1,31 @@ +package fix.v0_7_0 + +import scalafix.v1._ + +import scala.meta._ + +object MapBasedConverters { + private val ExampleType: SymbolMatcher = + SymbolMatcher.normalized("magnolify/tensorflow/ExampleType") + + private val ConverterFn: SymbolMatcher = + SymbolMatcher.normalized("magnolify/shared/Converter#from") + + SymbolMatcher.normalized("magnolify/shared/Converter#to") +} + +class MapBasedConverters extends SemanticRule("MapBasedConverters") { + import MapBasedConverters._ + + def isExampleType(term: Term)(implicit doc: SemanticDocument): Boolean = + term.symbol.info.map(_.signature) match { + case Some(MethodSignature(_, _, TypeRef(_, sym, _))) => ExampleType.matches(sym) + case _ => false + } + + override def fix(implicit doc: SemanticDocument): Patch = + doc.tree.collect { + case t @ q"$qual.$fn(..$params)" if isExampleType(qual) && ConverterFn.matches(fn) => + Patch.replaceTree(t, q"$qual(..$params)".syntax) + }.asPatch + +} diff --git a/scalafix/tests/src/test/scala/fix/RuleSuite.scala b/scalafix/tests/src/test/scala/fix/RuleSuite.scala new file mode 100644 index 00000000..5ca361bc --- /dev/null +++ b/scalafix/tests/src/test/scala/fix/RuleSuite.scala @@ -0,0 +1,8 @@ +package fix + +import org.scalatest.funsuite.AnyFunSuiteLike +import scalafix.testkit.AbstractSemanticRuleSuite + +class RuleSuite extends AbstractSemanticRuleSuite with AnyFunSuiteLike { + runAllTests() +}