From e4c858cd25140f01c55326459331ad42faf873d1 Mon Sep 17 00:00:00 2001 From: HenningWaack Date: Mon, 10 Aug 2020 03:40:19 +0200 Subject: [PATCH] [gradle] Enabling up-to-date checks and gradle caching for openapigenerator tasks (#6716) --- appveyor.yml | 6 +- .../README.adoc | 29 ++++ .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../samples/local-spec/README.md | 16 +- .../gradle/plugin/OpenApiGeneratorPlugin.kt | 6 +- .../OpenApiGeneratorGenerateExtension.kt | 2 +- .../gradle/plugin/tasks/GenerateTask.kt | 157 ++++++++++++------ .../generator/gradle/plugin/tasks/MetaTask.kt | 24 +-- .../gradle/plugin/tasks/ValidateTask.kt | 14 +- .../src/test/kotlin/GenerateTaskDslTest.kt | 95 ++++++++--- 10 files changed, 250 insertions(+), 101 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index dd8ab4c8bc33..d9a420159e36 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,14 +15,14 @@ install: # install gradle - ps: | Add-Type -AssemblyName System.IO.Compression.FileSystem - if (!(Test-Path -Path "C:\gradle" )) { + if (!(Test-Path -Path "C:\gradle\gradle-5.6.4" )) { (new-object System.Net.WebClient).DownloadFile( - 'https://services.gradle.org/distributions/gradle-5.3.1-bin.zip', + 'https://services.gradle.org/distributions/gradle-5.6.4-bin.zip', 'C:\gradle-bin.zip' ) [System.IO.Compression.ZipFile]::ExtractToDirectory("C:\gradle-bin.zip", "C:\gradle") } - - cmd: SET PATH=C:\maven\apache-maven-3.2.5\bin;C:\gradle\gradle-5.3.1\bin;%JAVA_HOME%\bin;%PATH% + - cmd: SET PATH=C:\maven\apache-maven-3.2.5\bin;C:\gradle\gradle-5.6.4\bin;%JAVA_HOME%\bin;%PATH% - cmd: SET MAVEN_OPTS=-Xmx4g - cmd: SET JAVA_OPTS=-Xmx4g - cmd: SET M2_HOME=C:\maven\apache-maven-3.2.5 diff --git a/modules/openapi-generator-gradle-plugin/README.adoc b/modules/openapi-generator-gradle-plugin/README.adoc index 2c10b0a8b342..160f4e57217d 100644 --- a/modules/openapi-generator-gradle-plugin/README.adoc +++ b/modules/openapi-generator-gradle-plugin/README.adoc @@ -61,6 +61,35 @@ task validateBadSpec(type: org.openapitools.generator.gradle.plugin.tasks.Valida task validateSpecs(dependsOn: ['validateGoodSpec', 'validateBadSpec']) ---- +[NOTE] +==== +The tasks support Gradle Up-To-Date checking and Gradle Cache. Enable caching globally by setting `org.gradle.caching=true` in the `gradle.settings` +file or by passing the command line property `--build-cache` when executing on the command line. + +Disable up-to-date checks and caching by setting the following property when using the extension: + +.Disable caching for extension +[source,groovy] +---- +tasks.withType(org.openapitools.generator.gradle.plugin.tasks.GenerateTask) { + outputs.upToDateWhen { false } + outputs.cacheIf { false } +} +---- +Disable up-to-date checks and caching for a custom task: + +.Disable caching for custom task +[source,groovy] +---- +task validateGoodSpec(type: org.openapitools.generator.gradle.plugin.tasks.ValidateTask){ + outputs.upToDateWhen { false } + outputs.cacheIf { false } + + inputSpec = "$rootDir/petstore-v3.0.yaml".toString() +} +---- +==== + == Plugin Setup //# RELEASE_VERSION diff --git a/modules/openapi-generator-gradle-plugin/gradle/wrapper/gradle-wrapper.properties b/modules/openapi-generator-gradle-plugin/gradle/wrapper/gradle-wrapper.properties index 5b9bdfe705b8..6925261cce5d 100644 --- a/modules/openapi-generator-gradle-plugin/gradle/wrapper/gradle-wrapper.properties +++ b/modules/openapi-generator-gradle-plugin/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ #Thu Jan 30 22:14:34 EST 2020 -distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStorePath=wrapper/dists diff --git a/modules/openapi-generator-gradle-plugin/samples/local-spec/README.md b/modules/openapi-generator-gradle-plugin/samples/local-spec/README.md index 88e61fd97270..713c52d15abc 100644 --- a/modules/openapi-generator-gradle-plugin/samples/local-spec/README.md +++ b/modules/openapi-generator-gradle-plugin/samples/local-spec/README.md @@ -1,18 +1,18 @@ # Local Spec Sample -This example assumes you have Gradle 4.7+ installed. No gradle wrapper is provided in samples. +This example assumes you have Gradle 5.6.4+ installed. No gradle wrapper is provided in samples. -First, publish the openapi-generator-gradle-plugin locally via `./gradlew assemble install` in the module directory. +First, publish the openapi-generator-gradle-plugin locally via `./gradlew assemble publishToMavenLocal` in the module directory. Then, run the following tasks in this example directory. ```bash -gradle openApiGenerate -gradle openApiMeta -gradle openApiValidate -gradle buildGoSdk -gradle buildDotnetSdk -gradle generateGoWithInvalidSpec +gradle openApiGenerate # expected outcome: BUILD SCCESSFUL +gradle openApiMeta # expected outcome: BUILD SCCESSFUL +gradle openApiValidate # expected outcome: BUILD FAILED +gradle buildGoSdk # expected outcome: BUILD SCCESSFUL +gradle buildDotnetSdk # expected outcome: BUILD SCCESSFUL +gradle generateGoWithInvalidSpec # expected outcome: BUILD FAILED ``` The samples can be tested against other versions of the plugin using the `openApiGeneratorVersion` property. For example: diff --git a/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/OpenApiGeneratorPlugin.kt b/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/OpenApiGeneratorPlugin.kt index 84caadfad839..7c053b712bee 100644 --- a/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/OpenApiGeneratorPlugin.kt +++ b/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/OpenApiGeneratorPlugin.kt @@ -55,9 +55,9 @@ class OpenApiGeneratorPlugin : Plugin { ) val generators = extensions.create( - "openApiGenerators", - OpenApiGeneratorGeneratorsExtension::class.java, - project + "openApiGenerators", + OpenApiGeneratorGeneratorsExtension::class.java, + project ) generate.outputDir.set("$buildDir/generate-resources/main") diff --git a/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/extensions/OpenApiGeneratorGenerateExtension.kt b/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/extensions/OpenApiGeneratorGenerateExtension.kt index 4f099db7f6ff..b9319cfaa4c9 100644 --- a/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/extensions/OpenApiGeneratorGenerateExtension.kt +++ b/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/extensions/OpenApiGeneratorGenerateExtension.kt @@ -317,7 +317,7 @@ open class OpenApiGeneratorGenerateExtension(project: Project) { } @Suppress("MemberVisibilityCanBePrivate") - fun applyDefaults(){ + fun applyDefaults() { releaseNote.set("Minor update") modelNamePrefix.set("") modelNameSuffix.set("") diff --git a/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/tasks/GenerateTask.kt b/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/tasks/GenerateTask.kt index 500597599b36..a7a3f84e26ed 100644 --- a/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/tasks/GenerateTask.kt +++ b/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/tasks/GenerateTask.kt @@ -19,7 +19,14 @@ 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.CacheableTask +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.Optional +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.options.Option import org.gradle.internal.logging.text.StyledTextOutput @@ -32,7 +39,6 @@ import org.openapitools.codegen.DefaultGenerator import org.openapitools.codegen.config.CodegenConfigurator import org.openapitools.codegen.config.GlobalSettings - /** * A task which generates the desired code. * @@ -43,63 +49,73 @@ import org.openapitools.codegen.config.GlobalSettings * @author Jim Schubert */ @Suppress("UnstableApiUsage") +@CacheableTask open class GenerateTask : DefaultTask() { /** * The verbosity of generation */ - @get:Internal + @Optional + @Input val verbose = project.objects.property() /** * Whether or not an input specification should be validated upon generation. */ - @get:Internal + @Optional + @Input val validateSpec = project.objects.property() /** * The name of the generator which will handle codegen. (see "openApiGenerators" task) */ - @get:Internal + @Optional + @Input val generatorName = project.objects.property() /** * The output target directory into which code will be generated. */ - @get:Internal + @Optional + @get:OutputDirectory val outputDir = project.objects.property() @Suppress("unused") @get:Internal @set:Option(option = "input", description = "The input specification.") + @Input var input: String? = null set(value) { inputSpec.set(value) } - + /** * The Open API 2.0/3.x specification location. */ - @get:Internal + @get:InputFile + @PathSensitive(PathSensitivity.RELATIVE) val inputSpec = project.objects.property() /** * The template directory holding a custom template. */ - @get:Internal + @Optional + @Input val templateDir = project.objects.property() /** * 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 + @Optional + @Input val auth = project.objects.property() /** * Sets specified global properties. */ - @get:Internal + @Optional + @Input val globalProperties = project.objects.mapProperty() /** @@ -107,159 +123,185 @@ open class GenerateTask : DefaultTask() { * 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 + @Optional + @Input val configFile = project.objects.property() /** * Specifies if the existing files should be overwritten during the generation. */ - @get:Internal + @Optional + @Input val skipOverwrite = project.objects.property() /** * Package for generated classes (where supported) */ - @get:Internal + @Optional + @Input val packageName = project.objects.property() /** * Package for generated api classes */ - @get:Internal + @Optional + @Input val apiPackage = project.objects.property() /** * Package for generated models */ - @get:Internal + @Optional + @Input val modelPackage = project.objects.property() /** * Prefix that will be prepended to all model names. Default is the empty string. */ - @get:Internal + @Optional + @Input val modelNamePrefix = project.objects.property() /** * Suffix that will be appended to all model names. Default is the empty string. */ - @get:Internal + @Optional + @Input val modelNameSuffix = project.objects.property() /** * Sets instantiation type mappings. */ - @get:Internal + @Optional + @Input val instantiationTypes = project.objects.mapProperty() /** * Sets mappings between OpenAPI spec types and generated code types. */ - @get:Internal + @Optional + @Input val typeMappings = project.objects.mapProperty() /** * 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 + @Optional + @Input val additionalProperties = project.objects.mapProperty() /** * Sets server variable for server URL template substitution, in the format of name=value,name=value. * You can also have multiple occurrences of this option. */ - @get:Internal + @Optional + @Input val serverVariables = project.objects.mapProperty() /** * Specifies additional language specific primitive types in the format of type1,type2,type3,type3. For example: String,boolean,Boolean,Double. */ - @get:Internal + @Optional + @Input val languageSpecificPrimitives = project.objects.listProperty() /** * Specifies mappings between a given class and the import that should be used for that class. */ - @get:Internal + @Optional + @Input val importMappings = project.objects.mapProperty() /** * Root package for generated code. */ - @get:Internal + @Optional + @Input val invokerPackage = project.objects.property() /** * GroupId in generated pom.xml/build.gradle or other build script. Language-specific conversions occur in non-jvm generators. */ - @get:Internal + @Optional + @Input val groupId = project.objects.property() /** * ArtifactId in generated pom.xml/build.gradle or other build script. Language-specific conversions occur in non-jvm generators. */ - @get:Internal + @Optional + @Input val id = project.objects.property() /** * Artifact version in generated pom.xml/build.gradle or other build script. Language-specific conversions occur in non-jvm generators. */ - @get:Internal + @Optional + @Input val version = project.objects.property() /** * Reference the library template (sub-template) of a generator. */ - @get:Internal + @Optional + @Input val library = project.objects.property() /** * Git host, e.g. gitlab.com. */ - @get:Internal + @Optional + @Input val gitHost = project.objects.property() /** * Git user ID, e.g. openapitools. */ - @get:Internal + @Optional + @Input val gitUserId = project.objects.property() /** * Git repo ID, e.g. openapi-generator. */ - @get:Internal + @Optional + @Input val gitRepoId = project.objects.property() /** * Release note, default to 'Minor update'. */ - @get:Internal + @Optional + @Input val releaseNote = project.objects.property() /** * HTTP user agent, e.g. codegen_csharp_api_client, default to 'OpenAPI-Generator/{packageVersion}/{language}' */ - @get:Internal + @Optional + @Input val httpUserAgent = project.objects.property() /** * Specifies how a reserved name should be escaped to. */ - @get:Internal + @Optional + @Input val reservedWordsMappings = project.objects.mapProperty() /** * Specifies an override location for the .openapi-generator-ignore file. Most useful on initial generation. */ - @get:Internal + @Optional + @Input val ignoreFileOverride = project.objects.property() /** * Remove prefix of operationId, e.g. config_getId => getId */ - @get:Internal + @Optional + @Input val removeOperationIdPrefix = project.objects.property() /** @@ -271,7 +313,8 @@ open class GenerateTask : DefaultTask() { * 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 + @Optional + @Input val apiFilesConstrainedTo = project.objects.listProperty() /** @@ -281,7 +324,8 @@ open class GenerateTask : DefaultTask() { * 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 + @Optional + @Input val modelFilesConstrainedTo = project.objects.listProperty() /** @@ -294,7 +338,8 @@ open class GenerateTask : DefaultTask() { * 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 + @Optional + @Input val supportingFilesConstrainedTo = project.objects.listProperty() /** @@ -305,7 +350,8 @@ open class GenerateTask : DefaultTask() { * For more control over generation of individual files, configure an ignore file and * refer to it via [ignoreFileOverride]. */ - @get:Internal + @Optional + @Input val generateModelTests = project.objects.property() /** @@ -316,7 +362,8 @@ open class GenerateTask : DefaultTask() { * For more control over generation of individual files, configure an ignore file and * refer to it via [ignoreFileOverride]. */ - @get:Internal + @Optional + @Input val generateModelDocumentation = project.objects.property() /** @@ -327,7 +374,8 @@ open class GenerateTask : DefaultTask() { * For more control over generation of individual files, configure an ignore file and * refer to it via [ignoreFileOverride]. */ - @get:Internal + @Optional + @Input val generateApiTests = project.objects.property() /** @@ -338,21 +386,23 @@ open class GenerateTask : DefaultTask() { * For more control over generation of individual files, configure an ignore file and * refer to it via [ignoreFileOverride]. */ - @get:Internal + @Optional + @Input val generateApiDocumentation = project.objects.property() /** * 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 + @Optional + @Input val withXml = project.objects.property() - /** * To write all log messages (not just errors) to STDOUT */ - @get:Internal + @Optional + @Input val logToStderr = project.objects.property() /** @@ -361,13 +411,15 @@ open class GenerateTask : DefaultTask() { * LANG_POST_PROCESS_FILE (e.g. GO_POST_PROCESS_FILE, SCALA_POST_PROCESS_FILE). Please open an issue if your target * generator does not support this functionality. */ - @get:Internal + @Optional + @Input val enablePostProcessFile = project.objects.property() /** * To skip spec validation. When true, we will skip the default behavior of validating a spec before generation. */ - @get:Internal + @Optional + @Input val skipValidateSpec = project.objects.property() /** @@ -375,19 +427,22 @@ open class GenerateTask : DefaultTask() { * definitions generated as top-level Array-of-items, List-of-items, Map-of-items definitions. * When true, A model representation either containing or extending the array,list,map (depending on specific generator implementation) will be generated. */ - @get:Internal + @Optional + @Input val generateAliasAsModel = project.objects.property() /** * A dynamic map of options specific to a generator. */ - @get:Internal + @Optional + @Input val configOptions = project.objects.mapProperty() /** * Templating engine: "mustache" (default) or "handlebars" (beta) */ - @get:Internal + @Optional + @Input val engine = project.objects.property() private fun Property.ifNotEmpty(block: Property.(T) -> Unit) { diff --git a/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/tasks/MetaTask.kt b/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/tasks/MetaTask.kt index 9bebdd4f4571..0aa49c22cff1 100644 --- a/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/tasks/MetaTask.kt +++ b/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/tasks/MetaTask.kt @@ -19,15 +19,18 @@ 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.CacheableTask +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.OutputDirectory 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.* -import org.openapitools.codegen.api.TemplatePathLocator +import org.openapitools.codegen.CodegenConfig +import org.openapitools.codegen.CodegenConstants +import org.openapitools.codegen.SupportingFile +import org.openapitools.codegen.TemplateManager import org.openapitools.codegen.templating.CommonTemplateContentLocator -import org.openapitools.codegen.templating.GeneratorTemplateContentLocator import org.openapitools.codegen.templating.MustacheEngineAdapter import org.openapitools.codegen.templating.TemplateManagerOptions import java.io.File @@ -39,15 +42,16 @@ import java.nio.charset.Charset * * @author Jim Schubert */ +@CacheableTask open class MetaTask : DefaultTask() { - @get:Internal + @get:Input val generatorName = project.objects.property() - @get:Internal + @get:Input val packageName = project.objects.property() - @get:Internal + @get:OutputDirectory val outputFolder = project.objects.property() @Suppress("unused") @@ -92,9 +96,9 @@ open class MetaTask : DefaultTask() { val outputFile = File(destinationFolder, it.destinationFilename) val templateProcessor = TemplateManager( - TemplateManagerOptions(false, false), - MustacheEngineAdapter(), - arrayOf(CommonTemplateContentLocator("codegen")) + TemplateManagerOptions(false, false), + MustacheEngineAdapter(), + arrayOf(CommonTemplateContentLocator("codegen")) ) val template = templateProcessor.getFullTemplateContents(it.templateFile) diff --git a/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/tasks/ValidateTask.kt b/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/tasks/ValidateTask.kt index c46c5f2cf556..3d0cbab2b064 100644 --- a/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/tasks/ValidateTask.kt +++ b/modules/openapi-generator-gradle-plugin/src/main/kotlin/org/openapitools/generator/gradle/plugin/tasks/ValidateTask.kt @@ -23,7 +23,12 @@ import io.swagger.v3.parser.core.models.ParseOptions import org.gradle.api.DefaultTask import org.gradle.api.GradleException import org.gradle.api.logging.Logging +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.Optional +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.options.Option import org.gradle.internal.logging.text.StyledTextOutput @@ -49,10 +54,12 @@ import org.openapitools.codegen.validations.oas.RuleConfiguration * @author Jim Schubert */ open class ValidateTask : DefaultTask() { - @get:Internal + @get:InputFile + @PathSensitive(PathSensitivity.RELATIVE) var inputSpec = project.objects.property() - @get:Internal + @Optional + @Input var recommend = project.objects.property() @Suppress("unused") @@ -75,12 +82,11 @@ open class ValidateTask : DefaultTask() { val options = ParseOptions() options.isResolve = true - + val result = OpenAPIParser().readLocation(spec, null, options) val messages = result.messages.toSet() val out = services.get(StyledTextOutputFactory::class.java).create("openapi") - val ruleConfiguration = RuleConfiguration() ruleConfiguration.isEnableRecommendations = recommendations diff --git a/modules/openapi-generator-gradle-plugin/src/test/kotlin/GenerateTaskDslTest.kt b/modules/openapi-generator-gradle-plugin/src/test/kotlin/GenerateTaskDslTest.kt index 5586a1d3fbf5..08fc3cf73798 100644 --- a/modules/openapi-generator-gradle-plugin/src/test/kotlin/GenerateTaskDslTest.kt +++ b/modules/openapi-generator-gradle-plugin/src/test/kotlin/GenerateTaskDslTest.kt @@ -7,7 +7,7 @@ import java.io.File import kotlin.test.assertEquals import kotlin.test.assertTrue -class GenerateTaskDslTest : TestBase() { +class GenerateTaskDslTest : TestBase() { override var temp: File = createTempDir(javaClass.simpleName) private val defaultBuildGradle = """ @@ -46,18 +46,18 @@ class GenerateTaskDslTest : TestBase() { 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/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/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" + "build/kotlin/.openapi-generator-ignore", + "build/kotlin/docs/PetsApi.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/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.") @@ -67,6 +67,61 @@ class GenerateTaskDslTest : TestBase() { "Expected a successful run, but found ${result.task(":openApiGenerate")?.outcome}") } + @Test + fun `openApiGenerate should used up-to-date instead of regenerate`() { + // Arrange + val projectFiles = mapOf( + "spec.yaml" to javaClass.classLoader.getResourceAsStream("specs/petstore-v3.0.yaml") + ) + withProject(defaultBuildGradle, projectFiles) + + // Act + val resultFirstRun = GradleRunner.create() + .withProjectDir(temp) + .withArguments("openApiGenerate") + .withPluginClasspath() + .build() + val resultSecondRun = GradleRunner.create() + .withProjectDir(temp) + .withArguments("openApiGenerate") + .withPluginClasspath() + .build() + + // Assert + assertTrue(resultFirstRun.output.contains("Task ':openApiGenerate' is not up-to-date"), "First run should not be up-to-date") + assertTrue(resultSecondRun.output.contains("Task :openApiGenerate UP-TO-DATE"), "Task of second run should be up-to-date") + } + + @Test + fun `openApiGenerate should use cache instead of regenerate`() { + // Arrange + val projectFiles = mapOf( + "spec.yaml" to javaClass.classLoader.getResourceAsStream("specs/petstore-v3.0.yaml") + ) + withProject(defaultBuildGradle, projectFiles) + + // Act + val resultFirstRun = GradleRunner.create() + .withProjectDir(temp) + .withArguments("openApiGenerate", "--build-cache") + .withPluginClasspath() + .build() + + // delete the build directory from the last run + File(temp, "build/kotlin").deleteRecursively() + + // re-run + val resultSecondRun = GradleRunner.create() + .withProjectDir(temp) + .withArguments("openApiGenerate", "--build-cache") + .withPluginClasspath() + .build() + + // Assert + assertTrue(resultFirstRun.output.contains("Task ':openApiGenerate' is not up-to-date"), "First run should not be up-to-date") + assertTrue(resultSecondRun.output.contains("Task :openApiGenerate FROM-CACHE"), "Task of second run should be from cache") + } + @Test fun `openApiValidate should fail on invalid spec`() { // Arrange @@ -128,10 +183,10 @@ class GenerateTaskDslTest : TestBase() { } @Test - fun `openapiGenerate should attempt to set handlebars when specified as engine`(){ + fun `openapiGenerate should attempt to set handlebars when specified as engine`() { // Arrange val projectFiles = mapOf( - "spec.yaml" to javaClass.classLoader.getResourceAsStream("specs/petstore-v3.0.yaml") + "spec.yaml" to javaClass.classLoader.getResourceAsStream("specs/petstore-v3.0.yaml") ) withProject(""" @@ -151,16 +206,16 @@ class GenerateTaskDslTest : TestBase() { // Act val result = GradleRunner.create() - .withProjectDir(temp) - .withArguments("openApiGenerate", "--stacktrace") - .withPluginClasspath() - .buildAndFail() + .withProjectDir(temp) + .withArguments("openApiGenerate", "--stacktrace") + .withPluginClasspath() + .buildAndFail() // Assert // rather than write out full handlebars generator templates, we'll just test that the configurator has set handlebars as the engine. assertTrue(result.output.contains("HandlebarsException"), "Stack should expose an exception for missing templates.") assertTrue(result.output.contains("handlebars"), "Build should have attempted to use handlebars.") assertEquals(TaskOutcome.FAILED, result.task(":openApiGenerate")?.outcome, - "Expected a failed run, but found ${result.task(":openApiGenerate")?.outcome}") + "Expected a failed run, but found ${result.task(":openApiGenerate")?.outcome}") } } \ No newline at end of file