Skip to content

Commit

Permalink
Merge pull request #42 from Dwolla/finagle
Browse files Browse the repository at this point in the history
update Finagle and Scalafix rule to rewrite Scrooge-generated code to work with this project
  • Loading branch information
bpholt authored Apr 14, 2022
2 parents 98c3868 + 76cefd8 commit 3e5201e
Show file tree
Hide file tree
Showing 17 changed files with 432 additions and 433 deletions.
1 change: 1 addition & 0 deletions .sbtopts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-J-Xmx2G
31 changes: 17 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,15 @@ Add Scalafix to your project's build by [following the instructions](https://sca

1. Add the Scalafix plugin to the project by adding this to `project/plugins.sbt`:
```scala
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.31")
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.34")
```

2. Enable SemanticDB by adding this to `build.sbt`:
```scala
ThisBuild / semanticdbEnabled := true
ThisBuild / semanticdbVersion := scalafixSemanticdb.revision
ThisBuild / scalafixScalaBinaryVersion := CrossVersion.binaryScalaVersion(scalaVersion.value)
ThisBuild / scalafixDependencies += "com.dwolla" %% "finagle-tagless-scalafix" % "0.0.4"
ThisBuild / scalafixDependencies += "com.dwolla" %% "finagle-tagless-scalafix" % "0.0.7"
```

3. Run the Scalafix rule automatically after generating the Thrift sources by adding this to `build.sbt`:
Expand All @@ -137,6 +137,21 @@ Add Scalafix to your project's build by [following the instructions](https://sca
}
```

### `AddCatsTaglessInstances`

The `AddCatsTaglessInstances` rule finds generated Thrift service traits and adds implicit instances of
`ThriftService[Kleisli[F, ThriftService[Future], *]]` and `FunctorK[ThriftService]` to each service's
companion object.

Twitter's Scrooge project changed the way it generates code for Thrift services, removing the
higher-kinded service trait used by this library, leaving only the `MethodPerEndpoint` trait
that used to extend the higher-kinded service trait, setting the type parameter to `com.twitter.util.Future`.
The `AddCatsTaglessInstances` rule now addresses this as well, rewriting `MethodPerEndpoint` to
`{Name}Service` and reintroducing the type parameter. (A new `MethodPerEndpoint` is also added,
going back to how it used to `extend {Name}Service[Future]`.)

This Scalafix rule should be idempotent, so it can be rerun many times.

## Artifacts

The Group ID for each artifact is `"com.dwolla"`. All artifacts are published to Maven Central.
Expand Down Expand Up @@ -198,18 +213,6 @@ The Group ID for each artifact is `"com.dwolla"`. All artifacts are published to
<td align="center">N/A</td>
</tr>
<tr>
<td><code>"async-utils-twitter-19-4-ce2"</code></td>
<td rowspan="2">Implementation for Twitter <code>Future</code><br>(with <code>"com.twitter" %% "util-core" % "19.4.0"</code>)</td>
<td align="center">Cats Effect 2</td>
<td align="center" rowspan="2"><g-emoji class="g-emoji" alias="white_check_mark" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2705.png">✅</g-emoji></td>
<td align="center" rowspan="2"><g-emoji class="g-emoji" alias="no_entry_sign" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f6ab.png">🚫</g-emoji></td>
<td align="center" rowspan="2"><g-emoji class="g-emoji" alias="no_entry_sign" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f6ab.png">🚫</g-emoji></td>
</tr>
<tr>
<td><code>"async-utils-twitter-19-4-ce3"</code></td>
<td align="center">Cats Effect 3</td>
</tr>
<tr>
<td><code>"async-utils-core-ce2"</code></td>
<td rowspan="2">Shared definition of <code>AsyncFunctorK</code> and supporting code</td>
<td align="center">Cats Effect 2</td>
Expand Down
40 changes: 7 additions & 33 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ inThisBuild(List(

lazy val CatsEffect2V = "2.5.4"
lazy val CatsEffect3V = "3.3.11"
lazy val TwitterUtilsLatestV = "21.8.0"
lazy val TwitterUtils19_4V = "19.4.0"
lazy val TwitterUtilsLatestV = "22.3.0"
lazy val CatsTaglessV = "0.14.0"
lazy val libthriftV = "0.10.0"

Expand Down Expand Up @@ -158,7 +157,7 @@ lazy val `async-utils` = (projectMatrix in file("scala-futures"))
lazy val `async-utils-twitter` = (projectMatrix in file("twitter-futures"))
.customRow(
scalaVersions = Scala2Versions,
axisValues = Seq(CatsEffect2, TwitterUtilsLatest, VirtualAxis.jvm),
axisValues = Seq(CatsEffect2, VirtualAxis.jvm),
_.settings(
moduleName := name.value + "-ce2",
Compile / unmanagedSourceDirectories += moduleBase.value / "scala-ce2",
Expand All @@ -172,7 +171,7 @@ lazy val `async-utils-twitter` = (projectMatrix in file("twitter-futures"))
)
.customRow(
scalaVersions = Scala2Versions,
axisValues = Seq(CatsEffect3, TwitterUtilsLatest, VirtualAxis.jvm),
axisValues = Seq(CatsEffect3, VirtualAxis.jvm),
_.settings(
moduleName := name.value + "-ce3",
Compile / unmanagedSourceDirectories += moduleBase.value / "scala-ce3",
Expand All @@ -184,38 +183,12 @@ lazy val `async-utils-twitter` = (projectMatrix in file("twitter-futures"))
}
)
)
.customRow(
scalaVersions = Seq(SCALA_2_12),
axisValues = Seq(CatsEffect2, TwitterUtils19_4, VirtualAxis.jvm),
_.settings(
moduleName := name.value + "-19-4-ce2",
libraryDependencies ++= {
Seq(
"org.typelevel" %% "cats-effect" % CatsEffect2V,
"com.twitter" %% "util-core" % TwitterUtils19_4V,
) ++ (if (scalaVersion.value.startsWith("2")) scala2CompilerPlugins else Nil)
},
)
)
.customRow(
scalaVersions = Seq(SCALA_2_12),
axisValues = Seq(CatsEffect3, TwitterUtils19_4, VirtualAxis.jvm),
_.settings(
moduleName := name.value + "-19-4-ce3",
libraryDependencies ++= {
Seq(
"org.typelevel" %% "cats-effect" % CatsEffect3V,
"com.twitter" %% "util-core" % TwitterUtils19_4V,
) ++ (if (scalaVersion.value.startsWith("2")) scala2CompilerPlugins else Nil)
},
)
)
.dependsOn(`async-utils-core`)

lazy val `async-utils-finagle` = (projectMatrix in file("twitter-finagle"))
.customRow(
scalaVersions = Scala2Versions,
axisValues = Seq(CatsEffect2, TwitterUtilsLatest, VirtualAxis.jvm),
axisValues = Seq(CatsEffect2, VirtualAxis.jvm),
_.settings(
moduleName := name.value + "-ce2",
Compile / unmanagedSourceDirectories += moduleBase.value / "scala-ce2",
Expand All @@ -228,7 +201,7 @@ lazy val `async-utils-finagle` = (projectMatrix in file("twitter-finagle"))
)
.customRow(
scalaVersions = Scala2Versions,
axisValues = Seq(CatsEffect3, TwitterUtilsLatest, VirtualAxis.jvm),
axisValues = Seq(CatsEffect3, VirtualAxis.jvm),
_.settings(
moduleName := name.value + "-ce3",
Compile / unmanagedSourceDirectories += moduleBase.value / "scala-ce3",
Expand Down Expand Up @@ -259,7 +232,8 @@ lazy val `scalafix-rules` = (projectMatrix in file("scalafix/rules"))
moduleName := "finagle-tagless-scalafix",
libraryDependencies ++= Seq(
"ch.epfl.scala" %% "scalafix-core" % _root_.scalafix.sbt.BuildInfo.scalafixVersion,

"org.scalameta" %% "munit" % "0.7.29" % Test,
"com.eed3si9n.expecty" %% "expecty" % "0.15.4" % Test,
),
scalacOptions ~= { _.filterNot(_ == "-Xfatal-warnings") },
)
Expand Down
4 changes: 0 additions & 4 deletions project/ConfigAxes.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import sbt._

case class CatsEffectAxis(idSuffix: String, directorySuffix: String) extends VirtualAxis.WeakAxis
case class TwitterUtilsAxis(idSuffix: String, directorySuffix: String) extends VirtualAxis.WeakAxis

object ConfigAxes {
val CatsEffect2 = CatsEffectAxis("_ce2", "-ce2")
val CatsEffect3 = CatsEffectAxis("_ce3", "-ce3")

val TwitterUtilsLatest = TwitterUtilsAxis("_latest", "latest")
val TwitterUtils19_4 = TwitterUtilsAxis("_19_4", "19.4")
}
24 changes: 8 additions & 16 deletions scalafix/input/src/main/scala/example/thrift/SimpleRequest.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
/*
rule = AddCatsTaglessInstances
*/
/*rule = AddCatsTaglessInstances*/
/**
* Generated by Scrooge
* version: 21.8.0
* rev: 75b832815f5da5328f0225e2ab3e06a14afb3446
* built at: 20210813-170828
* version: 22.3.0
* rev: 2f6ae2f0908271965ba99fd3643c2d35b1e69a10
* built at: 20220329-191327
*/
package example.thrift

Expand All @@ -32,8 +30,6 @@ import scala.reflect.{ClassTag, classTag}


object SimpleRequest extends ValidatingThriftStructCodec3[SimpleRequest] with StructBuilderFactory[SimpleRequest] {
private[this] val _protos: _root_.com.twitter.scrooge.internal.TProtocols = _root_.com.twitter.scrooge.internal.TProtocols()

val Struct: TStruct = new TStruct("SimpleRequest")
val IdField: TField = new TField("id", TType.STRING, 1)
val IdFieldManifest: Manifest[String] = manifest[String]
Expand Down Expand Up @@ -100,11 +96,9 @@ object SimpleRequest extends ValidatingThriftStructCodec3[SimpleRequest] with St
* Validate that all validation annotations on the struct meet the criteria defined in the
* corresponding [[com.twitter.scrooge.validation.ThriftConstraintValidator]].
*/
def validateInstanceValue(item: SimpleRequest): Set[com.twitter.scrooge.validation.ThriftValidationViolation] = {
val thriftValidator = com.twitter.scrooge.ThriftValidator()
val violations = scala.collection.mutable.Set.empty[com.twitter.scrooge.validation.ThriftValidationViolation]
val fieldInfo0 = fieldInfos.apply(0)
violations ++= validateFieldValue(fieldInfo0.tfield.name, item.id, fieldInfo0.fieldAnnotations, thriftValidator)
def validateInstanceValue(item: SimpleRequest): Set[com.twitter.scrooge.thrift_validation.ThriftValidationViolation] = {
val violations = scala.collection.mutable.Set.empty[com.twitter.scrooge.thrift_validation.ThriftValidationViolation]
violations ++= validateFieldValue("id", item.id, fieldInfos.apply(0).fieldAnnotations, scala.None)
violations.toSet
}

Expand Down Expand Up @@ -303,7 +297,6 @@ trait SimpleRequest
if (passedthroughValue.isDefined) {
passedthroughValue
} else {
val _protos = _root_.com.twitter.scrooge.internal.TProtocols()
val _buff = new TMemoryBuffer(32)
val _oprot = new TCompactProtocol(_buff)

Expand Down Expand Up @@ -339,7 +332,6 @@ trait SimpleRequest
* _passthroughFields.
*/
def setField(_blob: TFieldBlob): SimpleRequest = {
val _protos: _root_.com.twitter.scrooge.internal.TProtocols = _root_.com.twitter.scrooge.internal.TProtocols()
var id: String = this.id
var _passthroughFields = this._passthroughFields
val _iprot = _blob.read
Expand Down Expand Up @@ -383,7 +375,6 @@ trait SimpleRequest

override def write(_oprot: TProtocol): Unit = {
SimpleRequest.validate(this)
val _protos = _root_.com.twitter.scrooge.internal.TProtocols()
_oprot.writeStructBegin(Struct)
if (id ne null) {
_oprot.writeFieldBegin(IdField)
Expand Down Expand Up @@ -443,3 +434,4 @@ private[thrift] class SimpleRequestStructBuilder(instance: _root_.scala.Option[S
}
}
}

24 changes: 8 additions & 16 deletions scalafix/input/src/main/scala/example/thrift/SimpleResponse.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
/*
rule = AddCatsTaglessInstances
*/
/*rule = AddCatsTaglessInstances*/
/**
* Generated by Scrooge
* version: 21.8.0
* rev: 75b832815f5da5328f0225e2ab3e06a14afb3446
* built at: 20210813-170828
* version: 22.3.0
* rev: 2f6ae2f0908271965ba99fd3643c2d35b1e69a10
* built at: 20220329-191327
*/
package example.thrift

Expand All @@ -32,8 +30,6 @@ import scala.reflect.{ClassTag, classTag}


object SimpleResponse extends ValidatingThriftStructCodec3[SimpleResponse] with StructBuilderFactory[SimpleResponse] {
private[this] val _protos: _root_.com.twitter.scrooge.internal.TProtocols = _root_.com.twitter.scrooge.internal.TProtocols()

val Struct: TStruct = new TStruct("SimpleResponse")
val IdField: TField = new TField("id", TType.STRING, 1)
val IdFieldManifest: Manifest[String] = manifest[String]
Expand Down Expand Up @@ -100,11 +96,9 @@ object SimpleResponse extends ValidatingThriftStructCodec3[SimpleResponse] with
* Validate that all validation annotations on the struct meet the criteria defined in the
* corresponding [[com.twitter.scrooge.validation.ThriftConstraintValidator]].
*/
def validateInstanceValue(item: SimpleResponse): Set[com.twitter.scrooge.validation.ThriftValidationViolation] = {
val thriftValidator = com.twitter.scrooge.ThriftValidator()
val violations = scala.collection.mutable.Set.empty[com.twitter.scrooge.validation.ThriftValidationViolation]
val fieldInfo0 = fieldInfos.apply(0)
violations ++= validateFieldValue(fieldInfo0.tfield.name, item.id, fieldInfo0.fieldAnnotations, thriftValidator)
def validateInstanceValue(item: SimpleResponse): Set[com.twitter.scrooge.thrift_validation.ThriftValidationViolation] = {
val violations = scala.collection.mutable.Set.empty[com.twitter.scrooge.thrift_validation.ThriftValidationViolation]
violations ++= validateFieldValue("id", item.id, fieldInfos.apply(0).fieldAnnotations, scala.None)
violations.toSet
}

Expand Down Expand Up @@ -303,7 +297,6 @@ trait SimpleResponse
if (passedthroughValue.isDefined) {
passedthroughValue
} else {
val _protos = _root_.com.twitter.scrooge.internal.TProtocols()
val _buff = new TMemoryBuffer(32)
val _oprot = new TCompactProtocol(_buff)

Expand Down Expand Up @@ -339,7 +332,6 @@ trait SimpleResponse
* _passthroughFields.
*/
def setField(_blob: TFieldBlob): SimpleResponse = {
val _protos: _root_.com.twitter.scrooge.internal.TProtocols = _root_.com.twitter.scrooge.internal.TProtocols()
var id: String = this.id
var _passthroughFields = this._passthroughFields
val _iprot = _blob.read
Expand Down Expand Up @@ -383,7 +375,6 @@ trait SimpleResponse

override def write(_oprot: TProtocol): Unit = {
SimpleResponse.validate(this)
val _protos = _root_.com.twitter.scrooge.internal.TProtocols()
_oprot.writeStructBegin(Struct)
if (id ne null) {
_oprot.writeFieldBegin(IdField)
Expand Down Expand Up @@ -443,3 +434,4 @@ private[thrift] class SimpleResponseStructBuilder(instance: _root_.scala.Option[
}
}
}

Loading

0 comments on commit 3e5201e

Please sign in to comment.