Skip to content

Commit

Permalink
Merge pull request #10 from electronicarts/0.2.2
Browse files Browse the repository at this point in the history
Fix regression that prevented the generation of a Swagger UI for multiple Thrift services
  • Loading branch information
Daniele Riccardelli authored Mar 28, 2022
2 parents 39bb5c9 + 19653f2 commit bc18f8e
Show file tree
Hide file tree
Showing 22 changed files with 243 additions and 50 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ And since a HTTP/JSON API is exposed, you don't necessarily have to deal with th
**NOTE**: while extremely useful during development, **kara** is not intended for production use.

## Usage
- Add **kara** as a plugin to the sbt project adding a line containing `addSbtPlugin("com.ea.kara" % "kara" % "0.2.1")` in `project/plugins.sbt`.
- Add **kara** as a plugin to the sbt project adding a line containing `addSbtPlugin("com.ea.kara" % "kara" % "0.2.2")` in `project/plugins.sbt`.
- In your project settings in `build.sbt`:
- configure `karaServices := Seq("fully_qualified_service_1", "fully_qualified_service_2, ...)` to indicate the Thrift services Kara should generate Finagle services and Swagger UI for. Services should be listed in `<JAVA_NAMESPACE>.<SERVICE_NAME>` format.
- enable the the plugin with `.enablePlugins(Kara)` on the project that lists the Thrift sources and on which `ScroogeSBT` is enabled.
Expand All @@ -31,7 +31,7 @@ On compilation (`sbt compile`), a Finagle HTTP service named `Http<SERVICE_NAME>

#### project/plugins.sbt
```scala
addSbtPlugin("com.ea.kara" % "kara" % "0.2.1")
addSbtPlugin("com.ea.kara" % "kara" % "0.2.2")
```

#### build.sbt
Expand Down
4 changes: 2 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ val circeVersion = "0.14.1"
ThisBuild / credentials += Credentials(Path.userHome / ".ivy2" / ".credentials")
ThisBuild / envVars ++= Map("CI_PROJECT_DIR" -> sys.env.getOrElse("CI_PROJECT_DIR", "."))
ThisBuild / scalaVersion := "2.12.15"
ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-parser-combinators" % "always"
ThisBuild / versionScheme := Some("early-semver")
ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-parser-combinators" % VersionScheme.Always
ThisBuild / versionScheme := Some(VersionScheme.EarlySemVer)

lazy val sbtOps = sys.env
.get("SBT_OPTS")
Expand Down
10 changes: 5 additions & 5 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
*/

libraryDependencies += "org.scala-sbt" %% "scripted-plugin" % sbtVersion.value
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6")
addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.3.0")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.9.3")
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.11")
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6")
addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.3.0")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.9.3")
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.11")
46 changes: 21 additions & 25 deletions src/main/scala/com/ea/kara/Context.scala
Original file line number Diff line number Diff line change
Expand Up @@ -65,33 +65,29 @@ case class CodegenContext(
val docToSvc = thriftFiles
.flatMap(file => file.document.services.map(service => (file.document, service)))

val pkgToSvc = servicePackageAndName.flatMap {
case (pkg, names) => names.map((pkg, _))
}
val servicesByDocument: Map[Document, Seq[String]] = pkgToSvc
.map {
case (pkg, name) =>
docToSvc
.find {
case (doc, docSvc) =>
doc.javaNamespace == pkg &&
docSvc.sid.name == name
}
.getOrElse {
throw new RuntimeException(
s"No service '$name' found in package '$pkg'." +
"Valid alternatives are: " +
docToSvc
.filter { case (doc, _) => doc.javaNamespace == pkg }
.map { case (_, svc) => svc.sid.name }
.mkString(", ")
)
}
val servicesByDocument: Map[Document, Seq[String]] = servicePackageAndName
.toList
.flatMap { case (pkg, svcNames) => svcNames.map((pkg, _)) }
.map { case (pkg, svcName) =>
docToSvc
.find {
case (doc, docSvc) =>
doc.javaNamespace == pkg &&
docSvc.sid.name == svcName
}
.getOrElse {
throw new RuntimeException(
s"No service '$svcName' found in package '$pkg'." +
"Valid alternatives are: " +
docToSvc
.filter { case (doc, _) => doc.javaNamespace == pkg }
.map { case (_, svc) => svc.sid.name }
.mkString(", ")
)
}
}
.groupBy(_._1)
.map {
case (k, v) => (k, v.map(_._2.sid.name).toSeq)
}
.map { case (k, v) => (k, v.map(_._2.sid.name)) }

servicesByDocument
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/com/ea/kara/Generator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class Generator(
thriftFile.document.services.filter(service => serviceNames.contains(service.sid.name))

logger.debug(
s"Generating services [${services.map(_.sid.name)}] for Thrift file ${thriftFile.name}..."
s"Generating services [${services.map(_.sid.name).mkString(", ")}] for Thrift file ${thriftFile.name}..."
)

services.foreach { service =>
Expand Down
14 changes: 7 additions & 7 deletions src/main/scala/com/ea/kara/Kara.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
package com.ea.kara

import com.twitter.scrooge.ScroogeSBT
import sbt._
import sbt.Keys._
import sbt.*
import sbt.Keys.*

object Kara extends AutoPlugin {

Expand Down Expand Up @@ -44,16 +44,16 @@ object Kara extends AutoPlugin {
)
}

import autoImport._
import ScroogeSBT.autoImport._
import autoImport.*
import ScroogeSBT.autoImport.*

val circeVersion: String = "0.14.1"

override lazy val globalSettings: Seq[Setting[_]] = Seq(
override lazy val globalSettings: Seq[Setting[?]] = Seq(
Compile / karaHeaders := Seq.empty
)

override lazy val projectSettings: Seq[Setting[_]] = Seq(
override lazy val projectSettings: Seq[Setting[?]] = Seq(
libraryDependencies ++=
Seq("finagle-http", "scrooge-serializer", "finagle-thrift")
.map("com.twitter" %% _)
Expand Down Expand Up @@ -82,7 +82,7 @@ object Kara extends AutoPlugin {
if (oldSources.nonEmpty) {
val karaDir = (generator.sourcePath ** "kara").filter(_.isDirectory).get.headOption
logger.info(
s"Generated Kara sources in $karaDir are out of date, deleting them and re-generating"
s"Generated Kara sources in $karaDir are out of date, deleting them and re-generating..."
)
karaDir.foreach(IO.delete)
}
Expand Down
6 changes: 5 additions & 1 deletion src/sbt-test/kara/declaration_order/project/build.sbt
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-parser-combinators" % "always"
/*
* Copyright (C) 2022 Electronic Arts Inc. All rights reserved.
*/

ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-parser-combinators" % VersionScheme.Always
6 changes: 5 additions & 1 deletion src/sbt-test/kara/dirty/project/build.sbt
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-parser-combinators" % "always"
/*
* Copyright (C) 2022 Electronic Arts Inc. All rights reserved.
*/

ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-parser-combinators" % VersionScheme.Always
6 changes: 5 additions & 1 deletion src/sbt-test/kara/e2e/project/build.sbt
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-parser-combinators" % "always"
/*
* Copyright (C) 2022 Electronic Arts Inc. All rights reserved.
*/

ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-parser-combinators" % VersionScheme.Always
2 changes: 1 addition & 1 deletion src/sbt-test/kara/e2e/test
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Copyright (C) 2022 Electronic Arts Inc. All rights reserved.

# Make sure the generated sources compile
# Make sure all request/response patterns are supported
> run mirror
> run oneArgUnwrapped
> run knownException
Expand Down
6 changes: 5 additions & 1 deletion src/sbt-test/kara/imports/project/build.sbt
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-parser-combinators" % "always"
/*
* Copyright (C) 2022 Electronic Arts Inc. All rights reserved.
*/

ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-parser-combinators" % VersionScheme.Always
6 changes: 5 additions & 1 deletion src/sbt-test/kara/invalid_service/project/build.sbt
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-parser-combinators" % "always"
/*
* Copyright (C) 2022 Electronic Arts Inc. All rights reserved.
*/

ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-parser-combinators" % VersionScheme.Always
27 changes: 27 additions & 0 deletions src/sbt-test/kara/multi_service/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2022 Electronic Arts Inc. All rights reserved.
*/

import sbt._

val twitterVersion = "20.10.0"
val circeVersion = "0.14.1"

lazy val root = (project in file("."))
.settings(
scalaVersion := "2.12.15",
libraryDependencies ++= Seq(
"com.twitter" %% "twitter-server" % twitterVersion,
"com.twitter" %% "scrooge-core" % twitterVersion,
"com.twitter" %% "finagle-http" % twitterVersion,
"io.circe" %% "circe-generic" % circeVersion,
"io.circe" %% "circe-parser" % circeVersion
),
karaServices := Seq(
"com.local.ServiceOne",
"com.local.ServiceTwo",
"com.local.ServiceThree",
"com.local.ServiceFour",
)
)
.enablePlugins(Kara)
5 changes: 5 additions & 0 deletions src/sbt-test/kara/multi_service/project/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/*
* Copyright (C) 2022 Electronic Arts Inc. All rights reserved.
*/

ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-parser-combinators" % VersionScheme.Always
9 changes: 9 additions & 0 deletions src/sbt-test/kara/multi_service/project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright (C) 2022 Electronic Arts Inc. All rights reserved.
*/

sys.props.get("plugin.version") match {
case Some(x) => addSbtPlugin("com.ea.kara" % "kara" % x)
case _ => sys.error("""|The system property 'plugin.version' is not defined.
|Specify this property using the scriptedLaunchOpts -D.""".stripMargin)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright (C) 2022 Electronic Arts Inc. All rights reserved.
*/

import java.net.InetSocketAddress

import com.local._
import com.twitter.finagle.http
import com.twitter.finagle.Http
import com.twitter.finagle.Service
import com.twitter.util.{Await, Future}
import io.circe._
import io.circe.generic.auto._
import com.ea.kara.generated.svc_one._
import com.ea.kara.generated.svc_two._
import com.ea.kara.generated.svcs_three_four._

object MultiServiceTest extends App {

case class GenericError(message: String)

lazy val svcOne: Service[http.Request, http.Response] = new HttpServiceOne(new ServiceOne)
lazy val svcTwo: Service[http.Request, http.Response] = new HttpServiceTwo(new ServiceTwo)
lazy val svcThree: Service[http.Request, http.Response] = new HttpServiceThree(new ServiceThree)
lazy val svcFour: Service[http.Request, http.Response] = new HttpServiceFour(new ServiceFour)

override def main(args: Array[String]): Unit = {
assert(args.length == 1, "Should pass the name of the test to run.")

val testName = args.head

val request = finagleRequest("ping")

testName match {
case "pingServiceOne" => serve(svcOne, request)
case "pingServiceTwo" => serve(svcTwo, request)
case "pingServiceThree" => serve(svcThree, request)
case "pingServiceFour" => serve(svcFour, request)
}
}

def serve(svc: Service[http.Request, http.Response], request: http.Request): Unit = {
val response = Await.result(svc(request))
assertSuccessfulResponse(response)
}

def finagleRequest(rpcName: String): http.Request = {
val request = http.Request(method = com.twitter.finagle.http.Method.Post, uri = s"/$rpcName")
request.setContentTypeJson()
request
}

def assertSuccessfulResponse(response: http.Response): Unit = {
assertJsonResponse(response)
assertResponseStatus(response, http.Status.Ok)
}

def assertResponseStatus(response: http.Response, expectedStatus: http.Status): Unit =
assert(
response.status == expectedStatus,
s"""
|Status code should be '$expectedStatus',
|instead was found ${response.status}.
""".stripMargin
)

def assertJsonResponse(response: http.Response): Unit = {
val applicationJsonContentType = "application/json;charset=utf-8"
assert(
response.contentType == Some(applicationJsonContentType),
s"""
|Content type should be '$applicationJsonContentType',
|instead was found '${response.contentType}'.
""".stripMargin
)
}
}

class ServiceOne extends ServiceOne.MethodPerEndpoint {
override def ping(): Future[Unit] = Future.Unit
}

class ServiceTwo extends ServiceTwo.MethodPerEndpoint {
override def ping(): Future[Unit] = Future.Unit
}

class ServiceThree extends ServiceThree.MethodPerEndpoint {
override def ping(): Future[Unit] = Future.Unit
}

class ServiceFour extends ServiceFour.MethodPerEndpoint {
override def ping(): Future[Unit] = Future.Unit
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright (C) 2022 Electronic Arts Inc. All rights reserved.
*/

namespace java com.local

service ServiceOne {
void ping()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright (C) 2022 Electronic Arts Inc. All rights reserved.
*/

namespace java com.local

service ServiceTwo {
void ping()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright (C) 2022 Electronic Arts Inc. All rights reserved.
*/

namespace java com.local

service ServiceThree {
void ping()
}

service ServiceFour {
void ping()
}
8 changes: 8 additions & 0 deletions src/sbt-test/kara/multi_service/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (C) 2022 Electronic Arts Inc. All rights reserved.

# Make sure both services can be hit
> run pingServiceOne
> run pingServiceTwo
> run pingServiceThree
> run pingServiceFour

6 changes: 5 additions & 1 deletion src/sbt-test/kara/no_package/project/build.sbt
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-parser-combinators" % "always"
/*
* Copyright (C) 2022 Electronic Arts Inc. All rights reserved.
*/

ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-parser-combinators" % VersionScheme.Always
2 changes: 1 addition & 1 deletion version.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ def buildSuffix: String = {
if (isSnapshot) "-SNAPSHOT" else ""
}

ThisBuild / version := "0.2.1" + buildSuffix
ThisBuild / version := "0.2.2" + buildSuffix

0 comments on commit bc18f8e

Please sign in to comment.