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 aef0326d031..8b3b082d827 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 @@ -16,8 +16,12 @@ package org.openapitools.generator.gradle.plugin.tasks +import javax.inject.Inject import org.gradle.api.DefaultTask import org.gradle.api.GradleException +import org.gradle.api.Project +import org.gradle.api.file.FileSystemOperations +import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Property import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input @@ -35,6 +39,7 @@ import org.gradle.internal.logging.text.StyledTextOutputFactory import org.gradle.kotlin.dsl.listProperty import org.gradle.kotlin.dsl.mapProperty import org.gradle.kotlin.dsl.property +import org.gradle.util.GradleVersion import org.openapitools.codegen.CodegenConstants import org.openapitools.codegen.DefaultGenerator import org.openapitools.codegen.config.CodegenConfigurator @@ -52,7 +57,8 @@ import org.openapitools.codegen.config.MergedSpecBuilder */ @Suppress("UnstableApiUsage") @CacheableTask -open class GenerateTask : DefaultTask() { +open class GenerateTask @Inject constructor(private val objectFactory: ObjectFactory) : DefaultTask() { + /** * The verbosity of generation */ @@ -547,6 +553,14 @@ open class GenerateTask : DefaultTask() { protected open fun createDefaultCodegenConfigurator(): CodegenConfigurator = CodegenConfigurator() + private fun createFileSystemManager(): FileSystemManager { + return if(GradleVersion.current() >= GradleVersion.version("6.0")) { + objectFactory.newInstance(FileSystemManagerDefault::class.java) + } else { + objectFactory.newInstance(FileSystemManagerLegacy::class.java, project) + } + } + @Suppress("unused") @TaskAction fun doWork() { @@ -557,7 +571,7 @@ open class GenerateTask : DefaultTask() { cleanupOutput.ifNotEmpty { cleanup -> if (cleanup) { - project.delete(outputDir) + createFileSystemManager().delete(outputDir) val out = services.get(StyledTextOutputFactory::class.java).create("openapi") out.withStyle(StyledTextOutput.Style.Success) out.println("Cleaned up output directory ${outputDir.get()} before code generation (cleanupOutput set to true).") @@ -861,3 +875,23 @@ open class GenerateTask : DefaultTask() { } } } + +internal interface FileSystemManager { + + fun delete(outputDir: Property) + +} + +internal open class FileSystemManagerLegacy @Inject constructor(private val project: Project): FileSystemManager { + + override fun delete(outputDir: Property) { + project.delete(outputDir) + } +} + +internal open class FileSystemManagerDefault @Inject constructor(private val fs: FileSystemOperations) : FileSystemManager { + + override fun delete(outputDir: Property) { + fs.delete { delete(outputDir) } + } +} diff --git a/modules/openapi-generator-gradle-plugin/src/test/kotlin/GenerateTaskConfigurationCacheTest.kt b/modules/openapi-generator-gradle-plugin/src/test/kotlin/GenerateTaskConfigurationCacheTest.kt new file mode 100644 index 00000000000..b1636e2b0ae --- /dev/null +++ b/modules/openapi-generator-gradle-plugin/src/test/kotlin/GenerateTaskConfigurationCacheTest.kt @@ -0,0 +1,129 @@ +package org.openapitools.generator.gradle.plugin + +import org.gradle.testkit.runner.TaskOutcome +import org.testng.SkipException +import org.testng.annotations.BeforeMethod +import org.testng.annotations.DataProvider +import org.testng.annotations.Test +import java.io.File +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class GenerateTaskConfigurationCacheTest : TestBase() { + + private lateinit var projectDirCC: File + + @BeforeMethod + override fun before() { + initialize() + projectDirCC = temp.resolve("projectDirCC").apply { mkdir() } + } + + @DataProvider(name = "gradle_version_provider") + private fun gradleVersionProviderWithConfigurationCache(): Array> = arrayOf(arrayOf("8.1.1"), arrayOf("7.6")) + + @DataProvider(name = "gradle_version_provider_without_cc") + private fun gradleVersionProviderWithoutConfigurationCache(): Array> = arrayOf(arrayOf("5.6.1")) + + // inputSpec tests + + private val inputSpecExtensionContents = """ + generatorName = "kotlin" + inputSpec = file("spec.yaml").absolutePath + cleanupOutput.set(true) + """.trimIndent() + + @Test(dataProvider = "gradle_version_provider") + fun `openApiGenerate should reuse configuration cache`(gradleVersion: String) { + // Arrange + withProject(inputSpecExtensionContents) + + // Act + val result1 = build { + withProjectDir(projectDirCC) + withArguments("--configuration-cache", "clean", "openApiGenerate") + withGradleVersion(gradleVersion) + } + + val expectedRelativeFilePathSet = projectDirCC.toRelativeFilePathSet() + + val result2 = build { + withProjectDir(projectDirCC) + withArguments("--configuration-cache", "clean", "openApiGenerate") + withGradleVersion(gradleVersion) + } + + // Assert + assertEquals(TaskOutcome.SUCCESS, result1.task(":openApiGenerate")?.outcome) + assertTrue(result1.output.contains("Configuration cache entry stored.")) + assertEquals(TaskOutcome.SUCCESS, result2.task(":openApiGenerate")?.outcome) + assertTrue(result2.output.contains("Configuration cache entry reused.")) + assertEquals(expectedRelativeFilePathSet, projectDirCC.toRelativeFilePathSet()) + } + + private fun getJavaVersion(): Int { + val version = System.getProperty("java.version") + val parts = version.split('.') + if (parts.first() == "1") return parts.getOrElse(1) { "0" }.toInt() + return parts.first().toInt() + } + + @Test(dataProvider = "gradle_version_provider_without_cc") + fun `openApiGenerate should work with Gradle legacy versions`(gradleVersion: String) { + if(getJavaVersion() > 12) { + // https://docs.gradle.org/current/userguide/compatibility.html + throw SkipException("Skipping test as Gradle ${gradleVersion} is not compatible with Java ${getJavaVersion()}") + } + // Arrange + withProject(inputSpecExtensionContents) + + // Act + val result1 = build { + withProjectDir(projectDirCC) + withArguments("clean", "openApiGenerate") + withGradleVersion(gradleVersion) + } + + val expectedRelativeFilePathSet = projectDirCC.toRelativeFilePathSet() + + val result2 = build { + withProjectDir(projectDirCC) + withArguments("clean", "openApiGenerate") + withGradleVersion(gradleVersion) + } + + // Assert + assertEquals(TaskOutcome.SUCCESS, result1.task(":openApiGenerate")?.outcome) + assertEquals(TaskOutcome.SUCCESS, result2.task(":openApiGenerate")?.outcome) + assertEquals(expectedRelativeFilePathSet, projectDirCC.toRelativeFilePathSet()) + } + + // Helper methods & test fixtures + + private fun File.toRelativeFilePathSet() = + resolve("build").walk().map { it.toRelativeString(resolve("build")) }.toSet() + + private fun withProject(extensionContents: String) { + val settingsContents = """ + rootProject.name = "openapi-generator" + """.trimIndent() + val buildContents = """ + plugins { + id 'base' + id 'org.openapi.generator' + } + openApiGenerate { + $extensionContents + } + """.trimIndent() + val projectFiles = mapOf( + "spec.yaml" to javaClass.classLoader.getResourceAsStream("specs/petstore-v3.0.yaml")!! + ) + withProject( + projectDir = projectDirCC, + settingsContents = settingsContents, + buildContents = buildContents, + projectFiles = projectFiles + ) + } +}