Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleaning up structure #163

Merged
13 changes: 13 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,19 @@ v0.42.0
- #165 http4s server generator handle root path
- #152 Make akka-http clients handle all status codes and described entities (Breaking change, please see MIGRATING.md)

v0.41.5
=======

- #159 Making akka-http FormData return 413 instead of 500, delete failed files
- #158 Abstracting companion objects in preparation for java support

v0.41.4
=======

- #150 Exposing helpful error messages
- #156 Bumping sbt-pgp
- #157 Bumping kind-projector

v0.41.3
=======

Expand Down
116 changes: 53 additions & 63 deletions build.sbt
Expand Up @@ -23,64 +23,54 @@ val scalatestVersion = "3.0.5"

mainClass in assembly := Some("com.twilio.guardrail.CLI")

// (filename, prefix, tracing)
def sampleResource(name: String): java.io.File = file(s"modules/sample/src/main/resources/${name}")
val exampleCases: List[(java.io.File, String, Boolean, List[String])] = List(
(sampleResource("alias.yaml"), "alias", false, List.empty),
(sampleResource("contentType-textPlain.yaml"), "tests.contentTypes.textPlain", false, List.empty),
(sampleResource("custom-header-type.yaml"), "tests.customTypes.customHeader", false, List.empty),
(sampleResource("edgecases/defaults.yaml"), "edgecases.defaults", false, List.empty),
(sampleResource("formData.yaml"), "form", false, List.empty),
(sampleResource("issues/issue121.yaml"), "issues.issue121", false, List.empty),
(sampleResource("issues/issue127.yaml"), "issues.issue127", false, List.empty),
(sampleResource("issues/issue143.yaml"), "issues.issue143", false, List.empty),
(sampleResource("issues/issue148.yaml"), "issues.issue148", false, List.empty),
(sampleResource("issues/issue164.yaml"), "issues.issue148", false, List.empty),
(sampleResource("petstore.json"), "examples", false, List("--import", "support.PositiveLong")),
(sampleResource("plain.json"), "tests.dtos", false, List.empty),
(sampleResource("polymorphism.yaml"), "polymorphism", false, List.empty),
(sampleResource("raw-response.yaml"), "raw", false, List.empty),
(sampleResource("server1.yaml"), "tracer", true, List.empty),
(sampleResource("server2.yaml"), "tracer", true, List.empty)
)

val exampleArgs: List[List[String]] = exampleCases
.foldLeft(List.empty[List[String]])({
case (acc, (path, prefix, tracing, extra)) =>
acc ++ (for {
kind <- List("client", "server")
frameworkPair <- List(
("akka-http", "akkaHttp"),
("http4s", "http4s")
)
(frameworkName, frameworkPackage) = frameworkPair
tracingFlag = if (tracing) Option("--tracing") else Option.empty[String]
} yield
(
List(s"--${kind}") ++
List("--specPath", path.toString()) ++
List("--outputPath", "modules/sample/src/main/scala") ++
List("--packageName", s"${prefix}.${kind}.${frameworkPackage}") ++
List("--framework", frameworkName)
) ++ tracingFlag ++ extra)
})

lazy val runScalaExample: TaskKey[Unit] = taskKey[Unit]("Run scala generator with example args")
fullRunTask(
runScalaExample,
Test,
"com.twilio.guardrail.CLI",
"""
--defaults --import support.PositiveLong
--client --specPath modules/sample/src/main/resources/polymorphism.yaml --outputPath modules/sample/src/main/scala --packageName polymorphism.client.http4s --framework http4s
--client --specPath modules/sample/src/main/resources/polymorphism.yaml --outputPath modules/sample/src/main/scala --packageName polymorphism.client.akkaHttp --framework akka-http
--server --specPath modules/sample/src/main/resources/polymorphism.yaml --outputPath modules/sample/src/main/scala --packageName polymorphism.server.http4s --framework http4s
--server --specPath modules/sample/src/main/resources/polymorphism.yaml --outputPath modules/sample/src/main/scala --packageName polymorphism.server.akkaHttp --framework akka-http
--client --specPath modules/sample/src/main/resources/petstore.json --outputPath modules/sample/src/main/scala --packageName clients.http4s --framework http4s
--client --specPath modules/sample/src/main/resources/petstore.json --outputPath modules/sample/src/main/scala --packageName clients.akkaHttp --framework akka-http
--server --specPath modules/sample/src/main/resources/petstore.json --outputPath modules/sample/src/main/scala --packageName servers.http4s --framework http4s
--server --specPath modules/sample/src/main/resources/petstore.json --outputPath modules/sample/src/main/scala --packageName servers.akkaHttp --framework akka-http
--client --specPath modules/sample/src/main/resources/plain.json --outputPath modules/sample/src/main/scala --packageName tests.dtos.http4s --framework http4s
--client --specPath modules/sample/src/main/resources/plain.json --outputPath modules/sample/src/main/scala --packageName tests.dtos.akkaHttp --framework akka-http
--client --specPath modules/sample/src/main/resources/contentType-textPlain.yaml --outputPath modules/sample/src/main/scala --packageName tests.contentTypes.textPlain.client.http4s --framework http4s
--client --specPath modules/sample/src/main/resources/contentType-textPlain.yaml --outputPath modules/sample/src/main/scala --packageName tests.contentTypes.textPlain.client.akkaHttp --framework akka-http
--server --specPath modules/sample/src/main/resources/contentType-textPlain.yaml --outputPath modules/sample/src/main/scala --packageName tests.contentTypes.textPlain.server.http4s --framework http4s
--server --specPath modules/sample/src/main/resources/contentType-textPlain.yaml --outputPath modules/sample/src/main/scala --packageName tests.contentTypes.textPlain.server.akkaHttp --framework akka-http
--server --specPath modules/sample/src/main/resources/raw-response.yaml --outputPath modules/sample/src/main/scala --packageName raw.server.http4s --framework http4s
--server --specPath modules/sample/src/main/resources/raw-response.yaml --outputPath modules/sample/src/main/scala --packageName raw.server.akkaHttp --framework akka-http
--server --specPath modules/sample/src/test/resources/server1.yaml --outputPath modules/sample/src/main/scala --packageName tracer.servers.http4s --tracing --framework http4s
--server --specPath modules/sample/src/test/resources/server1.yaml --outputPath modules/sample/src/main/scala --packageName tracer.servers.akkaHttp --tracing --framework akka-http
--client --specPath modules/sample/src/test/resources/server1.yaml --outputPath modules/sample/src/main/scala --packageName tracer.clients.http4s --tracing --framework http4s
--client --specPath modules/sample/src/test/resources/server1.yaml --outputPath modules/sample/src/main/scala --packageName tracer.clients.akkaHttp --tracing --framework akka-http
--server --specPath modules/sample/src/test/resources/server2.yaml --outputPath modules/sample/src/main/scala --packageName tracer.servers.http4s --tracing --framework http4s
--server --specPath modules/sample/src/test/resources/server2.yaml --outputPath modules/sample/src/main/scala --packageName tracer.servers.akkaHttp --tracing --framework akka-http
--client --specPath modules/sample/src/test/resources/server2.yaml --outputPath modules/sample/src/main/scala --packageName tracer.clients.http4s --tracing --framework http4s
--client --specPath modules/sample/src/test/resources/server2.yaml --outputPath modules/sample/src/main/scala --packageName tracer.clients.akkaHttp --tracing --framework akka-http
--client --specPath modules/sample/src/main/resources/alias.yaml --outputPath modules/sample/src/main/scala --packageName alias.client.http4s --framework http4s
--client --specPath modules/sample/src/main/resources/alias.yaml --outputPath modules/sample/src/main/scala --packageName alias.client.akkaHttp --framework akka-http
--server --specPath modules/sample/src/main/resources/alias.yaml --outputPath modules/sample/src/main/scala --packageName alias.server.http4s --framework http4s
--server --specPath modules/sample/src/main/resources/alias.yaml --outputPath modules/sample/src/main/scala --packageName alias.server.akkaHttp --framework akka-http
--client --specPath modules/sample/src/main/resources/edgecases/defaults.yaml --outputPath modules/sample/src/main/scala --packageName edgecases.defaults.http4s --framework http4s
--client --specPath modules/sample/src/main/resources/edgecases/defaults.yaml --outputPath modules/sample/src/main/scala --packageName edgecases.defaults.akkaHttp --framework akka-http
--client --specPath modules/sample/src/main/resources/custom-header-type.yaml --outputPath modules/sample/src/main/scala --packageName tests.customTypes.customHeader.client.http4s --framework http4s
--client --specPath modules/sample/src/main/resources/custom-header-type.yaml --outputPath modules/sample/src/main/scala --packageName tests.customTypes.customHeader.client.akkaHttp --framework akka-http
--server --specPath modules/sample/src/main/resources/custom-header-type.yaml --outputPath modules/sample/src/main/scala --packageName tests.customTypes.customHeader.server.http4s --framework http4s
--server --specPath modules/sample/src/main/resources/custom-header-type.yaml --outputPath modules/sample/src/main/scala --packageName tests.customTypes.customHeader.server.akkaHttp --framework akka-http
--client --specPath modules/sample/src/main/resources/formData.yaml --outputPath modules/sample/src/main/scala --packageName form.client.http4s --framework http4s
--client --specPath modules/sample/src/main/resources/formData.yaml --outputPath modules/sample/src/main/scala --packageName form.client.akkaHttp --framework akka-http
--server --specPath modules/sample/src/main/resources/formData.yaml --outputPath modules/sample/src/main/scala --packageName form.server.http4s --framework http4s
--server --specPath modules/sample/src/main/resources/formData.yaml --outputPath modules/sample/src/main/scala --packageName form.server.akkaHttp --framework akka-http
--server --specPath modules/sample/src/main/resources/issues/issue121.yaml --outputPath modules/sample/src/main/scala --packageName issues.issue121.server.akkaHttp --framework akka-http
--client --specPath modules/sample/src/main/resources/issues/issue121.yaml --outputPath modules/sample/src/main/scala --packageName issues.issue121.client.akkaHttp --framework akka-http
--server --specPath modules/sample/src/main/resources/issues/issue121.yaml --outputPath modules/sample/src/main/scala --packageName issues.issue121.server.http4s --framework http4s
--client --specPath modules/sample/src/main/resources/issues/issue121.yaml --outputPath modules/sample/src/main/scala --packageName issues.issue121.client.http4s --framework http4s
--server --specPath modules/sample/src/main/resources/issues/issue127.yaml --outputPath modules/sample/src/main/scala --packageName issues.issue127
--server --specPath modules/sample/src/main/resources/issues/issue143.yaml --outputPath modules/sample/src/main/scala --packageName issues.issue143
--client --specPath modules/sample/src/main/resources/issues/issue148.yaml --outputPath modules/sample/src/main/scala --packageName issues.issue148.client.http4s --framework http4s
--client --specPath modules/sample/src/main/resources/issues/issue148.yaml --outputPath modules/sample/src/main/scala --packageName issues.issue148.client.akkaHttp --framework akka-http
--server --specPath modules/sample/src/main/resources/issues/issue148.yaml --outputPath modules/sample/src/main/scala --packageName issues.issue148.server.http4s --framework http4s
--server --specPath modules/sample/src/main/resources/issues/issue148.yaml --outputPath modules/sample/src/main/scala --packageName issues.issue148.server.akkaHttp --framework akka-http
--client --specPath modules/sample/src/main/resources/issues/issue164.yaml --outputPath modules/sample/src/main/scala --packageName issues.issue164.client.http4s --framework http4s
--client --specPath modules/sample/src/main/resources/issues/issue164.yaml --outputPath modules/sample/src/main/scala --packageName issues.issue164.client.akkaHttp --framework akka-http
""".replaceAllLiterally("\n", " ").split(' ').filter(_.nonEmpty): _*
exampleArgs.flatten.filter(_.nonEmpty): _*
)

artifact in (Compile, assembly) := {
Expand Down Expand Up @@ -126,9 +116,11 @@ val testDependencies = Seq(
"org.scalatest" %% "scalatest" % scalatestVersion % Test
)

val excludedWarts = Set(Wart.DefaultArguments, Wart.Product, Wart.Serializable)
val codegenSettings = Seq(
addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.9"),
addCompilerPlugin("org.spire-math" % "kind-projector" % "0.9.9" cross CrossVersion.binary),
wartremoverWarnings in Compile ++= Warts.unsafe.filterNot(w => excludedWarts.exists(_.clazz == w.clazz)),
wartremoverWarnings in Test := List.empty,
libraryDependencies ++= testDependencies ++ Seq(
"org.scalameta" %% "scalameta" % "4.1.0",
"io.swagger" % "swagger-parser" % "1.0.39",
Expand All @@ -137,23 +129,20 @@ val codegenSettings = Seq(
"org.typelevel" %% "cats-kernel" % catsVersion,
"org.typelevel" %% "cats-macros" % catsVersion,
"org.typelevel" %% "cats-free" % catsVersion
)
// Dev
,
),
scalacOptions in ThisBuild ++= Seq(
"-Ypartial-unification",
"-language:higherKinds",
"-Xexperimental",
"-Ydelambdafy:method",
// "-Yno-adapted-args",
"-Xlint:_,-unused",
"-feature",
"-unchecked",
"-deprecation",
"-target:jvm-1.8",
"-encoding",
"utf8"
),
) ++ (if (scalaVersion.value.startsWith("2.11.")) {
List("-Xexperimental", "-Xlint:_")
} else {
List("-Xlint:-unused,_")
}),
parallelExecution in Test := true,
fork := true
)
Expand All @@ -169,6 +158,7 @@ lazy val codegen = (project in file("modules/codegen"))
.settings(
(name := "guardrail") +:
codegenSettings,
scalacOptions += "-language:higherKinds",
bintrayRepository := {
if (isSnapshot.value) "snapshots"
else "releases"
Expand Down
Expand Up @@ -3,14 +3,13 @@ package com.twilio.guardrail
import _root_.io.swagger.models._
import _root_.io.swagger.models.parameters._
import _root_.io.swagger.models.properties._
import cats.{ FlatMap, Foldable, MonadError }
import cats.data.{ EitherK, EitherT }
import cats.{ FlatMap, Foldable }
import cats.free.Free
import cats.implicits._
import com.twilio.guardrail.terms.{ ScalaTerm, ScalaTerms, SwaggerTerm, SwaggerTerms }
import com.twilio.guardrail.terms.framework.{ FrameworkTerm, FrameworkTerms }
import com.twilio.guardrail.terms.{ ScalaTerms, SwaggerTerms }
import com.twilio.guardrail.terms.framework.FrameworkTerms
import com.twilio.guardrail.extract.{ Default, ScalaType }
import com.twilio.guardrail.generators.{ AkkaHttpGenerator, Responses, ScalaGenerator, ScalaParameter, SwaggerGenerator }
import com.twilio.guardrail.generators.{ Responses, ScalaParameter }
import com.twilio.guardrail.languages.LA
import java.util.{ Map => JMap }
import scala.language.reflectiveCalls
Expand Down
@@ -1,17 +1,15 @@
package com.twilio.guardrail
package core

import cats.data.NonEmptyList
import cats.instances.all._
import cats.syntax.flatMap._
import cats.syntax.either._
import cats.syntax.traverse._
import cats.data.{ NonEmptyList, State }
import cats.implicits._
import cats.{ FlatMap, ~> }
import com.twilio.guardrail.languages.LA
import com.twilio.guardrail.terms._
import java.nio.file.Paths
import scala.io.AnsiColor
import scala.meta._
import scala.util.control.NonFatal

object CoreTermInterp {
def apply[L <: LA](defaultFramework: String,
Expand Down Expand Up @@ -122,11 +120,41 @@ object CoreTermInterp {
} yield {
ReadSwagger(
Paths.get(specPath), { swagger =>
(for {
defs <- Common.prepareDefinitions[L, CodegenApplication[L, ?]](kind, context, swagger)
(proto, codegen) = defs
result <- Common.writePackage[L, CodegenApplication[L, ?]](proto, codegen, context)(Paths.get(outputPath), pkgName, dtoPackage, customImports)
} yield result).foldMap(targetInterpreter)
try {
(for {
defs <- Common.prepareDefinitions[L, CodegenApplication[L, ?]](kind, context, swagger)
(proto, codegen) = defs
result <- Common.writePackage[L, CodegenApplication[L, ?]](proto, codegen, context)(Paths.get(outputPath), pkgName, dtoPackage, customImports)
} yield result).foldMap(targetInterpreter)
} catch {
case NonFatal(ex) =>
val stackTrace =
ex.getStackTrace()
.toList
.foldLeftM[State[Option[String], ?], List[String]](List.empty)({
case (acc, next) =>
for {
lastClassName <- State.get
_ <- State.set(Option(next.getClassName()))
} yield {
if (next.getClassName().startsWith("com.twilio")) {
acc :+ s" at ${next.toString()}"
} else {
if (lastClassName.exists(_.startsWith("com.twilio"))) {
acc :+ " ..."
} else acc
}
}
})
.runA(Option.empty)
.value
Target.raiseError(s"""
|Error attempting to process ${specPath}:
|
|${ex.toString()}
|${stackTrace.mkString("\n")}
|""".stripMargin.trim)
}
}
)
}
Expand Down
Expand Up @@ -39,6 +39,7 @@ object AkkaHttpGenerator {
q"import cats.data.EitherT",
q"import cats.implicits._",
q"import scala.concurrent.{ExecutionContext, Future}",
q"import scala.language.higherKinds",
q"import scala.language.implicitConversions",
q"import java.io.File",
q"import java.security.MessageDigest",
Expand Down
Expand Up @@ -5,6 +5,7 @@ import _root_.io.swagger.models.{ ArrayModel, ComposedModel, Model, ModelImpl, R
import _root_.io.swagger.models.properties._
import cats.implicits._
import cats.~>
import cats.data.NonEmptyList
import com.twilio.guardrail.extract.{ Default, ScalaEmptyIsNull, ScalaType }
import com.twilio.guardrail.terms
import java.util.Locale
Expand Down Expand Up @@ -366,10 +367,15 @@ object CirceProtocolGenerator {
def allParents(model: Model): List[(String, Model, List[RefModel])] =
(model match {
case elem: ComposedModel =>
definitions.collectFirst {
case (clsName, e) if elem.getInterfaces.asScala.headOption.exists(_.getSimpleRef == clsName) =>
(clsName, e, elem.getInterfaces.asScala.tail.toList)
}
NonEmptyList
.fromList(elem.getInterfaces.asScala.toList)
.flatMap({
case NonEmptyList(head, tail) =>
definitions.collectFirst {
case (clsName, e) if head.getSimpleRef == clsName =>
(clsName, e, tail.toList)
}
})
case _ => None
}) match {
case Some(x @ (_, el, _)) => x :: allParents(el)
Expand Down
Expand Up @@ -40,6 +40,7 @@ object Http4sGenerator {
q"import org.http4s.EntityDecoder._",
q"import fs2.Stream",
q"import io.circe.Json",
q"import scala.language.higherKinds",
q"import scala.language.implicitConversions"
)
)
Expand Down
Expand Up @@ -2,7 +2,7 @@ package com.twilio.guardrail.generators.syntax

import cats.data.NonEmptyList
import com.twilio.guardrail.StaticDefns
import com.twilio.guardrail.generators._
import com.twilio.guardrail.generators.{ RawParameterName, ScalaParameter }
import com.twilio.guardrail.languages.ScalaLanguage
import scala.meta._

Expand Down