Typescript fetch fork (#569)

* added my fork from https://github.com/Place1/swagger-codegen-typescript-browser

* ran bin/typescript-fetch-petstore-all.sh

* use FormData.append rather than .set for IE11 compat

* reverted change to licenseInfo.mustache

* reverted some comments

* added package.json and tsconfig.json back to the generator

* added support for blob (application/octet-stream) responses

* models and apis are now in folders

* added support for modelPropertyNaming based on the spec

* bug fix

* updated samples

* Restore pom.xml for typescript project

* Restore samples/client/petstore/typescript-fetch/tests/default/package.json
≈

* added support for response type Date conversion

* updated samples

* Rework pom in "samples.ci"

* Restore "samples/client/petstore/typescript-fetch/tests/default"

* updated configuration class to use property getters to allow clients to implement configuration values as getters

* added {{datatype}}ToJSON functions to handle serialization and naming conversions

* fixed missing import

* fixed compilation error. updated samples

* 1 character change to get CI to run again

* updated samples

* added support for array type request body

* updated tests

* support for optional request bodies

* updated models json converters to handle undefined inputs (to simplify usage in optional contexts like optional request bodies)

* updated samples

* updated tests

* changed to typescript version 2.4

* updated samples

* support for optional properties being null, undefined or omitted

* updated samples

* bug fix

* bug fix

* updated samples

* ran npm install in test project

* patch to get tests running

* added support for retrieving raw response. added support for binary request bodies. added support for blob data type for files/binary.
This commit is contained in:
PLACE
2018-11-18 16:24:24 +11:00
committed by William Cheng
parent 736e8348b6
commit 334415dec2
133 changed files with 11388 additions and 8645 deletions

View File

@@ -0,0 +1,131 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.generator.gradle.plugin
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.invoke
import org.openapitools.generator.gradle.plugin.extensions.OpenApiGeneratorGenerateExtension
import org.openapitools.generator.gradle.plugin.extensions.OpenApiGeneratorMetaExtension
import org.openapitools.generator.gradle.plugin.extensions.OpenApiGeneratorValidateExtension
import org.openapitools.generator.gradle.plugin.tasks.GenerateTask
import org.openapitools.generator.gradle.plugin.tasks.GeneratorsTask
import org.openapitools.generator.gradle.plugin.tasks.MetaTask
import org.openapitools.generator.gradle.plugin.tasks.ValidateTask
/**
* A plugin providing common Open API Generator use cases.
*
* @author Jim Schubert
*/
@Suppress("unused")
class OpenApiGeneratorPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.run {
val meta = extensions.create(
"openApiMeta",
OpenApiGeneratorMetaExtension::class.java,
project
)
val validate = extensions.create(
"openApiValidate",
OpenApiGeneratorValidateExtension::class.java,
project
)
val generate = extensions.create(
"openApiGenerate",
OpenApiGeneratorGenerateExtension::class.java,
project
)
generate.outputDir.set("$buildDir/generate-resources/main")
tasks {
"openApiGenerators"(GeneratorsTask::class) {
group = pluginGroup
description = "Lists generators available via Open API Generators."
}
"openApiMeta"(MetaTask::class) {
group = pluginGroup
description = "Generates a new generator to be consumed via Open API Generator."
generatorName.set(meta.generatorName)
packageName.set(meta.packageName)
outputFolder.set(meta.outputFolder)
}
"openApiValidate"(ValidateTask::class) {
group = pluginGroup
description = "Validates an Open API 2.0 or 3.x specification document."
inputSpec.set(validate.inputSpec)
}
"openApiGenerate"(GenerateTask::class) {
group = pluginGroup
description = "Generate code via Open API Tools Generator for Open API 2.0 or 3.x specification documents."
verbose.set(generate.verbose)
validateSpec.set(generate.validateSpec)
generatorName.set(generate.generatorName)
outputDir.set(generate.outputDir)
inputSpec.set(generate.inputSpec)
templateDir.set(generate.templateDir)
auth.set(generate.auth)
systemProperties.set(generate.systemProperties)
configFile.set(generate.configFile)
skipOverwrite.set(generate.skipOverwrite)
apiPackage.set(generate.apiPackage)
modelPackage.set(generate.modelPackage)
modelNamePrefix.set(generate.modelNamePrefix)
modelNameSuffix.set(generate.modelNameSuffix)
instantiationTypes.set(generate.instantiationTypes)
typeMappings.set(generate.typeMappings)
additionalProperties.set(generate.additionalProperties)
languageSpecificPrimitives.set(generate.languageSpecificPrimitives)
importMappings.set(generate.importMappings)
invokerPackage.set(generate.invokerPackage)
groupId.set(generate.groupId)
id.set(generate.id)
version.set(generate.version)
library.set(generate.library)
gitUserId.set(generate.gitUserId)
gitRepoId.set(generate.gitRepoId)
releaseNote.set(generate.releaseNote)
httpUserAgent.set(generate.httpUserAgent)
reservedWordsMappings.set(generate.reservedWordsMappings)
ignoreFileOverride.set(generate.ignoreFileOverride)
removeOperationIdPrefix.set(generate.removeOperationIdPrefix)
apiFilesConstrainedTo.set(generate.apiFilesConstrainedTo)
modelFilesConstrainedTo.set(generate.modelFilesConstrainedTo)
supportingFilesConstrainedTo.set(generate.supportingFilesConstrainedTo)
generateModelTests.set(generate.generateModelTests)
generateModelDocumentation.set(generate.generateModelDocumentation)
generateApiTests.set(generate.generateApiTests)
generateApiDocumentation.set(generate.generateApiDocumentation)
withXml.set(generate.withXml)
configOptions.set(generate.configOptions)
}
}
}
}
companion object {
const val pluginGroup = "OpenAPI Tools"
}
}

View File

@@ -0,0 +1,286 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.generator.gradle.plugin.extensions
import org.gradle.api.Project
import org.gradle.kotlin.dsl.listProperty
import org.gradle.kotlin.dsl.property
/**
* Gradle project level extension object definition for the generate task
*
* @author Jim Schubert
*/
open class OpenApiGeneratorGenerateExtension(project: Project) {
/**
* The verbosity of generation
*/
val verbose = project.objects.property<Boolean>()
/**
* Whether or not an input specification should be validated upon generation.
*/
val validateSpec = project.objects.property<Boolean>()
/**
* The name of the generator which will handle codegen. (see "openApiGenerators" task)
*/
val generatorName = project.objects.property<String>()
/**
* The output target directory into which code will be generated.
*/
val outputDir = project.objects.property<String>()
/**
* The Open API 2.0/3.x specification location.
*/
val inputSpec = project.objects.property<String>()
/**
* The template directory holding a custom template.
*/
val templateDir = project.objects.property<String?>()
/**
* Adds authorization headers when fetching the OpenAPI definitions remotely.
* Pass in a URL-encoded string of name:header with a comma separating multiple values
*/
val auth = project.objects.property<String>()
/**
* Sets specified system properties.
*/
val systemProperties = project.objects.property<Map<String, String>>()
/**
* Path to json configuration file.
* File content should be in a json format { "optionKey":"optionValue", "optionKey1":"optionValue1"...}
* Supported options can be different for each language. Run config-help -g {generator name} command for language specific config options.
*/
val configFile = project.objects.property<String>()
/**
* Specifies if the existing files should be overwritten during the generation.
*/
val skipOverwrite = project.objects.property<Boolean?>()
/**
* Package for generated api classes
*/
val apiPackage = project.objects.property<String>()
/**
* Package for generated models
*/
val modelPackage = project.objects.property<String>()
/**
* Prefix that will be prepended to all model names. Default is the empty string.
*/
val modelNamePrefix = project.objects.property<String>()
/**
* Suffix that will be appended to all model names. Default is the empty string.
*/
val modelNameSuffix = project.objects.property<String>()
/**
* Sets instantiation type mappings.
*/
val instantiationTypes = project.objects.property<Map<String, String>>()
/**
* Sets mappings between OpenAPI spec types and generated code types.
*/
val typeMappings = project.objects.property<Map<String, String>>()
/**
* Sets additional properties that can be referenced by the mustache templates.
*/
val additionalProperties = project.objects.property<Map<String, String>>()
/**
* Specifies additional language specific primitive types in the format of type1,type2,type3,type3. For example: String,boolean,Boolean,Double.
*/
val languageSpecificPrimitives = project.objects.listProperty<String>()
/**
* Specifies mappings between a given class and the import that should be used for that class.
*/
val importMappings = project.objects.property<Map<String, String>>()
/**
* Root package for generated code.
*/
val invokerPackage = project.objects.property<String>()
/**
* GroupId in generated pom.xml/build.gradle or other build script. Language-specific conversions occur in non-jvm generators.
*/
val groupId = project.objects.property<String>()
/**
* ArtifactId in generated pom.xml/build.gradle or other build script. Language-specific conversions occur in non-jvm generators.
*/
val id = project.objects.property<String>()
/**
* Artifact version in generated pom.xml/build.gradle or other build script. Language-specific conversions occur in non-jvm generators.
*/
val version = project.objects.property<String>()
/**
* Reference the library template (sub-template) of a generator.
*/
val library = project.objects.property<String?>()
/**
* Git user ID, e.g. openapitools.
*/
val gitUserId = project.objects.property<String?>()
/**
* Git repo ID, e.g. openapi-generator.
*/
val gitRepoId = project.objects.property<String?>()
/**
* Release note, default to 'Minor update'.
*/
val releaseNote = project.objects.property<String?>()
/**
* HTTP user agent, e.g. codegen_csharp_api_client, default to 'OpenAPI-Generator/{packageVersion}}/{language}'
*/
val httpUserAgent = project.objects.property<String?>()
/**
* Specifies how a reserved name should be escaped to. Otherwise, the default _<name> is used.
*/
val reservedWordsMappings = project.objects.property<Map<String, String>>()
/**
* Specifies an override location for the .openapi-generator-ignore file. Most useful on initial generation.
*/
val ignoreFileOverride = project.objects.property<String?>()
/**
* Remove prefix of operationId, e.g. config_getId => getId
*/
val removeOperationIdPrefix = project.objects.property<Boolean?>()
/**
* Defines which API-related files should be generated. This allows you to create a subset of generated files (or none at all).
*
* NOTE: Configuring any one of [apiFilesConstrainedTo], [modelFilesConstrainedTo], or [supportingFilesConstrainedTo] results
* in others being disabled. That is, OpenAPI Generator considers any one of these to define a subset of generation.
* For more control over generation of individual files, configure an ignore file and refer to it via [ignoreFileOverride].
*/
val apiFilesConstrainedTo = project.objects.listProperty<String>()
/**
* Defines which model-related files should be generated. This allows you to create a subset of generated files (or none at all).
*
* NOTE: Configuring any one of [apiFilesConstrainedTo], [modelFilesConstrainedTo], or [supportingFilesConstrainedTo] results
* in others being disabled. That is, OpenAPI Generator considers any one of these to define a subset of generation.
* For more control over generation of individual files, configure an ignore file and refer to it via [ignoreFileOverride].
*/
val modelFilesConstrainedTo = project.objects.listProperty<String>()
/**
* Defines which supporting files should be generated. This allows you to create a subset of generated files (or none at all).
*
* Supporting files are those related to projects/frameworks which may be modified
* by consumers.
*
* NOTE: Configuring any one of [apiFilesConstrainedTo], [modelFilesConstrainedTo], or [supportingFilesConstrainedTo] results
* in others being disabled. That is, OpenAPI Generator considers any one of these to define a subset of generation.
* For more control over generation of individual files, configure an ignore file and refer to it via [ignoreFileOverride].
*/
val supportingFilesConstrainedTo = project.objects.listProperty<String>()
/**
* Defines whether or not model-related _test_ files should be generated.
*
* This option enables/disables generation of ALL model-related _test_ files.
*
* For more control over generation of individual files, configure an ignore file and
* refer to it via [ignoreFileOverride].
*/
val generateModelTests = project.objects.property<Boolean>()
/**
* Defines whether or not model-related _documentation_ files should be generated.
*
* This option enables/disables generation of ALL model-related _documentation_ files.
*
* For more control over generation of individual files, configure an ignore file and
* refer to it via [ignoreFileOverride].
*/
val generateModelDocumentation = project.objects.property<Boolean>()
/**
* Defines whether or not api-related _test_ files should be generated.
*
* This option enables/disables generation of ALL api-related _test_ files.
*
* For more control over generation of individual files, configure an ignore file and
* refer to it via [ignoreFileOverride].
*/
val generateApiTests = project.objects.property<Boolean>()
/**
* Defines whether or not api-related _documentation_ files should be generated.
*
* This option enables/disables generation of ALL api-related _documentation_ files.
*
* For more control over generation of individual files, configure an ignore file and
* refer to it via [ignoreFileOverride].
*/
val generateApiDocumentation = project.objects.property<Boolean>()
/**
* A special-case setting which configures some generators with XML support. In some cases,
* this forces json OR xml, so the default here is false.
*/
val withXml = project.objects.property<Boolean>()
/**
* A map of options specific to a generator.
*/
val configOptions = project.objects.property<Map<String, String>>()
init {
applyDefaults()
}
@Suppress("MemberVisibilityCanBePrivate")
fun applyDefaults(){
releaseNote.set("Minor update")
modelNamePrefix.set("")
modelNameSuffix.set("")
generateModelTests.set(true)
generateModelDocumentation.set(true)
generateApiTests.set(true)
generateApiDocumentation.set(true)
withXml.set(false)
configOptions.set(mapOf())
validateSpec.set(true)
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.generator.gradle.plugin.extensions
import org.gradle.api.Project
import org.gradle.kotlin.dsl.property
/**
* Gradle project level extension object definition for the meta-generator task
*
* @author Jim Schubert
*/
open class OpenApiGeneratorMetaExtension(project: Project) {
/**
* The human-readable generator name of the newly created template generator.
*/
val generatorName = project.objects.property<String>()
/**
* The packageName generatorName to put the main class into (defaults to org.openapitools.codegen)
*/
val packageName = project.objects.property<String>()
/**
* Where to write the generated files (current dir by default).
*/
val outputFolder = project.objects.property<String>()
init {
generatorName.set("default")
packageName.set("org.openapitools.codegen")
outputFolder.set("")
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.generator.gradle.plugin.extensions
import org.gradle.api.Project
import org.gradle.kotlin.dsl.property
/**
* Gradle project level extension object definition for the generators task
*
* @author Jim Schubert
*/
open class OpenApiGeneratorValidateExtension(project: Project) {
/**
* The input specification to validate. Supports all formats supported by the Parser.
*/
val inputSpec = project.objects.property<String>()
}

View File

@@ -0,0 +1,554 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.generator.gradle.plugin.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.TaskAction
import org.gradle.internal.logging.text.StyledTextOutput
import org.gradle.internal.logging.text.StyledTextOutputFactory
import org.gradle.kotlin.dsl.listProperty
import org.gradle.kotlin.dsl.property
import org.openapitools.codegen.CodegenConstants
import org.openapitools.codegen.DefaultGenerator
import org.openapitools.codegen.config.CodegenConfigurator
/**
* A task which generates the desired code.
*
* Example (CLI):
*
* ./gradlew -q openApiGenerate
*
* @author Jim Schubert
*/
open class GenerateTask : DefaultTask() {
/**
* The verbosity of generation
*/
@get:Internal
val verbose = project.objects.property<Boolean>()
/**
* Whether or not an input specification should be validated upon generation.
*/
@get:Internal
val validateSpec = project.objects.property<Boolean>()
/**
* The name of the generator which will handle codegen. (see "openApiGenerators" task)
*/
@get:Internal
val generatorName = project.objects.property<String>()
/**
* The output target directory into which code will be generated.
*/
@get:Internal
val outputDir = project.objects.property<String>()
/**
* The Open API 2.0/3.x specification location.
*/
@get:Internal
val inputSpec = project.objects.property<String>()
/**
* The template directory holding a custom template.
*/
@get:Internal
val templateDir = project.objects.property<String?>()
/**
* Adds authorization headers when fetching the OpenAPI definitions remotely.
* Pass in a URL-encoded string of name:header with a comma separating multiple values
*/
@get:Internal
val auth = project.objects.property<String>()
/**
* Sets specified system properties.
*/
@get:Internal
val systemProperties = project.objects.property<Map<String, String>>()
/**
* Path to json configuration file.
* File content should be in a json format { "optionKey":"optionValue", "optionKey1":"optionValue1"...}
* Supported options can be different for each language. Run config-help -g {generator name} command for language specific config options.
*/
@get:Internal
val configFile = project.objects.property<String>()
/**
* Specifies if the existing files should be overwritten during the generation.
*/
@get:Internal
val skipOverwrite = project.objects.property<Boolean?>()
/**
* Package for generated api classes
*/
@get:Internal
val apiPackage = project.objects.property<String>()
/**
* Package for generated models
*/
@get:Internal
val modelPackage = project.objects.property<String>()
/**
* Prefix that will be prepended to all model names. Default is the empty string.
*/
@get:Internal
val modelNamePrefix = project.objects.property<String>()
/**
* Suffix that will be appended to all model names. Default is the empty string.
*/
@get:Internal
val modelNameSuffix = project.objects.property<String>()
/**
* Sets instantiation type mappings.
*/
@get:Internal
val instantiationTypes = project.objects.property<Map<String, String>>()
/**
* Sets mappings between OpenAPI spec types and generated code types.
*/
@get:Internal
val typeMappings = project.objects.property<Map<String, String>>()
/**
* Sets additional properties that can be referenced by the mustache templates in the format of name=value,name=value.
* You can also have multiple occurrences of this option.
*/
@get:Internal
val additionalProperties = project.objects.property<Map<String, String>>()
/**
* Specifies additional language specific primitive types in the format of type1,type2,type3,type3. For example: String,boolean,Boolean,Double.
*/
@get:Internal
val languageSpecificPrimitives = project.objects.listProperty<String>()
/**
* Specifies mappings between a given class and the import that should be used for that class.
*/
@get:Internal
val importMappings = project.objects.property<Map<String, String>>()
/**
* Root package for generated code.
*/
@get:Internal
val invokerPackage = project.objects.property<String>()
/**
* GroupId in generated pom.xml/build.gradle or other build script. Language-specific conversions occur in non-jvm generators.
*/
@get:Internal
val groupId = project.objects.property<String>()
/**
* ArtifactId in generated pom.xml/build.gradle or other build script. Language-specific conversions occur in non-jvm generators.
*/
@get:Internal
val id = project.objects.property<String>()
/**
* Artifact version in generated pom.xml/build.gradle or other build script. Language-specific conversions occur in non-jvm generators.
*/
@get:Internal
val version = project.objects.property<String>()
/**
* Reference the library template (sub-template) of a generator.
*/
@get:Internal
val library = project.objects.property<String?>()
/**
* Git user ID, e.g. openapitools.
*/
@get:Internal
val gitUserId = project.objects.property<String?>()
/**
* Git repo ID, e.g. openapi-generator.
*/
@get:Internal
val gitRepoId = project.objects.property<String?>()
/**
* Release note, default to 'Minor update'.
*/
@get:Internal
val releaseNote = project.objects.property<String?>()
/**
* HTTP user agent, e.g. codegen_csharp_api_client, default to 'OpenAPI-Generator/{packageVersion}}/{language}'
*/
@get:Internal
val httpUserAgent = project.objects.property<String?>()
/**
* Specifies how a reserved name should be escaped to.
*/
@get:Internal
val reservedWordsMappings = project.objects.property<Map<String, String>>()
/**
* Specifies an override location for the .openapi-generator-ignore file. Most useful on initial generation.
*/
@get:Internal
val ignoreFileOverride = project.objects.property<String?>()
/**
* Remove prefix of operationId, e.g. config_getId => getId
*/
@get:Internal
val removeOperationIdPrefix = project.objects.property<Boolean?>()
/**
* Defines which API-related files should be generated. This allows you to create a subset of generated files (or none at all).
*
* This option enables/disables generation of ALL api-related files.
*
* NOTE: Configuring any one of [apiFilesConstrainedTo], [modelFilesConstrainedTo], or [supportingFilesConstrainedTo] results
* in others being disabled. That is, OpenAPI Generator considers any one of these to define a subset of generation.
* For more control over generation of individual files, configure an ignore file and refer to it via [ignoreFileOverride].
*/
@get:Internal
val apiFilesConstrainedTo = project.objects.listProperty<String>()
/**
* Defines which model-related files should be generated. This allows you to create a subset of generated files (or none at all).
*
* NOTE: Configuring any one of [apiFilesConstrainedTo], [modelFilesConstrainedTo], or [supportingFilesConstrainedTo] results
* in others being disabled. That is, OpenAPI Generator considers any one of these to define a subset of generation.
* For more control over generation of individual files, configure an ignore file and refer to it via [ignoreFileOverride].
*/
@get:Internal
val modelFilesConstrainedTo = project.objects.listProperty<String>()
/**
* Defines which supporting files should be generated. This allows you to create a subset of generated files (or none at all).
*
* Supporting files are those related to projects/frameworks which may be modified
* by consumers.
*
* NOTE: Configuring any one of [apiFilesConstrainedTo], [modelFilesConstrainedTo], or [supportingFilesConstrainedTo] results
* in others being disabled. That is, OpenAPI Generator considers any one of these to define a subset of generation.
* For more control over generation of individual files, configure an ignore file and refer to it via [ignoreFileOverride].
*/
@get:Internal
val supportingFilesConstrainedTo = project.objects.listProperty<String>()
/**
* Defines whether or not model-related _test_ files should be generated.
*
* This option enables/disables generation of ALL model-related _test_ files.
*
* For more control over generation of individual files, configure an ignore file and
* refer to it via [ignoreFileOverride].
*/
@get:Internal
val generateModelTests = project.objects.property<Boolean>()
/**
* Defines whether or not model-related _documentation_ files should be generated.
*
* This option enables/disables generation of ALL model-related _documentation_ files.
*
* For more control over generation of individual files, configure an ignore file and
* refer to it via [ignoreFileOverride].
*/
@get:Internal
val generateModelDocumentation = project.objects.property<Boolean>()
/**
* Defines whether or not api-related _test_ files should be generated.
*
* This option enables/disables generation of ALL api-related _test_ files.
*
* For more control over generation of individual files, configure an ignore file and
* refer to it via [ignoreFileOverride].
*/
@get:Internal
val generateApiTests = project.objects.property<Boolean>()
/**
* Defines whether or not api-related _documentation_ files should be generated.
*
* This option enables/disables generation of ALL api-related _documentation_ files.
*
* For more control over generation of individual files, configure an ignore file and
* refer to it via [ignoreFileOverride].
*/
@get:Internal
val generateApiDocumentation = project.objects.property<Boolean>()
/**
* A special-case setting which configures some generators with XML support. In some cases,
* this forces json OR xml, so the default here is false.
*/
@get:Internal
val withXml = project.objects.property<Boolean>()
/**
* A dynamic map of options specific to a generator.
*/
@get:Internal
val configOptions = project.objects.property<Map<String, String>>()
private val originalEnvironmentVariables = mutableMapOf<String, String?>()
private fun <T : Any?> Property<T>.ifNotEmpty(block: Property<T>.(T) -> Unit) {
if (isPresent) {
val item: T? = get()
if (item != null) {
when (get()) {
is String -> if ((get() as String).isNotEmpty()) {
block(get())
}
is String? -> if (true == (get() as String?)?.isNotEmpty()) {
block(get())
}
else -> block(get())
}
}
}
}
@Suppress("unused")
@TaskAction
fun doWork() {
val configurator: CodegenConfigurator = if (configFile.isPresent) {
CodegenConfigurator.fromFile(configFile.get())
} else CodegenConfigurator()
try {
if (systemProperties.isPresent) {
systemProperties.get().forEach { (key, value) ->
// System.setProperty returns the original value for a key, or null.
// Cache the original value or null…we will late put the properties back in their original state.
originalEnvironmentVariables[key] = System.setProperty(key, value)
configurator.addSystemProperty(key, value)
}
}
if (supportingFilesConstrainedTo.isPresent && supportingFilesConstrainedTo.get().isNotEmpty()) {
System.setProperty(CodegenConstants.SUPPORTING_FILES, supportingFilesConstrainedTo.get().joinToString(","))
} else {
System.clearProperty(CodegenConstants.SUPPORTING_FILES)
}
if (modelFilesConstrainedTo.isPresent && modelFilesConstrainedTo.get().isNotEmpty()) {
System.setProperty(CodegenConstants.MODELS, modelFilesConstrainedTo.get().joinToString(","))
} else {
System.clearProperty(CodegenConstants.MODELS)
}
if (apiFilesConstrainedTo.isPresent && apiFilesConstrainedTo.get().isNotEmpty()) {
System.setProperty(CodegenConstants.APIS, apiFilesConstrainedTo.get().joinToString(","))
} else {
System.clearProperty(CodegenConstants.APIS)
}
System.setProperty(CodegenConstants.API_DOCS, generateApiDocumentation.get().toString())
System.setProperty(CodegenConstants.MODEL_DOCS, generateModelDocumentation.get().toString())
System.setProperty(CodegenConstants.MODEL_TESTS, generateModelTests.get().toString())
System.setProperty(CodegenConstants.API_TESTS, generateApiTests.get().toString())
System.setProperty(CodegenConstants.WITH_XML, withXml.get().toString())
// now override with any specified parameters
verbose.ifNotEmpty { value ->
configurator.isVerbose = value
}
validateSpec.ifNotEmpty { value ->
configurator.isValidateSpec = value
}
skipOverwrite.ifNotEmpty { value ->
configurator.isSkipOverwrite = value ?: false
}
inputSpec.ifNotEmpty { value ->
configurator.inputSpec = value
}
generatorName.ifNotEmpty { value ->
configurator.generatorName = value
}
outputDir.ifNotEmpty { value ->
configurator.outputDir = value
}
auth.ifNotEmpty { value ->
configurator.auth = value
}
templateDir.ifNotEmpty { value ->
configurator.templateDir = value
}
apiPackage.ifNotEmpty { value ->
configurator.apiPackage = value
}
modelPackage.ifNotEmpty { value ->
configurator.modelPackage = value
}
modelNamePrefix.ifNotEmpty { value ->
configurator.modelNamePrefix = value
}
modelNameSuffix.ifNotEmpty { value ->
configurator.modelNameSuffix = value
}
invokerPackage.ifNotEmpty { value ->
configurator.invokerPackage = value
}
groupId.ifNotEmpty { value ->
configurator.groupId = value
}
id.ifNotEmpty { value ->
configurator.artifactId = value
}
version.ifNotEmpty { value ->
configurator.artifactVersion = value
}
library.ifNotEmpty { value ->
configurator.library = value
}
gitUserId.ifNotEmpty { value ->
configurator.gitUserId = value
}
gitRepoId.ifNotEmpty { value ->
configurator.gitRepoId = value
}
releaseNote.ifNotEmpty { value ->
configurator.releaseNote = value
}
httpUserAgent.ifNotEmpty { value ->
configurator.httpUserAgent = value
}
ignoreFileOverride.ifNotEmpty { value ->
configurator.ignoreFileOverride = value
}
removeOperationIdPrefix.ifNotEmpty { value ->
configurator.removeOperationIdPrefix = value!!
}
if (systemProperties.isPresent) {
systemProperties.get().forEach { entry ->
configurator.addSystemProperty(entry.key, entry.value)
}
}
if (instantiationTypes.isPresent) {
instantiationTypes.get().forEach { entry ->
configurator.addInstantiationType(entry.key, entry.value)
}
}
if (importMappings.isPresent) {
importMappings.get().forEach { entry ->
configurator.addImportMapping(entry.key, entry.value)
}
}
if (typeMappings.isPresent) {
typeMappings.get().forEach { entry ->
configurator.addTypeMapping(entry.key, entry.value)
}
}
if (additionalProperties.isPresent) {
additionalProperties.get().forEach { entry ->
configurator.addAdditionalProperty(entry.key, entry.value)
}
}
if (languageSpecificPrimitives.isPresent) {
languageSpecificPrimitives.get().forEach {
configurator.addLanguageSpecificPrimitive(it)
}
}
if (reservedWordsMappings.isPresent) {
reservedWordsMappings.get().forEach { entry ->
configurator.addAdditionalReservedWordMapping(entry.key, entry.value)
}
}
val clientOptInput = configurator.toClientOptInput()
val codgenConfig = clientOptInput.config
if (configOptions.isPresent) {
val userSpecifiedConfigOptions = configOptions.get()
codgenConfig.cliOptions().forEach {
if (userSpecifiedConfigOptions.containsKey(it.opt)) {
clientOptInput.config.additionalProperties()[it.opt] = userSpecifiedConfigOptions[it.opt]
}
}
}
try {
val out = services.get(StyledTextOutputFactory::class.java).create("openapi")
out.withStyle(StyledTextOutput.Style.Success)
DefaultGenerator().opts(clientOptInput).generate()
out.println("Successfully generated code to ${configurator.outputDir}")
} catch (e: RuntimeException) {
throw GradleException("Code generation failed.", e)
}
} finally {
// Reset all modified system properties back to their original state
originalEnvironmentVariables.forEach {
when {
it.value == null -> System.clearProperty(it.key)
else -> System.setProperty(it.key, it.value)
}
}
originalEnvironmentVariables.clear()
}
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.generator.gradle.plugin.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
import org.gradle.internal.logging.text.StyledTextOutput
import org.gradle.internal.logging.text.StyledTextOutputFactory
import org.openapitools.codegen.CodegenConfigLoader
import org.openapitools.codegen.CodegenType
/**
* A task which lists out the generators available in OpenAPI Generator
*
* Example (CLI):
*
* ./gradlew -q openApiGenerators
*
* @author Jim Schubert
*/
open class GeneratorsTask : DefaultTask() {
@Suppress("unused")
@TaskAction
fun doWork() {
val generators = CodegenConfigLoader.getAll()
val out = services.get(StyledTextOutputFactory::class.java).create("openapi")
StringBuilder().apply {
val types = CodegenType.values()
append("The following generators are available:")
append(System.lineSeparator())
append(System.lineSeparator())
for (type in types) {
append(type.name).append(" generators:")
append(System.lineSeparator())
generators.filter { it.tag == type }
.sortedBy { it.name }
.forEach({ generator ->
append(" - ")
append(generator.name)
append(System.lineSeparator())
})
append(System.lineSeparator())
append(System.lineSeparator())
}
out.withStyle(StyledTextOutput.Style.Success)
out.formatln("%s%n", toString())
}
}
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.generator.gradle.plugin.tasks
import com.samskivert.mustache.Mustache
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.TaskAction
import org.gradle.internal.logging.text.StyledTextOutput
import org.gradle.internal.logging.text.StyledTextOutputFactory
import org.gradle.kotlin.dsl.property
import org.openapitools.codegen.CodegenConfig
import org.openapitools.codegen.CodegenConstants
import org.openapitools.codegen.DefaultGenerator
import org.openapitools.codegen.SupportingFile
import java.io.File
import java.io.IOException
import java.nio.charset.Charset
/**
* A task which generates a new generator (meta). Useful for redistributable generator packages.
*
* @author Jim Schubert
*/
open class MetaTask : DefaultTask() {
@get:Internal
val generatorName = project.objects.property<String>()
@get:Internal
val packageName = project.objects.property<String>()
@get:Internal
val outputFolder = project.objects.property<String>()
@Suppress("unused")
@TaskAction
fun doWork() {
val packageToPath = packageName.get().replace(".", File.separator)
val dir = File(outputFolder.get())
val klass = "${generatorName.get().titleCasedTextOnly()}Generator"
val templateResourceDir = generatorName.get().hyphenatedTextOnly()
val out = services.get(StyledTextOutputFactory::class.java).create("openapi")
out.withStyle(StyledTextOutput.Style.Info)
logger.debug("package: {}", packageName.get())
logger.debug("dir: {}", dir.absolutePath)
logger.debug("generator class: {}", klass)
val supportingFiles = listOf(
SupportingFile("pom.mustache", "", "pom.xml"),
SupportingFile("generatorClass.mustache", dir("src", "main", "java", packageToPath), "$klass.java"),
SupportingFile("README.mustache", "", "README.md"),
SupportingFile("api.template", dir("src", "main", "resources", templateResourceDir), "api.mustache"),
SupportingFile("model.template", dir("src", "main", "resources", templateResourceDir), "model.mustache"),
SupportingFile("myFile.template", dir("src", "main", "resources", templateResourceDir), "myFile.mustache"),
SupportingFile("services.mustache", dir("src", "main", "resources", "META-INF", "services"), CodegenConfig::class.java.canonicalName))
val currentVersion = CodegenConstants::class.java.`package`.implementationVersion
val data = mapOf("generatorPackage" to packageToPath,
"generatorClass" to klass,
"name" to templateResourceDir,
"fullyQualifiedGeneratorClass" to "${packageName.get()}.$klass",
"openapiGeneratorVersion" to currentVersion)
val generator = DefaultGenerator()
supportingFiles.map {
try {
val destinationFolder = File(File(dir.absolutePath), it.folder)
destinationFolder.mkdirs()
val outputFile = File(destinationFolder, it.destinationFilename)
val template = generator.readTemplate(File("codegen", it.templateFile).path)
var formatted = template
if (it.templateFile.endsWith(".mustache")) {
formatted = Mustache.compiler()
.withLoader(loader(generator))
.defaultValue("")
.compile(template).execute(data)
}
outputFile.writeText(formatted, Charset.forName("UTF8"))
out.formatln("Wrote file to %s", outputFile.absolutePath)
// TODO: register outputs
// return outputFile
} catch (e: IOException) {
logger.error(e.message)
throw GradleException("Can't generate project", e)
}
}
out.withStyle(StyledTextOutput.Style.Success)
out.formatln("Created generator %s", klass)
}
private fun loader(generator: DefaultGenerator): Mustache.TemplateLoader {
return Mustache.TemplateLoader { name ->
generator.getTemplateReader("codegen${File.separator}$name.mustache")
}
}
private fun String.titleCasedTextOnly(): String =
this.split(Regex("[^a-zA-Z0-9]")).joinToString(separator = "", transform = String::capitalize)
private fun String.hyphenatedTextOnly(): String =
this.split(Regex("[^a-zA-Z0-9]")).joinToString(separator = "-", transform = String::toLowerCase)
private fun dir(vararg parts: String): String =
parts.joinToString(separator = File.separator)
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.generator.gradle.plugin.tasks
import io.swagger.parser.OpenAPIParser
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.options.Option
import org.gradle.internal.logging.text.StyledTextOutput
import org.gradle.internal.logging.text.StyledTextOutputFactory
import org.gradle.kotlin.dsl.property
/**
* A generator which validates an Open API spec. This task outputs a list of validation issues and errors.
*
* Example:
* cli:
*
* ./gradlew openApiValidate --input=/path/to/file
*
* build.gradle:
*
* openApiMeta {
* inputSpec = "path/to/spec.yaml"
* }
*
* @author Jim Schubert
*/
open class ValidateTask : DefaultTask() {
@get:Internal
var inputSpec = project.objects.property<String>()
@Suppress("unused")
@get:Internal
@set:Option(option = "input", description = "The input specification.")
var input: String? = null
set(value) {
inputSpec.set(value)
}
@Suppress("unused")
@TaskAction
fun doWork() {
val spec = inputSpec.get()
logger.quiet("Validating spec $spec")
val result = OpenAPIParser().readLocation(spec, null, null)
val messages = result.messages.toSet()
val out = services.get(StyledTextOutputFactory::class.java).create("openapi")
if (messages.isNotEmpty()) {
out.withStyle(StyledTextOutput.Style.Error)
out.println("\nSpec is invalid.\nIssues:\n")
messages.forEach {
out.withStyle(StyledTextOutput.Style.Error)
out.println("\t$it\n")
}
throw GradleException("Validation failed.")
} else {
out.withStyle(StyledTextOutput.Style.Success)
out.println("Spec is valid.")
}
}
}

View File

@@ -0,0 +1,71 @@
package org.openapitools.generator.gradle.plugin
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome
import org.testng.annotations.Test
import java.io.File
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class GenerateTaskDslTest : TestBase() {
override var temp: File = createTempDir(javaClass.simpleName)
private val defaultBuildGradle = """
plugins {
id 'org.openapi.generator'
}
openApiGenerate {
generatorName = "kotlin"
inputSpec = file("spec.yaml").absolutePath
outputDir = file("build/kotlin").absolutePath
apiPackage = "org.openapitools.example.api"
invokerPackage = "org.openapitools.example.invoker"
modelPackage = "org.openapitools.example.model"
configOptions = [
dateLibrary: "java8"
]
}
""".trimIndent()
@Test
fun `openApiGenerate should create an expected file structure from DSL config`() {
// Arrange
val projectFiles = mapOf(
"spec.yaml" to javaClass.classLoader.getResourceAsStream("specs/petstore-v3.0.yaml")
)
withProject(defaultBuildGradle, projectFiles)
// Act
val result = GradleRunner.create()
.withProjectDir(temp)
.withArguments("openApiGenerate")
.withPluginClasspath()
.build()
// Assert
assertTrue(result.output.contains("Successfully generated code to"), "User friendly generate notice is missing.")
listOf(
"build/kotlin/.openapi-generator-ignore",
"build/kotlin/docs/PetsApi.md",
"build/kotlin/docs/Pets.md",
"build/kotlin/docs/Error.md",
"build/kotlin/docs/Pet.md",
"build/kotlin/README.md",
"build/kotlin/build.gradle",
"build/kotlin/.openapi-generator/VERSION",
"build/kotlin/settings.gradle",
"build/kotlin/src/main/kotlin/org/openapitools/example/model/Pets.kt",
"build/kotlin/src/main/kotlin/org/openapitools/example/model/Pet.kt",
"build/kotlin/src/main/kotlin/org/openapitools/example/model/Error.kt",
"build/kotlin/src/main/kotlin/org/openapitools/example/api/PetsApi.kt",
"build/kotlin/src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt"
).map {
val f = File(temp, it)
assertTrue(f.exists() && f.isFile, "An expected file was not generated when invoking the generation.")
}
assertEquals(TaskOutcome.SUCCESS, result.task(":openApiGenerate")?.outcome,
"Expected a successful run, but found ${result.task(":openApiGenerate")?.outcome}")
}
}

View File

@@ -0,0 +1,38 @@
package org.openapitools.generator.gradle.plugin
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome
import org.testng.annotations.Test
import java.io.File
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class GeneratorsTaskDslTest : TestBase() {
override var temp: File = createTempDir(javaClass.simpleName)
@Test
fun `openApiGenerators should list generators available to the user`() {
// Arrange
withProject("""
| plugins {
| id 'org.openapi.generator'
| }
""".trimMargin())
// Act
val result = GradleRunner.create()
.withProjectDir(temp)
.withArguments("openApiGenerators")
.withPluginClasspath()
.build()
// Assert
assertTrue(result.output.contains("The following generators are available:"), "User friendly generator notice is missing.")
assertTrue(result.output.contains("CLIENT generators:"), "Expected client generator header is missing.")
assertTrue(result.output.contains("android"), "Spot-checking listed client generators is missing a client generator.")
assertTrue(result.output.contains("SERVER generators:"), "Expected server generator header is missing.")
assertTrue(result.output.contains("kotlin-server"), "Spot-checking listed server generators is missing a server generator.")
assertEquals(TaskOutcome.SUCCESS, result.task(":openApiGenerators")?.outcome,
"Expected a successful run, but found ${result.task(":openApiGenerators")?.outcome}")
}
}

View File

@@ -0,0 +1,58 @@
package org.openapitools.generator.gradle.plugin
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome
import org.testng.annotations.Test
import java.io.File
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class MetaTaskDslTest : TestBase() {
override var temp: File = createTempDir(javaClass.simpleName)
@Test
fun `openApiMeta should generate desired project contents`() {
// Arrange
val buildDirReplacement = "\$buildDir/meta"
withProject("""
| plugins {
| id 'org.openapi.generator'
| }
|
| openApiMeta {
| generatorName = "Sample"
| packageName = "org.openapitools.example"
| outputFolder = "$buildDirReplacement".toString()
| }
""".trimMargin())
// Act
val result = GradleRunner.create()
.withProjectDir(temp)
.withArguments("openApiMeta")
.withPluginClasspath()
.build()
// Assert
assertTrue(result.output.contains("Wrote file to"), "User friendly write notice is missing.")
// To avoid any OS-specific output causing issues with our stdout comparisons, only compare on expected filenames.
listOf(
"SampleGenerator.java",
"README.md",
"api.mustache",
"model.mustache",
"myFile.mustache",
"org.openapitools.codegen.CodegenConfig",
"pom.xml"
).map {
assertTrue(result.output.contains(it), "Expected $it to be listed in gradle stdout.")
}
assertEquals(
TaskOutcome.SUCCESS,
result.task(":openApiMeta")?.outcome,
"Expected a successful run, but found ${result.task(":openApiMeta")?.outcome}"
)
}
}

View File

@@ -0,0 +1,34 @@
package org.openapitools.generator.gradle.plugin
import org.testng.annotations.AfterMethod
import org.testng.annotations.BeforeMethod
import java.io.File
import java.io.InputStream
abstract class TestBase {
protected open lateinit var temp: File
@BeforeMethod
protected fun before() {
temp = createTempDir(javaClass.simpleName)
temp.deleteOnExit()
}
@AfterMethod
protected fun after(){
temp.deleteRecursively()
}
protected fun withProject(
buildContents: String,
projectFiles: Map<String, InputStream> = mapOf()
) {
val buildFile = File(temp,"build.gradle")
buildFile.writeText(buildContents)
projectFiles.forEach { entry ->
val target = File(temp, entry.key)
entry.value.copyTo(target.outputStream())
}
}
}

View File

@@ -0,0 +1,99 @@
package org.openapitools.generator.gradle.plugin
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome.FAILED
import org.gradle.testkit.runner.TaskOutcome.SUCCESS
import org.testng.annotations.Test
import java.io.File
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class ValidateTaskDslTest : TestBase() {
override var temp: File = createTempDir(javaClass.simpleName)
@Test
fun `openApiValidate should fail on non-file spec`() {
// Arrange
withProject("""
| plugins {
| id 'org.openapi.generator'
| }
|
| openApiValidate {
| inputSpec = "some_location"
| }
""".trimMargin())
// Act
val result = GradleRunner.create()
.withProjectDir(temp)
.withArguments("openApiValidate")
.withPluginClasspath()
.buildAndFail()
// Assert
assertTrue(result.output.contains("unable to read location `some_location`"), "Unexpected/no message presented to the user for a spec pointing to an invalid URI.")
assertEquals(FAILED, result.task(":openApiValidate")?.outcome,
"Expected a failed run, but found ${result.task(":openApiValidate")?.outcome}")
}
@Test
fun `openApiValidate should succeed on valid spec`() {
// Arrange
val projectFiles = mapOf(
"spec.yaml" to javaClass.classLoader.getResourceAsStream("specs/petstore-v3.0.yaml")
)
withProject("""
| plugins {
| id 'org.openapi.generator'
| }
|
| openApiValidate {
| inputSpec = file("spec.yaml").absolutePath
| }
""".trimMargin(), projectFiles)
// Act
val result = GradleRunner.create()
.withProjectDir(temp)
.withArguments("openApiValidate")
.withPluginClasspath()
.build()
// Assert
assertTrue(result.output.contains("Spec is valid."), "Unexpected/no message presented to the user for a valid spec.")
assertEquals(SUCCESS, result.task(":openApiValidate")?.outcome,
"Expected a successful run, but found ${result.task(":openApiValidate")?.outcome}")
}
@Test
fun `openApiValidate should fail on invalid spec`() {
// Arrange
val projectFiles = mapOf(
"spec.yaml" to javaClass.classLoader.getResourceAsStream("specs/petstore-v3.0-invalid.yaml")
)
withProject("""
| plugins {
| id 'org.openapi.generator'
| }
|
| openApiValidate {
| inputSpec = file('spec.yaml').absolutePath
| }
""".trimMargin(), projectFiles)
// Act
val result = GradleRunner.create()
.withProjectDir(temp)
.withArguments("openApiValidate")
.withPluginClasspath()
.buildAndFail()
// Assert
assertTrue(result.output.contains("Spec is invalid."), "Unexpected/no message presented to the user for an invalid spec.")
assertEquals(FAILED, result.task(":openApiValidate")?.outcome,
"Expected a failed run, but found ${result.task(":openApiValidate")?.outcome}")
}
}

View File

@@ -0,0 +1,103 @@
openapi: "3.0.0"
servers:
- url: http://petstore.swagger.io/v1
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
schema:
type: integer
format: int32
responses:
'200':
description: A paged array of pets
headers:
x-next:
description: A link to the next page of responses
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/Pets"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
post:
summary: Create a pet
tags:
- pets
responses:
'201':
description: Null response
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/pets/{petId}:
get:
summary: Info for a specific pet
operationId: showPetById
tags:
- pets
parameters:
- name: petId
in: path
required: true
description: The id of the pet to retrieve
schema:
type: string
responses:
'200':
description: Expected response to a valid request
content:
application/json:
schema:
$ref: "#/components/schemas/Pets"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
components:
schemas:
Pet:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: "#/components/schemas/Pet"
Error:
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string

View File

@@ -0,0 +1,109 @@
openapi: "3.0.0"
info:
version: 1.0.0
title: Swagger Petstore
license:
name: MIT
servers:
- url: http://petstore.swagger.io/v1
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
schema:
type: integer
format: int32
responses:
'200':
description: A paged array of pets
headers:
x-next:
description: A link to the next page of responses
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/Pets"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
post:
summary: Create a pet
operationId: createPets
tags:
- pets
responses:
'201':
description: Null response
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/pets/{petId}:
get:
summary: Info for a specific pet
operationId: showPetById
tags:
- pets
parameters:
- name: petId
in: path
required: true
description: The id of the pet to retrieve
schema:
type: string
responses:
'200':
description: Expected response to a valid request
content:
application/json:
schema:
$ref: "#/components/schemas/Pets"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
components:
schemas:
Pet:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: "#/components/schemas/Pet"
Error:
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string