From 7c65aec2fb2db79d65291e949eb1535261481f98 Mon Sep 17 00:00:00 2001 From: Jim Schubert Date: Thu, 1 Oct 2020 22:40:59 -0400 Subject: [PATCH 1/9] [maven] Custom template in java example --- .../examples/java-client.xml | 3 +-- .../examples/templates/README.mustache | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 modules/openapi-generator-maven-plugin/examples/templates/README.mustache diff --git a/modules/openapi-generator-maven-plugin/examples/java-client.xml b/modules/openapi-generator-maven-plugin/examples/java-client.xml index c966e5c63ee4..caa28302a7f5 100644 --- a/modules/openapi-generator-maven-plugin/examples/java-client.xml +++ b/modules/openapi-generator-maven-plugin/examples/java-client.xml @@ -53,8 +53,7 @@ java - + ${project.basedir}/templates diff --git a/modules/openapi-generator-maven-plugin/examples/templates/README.mustache b/modules/openapi-generator-maven-plugin/examples/templates/README.mustache new file mode 100644 index 000000000000..cee4f752e72a --- /dev/null +++ b/modules/openapi-generator-maven-plugin/examples/templates/README.mustache @@ -0,0 +1,21 @@ +# TEST TEST TEST + +# {{artifactId}} + +{{appName}} + +- API version: {{appVersion}} +{{^hideGenerationTimestamp}} + +- Build date: {{generatedDate}} +{{/hideGenerationTimestamp}} + +{{#appDescriptionWithNewLines}}{{{appDescriptionWithNewLines}}}{{/appDescriptionWithNewLines}} + +{{#infoUrl}} + For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}}) +{{/infoUrl}} + +*Automatically generated by the [OpenAPI Generator](https://openapi-generator.tech)* + +… etc. From 524bd107a2673bb367328d09a0bca14e1eaeebd0 Mon Sep 17 00:00:00 2001 From: Jim Schubert Date: Thu, 1 Oct 2020 22:53:25 -0400 Subject: [PATCH 2/9] [maven] Fallback to templates using classpath rather than OS-specific paths Previous checks would cause logic in Windows to return early, for built-in templates only. This reorganizes and simplifies the ordering behavior. --- .../GeneratorTemplateContentLocator.java | 7 +- .../codegen/DefaultGeneratorTest.java | 204 ++++++++++++++++++ 2 files changed, 208 insertions(+), 3 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/GeneratorTemplateContentLocator.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/GeneratorTemplateContentLocator.java index 14b71d865385..c6c77cf1167b 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/GeneratorTemplateContentLocator.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/GeneratorTemplateContentLocator.java @@ -6,6 +6,7 @@ import org.openapitools.codegen.api.TemplatePathLocator; import java.io.File; +import java.nio.file.Paths; /** * Locates templates according to {@link CodegenConfig} settings. @@ -23,7 +24,7 @@ public GeneratorTemplateContentLocator(CodegenConfig codegenConfig) { } private String buildLibraryFilePath(String dir, String library, String file) { - return dir + File.separator + "libraries" + File.separator + library + File.separator + file; + return Paths.get(dir, "libraries", library, file).normalize().toString(); } /** @@ -60,14 +61,14 @@ public String getFullTemplatePath(String relativeTemplateFile) { if (StringUtils.isNotEmpty(library)) { //look for the file in the library subfolder of the supplied template final String libTemplateFile = buildLibraryFilePath(config.templateDir(), library, relativeTemplateFile); - if (new File(libTemplateFile).exists() || this.getClass().getClassLoader().getResource(libTemplateFile) != null) { + if (new File(libTemplateFile).exists()) { return libTemplateFile; } } //check the supplied template main folder for the file final String template = config.templateDir() + File.separator + relativeTemplateFile; - if (new File(template).exists() || this.getClass().getClassLoader().getResource(template) != null) { + if (new File(template).exists()) { return template; } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultGeneratorTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultGeneratorTest.java index 1a1806d6f835..1bf5dc702579 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultGeneratorTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultGeneratorTest.java @@ -433,4 +433,208 @@ public void testRefModelValidationProperties() { Assert.assertEquals(((Schema) codegenResponse.schema).getPattern(), expectedPattern); Assert.assertEquals(codegenResponse.pattern, escapedPattern); } + + @Test + public void testBuiltinLibraryTemplates() throws IOException { + Path target = Files.createTempDirectory("test"); + File output = target.toFile(); + try { + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("kotlin") + .setLibrary("jvm-okhttp4") + .setInputSpec("src/test/resources/3_0/petstore.yaml") + .setSkipOverwrite(false) + .setOutputDir(target.toAbsolutePath().toString()); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + DefaultGenerator generator = new DefaultGenerator(false); + + generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.API_DOCS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.API_TESTS, "false"); + + List files = generator.opts(clientOptInput).generate(); + + Assert.assertEquals(files.size(), 20); + + // Generator should report a library templated file as a generated file + TestUtils.ensureContainsFile(files, output, "src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt"); + + // Generated file should exist on the filesystem after generation + File generatedFile = new File(output, "src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt"); + Assert.assertTrue(generatedFile.exists()); + + // Generated file should contain some expected text + TestUtils.assertFileContains(generatedFile.toPath(), "package org.openapitools.client.infrastructure", + "open class ClientException", + "open class ServerException"); + } finally { + output.delete(); + } + } + + @Test + public void testBuiltinNonLibraryTemplates() throws IOException { + Path target = Files.createTempDirectory("test"); + File output = target.toFile(); + try { + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("kotlin") + .setInputSpec("src/test/resources/3_0/petstore.yaml") + .setSkipOverwrite(false) + .setOutputDir(target.toAbsolutePath().toString()); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + DefaultGenerator generator = new DefaultGenerator(false); + + generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.API_DOCS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.API_TESTS, "false"); + + List files = generator.opts(clientOptInput).generate(); + + Assert.assertEquals(files.size(), 20); + + // Generator should report README.md as a generated file + TestUtils.ensureContainsFile(files, output, "README.md"); + + // Generated file should exist on the filesystem after generation + File readme = new File(output, "README.md"); + Assert.assertTrue(readme.exists()); + + // README.md should contain some expected text + TestUtils.assertFileContains(readme.toPath(), "# org.openapitools.client - Kotlin client library for OpenAPI Petstore", + "## Requires", + "## Build", + "## Features/Implementation Notes"); + } finally { + output.delete(); + } + } + + @Test + public void testCustomLibraryTemplates() throws IOException { + Path target = Files.createTempDirectory("test"); + Path templates = Files.createTempDirectory("templates"); + File output = target.toFile(); + try { + // Create custom template + File customTemplate = new File(templates.toFile(), "libraries/jvm-okhttp/infrastructure/Errors.kt.mustache"); + new File(customTemplate.getParent()).mkdirs(); + StringBuilder sb = new StringBuilder(); + sb.append("// {{someKey}}").append("\n"); + sb.append("@file:Suppress(\"unused\")").append("\n"); + sb.append("package org.openapitools.client.infrastructure").append("\n"); + sb.append("import java.lang.RuntimeException").append("\n"); + sb.append("open class CustomException(").append("\n"); + sb.append(" message: kotlin.String? = null, val statusCode: Int = -1, val response: Response? = null) : RuntimeException(message) {").append("\n"); + sb.append(" companion object {").append("\n"); + sb.append(" private const val serialVersionUID: Long = 789L").append("\n"); + sb.append(" }").append("\n"); + sb.append("}").append("\n"); + Files.write(customTemplate.toPath(), + sb.toString().getBytes(StandardCharsets.UTF_8), + StandardOpenOption.CREATE); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("kotlin") + .addAdditionalProperty("someKey", "testCustomLibraryTemplates") + .setTemplateDir(templates.toAbsolutePath().toString()) + .setLibrary("jvm-okhttp4") + .setInputSpec("src/test/resources/3_0/petstore.yaml") + .setSkipOverwrite(false) + .setOutputDir(target.toAbsolutePath().toString()); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + DefaultGenerator generator = new DefaultGenerator(false); + + generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.API_DOCS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.API_TESTS, "false"); + + List files = generator.opts(clientOptInput).generate(); + + Assert.assertEquals(files.size(), 20); + + // Generator should report a library templated file as a generated file + TestUtils.ensureContainsFile(files, output, "src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt"); + + // Generated file should exist on the filesystem after generation + File readme = new File(output, "src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt"); + Assert.assertTrue(readme.exists()); + + // Generated file should contain our custom templated text + TestUtils.assertFileContains(readme.toPath(), "// testCustomLibraryTemplates", + "package org.openapitools.client.infrastructure", + "open class CustomException(", + "private const val serialVersionUID: Long = 789L"); + } finally { + output.delete(); + templates.toFile().delete(); + } + } + + @Test + public void testCustomNonLibraryTemplates() throws IOException { + Path target = Files.createTempDirectory("test"); + Path templates = Files.createTempDirectory("templates"); + File output = target.toFile(); + try { + // Create custom template + File customTemplate = new File(templates.toFile(), "README.mustache"); + new File(customTemplate.getParent()).mkdirs(); + Files.write(customTemplate.toPath(), + "# {{someKey}}".getBytes(StandardCharsets.UTF_8), + StandardOpenOption.CREATE); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("kotlin") + .addAdditionalProperty("someKey", "testCustomNonLibraryTemplates") + .setTemplateDir(templates.toAbsolutePath().toString()) + .setInputSpec("src/test/resources/3_0/petstore.yaml") + .setSkipOverwrite(false) + .setOutputDir(target.toAbsolutePath().toString()); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + DefaultGenerator generator = new DefaultGenerator(false); + + generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.API_DOCS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.API_TESTS, "false"); + + List files = generator.opts(clientOptInput).generate(); + + Assert.assertEquals(files.size(), 20); + + // Generator should report README.md as a generated file + TestUtils.ensureContainsFile(files, output, "README.md"); + + // Generated file should exist on the filesystem after generation + File readme = new File(output, "README.md"); + Assert.assertTrue(readme.exists()); + + // README.md should contain our custom templated text + TestUtils.assertFileContains(readme.toPath(), "# testCustomNonLibraryTemplates"); + } finally { + output.delete(); + templates.toFile().delete(); + } + } } + From 5875c1108950d926703b4198d98a71e002ddae7a Mon Sep 17 00:00:00 2001 From: Jim Schubert Date: Sat, 3 Oct 2020 15:29:44 -0400 Subject: [PATCH 3/9] Match classpath check in WorkflowSettings with that in TemplateManager --- .../codegen/config/WorkflowSettings.java | 13 ++++++++++++- .../GeneratorTemplateContentLocator.java | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/modules/openapi-generator-core/src/main/java/org/openapitools/codegen/config/WorkflowSettings.java b/modules/openapi-generator-core/src/main/java/org/openapitools/codegen/config/WorkflowSettings.java index 68d8b2e9b292..8d24d3b0a50d 100644 --- a/modules/openapi-generator-core/src/main/java/org/openapitools/codegen/config/WorkflowSettings.java +++ b/modules/openapi-generator-core/src/main/java/org/openapitools/codegen/config/WorkflowSettings.java @@ -29,6 +29,7 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.atomic.AtomicLong; +import java.util.regex.Pattern; /** * Represents those settings applied to a generation workflow. @@ -444,10 +445,20 @@ public Builder withTemplateDir(String templateDir) { uri = f.toURI(); this.templateDir = Paths.get(uri).toAbsolutePath().normalize().toString(); } else { - URL url = this.getClass().getClassLoader().getResource(templateDir); + String cpDir; + // HACK: this duplicates TemplateManager.getCPResourcePath a bit. We should probably move that function to core. + if (!"/".equals(File.separator)) { + // Windows users may pass path specific to OS, but classpath must be "/" separators + cpDir = templateDir.replaceAll(Pattern.quote(File.separator), "/"); + } else { + cpDir = templateDir; + } + + URL url = this.getClass().getClassLoader().getResource(cpDir); if (url != null) { try { uri = url.toURI(); + // we can freely set to templateDir here and allow templating to manage template lookups this.templateDir = templateDir; } catch (URISyntaxException e) { LOGGER.warn("The requested template was found on the classpath, but resulted in a syntax error."); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/GeneratorTemplateContentLocator.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/GeneratorTemplateContentLocator.java index c6c77cf1167b..423dec5bc0a0 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/GeneratorTemplateContentLocator.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/GeneratorTemplateContentLocator.java @@ -35,6 +35,10 @@ private String buildLibraryFilePath(String dir, String library, String file) { * @return true if file is an embedded resource, false if it does not exist */ public boolean embeddedTemplateExists(String name) { + return classpathTemplateExists(name); + } + + private boolean classpathTemplateExists(String name) { return this.getClass().getClassLoader().getResource(TemplateManager.getCPResourcePath(name)) != null; } @@ -61,20 +65,25 @@ public String getFullTemplatePath(String relativeTemplateFile) { if (StringUtils.isNotEmpty(library)) { //look for the file in the library subfolder of the supplied template final String libTemplateFile = buildLibraryFilePath(config.templateDir(), library, relativeTemplateFile); - if (new File(libTemplateFile).exists()) { + // looks for user-defined file or classpath + // supports template dir which refers to local file system or custom path in classpath as defined by templateDir + if (new File(libTemplateFile).exists() || classpathTemplateExists(libTemplateFile)) { return libTemplateFile; } } //check the supplied template main folder for the file final String template = config.templateDir() + File.separator + relativeTemplateFile; - if (new File(template).exists()) { + // looks for user-defined file or classpath + // supports template dir which refers to local file system or custom path in classpath as defined by templateDir + if (new File(template).exists() || classpathTemplateExists(template)) { return template; } //try the embedded template library folder next if (StringUtils.isNotEmpty(library)) { final String embeddedLibTemplateFile = buildLibraryFilePath(config.embeddedTemplateDir(), library, relativeTemplateFile); + // *only* looks for those files in classpath as defined by embeddedTemplateDir if (embeddedTemplateExists(embeddedLibTemplateFile)) { // Fall back to the template file embedded/packaged in the JAR file library folder... return embeddedLibTemplateFile; @@ -83,6 +92,7 @@ public String getFullTemplatePath(String relativeTemplateFile) { // Fall back to the template file for generator root directory embedded/packaged in the JAR file... String loc = config.embeddedTemplateDir() + File.separator + relativeTemplateFile; + // *only* looks for those files in classpath as defined by embeddedTemplateDir if (embeddedTemplateExists(loc)) { return loc; } From 5cae18f8779e924aba1d1d160abc97c0c41d03ab Mon Sep 17 00:00:00 2001 From: Jim Schubert Date: Tue, 6 Oct 2020 22:58:35 -0400 Subject: [PATCH 4/9] [maven] Much needed unit/integration tests This follows similar approach used in PMD and other plugins managed by maven. Unit tests simply verify we can load configuration as expected into the Mojo. Integration tests execute actual sample projects bound to the current build's Maven plugin. This uses maven-invoker-plugin, which also allows for specifying the maven options in invoker.properties to execute the test. It also provides a verification framework using groovy files with the required naming convention of "verify.groovy". This allows us to quickly and easily check that certain files are outputted by generation, and we may also spotcheck file contents. templateResourcePath option is skipped on windows. I've tested back to version 3.3.3 and this doesn't seem to have worked consistently with how the property works on non-Windows. --- .../openapi-generator-maven-plugin/pom.xml | 38 +- .../invoker.properties | 2 + .../src/it/custom-template-resource/pom.xml | 57 ++ .../it/custom-template-resource/verify.groovy | 32 + .../src/it/custom-template/invoker.properties | 2 + .../src/it/custom-template/pom.xml | 53 ++ .../custom-template/templates/README.mustache | 21 + .../src/it/custom-template/verify.groovy | 31 + .../codegen/plugin/BaseTestCase.java | 31 + .../codegen/plugin/CodeGenMojoTest.java | 46 ++ .../plugin/stubs/CommonMavenProjectStub.java | 25 + .../codegen/plugin/stubs/StubUtility.java | 94 +++ .../unit/common-maven/common-maven.xml | 56 ++ .../resources/unit/common-maven/petstore.yaml | 736 ++++++++++++++++++ .../src/main/java/com/example/Example.java | 7 + .../GeneratorTemplateContentLocator.java | 3 +- 16 files changed, 1232 insertions(+), 2 deletions(-) create mode 100644 modules/openapi-generator-maven-plugin/src/it/custom-template-resource/invoker.properties create mode 100644 modules/openapi-generator-maven-plugin/src/it/custom-template-resource/pom.xml create mode 100644 modules/openapi-generator-maven-plugin/src/it/custom-template-resource/verify.groovy create mode 100644 modules/openapi-generator-maven-plugin/src/it/custom-template/invoker.properties create mode 100644 modules/openapi-generator-maven-plugin/src/it/custom-template/pom.xml create mode 100644 modules/openapi-generator-maven-plugin/src/it/custom-template/templates/README.mustache create mode 100644 modules/openapi-generator-maven-plugin/src/it/custom-template/verify.groovy create mode 100644 modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/BaseTestCase.java create mode 100644 modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/CodeGenMojoTest.java create mode 100644 modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/stubs/CommonMavenProjectStub.java create mode 100644 modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/stubs/StubUtility.java create mode 100644 modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/common-maven.xml create mode 100644 modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/petstore.yaml create mode 100644 modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/src/main/java/com/example/Example.java diff --git a/modules/openapi-generator-maven-plugin/pom.xml b/modules/openapi-generator-maven-plugin/pom.xml index d0eb7ad57921..1ff96aa4c0a2 100644 --- a/modules/openapi-generator-maven-plugin/pom.xml +++ b/modules/openapi-generator-maven-plugin/pom.xml @@ -60,6 +60,23 @@ test + + org.apache.maven.shared + maven-verifier + 1.7.2 + + + org.apache.maven.plugin-testing + maven-plugin-testing-harness + 3.3.0 + test + + + org.codehaus.plexus + plexus-utils + 3.3.0 + test + @@ -105,10 +122,29 @@ ${project.basedir}${file.separator}${project.parent.relativePath}${file.separator}eclipse-formatter.xml + + org.apache.maven.plugins + maven-invoker-plugin + 3.2.1 + + verify + true + true + false + true + + + + integration-test + + run + + + + - static-analysis diff --git a/modules/openapi-generator-maven-plugin/src/it/custom-template-resource/invoker.properties b/modules/openapi-generator-maven-plugin/src/it/custom-template-resource/invoker.properties new file mode 100644 index 000000000000..1f2cc145e635 --- /dev/null +++ b/modules/openapi-generator-maven-plugin/src/it/custom-template-resource/invoker.properties @@ -0,0 +1,2 @@ +invoker.goals = -nsu generate-sources +invoker.name = Test Custom Templates via Resource diff --git a/modules/openapi-generator-maven-plugin/src/it/custom-template-resource/pom.xml b/modules/openapi-generator-maven-plugin/src/it/custom-template-resource/pom.xml new file mode 100644 index 000000000000..b8d127dadd73 --- /dev/null +++ b/modules/openapi-generator-maven-plugin/src/it/custom-template-resource/pom.xml @@ -0,0 +1,57 @@ + + + + + 4.0.0 + + org.openapitools.maven.its + custom-template-resource + 1.0-SNAPSHOT + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + https://raw.githubusercontent.com/OpenAPITools/openapi-generator/master/modules/openapi-generator/src/test/resources/2_0/petstore.yaml + kotlin + ${basedir}/out + + bash + + true + + + + + default + generate-sources + + generate + + + + + + + diff --git a/modules/openapi-generator-maven-plugin/src/it/custom-template-resource/verify.groovy b/modules/openapi-generator-maven-plugin/src/it/custom-template-resource/verify.groovy new file mode 100644 index 000000000000..6efd1b3d318c --- /dev/null +++ b/modules/openapi-generator-maven-plugin/src/it/custom-template-resource/verify.groovy @@ -0,0 +1,32 @@ +/* + * Copyright 2020 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. + */ + +File readme = new File(basedir, "out/README.md") + +assert readme.isFile() +if (File.separator == "/") { + // For whatever reason, resource path templates fail in this test in Windows + assert readme.text.contains("# OpenAPI Petstore Bash client") +} + +File gradle = new File(basedir, "out/build.gradle") +assert gradle.isFile() + +File api = new File(basedir, "out/src/main/kotlin/org/openapitools/client/apis/PetApi.kt") +assert api.isFile() + +File model = new File(basedir, "out/src/main/kotlin/org/openapitools/client/models/Pet.kt") +assert model.isFile() diff --git a/modules/openapi-generator-maven-plugin/src/it/custom-template/invoker.properties b/modules/openapi-generator-maven-plugin/src/it/custom-template/invoker.properties new file mode 100644 index 000000000000..65393cde95a5 --- /dev/null +++ b/modules/openapi-generator-maven-plugin/src/it/custom-template/invoker.properties @@ -0,0 +1,2 @@ +invoker.goals = -nsu generate-sources +invoker.name = Test Custom Templates diff --git a/modules/openapi-generator-maven-plugin/src/it/custom-template/pom.xml b/modules/openapi-generator-maven-plugin/src/it/custom-template/pom.xml new file mode 100644 index 000000000000..52313b33d2fe --- /dev/null +++ b/modules/openapi-generator-maven-plugin/src/it/custom-template/pom.xml @@ -0,0 +1,53 @@ + + + + + 4.0.0 + + org.openapitools.maven.its + custom-template + 1.0-SNAPSHOT + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + https://raw.githubusercontent.com/OpenAPITools/openapi-generator/master/modules/openapi-generator/src/test/resources/2_0/petstore.yaml + kotlin + ${basedir}/out + ${project.basedir}/templates + + true + + + + + remote + generate-sources + + generate + + + + + + + diff --git a/modules/openapi-generator-maven-plugin/src/it/custom-template/templates/README.mustache b/modules/openapi-generator-maven-plugin/src/it/custom-template/templates/README.mustache new file mode 100644 index 000000000000..cee4f752e72a --- /dev/null +++ b/modules/openapi-generator-maven-plugin/src/it/custom-template/templates/README.mustache @@ -0,0 +1,21 @@ +# TEST TEST TEST + +# {{artifactId}} + +{{appName}} + +- API version: {{appVersion}} +{{^hideGenerationTimestamp}} + +- Build date: {{generatedDate}} +{{/hideGenerationTimestamp}} + +{{#appDescriptionWithNewLines}}{{{appDescriptionWithNewLines}}}{{/appDescriptionWithNewLines}} + +{{#infoUrl}} + For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}}) +{{/infoUrl}} + +*Automatically generated by the [OpenAPI Generator](https://openapi-generator.tech)* + +… etc. diff --git a/modules/openapi-generator-maven-plugin/src/it/custom-template/verify.groovy b/modules/openapi-generator-maven-plugin/src/it/custom-template/verify.groovy new file mode 100644 index 000000000000..aec483caf911 --- /dev/null +++ b/modules/openapi-generator-maven-plugin/src/it/custom-template/verify.groovy @@ -0,0 +1,31 @@ +/* + * Copyright 2020 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. + */ + +File readme = new File(basedir, "out/README.md") + +assert readme.isFile() +assert readme.text.contains("# TEST TEST TEST") +assert readme.text.contains("# kotlin-client") +assert readme.text.contains("OpenAPI Petstore") + +File gradle = new File(basedir, "out/build.gradle") +assert gradle.isFile() + +File api = new File(basedir, "out/src/main/kotlin/org/openapitools/client/apis/PetApi.kt") +assert api.isFile() + +File model = new File(basedir, "out/src/main/kotlin/org/openapitools/client/models/Pet.kt") +assert model.isFile() diff --git a/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/BaseTestCase.java b/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/BaseTestCase.java new file mode 100644 index 000000000000..ba69d021af3d --- /dev/null +++ b/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/BaseTestCase.java @@ -0,0 +1,31 @@ +/* + * Copyright 2020 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.codegen.plugin; + +import org.apache.maven.plugin.testing.AbstractMojoTestCase; + +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * A base test class where we can add helper methods and whatnot + */ +public abstract class BaseTestCase extends AbstractMojoTestCase { + protected Path getUnitTestDir() { + return Paths.get(getBasedir(), "src", "test", "resources", "unit"); + } +} diff --git a/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/CodeGenMojoTest.java b/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/CodeGenMojoTest.java new file mode 100644 index 000000000000..7b29b522409c --- /dev/null +++ b/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/CodeGenMojoTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2020 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.codegen.plugin; + +import org.junit.Test; +import org.openapitools.codegen.plugin.stubs.StubUtility; + +import java.io.File; +import java.util.Map; + +public class CodeGenMojoTest extends BaseTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @SuppressWarnings("unchecked") + public void testCommonConfiguration() throws Exception { + File testPom = StubUtility.basedPath(getUnitTestDir().toFile(), "common-maven", "common-maven.xml").toFile(); + final CodeGenMojo mojo = (CodeGenMojo) lookupMojo("generate", testPom); + mojo.execute(); + assertEquals("java", getVariableValueFromObject(mojo, "generatorName")); + assertEquals("jersey2", getVariableValueFromObject(mojo, "library")); + assertEquals("remote.org.openapitools.client.api", getVariableValueFromObject(mojo, "apiPackage")); + assertEquals("remote.org.openapitools.client.model", getVariableValueFromObject(mojo, "modelPackage")); + assertEquals("remote.org.openapitools.client", getVariableValueFromObject(mojo, "invokerPackage")); + + Map configOptions = (Map) getVariableValueFromObject(mojo, "configOptions"); + assertNotNull(configOptions); + assertEquals("joda", configOptions.get("dateLibrary")); + } +} \ No newline at end of file diff --git a/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/stubs/CommonMavenProjectStub.java b/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/stubs/CommonMavenProjectStub.java new file mode 100644 index 000000000000..9577061f0a87 --- /dev/null +++ b/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/stubs/CommonMavenProjectStub.java @@ -0,0 +1,25 @@ +/* + * Copyright 2020 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.codegen.plugin.stubs; + +import org.apache.maven.plugin.testing.stubs.MavenProjectStub; + +public class CommonMavenProjectStub extends MavenProjectStub { + public CommonMavenProjectStub() { + StubUtility.configureStub(this,"common-maven", "common-maven.xml"); + } +} diff --git a/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/stubs/StubUtility.java b/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/stubs/StubUtility.java new file mode 100644 index 000000000000..c7ccd1a2a9ee --- /dev/null +++ b/modules/openapi-generator-maven-plugin/src/test/java/org/openapitools/codegen/plugin/stubs/StubUtility.java @@ -0,0 +1,94 @@ +/* + * Copyright 2020 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.codegen.plugin.stubs; + +import org.apache.maven.model.Build; +import org.apache.maven.model.Model; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import org.apache.maven.plugin.testing.stubs.ArtifactStub; +import org.apache.maven.plugin.testing.stubs.DefaultArtifactHandlerStub; +import org.apache.maven.plugin.testing.stubs.MavenProjectStub; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +public abstract class StubUtility { + private StubUtility() { + throw new UnsupportedOperationException("Utility class"); + } + + /** + * Configures a stub to conventional directories based on test name and pom file name. + *

+ * Taken largely from PMD plugin: + * https://github.com/apache/maven-pmd-plugin/blob/d766fdb0c93a6630ad7a788f260746b05c804a71/src/test/java/org/apache/maven/plugins/pmd/stubs/CustomConfigurationMavenProjectStub.java + * License: Apache 2.0 + * + * @param configure The stub to configure + * @param testName A name used to identify this stub, used in resource lookup + * @param pomFileName The filename and extension, e.g. "my-test-pom.xml" + */ + public static void configureStub(MavenProjectStub configure, String testName, String pomFileName) { + MavenXpp3Reader pomReader = new MavenXpp3Reader(); + Model model = null; + try { + File pomFile = basedPath( + configure.getBasedir(), "src", "test", "resources", "unit", testName, pomFileName + ).toFile(); + model = pomReader.read(new InputStreamReader(new FileInputStream(pomFile), StandardCharsets.UTF_8)); + configure.setModel(model); + } catch (Exception ignored) { + + } + + configure.setGroupId(model.getGroupId()); + configure.setArtifactId(model.getArtifactId()); + configure.setVersion(model.getVersion()); + configure.setName(model.getName()); + configure.setUrl(model.getUrl()); + configure.setPackaging(model.getPackaging()); + + Build build = new Build(); + build.setFinalName(model.getBuild().getFinalName()); + build.setDirectory(basedPath(configure.getBasedir(), "target", "test", "unit", testName, "target").toString()); + build.setSourceDirectory(basedPath(configure.getBasedir(), "src", "test", "resources", "unit", testName).toString()); + configure.setBuild(build); + + List compileSourceRoots = new ArrayList<>(); + compileSourceRoots.add(basedPath(configure.getBasedir(), "src", "test", "resources", "unit", testName, "src").toString()); + configure.setCompileSourceRoots(compileSourceRoots); + + ArtifactStub artifactStub = new ArtifactStub(); + artifactStub.setGroupId(configure.getGroupId()); + artifactStub.setArtifactId(configure.getArtifactId()); + artifactStub.setVersion(configure.getVersion()); + artifactStub.setArtifactHandler(new DefaultArtifactHandlerStub("jar")); + configure.setArtifact(artifactStub); + + configure.setFile(configure.getBasedir().toPath().resolve(pomFileName).toFile()); + } + + public static Path basedPath(File baseDir, String first, String... more) { + return baseDir.toPath().resolve(Paths.get(first, more)).normalize().toAbsolutePath(); + } +} diff --git a/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/common-maven.xml b/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/common-maven.xml new file mode 100644 index 000000000000..767caeab2ddf --- /dev/null +++ b/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/common-maven.xml @@ -0,0 +1,56 @@ + + + + 4.0.0 + common.maven + common-maven + jar + 1.0.0-SNAPSHOT + OpenAPI Generator Configuration Test + https://openapi-generator.tech/ + + common-maven + + + org.openapitools + openapi-generator-maven-plugin + + + ${basedir}/src/test/resources/unit/common-maven/petstore.yaml + java + + joda + + jersey2 + ${basedir}/target/generated-sources/common-maven/remote-openapi + remote.org.openapitools.client.api + remote.org.openapitools.client.model + remote.org.openapitools.client + + + + default + generate-sources + + generate + + + + + + + \ No newline at end of file diff --git a/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/petstore.yaml b/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/petstore.yaml new file mode 100644 index 000000000000..f5e98eec38da --- /dev/null +++ b/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/petstore.yaml @@ -0,0 +1,736 @@ +openapi: 3.0.0 +servers: + - url: 'http://petstore.swagger.io/v2' +info: + description: >- + This is a sample server Petstore server. For this sample, you can use the api key + `special-key` to test the authorization filters. + version: 1.0.0 + title: OpenAPI Petstore + license: + name: Apache-2.0 + url: 'https://www.apache.org/licenses/LICENSE-2.0.html' +tags: + - name: pet + description: Everything about your Pets + - name: store + description: Access to Petstore orders + - name: user + description: Operations about user +paths: + /pet: + post: + tags: + - pet + summary: Add a new pet to the store + description: '' + operationId: addPet + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + '405': + description: Invalid input + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + requestBody: + $ref: '#/components/requestBodies/Pet' + put: + tags: + - pet + summary: Update an existing pet + description: '' + operationId: updatePet + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + '405': + description: Validation exception + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + requestBody: + $ref: '#/components/requestBodies/Pet' + /pet/findByStatus: + get: + tags: + - pet + summary: Finds Pets by status + description: Multiple status values can be provided with comma separated strings + operationId: findPetsByStatus + parameters: + - name: status + in: query + description: Status values that need to be considered for filter + required: true + style: form + explode: false + schema: + type: array + items: + type: string + enum: + - available + - pending + - sold + default: available + responses: + '200': + description: successful operation + content: + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid status value + security: + - petstore_auth: + - 'read:pets' + /pet/findByTags: + get: + tags: + - pet + summary: Finds Pets by tags + description: >- + Multiple tags can be provided with comma separated strings. Use tag1, + tag2, tag3 for testing. + operationId: findPetsByTags + parameters: + - name: tags + in: query + description: Tags to filter by + required: true + style: form + explode: false + schema: + type: array + items: + type: string + responses: + '200': + description: successful operation + content: + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid tag value + security: + - petstore_auth: + - 'read:pets' + deprecated: true + '/pet/{petId}': + get: + tags: + - pet + summary: Find pet by ID + description: Returns a single pet + operationId: getPetById + parameters: + - name: petId + in: path + description: ID of pet to return + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + security: + - api_key: [] + post: + tags: + - pet + summary: Updates a pet in the store with form data + description: '' + operationId: updatePetWithForm + parameters: + - name: petId + in: path + description: ID of pet that needs to be updated + required: true + schema: + type: integer + format: int64 + responses: + '405': + description: Invalid input + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + requestBody: + content: + application/x-www-form-urlencoded: + schema: + type: object + properties: + name: + description: Updated name of the pet + type: string + status: + description: Updated status of the pet + type: string + delete: + tags: + - pet + summary: Deletes a pet + description: '' + operationId: deletePet + parameters: + - name: api_key + in: header + required: false + schema: + type: string + - name: petId + in: path + description: Pet id to delete + required: true + schema: + type: integer + format: int64 + responses: + '400': + description: Invalid pet value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + '/pet/{petId}/uploadImage': + post: + tags: + - pet + summary: uploads an image + description: '' + operationId: uploadFile + parameters: + - name: petId + in: path + description: ID of pet to update + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + additionalMetadata: + description: Additional data to pass to server + type: string + file: + description: file to upload + type: string + format: binary + /store/inventory: + get: + tags: + - store + summary: Returns pet inventories by status + description: Returns a map of status codes to quantities + operationId: getInventory + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: object + additionalProperties: + type: integer + format: int32 + security: + - api_key: [] + /store/order: + post: + tags: + - store + summary: Place an order for a pet + description: '' + operationId: placeOrder + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Order' + application/json: + schema: + $ref: '#/components/schemas/Order' + '400': + description: Invalid Order + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Order' + description: order placed for purchasing the pet + required: true + '/store/order/{orderId}': + get: + tags: + - store + summary: Find purchase order by ID + description: >- + For valid response try integer IDs with value <= 5 or > 10. Other values + will generated exceptions + operationId: getOrderById + parameters: + - name: orderId + in: path + description: ID of pet that needs to be fetched + required: true + schema: + type: integer + format: int64 + minimum: 1 + maximum: 5 + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Order' + application/json: + schema: + $ref: '#/components/schemas/Order' + '400': + description: Invalid ID supplied + '404': + description: Order not found + delete: + tags: + - store + summary: Delete purchase order by ID + description: >- + For valid response try integer IDs with value < 1000. Anything above + 1000 or nonintegers will generate API errors + operationId: deleteOrder + parameters: + - name: orderId + in: path + description: ID of the order that needs to be deleted + required: true + schema: + type: string + responses: + '400': + description: Invalid ID supplied + '404': + description: Order not found + /user: + post: + tags: + - user + summary: Create user + description: This can only be done by the logged in user. + operationId: createUser + responses: + default: + description: successful operation + security: + - api_key: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/User' + description: Created user object + required: true + /user/createWithArray: + post: + tags: + - user + summary: Creates list of users with given input array + description: '' + operationId: createUsersWithArrayInput + responses: + default: + description: successful operation + security: + - api_key: [] + requestBody: + $ref: '#/components/requestBodies/UserArray' + /user/createWithList: + post: + tags: + - user + summary: Creates list of users with given input array + description: '' + operationId: createUsersWithListInput + responses: + default: + description: successful operation + security: + - api_key: [] + requestBody: + $ref: '#/components/requestBodies/UserArray' + /user/login: + get: + tags: + - user + summary: Logs user into the system + description: '' + operationId: loginUser + parameters: + - name: username + in: query + description: The user name for login + required: true + schema: + type: string + pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$' + - name: password + in: query + description: The password for login in clear text + required: true + schema: + type: string + responses: + '200': + description: successful operation + headers: + Set-Cookie: + description: >- + Cookie authentication key for use with the `api_key` + apiKey authentication. + schema: + type: string + example: AUTH_KEY=abcde12345; Path=/; HttpOnly + X-Rate-Limit: + description: calls per hour allowed by the user + schema: + type: integer + format: int32 + X-Expires-After: + description: date in UTC when toekn expires + schema: + type: string + format: date-time + content: + application/xml: + schema: + type: string + application/json: + schema: + type: string + '400': + description: Invalid username/password supplied + /user/logout: + get: + tags: + - user + summary: Logs out current logged in user session + description: '' + operationId: logoutUser + responses: + default: + description: successful operation + security: + - api_key: [] + '/user/{username}': + get: + tags: + - user + summary: Get user by user name + description: '' + operationId: getUserByName + parameters: + - name: username + in: path + description: The name that needs to be fetched. Use user1 for testing. + required: true + schema: + type: string + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/User' + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + description: Invalid username supplied + '404': + description: User not found + put: + tags: + - user + summary: Updated user + description: This can only be done by the logged in user. + operationId: updateUser + parameters: + - name: username + in: path + description: name that need to be deleted + required: true + schema: + type: string + responses: + '400': + description: Invalid user supplied + '404': + description: User not found + security: + - api_key: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/User' + description: Updated user object + required: true + delete: + tags: + - user + summary: Delete user + description: This can only be done by the logged in user. + operationId: deleteUser + parameters: + - name: username + in: path + description: The name that needs to be deleted + required: true + schema: + type: string + responses: + '400': + description: Invalid username supplied + '404': + description: User not found + security: + - api_key: [] +externalDocs: + description: Find out more about Swagger + url: 'http://swagger.io' +components: + requestBodies: + UserArray: + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + description: List of user object + required: true + Pet: + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + description: Pet object that needs to be added to the store + required: true + securitySchemes: + petstore_auth: + type: oauth2 + flows: + implicit: + authorizationUrl: 'http://petstore.swagger.io/api/oauth/dialog' + scopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + api_key: + type: apiKey + name: api_key + in: header + schemas: + Order: + title: Pet Order + description: An order for a pets from the pet store + type: object + properties: + id: + type: integer + format: int64 + petId: + type: integer + format: int64 + quantity: + type: integer + format: int32 + shipDate: + type: string + format: date-time + status: + type: string + description: Order Status + enum: + - placed + - approved + - delivered + complete: + type: boolean + default: false + xml: + name: Order + Category: + title: Pet category + description: A category for a pet + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$' + xml: + name: Category + User: + title: a User + description: A User who is purchasing from the pet store + type: object + properties: + id: + type: integer + format: int64 + username: + type: string + firstName: + type: string + lastName: + type: string + email: + type: string + password: + type: string + phone: + type: string + userStatus: + type: integer + format: int32 + description: User Status + xml: + name: User + Tag: + title: Pet Tag + description: A tag for a pet + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + xml: + name: Tag + Pet: + title: a Pet + description: A pet for sale in the pet store + type: object + required: + - name + - photoUrls + properties: + id: + type: integer + format: int64 + category: + $ref: '#/components/schemas/Category' + name: + type: string + example: doggie + photoUrls: + type: array + xml: + name: photoUrl + wrapped: true + items: + type: string + tags: + type: array + xml: + name: tag + wrapped: true + items: + $ref: '#/components/schemas/Tag' + status: + type: string + description: pet status in the store + enum: + - available + - pending + - sold + xml: + name: Pet + ApiResponse: + title: An uploaded response + description: Describes the result of uploading an image resource + type: object + properties: + code: + type: integer + format: int32 + type: + type: string + message: + type: string diff --git a/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/src/main/java/com/example/Example.java b/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/src/main/java/com/example/Example.java new file mode 100644 index 000000000000..8447f00216de --- /dev/null +++ b/modules/openapi-generator-maven-plugin/src/test/resources/unit/common-maven/src/main/java/com/example/Example.java @@ -0,0 +1,7 @@ +package com.example; + +public class Example { + public static void main(String[] args) { + System.out.println("You did it!"); + } +} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/GeneratorTemplateContentLocator.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/GeneratorTemplateContentLocator.java index 423dec5bc0a0..861b9bc3a3d3 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/GeneratorTemplateContentLocator.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/GeneratorTemplateContentLocator.java @@ -72,7 +72,8 @@ public String getFullTemplatePath(String relativeTemplateFile) { } } - //check the supplied template main folder for the file + // check the supplied template main folder for the file + // File.separator is necessary here as the file load is OS-specific final String template = config.templateDir() + File.separator + relativeTemplateFile; // looks for user-defined file or classpath // supports template dir which refers to local file system or custom path in classpath as defined by templateDir From 799c480c936f4f6dd146488b1e2073153bd1a11a Mon Sep 17 00:00:00 2001 From: Jim Schubert Date: Thu, 8 Oct 2020 21:46:10 -0400 Subject: [PATCH 5/9] Set groovy 3.0.5 for test harness --- modules/openapi-generator-maven-plugin/pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/openapi-generator-maven-plugin/pom.xml b/modules/openapi-generator-maven-plugin/pom.xml index 1ff96aa4c0a2..e9fa94fd5d96 100644 --- a/modules/openapi-generator-maven-plugin/pom.xml +++ b/modules/openapi-generator-maven-plugin/pom.xml @@ -16,6 +16,8 @@ UTF-8 **/src/main/java/org/openapitools/codegen/plugin/**/* + + 3.0.5 From 011bea78f1ba1bce140afc1b243d380ac064481b Mon Sep 17 00:00:00 2001 From: Jim Schubert Date: Sat, 10 Oct 2020 08:29:48 -0400 Subject: [PATCH 6/9] Print stacktrace on Maven error --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index ddf43cf484c3..359a3b0688b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -148,8 +148,8 @@ script: - /bin/bash ./bin/utils/detect_tab_in_java_class.sh # run integration tests defined in maven pom.xml # WARN: Travis will timeout after 10 minutes of no stdout/stderr activity, which is problematic with mvn --quiet. - - mvn --no-snapshot-updates --quiet --batch-mode --show-version clean install -Dorg.slf4j.simpleLogger.defaultLogLevel=error - - mvn --no-snapshot-updates --quiet --batch-mode --show-version verify -Psamples -Dorg.slf4j.simpleLogger.defaultLogLevel=error + - mvn -e --no-snapshot-updates --quiet --batch-mode --show-version clean install -Dorg.slf4j.simpleLogger.defaultLogLevel=error + - mvn -e --no-snapshot-updates --quiet --batch-mode --show-version verify -Psamples -Dorg.slf4j.simpleLogger.defaultLogLevel=error after_success: # push to maven repo - if [ $SONATYPE_USERNAME ] && [ "$TRAVIS_PULL_REQUEST" == "false" ]; then From 807d745ebeb69d9bb83913a25fad6f7e60b7d306 Mon Sep 17 00:00:00 2001 From: Jim Schubert Date: Fri, 16 Oct 2020 23:02:02 -0400 Subject: [PATCH 7/9] [maven] Set groovy version in tests to supported in Java 11+ --- modules/openapi-generator-maven-plugin/pom.xml | 8 ++++++++ .../src/it/custom-template-resource/verify.groovy | 7 +++++++ .../src/it/custom-template/verify.groovy | 7 +++++++ 3 files changed, 22 insertions(+) diff --git a/modules/openapi-generator-maven-plugin/pom.xml b/modules/openapi-generator-maven-plugin/pom.xml index e9fa94fd5d96..0e19b9c45c8b 100644 --- a/modules/openapi-generator-maven-plugin/pom.xml +++ b/modules/openapi-generator-maven-plugin/pom.xml @@ -135,6 +135,14 @@ false true + + + org.codehaus.groovy + groovy + ${groovy.version} + runtime + + integration-test diff --git a/modules/openapi-generator-maven-plugin/src/it/custom-template-resource/verify.groovy b/modules/openapi-generator-maven-plugin/src/it/custom-template-resource/verify.groovy index 6efd1b3d318c..0af466d2635a 100644 --- a/modules/openapi-generator-maven-plugin/src/it/custom-template-resource/verify.groovy +++ b/modules/openapi-generator-maven-plugin/src/it/custom-template-resource/verify.groovy @@ -30,3 +30,10 @@ assert api.isFile() File model = new File(basedir, "out/src/main/kotlin/org/openapitools/client/models/Pet.kt") assert model.isFile() + +// note that in Java 11+, this anything matching this condition could fail due to +// Illegal reflective access by org.codehaus.groovy.reflection.CachedClass +// and cause tests to fail. This is more to document for engineers. +if (GroovySystem.version.tokenize('.')[0].toInteger() < 3) { + throw new IllegalStateException("Found:" + GroovySystem.version + ", need Groovy 3.x or higher for Java 11+, so we require it for all versions") +} diff --git a/modules/openapi-generator-maven-plugin/src/it/custom-template/verify.groovy b/modules/openapi-generator-maven-plugin/src/it/custom-template/verify.groovy index aec483caf911..026989152580 100644 --- a/modules/openapi-generator-maven-plugin/src/it/custom-template/verify.groovy +++ b/modules/openapi-generator-maven-plugin/src/it/custom-template/verify.groovy @@ -29,3 +29,10 @@ assert api.isFile() File model = new File(basedir, "out/src/main/kotlin/org/openapitools/client/models/Pet.kt") assert model.isFile() + +// note that in Java 11+, this anything matching this condition could fail due to +// Illegal reflective access by org.codehaus.groovy.reflection.CachedClass +// and cause tests to fail. This is more to document for engineers. +if (GroovySystem.version.tokenize('.')[0].toInteger() < 3) { + throw new IllegalStateException("Found:" + GroovySystem.version + ", need Groovy 3.x or higher for Java 11+, so we require it for all versions") +} From 7d02ffca28138a6aff4354a34a6d923e127ab483 Mon Sep 17 00:00:00 2001 From: Jim Schubert Date: Sat, 17 Oct 2020 15:44:37 -0400 Subject: [PATCH 8/9] Put maven integration tests in separate profile --- .../openapi-generator-maven-plugin/pom.xml | 63 ++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/modules/openapi-generator-maven-plugin/pom.xml b/modules/openapi-generator-maven-plugin/pom.xml index 0e19b9c45c8b..883346d7d8cd 100644 --- a/modules/openapi-generator-maven-plugin/pom.xml +++ b/modules/openapi-generator-maven-plugin/pom.xml @@ -124,37 +124,44 @@ ${project.basedir}${file.separator}${project.parent.relativePath}${file.separator}eclipse-formatter.xml - - org.apache.maven.plugins - maven-invoker-plugin - 3.2.1 - - verify - true - true - false - true - - - - org.codehaus.groovy - groovy - ${groovy.version} - runtime - - - - - integration-test - - run - - - - + + integration + + + + org.apache.maven.plugins + maven-invoker-plugin + 3.2.1 + + verify + true + true + false + true + + + + org.codehaus.groovy + groovy + ${groovy.version} + runtime + + + + + integration-test + + run + + + + + + + static-analysis From b08fa7c61aa337d5257f117be23c46b04a04069d Mon Sep 17 00:00:00 2001 From: Jim Schubert Date: Sat, 17 Oct 2020 17:54:46 -0400 Subject: [PATCH 9/9] Set maven-verifier test scope --- modules/openapi-generator-maven-plugin/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/openapi-generator-maven-plugin/pom.xml b/modules/openapi-generator-maven-plugin/pom.xml index 883346d7d8cd..af8a424ee7bb 100644 --- a/modules/openapi-generator-maven-plugin/pom.xml +++ b/modules/openapi-generator-maven-plugin/pom.xml @@ -66,6 +66,7 @@ org.apache.maven.shared maven-verifier 1.7.2 + test org.apache.maven.plugin-testing