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

Improve sttpOpenApiClient generator #6684

Merged
merged 38 commits into from
Jul 1, 2020
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
a09822e
Base changes
ghostbuster91 Jun 4, 2020
a412444
Fix rendering too many colons
ghostbuster91 Jun 4, 2020
e8c3890
Fix formatting
ghostbuster91 Jun 4, 2020
e3a0654
Allow sttp version customization
ghostbuster91 Jun 4, 2020
4ac8894
Add option to return errors in terms of monadError
ghostbuster91 Jun 4, 2020
88908e2
Add option to customize jodaTime version
ghostbuster91 Jun 4, 2020
5c255e4
Add option to customize json4s version
ghostbuster91 Jun 4, 2020
6c5d792
Simplify jsonHandling
ghostbuster91 Jun 4, 2020
3b27bc5
Remove helpers as such functionality was added to sttp
ghostbuster91 Jun 4, 2020
cac19fc
Rename file
ghostbuster91 Jun 4, 2020
86ec499
Fix uploading multipart data
ghostbuster91 Jun 4, 2020
97fd17f
Extract common abstraction for generator properties
ghostbuster91 Jun 4, 2020
a7a15a2
Add partial circe support
ghostbuster91 Jun 4, 2020
551bb35
Remove unsed method
ghostbuster91 Jun 4, 2020
2a91b11
Refactor picking up json library
ghostbuster91 Jun 4, 2020
a380531
Add missing DateSerializers for circe
ghostbuster91 Jun 9, 2020
5cab35d
Simplify credentials
ghostbuster91 Jun 9, 2020
714f930
Simplify code
ghostbuster91 Jun 9, 2020
a5f0a05
Update docs
ghostbuster91 Jun 9, 2020
dfca277
Fix auto formatting
ghostbuster91 Jun 9, 2020
5efad87
Simplify code
ghostbuster91 Jun 9, 2020
3c836f9
SttpCodegen should not depend on akka
ghostbuster91 Jun 9, 2020
a377921
Rewrite properties handling
ghostbuster91 Jun 10, 2020
d176eeb
Fix mainProperty application
ghostbuster91 Jun 10, 2020
f7c384c
Pass credentials to methods as regular parameters
ghostbuster91 Jun 10, 2020
4a5ff27
Put auth params first
ghostbuster91 Jun 10, 2020
e2df636
[Sttp] SeparateErrorChannel is true by default
ghostbuster91 Jun 16, 2020
b3017bb
[Sttp] Simplify generated build.sbt
ghostbuster91 Jun 16, 2020
86150cb
[Sttp] Regenerate project
ghostbuster91 Jun 16, 2020
4588362
[Sttp] Update default version to 2.2.0
ghostbuster91 Jun 16, 2020
b572673
Regenerate petstore sample
ghostbuster91 Jun 16, 2020
91dd9b0
Restore cross-compilation to scala 2.12
ghostbuster91 Jun 23, 2020
9242bc4
Restore syntax with companion object for api definitions
ghostbuster91 Jun 23, 2020
de82caf
Remove specifying reservedWords as it was already specified in upper …
ghostbuster91 Jun 23, 2020
d868eda
Refactor mainPackageProperty and add tests for it
ghostbuster91 Jun 23, 2020
1f9cd3e
Update samples/client/petstore/scala-sttp/build.sbt
ghostbuster91 Jun 29, 2020
a6647d2
Update sbt to 1.3.12
ghostbuster91 Jun 29, 2020
8f5a98f
Run bin/utils/ensure-up-to-date and commit changes
ghostbuster91 Jun 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/generators/scala-sttp.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ sidebar_label: scala-sttp
| ------ | ----------- | ------ | ------- |
|allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false|
|apiPackage|package for generated api classes| |null|
|sttpClientVersion|Option. Allows to override default version of sttp client library. Minimal version required for this project to compile is 2.2.0 |2.2.0
|dateLibrary|Option. Date library to use|<dl><dt>**joda**</dt><dd>Joda (for legacy app)</dd><dt>**java8**</dt><dd>Java 8 native JSR310 (prefered for JDK 1.8+)</dd></dl>|java8|
|jodaTimeVersion|Only if dateLibrary was set to joda. Allows to override default jodatime version.|2.10.6
|json4sVersion|Only if jsonLibrary was set to json4s. Allows to override default json4s version.|3.6.8
|circeVersion|Only if jsonLibrary was set to circe. Allows to override default circe version.|0.13.0
|jsonLibrary|Option. Json library to use|<dl><dt>**json4s**</dt>https://github.com/json4s/json4s<dt>**circe**</dt><dd>https://github.com/circe/circe</dd></dl>|json4s|
|separateErrorChannel| Option. Whether to return response as `F[Either[ResponseError[ErrorType], ReturnType]]]` or to flatten response's error raising them through enclosing monad (`F[ReturnType]`).|true
|disallowAdditionalPropertiesIfNotPresent|Specify the behavior when the 'additionalProperties' keyword is not present in the OAS document. If false: the 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications. If true: when the 'additionalProperties' keyword is not present in a schema, the value of 'additionalProperties' is set to false, i.e. no additional properties are allowed. Note: this mode is not compliant with the JSON schema specification. This is the original openapi-generator behavior.This setting is currently ignored for OAS 2.0 documents: 1) When the 'additionalProperties' keyword is not present in a 2.0 schema, additional properties are NOT allowed. 2) Boolean values of the 'additionalProperties' keyword are ignored. It's as if additional properties are NOT allowed.Note: the root cause are issues #1369 and #1371, which must be resolved in the swagger-parser project.|<dl><dt>**false**</dt><dd>The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.</dd><dt>**true**</dt><dd>when the 'additionalProperties' keyword is not present in a schema, the value of 'additionalProperties' is automatically set to false, i.e. no additional properties are allowed. Note: this mode is not compliant with the JSON schema specification. This is the original openapi-generator behavior.</dd></dl>|true|
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
|legacyDiscriminatorBehavior|This flag is used by OpenAPITools codegen to influence the processing of the discriminator attribute in OpenAPI documents. This flag has no impact if the OAS document does not use the discriminator attribute. The default value of this flag is set in each language-specific code generator (e.g. Python, Java, go...)using the method toModelName. Note to developers supporting a language generator in OpenAPITools; to fully support the discriminator attribute as defined in the OAS specification 3.x, language generators should set this flag to true by default; however this requires updating the mustache templates to generate a language-specific discriminator lookup function that iterates over {{#mappedModels}} and does not iterate over {{children}}, {{#anyOf}}, or {{#oneOf}}.|<dl><dt>**true**</dt><dd>The mapping in the discriminator includes descendent schemas that allOf inherit from self and the discriminator mapping schemas in the OAS document.</dd><dt>**false**</dt><dd>The mapping in the discriminator includes any descendent schemas that allOf inherit from self, any oneOf schemas, any anyOf schemas, any x-discriminator-values, and the discriminator mapping schemas in the OAS document AND Codegen validates that oneOf and anyOf schemas contain the required discriminator and throws an error if the discriminator is missing.</dd></dl>|true|
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,35 @@ package {{package}}
{{#imports}}
import {{import}}
{{/imports}}
import {{invokerPackage}}._
import alias._
import {{invokerPackage}}.JsonSupport._
import sttp.client._
import sttp.model.Method

{{#operations}}
object {{classname}} {

def apply(baseUrl: String = "{{{basePath}}}")(implicit serializer: SttpSerializer) = new {{classname}}(baseUrl)
}

class {{classname}}(baseUrl: String)(implicit serializer: SttpSerializer) {

import Helpers._
import serializer._
class {{classname}}(baseUrl: String = "{{{basePath}}}") {

{{#operation}}
{{#javadocRenderer}}
{{>javadoc}}
{{/javadocRenderer}}
def {{operationId}}({{>methodParameters}}): ApiRequestT[{{>operationReturnType}}] =
def {{operationId}}({{>methodParameters}}): Request[{{#separateErrorChannel}}Either[ResponseError[Exception], {{>operationReturnType}}]{{/separateErrorChannel}}{{^separateErrorChannel}}{{>operationReturnType}}{{/separateErrorChannel}}, Nothing] =
basicRequest
.method(Method.{{httpMethod.toUpperCase}}, uri"$baseUrl{{{path}}}{{#queryParams.0}}?{{#queryParams}}{{baseName}}=${{{paramName}}}{{^-last}}&{{/-last}}{{/queryParams}}{{/queryParams.0}}{{#isApiKey}}{{#isKeyInQuery}}{{^queryParams.0}}?{{/queryParams.0}}{{#queryParams.0}}&{{/queryParams.0}}{{keyParamName}}=${apiKey.value}&{{/isKeyInQuery}}{{/isApiKey}}")
.contentType({{#consumes.0}}"{{{mediaType}}}"{{/consumes.0}}{{^consumes}}"application/json"{{/consumes}}){{#headerParams}}
.header({{>paramCreation}}){{/headerParams}}{{#authMethods}}{{#isBasic}}{{#isBasicBasic}}
.auth.withCredentials(basicAuth.user, basicAuth.password){{/isBasicBasic}}{{#isBasicBearer}}
.auth.bearer(bearerToken.token){{/isBasicBearer}}{{/isBasic}}{{#isApiKey}}{{#isKeyInHeader}}
.header("{{keyParamName}}", apiKey.value){{/isKeyInHeader}}{{#isKeyInCookie}}
.cookie("{{keyParamName}}", apiKey.value){{/isKeyInCookie}}{{/isApiKey}}{{/authMethods}}{{#formParams.0}}
.auth.withCredentials(username, password){{/isBasicBasic}}{{#isBasicBearer}}
.auth.bearer(bearerToken){{/isBasicBearer}}{{/isBasic}}{{#isApiKey}}{{#isKeyInHeader}}
.header("{{keyParamName}}", apiKey){{/isKeyInHeader}}{{#isKeyInCookie}}
.cookie("{{keyParamName}}", apiKey){{/isKeyInCookie}}{{/isApiKey}}{{/authMethods}}{{#formParams.0}}{{^isMultipart}}
.body(Map({{#formParams}}
{{>paramFormCreation}},{{/formParams}}
)){{/formParams.0}}{{#bodyParam}}
{{>paramFormCreation}}{{#hasMore}}, {{/hasMore}}{{/formParams}}
)){{/isMultipart}}{{#isMultipart}}
.multipartBody(Seq({{#formParams}}
{{>paramMultipartCreation}}{{#hasMore}}, {{/hasMore}}{{/formParams}}
).flatten){{/isMultipart}}{{/formParams.0}}{{#bodyParam}}
.body({{paramName}}){{/bodyParam}}
.response(asJson[{{>operationReturnType}}])
.response({{#separateErrorChannel}}asJson{{/separateErrorChannel}}{{^separateErrorChannel}}asJsonAlwaysUnsafe{{/separateErrorChannel}}[{{>operationReturnType}}])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Could you help to separate api errors as exceptions as described here softwaremill/sttp-model#5 ? The main idea is to split application exceptions (ideally with models) from transport level exceptions by using expected status codes.
Thanks

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Transport exceptions are already modeled using SttpClientException. These exceptions are thrown when read or connection exceptions occur, and result in a failed effect (failed Future or IO).

Though you are right that there's a piece missing here, if the OpenAPI description contains an e.g. JSON representation of an error? Then yes, we will need a custom hierarchy (as opposed to the standard ResponseError), covering three possibilities:

  • DeserializationError[T](body: String, error: T) - if deserializing the success or error json fails
  • UnknownHttpError(body: String) - for unmapped status codes
  • HttpError[T](body: T) - for mapped status codes

Then, the overall request type would be: Request[Either[ResponseError[T, U], V]], where:

  • T is the type of deserialization errors, e.g. io.circe.Error
  • U is the type of the http errors - but as there might be a couple of these, probably this needs to be a sealed trait, which is a implemented by all possible errors for this endpoint? This could be tricky, as each endpoint might have different error cases (e.g. NotFound).
  • V is the type of the deserialized http success value (e.g. User)

Of course we'd need better naming for these :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about exposing other http metadata inside errors, like status / status code, headers (some APIs expose debug/tracing information), hostname, etc?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another question (and I'm not sure whether OpenAPI Spec supports it) to return same info for correct (V) responses

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's always returned in the Response object which wraps the body. So the type of the result of a call is e.g. Response[Either[ResponseError, V]], where V is the type of success


{{/operation}}
}

{{/operations}}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,27 @@ version := "{{artifactVersion}}"
name := "{{artifactId}}"
organization := "{{groupId}}"

scalaVersion := "2.13.0"

crossScalaVersions := Seq(scalaVersion.value, "2.12.10", "2.11.12")
scalaVersion := "2.13.2"
ghostbuster91 marked this conversation as resolved.
Show resolved Hide resolved

libraryDependencies ++= Seq(
"com.softwaremill.sttp.client" %% "core" % "2.0.0",
"com.softwaremill.sttp.client" %% "json4s" % "2.0.0",
"com.softwaremill.sttp.client" %% "core" % "{{sttpClientVersion}}",
{{#joda}}
"joda-time" % "joda-time" % "2.10.1",
"joda-time" % "joda-time" % "{{jodaTimeVersion}}",
{{/joda}}
"org.json4s" %% "json4s-jackson" % "3.6.7",
// test dependencies
"org.scalatest" %% "scalatest" % "3.0.8" % Test,
"junit" % "junit" % "4.13" % "test"
{{#json4s}}
"com.softwaremill.sttp.client" %% "json4s" % "{{sttpClientVersion}}",
"org.json4s" %% "json4s-jackson" % "{{json4sVersion}}"
{{/json4s}}
{{#circe}}
"com.softwaremill.sttp.client" %% "circe" % "{{sttpClientVersion}}",
"io.circe" %% "circe-core" % "{{circeVersion}}",
"io.circe" %% "circe-generic" % "{{circeVersion}}",
"io.circe" %% "circe-parser" % "{{circeVersion}}"
{{/circe}}
)

scalacOptions := Seq(
"-unchecked",
"-deprecation",
"-feature"
)

publishArtifact in (Compile, packageDoc) := false
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package {{invokerPackage}}

{{#java8}}
import java.time.{LocalDate, LocalDateTime, OffsetDateTime, ZoneId}
import java.time.format.DateTimeFormatter
import scala.util.Try
{{/java8}}
{{#joda}}
import org.joda.time.DateTime
import org.joda.time.format.ISODateTimeFormat
{{/joda}}

{{#json4s}}
object DateSerializers {
import org.json4s.{Serializer, CustomSerializer, JNull}
import org.json4s.JsonAST.JString
{{#java8}}
case object DateTimeSerializer extends CustomSerializer[OffsetDateTime](_ => ( {
case JString(s) =>
Try(OffsetDateTime.parse(s, DateTimeFormatter.ISO_OFFSET_DATE_TIME)) orElse
Try(LocalDateTime.parse(s).atZone(ZoneId.systemDefault()).toOffsetDateTime) getOrElse (null)
case JNull => null
}, {
case d: OffsetDateTime =>
JString(d.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME))
}))

case object LocalDateSerializer extends CustomSerializer[LocalDate]( _ => ( {
case JString(s) => LocalDate.parse(s)
case JNull => null
}, {
case d: LocalDate =>
JString(d.format(DateTimeFormatter.ISO_LOCAL_DATE))
}))
{{/java8}}
{{#joda}}
case object DateTimeSerializer extends CustomSerializer[DateTime](_ => ( {
case JString(s) =>
ISODateTimeFormat.dateOptionalTimeParser().parseDateTime(s)
case JNull => null
}, {
case d: org.joda.time.DateTime =>
JString(ISODateTimeFormat.dateTime().print(d))
})
)

case object LocalDateSerializer extends CustomSerializer[org.joda.time.LocalDate](_ => ( {
case JString(s) => org.joda.time.format.DateTimeFormat.forPattern("yyyy-MM-dd").parseLocalDate(s)
case JNull => null
}, {
case d: org.joda.time.LocalDate => JString(d.toString("yyyy-MM-dd"))
}))
{{/joda}}

def all: Seq[Serializer[_]] = Seq[Serializer[_]]() :+ LocalDateSerializer :+ DateTimeSerializer
}
{{/json4s}}
{{#circe}}
trait DateSerializers {
import io.circe.{Decoder, Encoder}
{{#java8}}
implicit val isoOffsetDateTimeDecoder: Decoder[OffsetDateTime] = Decoder.decodeOffsetDateTimeWithFormatter(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
implicit val isoOffsetDateTimeEncoder: Encoder[OffsetDateTime] = Encoder.encodeOffsetDateTimeWithFormatter(DateTimeFormatter.ISO_OFFSET_DATE_TIME)

implicit val localDateDecoder: Decoder[LocalDate] = Decoder.decodeLocalDateWithFormatter(DateTimeFormatter.ISO_LOCAL_DATE)
implicit val localDateEncoder: Encoder[LocalDate] = Encoder.encodeLocalDateWithFormatter(DateTimeFormatter.ISO_LOCAL_DATE)
{{/java8}}
{{#joda}}
implicit val dateTimeDecoder: Decoder[DateTime] = Decoder.decodeString.map(ISODateTimeFormat.dateOptionalTimeParser().parseDateTime(_))
implicit val dateTimeEncoder: Encoder[DateTime] = Encoder.encodeString.contramap(ISODateTimeFormat.dateTime().print(_))

implicit val localDateDecoder: Decoder[org.joda.time.LocalDate] = Decoder.decodeString.map(org.joda.time.format.DateTimeFormat.forPattern("yyyy-MM-dd").parseLocalDate(_))
implicit val localDateEncoder: Encoder[org.joda.time.LocalDate] = Encoder.encodeString.contramap(_.toString("yyyy-MM-dd"))
{{/joda}}
}
{{/circe}}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{{>licenseInfo}}
package {{invokerPackage}}

{{#models.0}}
import {{modelPackage}}._
{{/models.0}}
{{#json4s}}
import org.json4s._
import sttp.client.json4s.SttpJson4sApi
import scala.reflect.ClassTag

object JsonSupport extends SttpJson4sApi {
def enumSerializers: Seq[Serializer[_]] = Seq[Serializer[_]](){{#models}}{{#model}}{{#hasEnums}}{{#vars}}{{#isEnum}} :+
new EnumNameSerializer({{classname}}Enums.{{datatypeWithEnum}}){{/isEnum}}{{/vars}}{{/hasEnums}}{{/model}}{{/models}}

private class EnumNameSerializer[E <: Enumeration: ClassTag](enum: E) extends Serializer[E#Value] {
import JsonDSL._
val EnumerationClass: Class[E#Value] = classOf[E#Value]

def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), E#Value] = {
case (t @ TypeInfo(EnumerationClass, _), json) if isValid(json) =>
json match {
case JString(value) => enum.withName(value)
case value => throw new MappingException(s"Can't convert $value to $EnumerationClass")
}
}

private[this] def isValid(json: JValue) = json match {
case JString(value) if enum.values.exists(_.toString == value) => true
case _ => false
}

def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
case i: E#Value => i.toString
}
}

implicit val format: Formats = DefaultFormats ++ enumSerializers ++ DateSerializers.all
implicit val serialization: org.json4s.Serialization = org.json4s.jackson.Serialization
}
{{/json4s}}
{{#circe}}
import io.circe.{Decoder, Encoder}
import io.circe.generic.AutoDerivation
import sttp.client.circe.SttpCirceApi

object JsonSupport extends SttpCirceApi with AutoDerivation with DateSerializers {
{{#models}}{{#model}}{{#hasEnums}}{{#vars}}{{#isEnum}}
implicit val {{classname}}{{datatypeWithEnum}}Decoder: Decoder[{{classname}}Enums.{{datatypeWithEnum}}] = Decoder.decodeEnumeration({{classname}}Enums.{{datatypeWithEnum}})
implicit val {{classname}}{{datatypeWithEnum}}Encoder: Encoder[{{classname}}Enums.{{datatypeWithEnum}}] = Encoder.encodeEnumeration({{classname}}Enums.{{datatypeWithEnum}})
{{/isEnum}}{{/vars}}{{/hasEnums}}{{/model}}{{/models}}
}
{{/circe}}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{{#allParams}}{{paramName}}: {{#required}}{{dataType}}{{/required}}{{^required}}{{#isContainer}}{{dataType}}{{/isContainer}}{{^isContainer}}Option[{{dataType}}]{{/isContainer}}{{/required}}{{^defaultValue}}{{^required}}{{^isContainer}} = None{{/isContainer}}{{/required}}{{/defaultValue}}{{#hasMore}}, {{/hasMore}}{{/allParams}}{{#authMethods.0}})(implicit {{#authMethods}}{{#isApiKey}}apiKey: ApiKeyValue{{/isApiKey}}{{#isBasic}}{{#isBasicBasic}}basicAuth: BasicCredentials{{/isBasicBasic}}{{#isBasicBearer}}bearerToken: BearerToken{{/isBasicBearer}}{{/isBasic}}{{#hasMore}}, {{/hasMore}}{{/authMethods}}{{/authMethods.0}}
{{#authMethods.0}}{{#authMethods}}{{#isApiKey}}apiKey: String{{/isApiKey}}{{#isBasic}}{{#isBasicBasic}}username: String, password: String{{/isBasicBasic}}{{#isBasicBearer}}bearerToken: String{{/isBasicBearer}}{{/isBasic}}{{#hasMore}}, {{/hasMore}}{{/authMethods}})({{/authMethods.0}}{{#allParams}}{{paramName}}: {{#required}}{{dataType}}{{/required}}{{^required}}{{#isContainer}}{{dataType}}{{/isContainer}}{{^isContainer}}Option[{{dataType}}]{{/isContainer}}{{/required}}{{^defaultValue}}{{^required}}{{^isContainer}} = None{{/isContainer}}{{/required}}{{/defaultValue}}{{#hasMore}}, {{/hasMore}}{{/allParams}}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ package {{package}}
{{#imports}}
import {{import}}
{{/imports}}
import {{invokerPackage}}.ApiModel

{{#models}}
{{#model}}
Expand All @@ -23,7 +22,7 @@ case class {{classname}}(
{{/description}}
{{{name}}}: {{^required}}Option[{{/required}}{{^isEnum}}{{dataType}}{{/isEnum}}{{#isEnum}}{{classname}}Enums.{{datatypeWithEnum}}{{/isEnum}}{{^required}}] = None{{/required}}{{#hasMore}},{{/hasMore}}
{{/vars}}
) extends ApiModel
)

{{#hasEnums}}
object {{classname}}Enums {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{{#required}}
{{#isFile}}
multipartFile("{{baseName}}", {{#isContainer}}ArrayValues({{{paramName}}}{{#collectionFormat}}, {{collectionFormat.toUpperCase}}{{/collectionFormat}}){{/isContainer}}{{^isContainer}}{{{paramName}}}{{/isContainer}})
{{/isFile}}
{{^isFile}}
multipart("{{baseName}}", {{paramName}})
{{/isFile}}
{{/required}}
{{^required}}
{{#isFile}}
{{paramName}}.map(multipartFile("{{baseName}}", _))
{{/isFile}}
{{^isFile}}
{{paramName}}.map(multipart("{{baseName}}", {{#isContainer}}ArrayValues(_{{#collectionFormat}}, {{collectionFormat.toUpperCase}}{{/collectionFormat}}){{/isContainer}}{{^isContainer}}_{{/isContainer}}))
{{/isFile}}
{{/required}}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sbt.version=1.2.4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file/version might be the cause of CI build failed with next error:

https://app.circleci.com/pipelines/github/OpenAPITools/openapi-generator/3736/workflows/1d16cd64-dd72-4f2b-8a68-92adfbdb29b7/jobs/17104/steps

[warn] 	::::::::::::::::::::::::::::::::::::::::::::::
[warn] 	::          UNRESOLVED DEPENDENCIES         ::
[warn] 	::::::::::::::::::::::::::::::::::::::::::::::
[warn] 	:: org.scala-sbt#compiler-bridge_2.13;1.2.3: not found
[warn] 	::::::::::::::::::::::::::::::::::::::::::::::
[error] ## Exception when compiling 14 sources to /home/circleci/OpenAPITools/openapi-generator/samples/client/petstore/scala-sttp/target/scala-2.13/classes
[error] The compiler bridge sources org.scala-sbt:compiler-bridge_2.13:1.2.3:compile could not be retrieved.
[error]  
[error] 	Note: Unresolved dependencies path:
[error] 		org.scala-sbt:compiler-bridge_2.13:1.2.3
[error] 		  +- org.scala-sbt.temp:temp-module-52f238aede5a1d8d7a484c2bec27a144810e2ac0:1.2.3

Could you try sbt.version=1.2.8? Should we even specify this version explicitly?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the sbt version should be specified in project/build.properties so that the version is fixed and not platform-dependent. However, we should probably use 1.3.12, which is the newest one.

Loading