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

Better error messages #402

Merged
merged 30 commits into from
Oct 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
724dbd6
Passing basePath through to ServerGenerator instead of all of swagger
blast-hardcheese Sep 10, 2019
895cb7e
Suppress throw warnings in Target
blast-hardcheese Sep 11, 2019
e13a93f
Removing unused imports
blast-hardcheese Sep 11, 2019
93f16fe
Reordering imports
blast-hardcheese Sep 11, 2019
eaca759
Instances
blast-hardcheese Sep 19, 2019
df5d50c
Adding contramap to VendorExtensible
blast-hardcheese Sep 19, 2019
d533bd4
Adding TreeEquality
blast-hardcheese Sep 19, 2019
c042980
Adding a spec runner for invalid specifications
blast-hardcheese Sep 19, 2019
d0f0634
Adding Tracker to keep track of accesses into OAI model
blast-hardcheese Sep 8, 2019
5674732
Passing through VendorExtensible to instances of Tracker
blast-hardcheese Sep 16, 2019
b64968a
Starting to convert some calling code over to Tracker
blast-hardcheese Sep 10, 2019
a426a0c
reformatting
blast-hardcheese Sep 19, 2019
73a84dc
Removing missing-interpolator warning
blast-hardcheese Sep 16, 2019
fab0194
Altering test definition descriptions
blast-hardcheese Sep 18, 2019
3e2cf59
Showing debug logs from spec runner
blast-hardcheese Sep 18, 2019
b1da6e7
Converting more functions over to Tracker
blast-hardcheese Sep 19, 2019
8cbc397
Adding some tests for Tracker error messages
blast-hardcheese Sep 19, 2019
fa3caba
NEL syntax for Tracker
blast-hardcheese Sep 19, 2019
710baf3
Converting even more functions
blast-hardcheese Sep 19, 2019
86b3596
Switching even more code over to Tracker
blast-hardcheese Sep 19, 2019
5eac3a3
Converting propMeta
blast-hardcheese Sep 19, 2019
70f3901
Adding Tracker Either syntax
blast-hardcheese Sep 20, 2019
e204d70
Adding Tracker to RouteMeta path
blast-hardcheese Sep 20, 2019
4875835
Breaking out IndexedFunctor/IndexedDistributive from bespoke Tracker …
blast-hardcheese Sep 25, 2019
b5be0fd
Removing extract and sequence helpers now that cotraverse and indexed…
blast-hardcheese Sep 25, 2019
b90df77
Commenting out printlns
blast-hardcheese Sep 25, 2019
79c39c9
Interpolating Tracker into format fallback error message
blast-hardcheese Sep 25, 2019
e187238
Consistency, dot-access Map fields, bracket-index arrays
blast-hardcheese Sep 25, 2019
6faa3de
Removing the last bit of bespoke sequence enriched syntax
blast-hardcheese Sep 25, 2019
f23cbf7
Renaming Mappish file to reflect name
blast-hardcheese Sep 25, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 6 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ val catsVersion = "1.6.0"
val catsEffectVersion = "1.0.0"
val circeVersion = "0.10.1"
val http4sVersion = "0.20.0"
val scalacheckVersion = "1.14.0"
val scalatestVersion = "3.0.8"
val javaparserVersion = "3.7.1"
val endpointsVersion = "0.8.0"
Expand Down Expand Up @@ -168,7 +169,8 @@ addCompilerPlugin("org.typelevel" % "kind-projector" % kindProjectorVersion cro
publishMavenStyle := true

val testDependencies = Seq(
"org.scalatest" %% "scalatest" % scalatestVersion % Test
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test
)

val excludedWarts = Set(Wart.DefaultArguments, Wart.Product, Wart.Serializable, Wart.Any)
Expand All @@ -187,9 +189,9 @@ val codegenSettings = Seq(
"-encoding",
"utf8"
) ++ (if (scalaVersion.value.startsWith("2.11.")) {
List("-Xexperimental", "-Xlint:_")
List("-Xexperimental", "-Xlint:-missing-interpolator,_")
} else {
List("-Xlint:-unused,_")
List("-Xlint:-unused,-missing-interpolator,_")
}),
parallelExecution in Test := true
)
Expand Down Expand Up @@ -221,6 +223,7 @@ lazy val codegen = (project in file("modules/codegen"))
scalacOptions ++= List(
"-language:higherKinds",
"-Ywarn-unused-import",
"-Xlint:_,-missing-interpolator"
),
bintrayRepository := {
if (isSnapshot.value) "snapshots"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ object ClientGenerator {
supportDefinitions <- generateSupportDefinitions(context.tracing, securitySchemes)
clients <- groupedRoutes.traverse({
case (className, unsortedRoutes) =>
val routes = unsortedRoutes.sortBy(r => (r.path, r.method))
val routes = unsortedRoutes.sortBy(r => (r.path.unwrapTracker, r.method))
val clientName = s"${className.lastOption.getOrElse("").capitalize}Client"
def splitOperationParts(operationId: String): (List[String], String) = {
val parts = operationId.split('.')
Expand Down
57 changes: 35 additions & 22 deletions modules/codegen/src/main/scala/com/twilio/guardrail/Common.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,23 @@ import cats.data.NonEmptyList
import cats.free.Free
import cats.implicits._
import cats.Id
import com.twilio.guardrail.core.Tracker
import com.twilio.guardrail.extract.SecurityOptional
import com.twilio.guardrail.languages.LA
import com.twilio.guardrail.protocol.terms.protocol.{ ArrayProtocolTerms, EnumProtocolTerms, ModelProtocolTerms, PolyProtocolTerms, ProtocolSupportTerms }
import com.twilio.guardrail.terms.framework.FrameworkTerms
import com.twilio.guardrail.protocol.terms.client.ClientTerms
import com.twilio.guardrail.protocol.terms.server.ServerTerms
import com.twilio.guardrail.shims._
import com.twilio.guardrail.terms.{ CoreTerms, ScalaTerms, SecurityRequirements, SwaggerTerms }
import java.nio.file.Path
import scala.collection.JavaConverters._
import java.net.URI

case class SupportDefinition[L <: LA](className: L#TermName, imports: List[L#Import], definition: L#ClassDefinition)

object Common {
val resolveFile: Path => List[String] => Path = root => _.foldLeft(root)(_.resolve(_))

def prepareDefinitions[L <: LA, F[_]](kind: CodegenTarget, context: Context, swagger: OpenAPI)(
def prepareDefinitions[L <: LA, F[_]](kind: CodegenTarget, context: Context, swagger: Tracker[OpenAPI])(
implicit
C: ClientTerms[L, F],
R: ArrayProtocolTerms[L, F],
Expand All @@ -43,26 +42,40 @@ object Common {
proto <- ProtocolGenerator.fromSwagger[L, F](swagger)
ProtocolDefinitions(protocolElems, protocolImports, packageObjectImports, packageObjectContents) = proto

serverUrls = Option(swagger.getServers)
.map(_.asScala.toList)
.map(_.flatMap({ x =>
Option(x.getUrl())
.map({ x =>
val uri = new URI(x.iterateWhileM[Id](_.stripSuffix("/"))(_.endsWith("/")))
val scheme = Option(uri.getScheme).orElse(Option(uri.getHost).filterNot(_.isEmpty).map(_ => "http")).getOrElse(null) // Only force a scheme if we have a host, falling back to null as required by URI
new URI(scheme, uri.getUserInfo, uri.getHost, uri.getPort, "", uri.getQuery, uri.getFragment)
})
.filterNot(_.toString().isEmpty)
}))
.flatMap(NonEmptyList.fromList(_))
basePath = swagger.basePath()

paths = swagger.getPathsOpt()
globalSecurityRequirements = Option(swagger.getSecurity).flatMap(SecurityRequirements(_, SecurityOptional(swagger), SecurityRequirements.Global))
requestBodies <- extractCommonRequestBodies(Option(swagger.getComponents))
serverUrls = NonEmptyList.fromList(
swagger
.downField("servers", _.getServers)
.flatExtract(
server =>
server
.downField("url", _.getUrl)
.get
.map({ x =>
val uri = new URI(x.iterateWhileM[Id](_.stripSuffix("/"))(_.endsWith("/")))
@SuppressWarnings(Array("org.wartremover.warts.Null"))
val scheme = Option(uri.getScheme).orElse(Option(uri.getHost).filterNot(_.isEmpty).map(_ => "http")).getOrElse(null) // Only force a scheme if we have a host, falling back to null as required by URI
new URI(scheme, uri.getUserInfo, uri.getHost, uri.getPort, "", uri.getQuery, uri.getFragment)
})
.filterNot(_.toString().isEmpty)
.toList
)
)
basePath = swagger
.downField("servers", _.getServers)
.cotraverse(_.downField("url", _.getUrl))
.headOption
.flatMap(_.get)
.flatMap(url => Option(new URI(url).getPath))
.filter(_ != "/")

paths = swagger.downField("paths", _.getPaths)
globalSecurityRequirements = NonEmptyList
.fromList(swagger.downField("security", _.getSecurity).get)
.flatMap(SecurityRequirements(_, SecurityOptional(swagger.get), SecurityRequirements.Global))
requestBodies <- extractCommonRequestBodies(swagger.downField("components", _.getComponents).get)
routes <- extractOperations(paths, requestBodies, globalSecurityRequirements)
prefixes <- vendorPrefixes()
securitySchemes <- SwaggerUtil.extractSecuritySchemes(swagger, prefixes)
securitySchemes <- SwaggerUtil.extractSecuritySchemes(swagger.get, prefixes)
classNamedRoutes <- routes.traverse(route => getClassName(route.operation, prefixes).map(_ -> route))
groupedRoutes = classNamedRoutes
.groupBy(_._1)
Expand All @@ -82,7 +95,7 @@ object Common {
case CodegenTarget.Server =>
for {
serverMeta <- ServerGenerator
.fromSwagger[L, F](context, swagger, frameworkImports)(groupedRoutes)(protocolElems, securitySchemes)
.fromSwagger[L, F](context, basePath, frameworkImports)(groupedRoutes)(protocolElems, securitySchemes)
Servers(servers, supportDefinitions) = serverMeta
frameworkImplicits <- getFrameworkImplicits()
} yield CodegenDefinitions[L](List.empty, servers, supportDefinitions, frameworkImplicits)
Expand Down