From ab9a64c26b89af102b15139d4227be6f5958673d Mon Sep 17 00:00:00 2001 From: Clemens Grabmann Date: Tue, 22 Aug 2023 09:13:02 +0200 Subject: [PATCH] patch: (#171) add workaround for the gradle task dependencies problem * we work around this by creating a dummy directory which we will use as a working directory for the forked spring bootRun task. Because some other tasks also seem to use this directory we also make them depend on this task. But that list might be incomplete. Signed-off-by: Clemens Grabmann --- build.gradle.kts | 1 + gradle/libs.versions.toml | 1 + .../gradle/api/NamedDomainObjectSetExt.kt | 10 +++- .../SpringDocOpenApiConfigurePlugin.kt | 49 +++++++++++++++++-- .../swagger/SwaggerApiConfigurePlugin.kt | 8 +-- .../settings.gradle.kts | 8 --- .../skeleton-server/build.gradle.kts | 21 ++++++-- .../SpringDocOpenApiConfigurePluginTest.kt | 4 +- 8 files changed, 74 insertions(+), 28 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index d56d8e8..5d540ad 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -46,6 +46,7 @@ dependencies { implementation(libs.springdoc.openapi.plugin) implementation(libs.kotlinx.serialization.json) + implementation(libs.exec.fork.plugin) testImplementation(libs.bundles.testImplementationDependencies) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c7adb2a..a0caba0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -38,6 +38,7 @@ swagger-codegen-plugin = { module = "gradle.plugin.org.hidetake:gradle-swagger-g swagger-jersey2-jaxrs = { module = "io.swagger:swagger-jersey2-jaxrs", version = { strictly = "1.6.2" } } springdoc-openapi-plugin = { module = "org.springdoc:springdoc-openapi-gradle-plugin", version = "1.7.0" } +exec-fork-plugin = { module = "com.github.psxpaul:gradle-execfork-plugin", version = "0.2.0" } # we need to manually inject this version because of https://github.com/ronmamo/reflections/issues/273 (we would transitively pull 0.9.2 otherwise) reflections = { module = "org.reflections:reflections", version = { strictly = "0.9.11" } } diff --git a/src/main/kotlin/io/cloudflight/gradle/autoconfigure/extentions/gradle/api/NamedDomainObjectSetExt.kt b/src/main/kotlin/io/cloudflight/gradle/autoconfigure/extentions/gradle/api/NamedDomainObjectSetExt.kt index 4fb7d28..05a0654 100644 --- a/src/main/kotlin/io/cloudflight/gradle/autoconfigure/extentions/gradle/api/NamedDomainObjectSetExt.kt +++ b/src/main/kotlin/io/cloudflight/gradle/autoconfigure/extentions/gradle/api/NamedDomainObjectSetExt.kt @@ -1,6 +1,14 @@ package io.cloudflight.gradle.autoconfigure.extentions.gradle.api +import org.gradle.api.DomainObjectCollection +import org.gradle.api.NamedDomainObjectProvider import org.gradle.api.NamedDomainObjectSet import kotlin.reflect.KClass -internal fun NamedDomainObjectSet.withType(klass: KClass): NamedDomainObjectSet = this.withType(klass.java) \ No newline at end of file +internal fun NamedDomainObjectSet.withType(klass: KClass): NamedDomainObjectSet = this.withType(klass.java) + +internal fun NamedDomainObjectSet.withType(klass: KClass, configuration: (it: S) -> Unit): DomainObjectCollection = this.withType(klass.java, configuration) + +internal fun NamedDomainObjectSet.named(name: String, klass: KClass): NamedDomainObjectProvider = this.named(name, klass.java) + +internal fun NamedDomainObjectSet.named(name: String, klass: KClass, configuration: (it: S) -> Unit): NamedDomainObjectProvider = this.named(name, klass.java, configuration) diff --git a/src/main/kotlin/io/cloudflight/gradle/autoconfigure/springdoc/openapi/SpringDocOpenApiConfigurePlugin.kt b/src/main/kotlin/io/cloudflight/gradle/autoconfigure/springdoc/openapi/SpringDocOpenApiConfigurePlugin.kt index bd19abc..d2cafe2 100644 --- a/src/main/kotlin/io/cloudflight/gradle/autoconfigure/springdoc/openapi/SpringDocOpenApiConfigurePlugin.kt +++ b/src/main/kotlin/io/cloudflight/gradle/autoconfigure/springdoc/openapi/SpringDocOpenApiConfigurePlugin.kt @@ -1,10 +1,15 @@ package io.cloudflight.gradle.autoconfigure.springdoc.openapi +import com.github.psxpaul.task.JavaExecFork +import io.cloudflight.gradle.autoconfigure.AutoConfigureGradlePlugin.Companion.TASK_GROUP +import io.cloudflight.gradle.autoconfigure.extentions.gradle.api.named +import io.cloudflight.gradle.autoconfigure.extentions.gradle.api.withType import io.cloudflight.gradle.autoconfigure.java.JavaConfigurePlugin import io.cloudflight.gradle.autoconfigure.util.addApiDocumentationPublication import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.Task +import org.gradle.api.publish.maven.tasks.GenerateMavenPom import org.gradle.api.tasks.TaskProvider import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -12,6 +17,7 @@ import org.springdoc.openapi.gradle.plugin.OpenApiExtension import org.springdoc.openapi.gradle.plugin.OpenApiGradlePlugin import org.springframework.boot.gradle.plugin.SpringBootPlugin import java.net.ServerSocket +import java.nio.file.Files class SpringDocOpenApiConfigurePlugin : Plugin { override fun apply(target: Project) { @@ -31,16 +37,50 @@ class SpringDocOpenApiConfigurePlugin : Plugin { } } - target.tasks.register("clfGenerateOpenApiDocumentation") { + val documentationTask = target.tasks.register("clfGenerateOpenApiDocumentation") { + it.group = TASK_GROUP it.dependsOn(json2Yaml) } + target.tasks.withType(GenerateMavenPom::class) { + it.dependsOn(documentationTask) + } + + `setupWorkaroundFor#171`(target, openapi) + target.afterEvaluate { configureJsonDocumentPublishing(openapi, target, openApiTask) configureYamlDocumentPublishing(target, openapi, json2Yaml) } } + private fun `setupWorkaroundFor#171`(target: Project, openapi: OpenApiExtension) { + val forkedSpringBootRun = target.tasks.named("forkedSpringBootRun", JavaExecFork::class) + + val createDirTask = target.tasks.register("createDummyForkedSpringBootWorkingDir") { task -> + // use same working dir resolution as plugin itself: https://github.com/springdoc/springdoc-openapi-gradle-plugin/blob/master/src/main/kotlin/org/springdoc/openapi/gradle/plugin/OpenApiGradlePlugin.kt#L98 + val workingDirProvider = openapi.customBootRun.workingDir.zip(forkedSpringBootRun) { dir, forked -> + dir?.asFile ?: forked.workingDir + } + task.outputs.dir(workingDirProvider) + task.doFirst { + val workingDir = workingDirProvider.get() + Files.createDirectories(workingDir.toPath()) + } + } + + // these tasks also need to depend on the createDirTask since they somehow access the dummy folder as well + val dependingTaskNames = setOf("resolveMainClassName", "processResources", "compileKotlin", "compileJava") + + target.tasks.matching { dependingTaskNames.contains(it.name) }.configureEach { + it.dependsOn(createDirTask) + } + + forkedSpringBootRun.configure { + it.dependsOn(createDirTask) + } + } + private fun configureOpenApiExtension( openapi: OpenApiExtension, target: Project, @@ -51,17 +91,16 @@ class SpringDocOpenApiConfigurePlugin : Plugin { val managementPort = freeServerSocketPort() outputDir.set(target.layout.buildDirectory.dir("generated/resources/openapi")) - logger.debug("outputDir={}", outputDir.get()) outputFileName.set("${basename}.json") - logger.debug("outputFileName={}", outputFileName.get()) apiDocsUrl.set("http://localhost:${serverPort}/v3/api-docs") - logger.debug("apiDocsUrl={}", apiDocsUrl.get()) + customBootRun { + it.workingDir.set(target.layout.buildDirectory.dir("dummyForkedSpringBootWorkingDir")) + } mapOf( "--server.port" to serverPort, "--management.server.port" to managementPort ).forEach { arg -> - logger.debug("Set ${arg.key}=${arg.value}") customBootRun.args.add("${arg.key}=${arg.value}") } } diff --git a/src/main/kotlin/io/cloudflight/gradle/autoconfigure/swagger/SwaggerApiConfigurePlugin.kt b/src/main/kotlin/io/cloudflight/gradle/autoconfigure/swagger/SwaggerApiConfigurePlugin.kt index bb13477..e6b3015 100644 --- a/src/main/kotlin/io/cloudflight/gradle/autoconfigure/swagger/SwaggerApiConfigurePlugin.kt +++ b/src/main/kotlin/io/cloudflight/gradle/autoconfigure/swagger/SwaggerApiConfigurePlugin.kt @@ -146,13 +146,7 @@ class SwaggerApiConfigurePlugin : Plugin { } } - - - - companion object { - - private fun getFilesFromSourceSet(project: Project): FileCollection { val javaPluginExtension = project.extensions.getByType(JavaPluginExtension::class.java) val sourceSetMain = javaPluginExtension.sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) @@ -160,4 +154,4 @@ class SwaggerApiConfigurePlugin : Plugin { return sourceSetMain.output.classesDirs } } -} \ No newline at end of file +} diff --git a/src/test/fixtures/springdocopenapi/kotlin-springboot-angular/settings.gradle.kts b/src/test/fixtures/springdocopenapi/kotlin-springboot-angular/settings.gradle.kts index 967af46..3f30ebe 100644 --- a/src/test/fixtures/springdocopenapi/kotlin-springboot-angular/settings.gradle.kts +++ b/src/test/fixtures/springdocopenapi/kotlin-springboot-angular/settings.gradle.kts @@ -1,13 +1,5 @@ import org.ajoberstar.reckon.gradle.ReckonExtension -pluginManagement { - repositories { - maven { - url = uri("https://artifacts.cloudflight.io/repository/plugins-maven") - } - } -} - plugins { id("io.cloudflight.autoconfigure-settings") } diff --git a/src/test/fixtures/springdocopenapi/kotlin-springboot-angular/skeleton-server/build.gradle.kts b/src/test/fixtures/springdocopenapi/kotlin-springboot-angular/skeleton-server/build.gradle.kts index 45079e2..e4fe516 100644 --- a/src/test/fixtures/springdocopenapi/kotlin-springboot-angular/skeleton-server/build.gradle.kts +++ b/src/test/fixtures/springdocopenapi/kotlin-springboot-angular/skeleton-server/build.gradle.kts @@ -1,5 +1,12 @@ plugins { - id("io.cloudflight.autoconfigure.springdoc-openapi-configure") + id("io.cloudflight.autoconfigure.springdoc-openapi-configure") + id("maven-publish") +} + +group = "io.cloudflight.skeleton.angular" + +java { + withJavadocJar() } dependencies { @@ -21,10 +28,14 @@ dependencies { implementation(libs.springdoc.openapi.starter.webmvc.api) } -tasks.named("forkedSpringBootRun") { - doNotTrackState("We cannot track the state during the test since the working directory is already blocked by the test-executing gradle-process.") -} - openApi { outputFileName.set("custom-openapi.json") } + +publishing { + publications { + create("maven") { + from(components.getByName("java")) + } + } +} diff --git a/src/test/kotlin/io/cloudflight/gradle/autoconfigure/springdocopenapi/SpringDocOpenApiConfigurePluginTest.kt b/src/test/kotlin/io/cloudflight/gradle/autoconfigure/springdocopenapi/SpringDocOpenApiConfigurePluginTest.kt index 03217b7..c353c33 100644 --- a/src/test/kotlin/io/cloudflight/gradle/autoconfigure/springdocopenapi/SpringDocOpenApiConfigurePluginTest.kt +++ b/src/test/kotlin/io/cloudflight/gradle/autoconfigure/springdocopenapi/SpringDocOpenApiConfigurePluginTest.kt @@ -1,6 +1,7 @@ package io.cloudflight.gradle.autoconfigure.springdocopenapi import io.cloudflight.gradle.autoconfigure.test.util.ProjectFixture +import io.cloudflight.gradle.autoconfigure.test.util.normalizedOutput import io.cloudflight.gradle.autoconfigure.test.util.useFixture import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -17,11 +18,10 @@ class SpringDocOpenApiConfigurePluginTest { assertThat(buildDir().resolve("generated/resources/openapi/springdoc-openapi.yaml")).exists() } - @Test fun `the openapi document is created in a multi module project`(): Unit = springdocFixture("kotlin-springboot-angular") { - val result = run("clfGenerateOpenApiDocumentation") + val result = run("publishToMavenLocal") assertThat(buildDir("skeleton-server").resolve("generated/resources/openapi/custom-openapi.json")).exists() assertThat(buildDir("skeleton-server").resolve("generated/resources/openapi/custom-openapi.yaml")).exists()