diff --git a/functional-tests/src/test/groovy/io/micronaut/gradle/openapi/OpenApiClientWithKotlinSpec.groovy b/functional-tests/src/test/groovy/io/micronaut/gradle/openapi/OpenApiClientWithKotlinSpec.groovy index 08c6e97c2..598084ba7 100644 --- a/functional-tests/src/test/groovy/io/micronaut/gradle/openapi/OpenApiClientWithKotlinSpec.groovy +++ b/functional-tests/src/test/groovy/io/micronaut/gradle/openapi/OpenApiClientWithKotlinSpec.groovy @@ -5,7 +5,7 @@ import org.gradle.testkit.runner.TaskOutcome class OpenApiClientWithKotlinSpec extends AbstractOpenApiWithKotlinSpec { - def "can generate an kotlin OpenAPI client implementation with some properties (KAPT)"() { + def "can generate an kotlin OpenAPI client implementation with clientId (KAPT)"() { given: settingsFile << "rootProject.name = 'openapi-client'" buildFile << """ @@ -26,6 +26,7 @@ class OpenApiClientWithKotlinSpec extends AbstractOpenApiWithKotlinSpec { generatedAnnotation = false fluxForArrays = true nameMapping = [test: "changedTest"] + clientId = "my-client" } } } @@ -55,9 +56,249 @@ class OpenApiClientWithKotlinSpec extends AbstractOpenApiWithKotlinSpec { and: file("build/generated/openapi/generateClientOpenApiModels/src/main/kotlin/io/micronaut/openapi/model/Pet.kt").exists() + def petApiFile = file("build/generated/openapi/generateClientOpenApiApis/src/main/kotlin/io/micronaut/openapi/api/PetApi.kt") + petApiFile.exists() + petApiFile.readLines() + .findAll { it.contains('@Client("my-client")') } + .size() == 1 } - def "can generate an kotlin OpenAPI client implementation with some properties (KSP)"() { + def "can generate an kotlin OpenAPI client implementation with clientId and clientPath (KAPT)"() { + given: + settingsFile << "rootProject.name = 'openapi-client'" + buildFile << """ + plugins { + id "io.micronaut.minimal.application" + id "io.micronaut.openapi" + id "org.jetbrains.kotlin.jvm" version "$kotlinVersion" + id "org.jetbrains.kotlin.plugin.allopen" version "$kotlinVersion" + id "org.jetbrains.kotlin.kapt" version "$kotlinVersion" + } + + micronaut { + version "$micronautVersion" + openapi { + client(file("petstore.json")) { + lang = "kotlin" + useReactive = true + generatedAnnotation = false + fluxForArrays = true + nameMapping = [test: "changedTest"] + clientId = "my-client" + clientPath = true + } + } + } + + $repositoriesBlock + + dependencies { + + kapt "io.micronaut.serde:micronaut-serde-processor" + + implementation "io.micronaut.serde:micronaut-serde-jackson" + implementation "io.micronaut.reactor:micronaut-reactor" + implementation "io.micronaut:micronaut-inject-kotlin" + } + + """ + + withPetstore() + + when: + def result = build('test') + + then: + result.task(":generateClientOpenApiApis").outcome == TaskOutcome.SUCCESS + result.task(":generateClientOpenApiModels").outcome == TaskOutcome.SUCCESS + result.task(":compileKotlin").outcome == TaskOutcome.SUCCESS + + and: + file("build/generated/openapi/generateClientOpenApiModels/src/main/kotlin/io/micronaut/openapi/model/Pet.kt").exists() + def petApiFile = file("build/generated/openapi/generateClientOpenApiApis/src/main/kotlin/io/micronaut/openapi/api/PetApi.kt") + petApiFile.exists() + petApiFile.readLines() + .findAll { it.contains('@Client(id = "my-client", path = "\\${my-client.base-path}")') } + .size() == 1 + } + + def "can generate an kotlin OpenAPI client implementation without clientId (KAPT)"() { + given: + settingsFile << "rootProject.name = 'openapi-client'" + buildFile << """ + plugins { + id "io.micronaut.minimal.application" + id "io.micronaut.openapi" + id "org.jetbrains.kotlin.jvm" version "$kotlinVersion" + id "org.jetbrains.kotlin.plugin.allopen" version "$kotlinVersion" + id "org.jetbrains.kotlin.kapt" version "$kotlinVersion" + } + + micronaut { + version "$micronautVersion" + openapi { + client(file("petstore.json")) { + lang = "kotlin" + useReactive = true + generatedAnnotation = false + fluxForArrays = true + nameMapping = [test: "changedTest"] + } + } + } + + $repositoriesBlock + + dependencies { + + kapt "io.micronaut.serde:micronaut-serde-processor" + + implementation "io.micronaut.serde:micronaut-serde-jackson" + implementation "io.micronaut.reactor:micronaut-reactor" + implementation "io.micronaut:micronaut-inject-kotlin" + } + + """ + + withPetstore() + + when: + def result = build('test') + + then: + result.task(":generateClientOpenApiApis").outcome == TaskOutcome.SUCCESS + result.task(":generateClientOpenApiModels").outcome == TaskOutcome.SUCCESS + result.task(":compileKotlin").outcome == TaskOutcome.SUCCESS + + and: + file("build/generated/openapi/generateClientOpenApiModels/src/main/kotlin/io/micronaut/openapi/model/Pet.kt").exists() + def petApiFile = file("build/generated/openapi/generateClientOpenApiApis/src/main/kotlin/io/micronaut/openapi/api/PetApi.kt") + petApiFile.exists() + petApiFile.readLines() + .findAll { it.contains('@Client("\\${openapi-micronaut-client.base-path}")') } + .size() == 1 + } + + def "can generate an kotlin OpenAPI client implementation with clientId (KSP)"() { + given: + settingsFile << "rootProject.name = 'openapi-client'" + buildFile << """ + plugins { + id "io.micronaut.minimal.application" + id "io.micronaut.openapi" + id "org.jetbrains.kotlin.jvm" version "$kotlinVersion" + id "org.jetbrains.kotlin.plugin.allopen" version "$kotlinVersion" + id "com.google.devtools.ksp" version "$kspVersion" + } + + micronaut { + version "$micronautVersion" + openapi { + client(file("petstore.json")) { + lang = "kotlin" + useReactive = true + generatedAnnotation = false + fluxForArrays = true + ksp = true + nameMapping = [test: "changedTest"] + clientId = "my-client" + } + } + } + + $repositoriesBlock + + dependencies { + + ksp "io.micronaut.serde:micronaut-serde-processor" + + implementation "io.micronaut.serde:micronaut-serde-jackson" + implementation "io.micronaut.reactor:micronaut-reactor" + implementation "io.micronaut:micronaut-inject-kotlin" + } + + """ + + withPetstore() + + when: + def result = build('test') + + then: + result.task(":generateClientOpenApiApis").outcome == TaskOutcome.SUCCESS + result.task(":generateClientOpenApiModels").outcome == TaskOutcome.SUCCESS + result.task(":compileKotlin").outcome == TaskOutcome.SUCCESS + + and: + file("build/generated/openapi/generateClientOpenApiModels/src/main/kotlin/io/micronaut/openapi/model/Pet.kt").exists() + def petApiFile = file("build/generated/openapi/generateClientOpenApiApis/src/main/kotlin/io/micronaut/openapi/api/PetApi.kt") + petApiFile.exists() + petApiFile.readLines() + .findAll { it.contains('@Client("my-client")') } + .size() == 1 + } + + def "can generate an kotlin OpenAPI client implementation with clientId and clientPath (KSP)"() { + given: + settingsFile << "rootProject.name = 'openapi-client'" + buildFile << """ + plugins { + id "io.micronaut.minimal.application" + id "io.micronaut.openapi" + id "org.jetbrains.kotlin.jvm" version "$kotlinVersion" + id "org.jetbrains.kotlin.plugin.allopen" version "$kotlinVersion" + id "com.google.devtools.ksp" version "$kspVersion" + } + + micronaut { + version "$micronautVersion" + openapi { + client(file("petstore.json")) { + lang = "kotlin" + useReactive = true + generatedAnnotation = false + fluxForArrays = true + ksp = true + nameMapping = [test: "changedTest"] + clientId = "my-client" + clientPath = true + } + } + } + + $repositoriesBlock + + dependencies { + + ksp "io.micronaut.serde:micronaut-serde-processor" + + implementation "io.micronaut.serde:micronaut-serde-jackson" + implementation "io.micronaut.reactor:micronaut-reactor" + implementation "io.micronaut:micronaut-inject-kotlin" + } + + """ + + withPetstore() + + when: + def result = build('test') + + then: + result.task(":generateClientOpenApiApis").outcome == TaskOutcome.SUCCESS + result.task(":generateClientOpenApiModels").outcome == TaskOutcome.SUCCESS + result.task(":compileKotlin").outcome == TaskOutcome.SUCCESS + + and: + file("build/generated/openapi/generateClientOpenApiModels/src/main/kotlin/io/micronaut/openapi/model/Pet.kt").exists() + def petApiFile = file("build/generated/openapi/generateClientOpenApiApis/src/main/kotlin/io/micronaut/openapi/api/PetApi.kt") + petApiFile.exists() + petApiFile.readLines() + .findAll { it.contains('@Client(id = "my-client", path = "\\${my-client.base-path}")') } + .size() == 1 + } + + def "can generate an kotlin OpenAPI client implementation without clientId (KSP)"() { given: settingsFile << "rootProject.name = 'openapi-client'" buildFile << """ @@ -108,5 +349,10 @@ class OpenApiClientWithKotlinSpec extends AbstractOpenApiWithKotlinSpec { and: file("build/generated/openapi/generateClientOpenApiModels/src/main/kotlin/io/micronaut/openapi/model/Pet.kt").exists() + def petApiFile = file("build/generated/openapi/generateClientOpenApiApis/src/main/kotlin/io/micronaut/openapi/api/PetApi.kt") + petApiFile.exists() + petApiFile.readLines() + .findAll { it.contains('@Client("\\${openapi-micronaut-client.base-path}")') } + .size() == 1 } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d3a2574c4..f65a13f4c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,7 +16,7 @@ tomlj = "1.1.1" micronaut-platform = "4.3.3" # This is the platform version, used in our tests micronaut-aot = "2.2.0" micronaut-testresources = "2.3.3" -micronaut-openapi = "6.6.3" +micronaut-openapi = "6.7.0" [libraries] # Core diff --git a/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/DefaultOpenApiExtension.java b/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/DefaultOpenApiExtension.java index 2b6b8e3d1..e4038ecea 100644 --- a/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/DefaultOpenApiExtension.java +++ b/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/DefaultOpenApiExtension.java @@ -29,6 +29,7 @@ import org.gradle.api.provider.Provider; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSetContainer; +import org.openapitools.codegen.CodegenConstants; import javax.inject.Inject; import java.io.File; @@ -81,14 +82,14 @@ public void server(String name, Provider definition, Action { configureCommonProperties(name, task, serverSpec, definition); task.getAot().set(serverSpec.getAot()); task.setDescription("Generates OpenAPI models from an OpenAPI definition"); configureServerTask(serverSpec, task); - task.getOutputKinds().add("MODELS"); + task.getOutputKinds().add(CodegenConstants.MODELS); }); withJavaSourceSets(sourceSets -> { var javaMain = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getJava(); @@ -207,13 +208,13 @@ public void client(String name, Provider definition, Action { configureCommonProperties(name, task, clientSpec, definition); task.setDescription("Generates OpenAPI client models from an OpenAPI definition"); configureClientTask(clientSpec, task); - task.getOutputKinds().add("MODELS"); + task.getOutputKinds().add(CodegenConstants.MODELS); }); withJavaSourceSets(sourceSets -> { var javaMain = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getJava(); @@ -260,6 +261,7 @@ private static Provider mainSrcDir(AbstractOpenApiGenerator t) private static void configureClientTask(OpenApiClientSpec clientSpec, OpenApiClientGenerator task) { task.getClientId().convention(clientSpec.getClientId()); + task.getClientPath().convention(clientSpec.getClientPath()); task.getAdditionalClientTypeAnnotations().set(clientSpec.getAdditionalClientTypeAnnotations()); task.getBasePathSeparator().convention(clientSpec.getBasePathSeparator()); task.getAuthorizationFilterPattern().convention(clientSpec.getAuthorizationFilterPattern()); diff --git a/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/OpenApiClientSpec.java b/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/OpenApiClientSpec.java index ce495f2b8..2601e9692 100644 --- a/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/OpenApiClientSpec.java +++ b/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/OpenApiClientSpec.java @@ -22,6 +22,8 @@ public interface OpenApiClientSpec extends OpenApiSpec { Property getClientId(); + Property getClientPath(); + Property getUseAuth(); Property getAuthorizationFilterPattern(); diff --git a/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/tasks/AbstractOpenApiWorkAction.java b/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/tasks/AbstractOpenApiWorkAction.java index eea281fd2..48409f42a 100644 --- a/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/tasks/AbstractOpenApiWorkAction.java +++ b/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/tasks/AbstractOpenApiWorkAction.java @@ -118,7 +118,7 @@ public void execute() { .withOutputs( parameters.getOutputKinds().get() .stream() - .map(s -> MicronautCodeGeneratorEntryPoint.OutputKind.valueOf(s.toUpperCase(Locale.US))) + .map(MicronautCodeGeneratorEntryPoint.OutputKind::of) .toArray(MicronautCodeGeneratorEntryPoint.OutputKind[]::new) ) .withOptions(options -> options.withInvokerPackage(parameters.getInvokerPackageName().get()) diff --git a/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/tasks/OpenApiClientGenerator.java b/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/tasks/OpenApiClientGenerator.java index 652a938c5..95e5fb276 100644 --- a/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/tasks/OpenApiClientGenerator.java +++ b/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/tasks/OpenApiClientGenerator.java @@ -28,6 +28,10 @@ public abstract class OpenApiClientGenerator extends AbstractOpenApiGenerator getClientId(); + @Input + @Optional + public abstract Property getClientPath(); + @Input public abstract Property getUseAuth(); @@ -50,6 +54,7 @@ protected Class getWorkerAction() { @Override protected void configureWorkerParameters(OpenApiClientWorkAction.ClientParameters params) { params.getClientId().set(getClientId()); + params.getClientPath().set(getClientPath()); params.getUseAuth().set(getUseAuth()); params.getAuthorizationFilterPattern().set(getAuthorizationFilterPattern()); params.getBasePathSeparator().set(getBasePathSeparator()); diff --git a/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/tasks/OpenApiClientWorkAction.java b/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/tasks/OpenApiClientWorkAction.java index 4cd745a5a..70d848964 100644 --- a/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/tasks/OpenApiClientWorkAction.java +++ b/openapi-plugin/src/main/java/io/micronaut/gradle/openapi/tasks/OpenApiClientWorkAction.java @@ -28,6 +28,8 @@ interface ClientParameters extends AbstractOpenApiWorkAction.OpenApiParameters { Property getClientId(); + Property getClientPath(); + Property getUseAuth(); Property getAuthorizationFilterPattern(); @@ -50,6 +52,9 @@ protected void configureBuilder(MicronautCodeGeneratorBuilder builder) { if (parameters.getClientId().isPresent()) { spec.withClientId(parameters.getClientId().get()); } + if (parameters.getClientPath().isPresent()) { + spec.withClientPath(parameters.getClientPath().get()); + } if (parameters.getBasePathSeparator().isPresent()) { spec.withBasePathSeparator(parameters.getBasePathSeparator().get()); } @@ -68,6 +73,9 @@ protected void configureBuilder(MicronautCodeGeneratorBuilder builder) { if (parameters.getClientId().isPresent()) { spec.withClientId(parameters.getClientId().get()); } + if (parameters.getClientPath().isPresent()) { + spec.withClientPath(parameters.getClientPath().get()); + } if (parameters.getBasePathSeparator().isPresent()) { spec.withBasePathSeparator(parameters.getBasePathSeparator().get()); } diff --git a/openapi-plugin/src/test/groovy/io/micronaut/openapi/gradle/OpenApiClientGeneratorSpec.groovy b/openapi-plugin/src/test/groovy/io/micronaut/openapi/gradle/OpenApiClientGeneratorSpec.groovy index e583c7bde..9ee5fe79b 100644 --- a/openapi-plugin/src/test/groovy/io/micronaut/openapi/gradle/OpenApiClientGeneratorSpec.groovy +++ b/openapi-plugin/src/test/groovy/io/micronaut/openapi/gradle/OpenApiClientGeneratorSpec.groovy @@ -48,7 +48,7 @@ class OpenApiClientGeneratorSpec extends AbstractOpenApiGeneratorSpec { } - def "can generate an java OpenAPI client implementation with some properties"() { + def "can generate an java OpenAPI client implementation with clientId"() { given: settingsFile << "rootProject.name = 'openapi-client'" buildFile << """ @@ -67,6 +67,7 @@ class OpenApiClientGeneratorSpec extends AbstractOpenApiGeneratorSpec { generatedAnnotation = false fluxForArrays = true nameMapping = [test: "changedTest"] + clientId = "my-client" } } } @@ -98,6 +99,127 @@ class OpenApiClientGeneratorSpec extends AbstractOpenApiGeneratorSpec { and: file("build/generated/openapi/generateClientOpenApiModels/src/main/java/io/micronaut/openapi/model/Pet.java").exists() + def petApiFile = file("build/generated/openapi/generateClientOpenApiApis/src/main/java/io/micronaut/openapi/api/PetApi.java") + petApiFile.exists() + petApiFile.readLines() + .findAll { it.contains('@Client("my-client")') } + .size() == 1 + } + + def "can generate an java OpenAPI client implementation with clientId and clientPath"() { + given: + settingsFile << "rootProject.name = 'openapi-client'" + buildFile << """ + plugins { + id "io.micronaut.minimal.application" + id "io.micronaut.openapi" + } + + micronaut { + version "$micronautVersion" + openapi { + client(file("petstore.json")) { + lang = "java" + lombok = true + useReactive = true + generatedAnnotation = false + fluxForArrays = true + nameMapping = [test: "changedTest"] + clientId = "my-client" + clientPath = true + } + } + } + + $repositoriesBlock + + dependencies { + + annotationProcessor "org.projectlombok:lombok" + annotationProcessor "io.micronaut.serde:micronaut-serde-processor" + + compileOnly "org.projectlombok:lombok" + + implementation "io.micronaut.serde:micronaut-serde-jackson" + implementation "io.micronaut.reactor:micronaut-reactor" + } + + """ + + withPetstore() + + when: + def result = build('test') + + then: + result.task(":generateClientOpenApiApis").outcome == TaskOutcome.SUCCESS + result.task(":generateClientOpenApiModels").outcome == TaskOutcome.SUCCESS + result.task(":compileJava").outcome == TaskOutcome.SUCCESS + + and: + file("build/generated/openapi/generateClientOpenApiModels/src/main/java/io/micronaut/openapi/model/Pet.java").exists() + def petApiFile = file("build/generated/openapi/generateClientOpenApiApis/src/main/java/io/micronaut/openapi/api/PetApi.java") + petApiFile.exists() + petApiFile.readLines() + .findAll { it.contains('@Client(id = "my-client", path = "${my-client.base-path}")') } + .size() == 1 + } + + def "can generate an java OpenAPI client implementation without clientId"() { + given: + settingsFile << "rootProject.name = 'openapi-client'" + buildFile << """ + plugins { + id "io.micronaut.minimal.application" + id "io.micronaut.openapi" + } + + micronaut { + version "$micronautVersion" + openapi { + client(file("petstore.json")) { + lang = "java" + lombok = true + useReactive = true + generatedAnnotation = false + fluxForArrays = true + nameMapping = [test: "changedTest"] + } + } + } + + $repositoriesBlock + + dependencies { + + annotationProcessor "org.projectlombok:lombok" + annotationProcessor "io.micronaut.serde:micronaut-serde-processor" + + compileOnly "org.projectlombok:lombok" + + implementation "io.micronaut.serde:micronaut-serde-jackson" + implementation "io.micronaut.reactor:micronaut-reactor" + } + + """ + + withPetstore() + + when: + def result = build('test') + + then: + result.task(":generateClientOpenApiApis").outcome == TaskOutcome.SUCCESS + result.task(":generateClientOpenApiModels").outcome == TaskOutcome.SUCCESS + result.task(":compileJava").outcome == TaskOutcome.SUCCESS + + and: + file("build/generated/openapi/generateClientOpenApiModels/src/main/java/io/micronaut/openapi/model/Pet.java").exists() + def petApiFile = file("build/generated/openapi/generateClientOpenApiApis/src/main/java/io/micronaut/openapi/api/PetApi.java") + petApiFile.exists() + petApiFile.readLines() + .findAll { it.contains('@Client("${openapi-micronaut-client.base-path}")') } + .size() == 1 } def "can generate an java OpenAPI client implementation using local file and custom name"() {