This is an automated email from the ASF dual-hosted git repository. ningjiang pushed a commit to branch import-oas-validator in repository https://gitbox.apache.org/repos/asf/servicecomb-toolkit.git
commit 37da70ba772f66f4d5f0d1ce8c55a3fecb91517b Author: Daniel Qian <chanjars...@gmail.com> AuthorDate: Thu Nov 7 14:25:47 2019 +0800 SCB-1555 Integrate oas-validator compability check to cli Add subcommands checkcompatibility and cs to cli --- cli/pom.xml | 5 + .../toolkit/cli/CheckCompatibility.java | 26 +++++ .../toolkit/cli/CheckCompatibilityAbbr.java | 26 +++++ .../toolkit/cli/CheckCompatibilityBase.java | 129 +++++++++++++++++++++ .../servicecomb/toolkit/cli/CheckStyleBase.java | 14 +-- .../servicecomb/toolkit/cli/ToolkitMain.java | 7 +- .../apache/servicecomb/toolkit/cli/CliTest.java | 25 +++- .../{parser-test.yaml => compatibility-left.yaml} | 6 +- .../{parser-test.yaml => compatibility-right.yaml} | 8 +- .../resources/oas/{parser-test.yaml => style.yaml} | 0 ...dingAllowedReservedChangeDiffValidatorTest.java | 1 - .../oasv/common/OasObjectPropertyLocation.java | 14 +++ .../oasv/common/OasObjectPropertyLocationTest.java | 16 +++ 13 files changed, 259 insertions(+), 18 deletions(-) diff --git a/cli/pom.xml b/cli/pom.xml index 6a222d7..4499804 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -85,6 +85,11 @@ <groupId>org.apache.servicecomb.toolkit</groupId> <artifactId>oas-validator-compliance</artifactId> </dependency> + + <dependency> + <groupId>org.apache.servicecomb.toolkit</groupId> + <artifactId>oas-validator-compatibility</artifactId> + </dependency> </dependencies> <build> diff --git a/cli/src/main/java/org/apache/servicecomb/toolkit/cli/CheckCompatibility.java b/cli/src/main/java/org/apache/servicecomb/toolkit/cli/CheckCompatibility.java new file mode 100644 index 0000000..c12439d --- /dev/null +++ b/cli/src/main/java/org/apache/servicecomb/toolkit/cli/CheckCompatibility.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.servicecomb.toolkit.cli; + +import io.airlift.airline.Command; + +@Command(name = "checkcompatibility", + description = "Check compatibility for two OpenAPI v3 spec yamls, right one should be semantically compatible with left one") +public class CheckCompatibility extends CheckCompatibilityBase { + +} diff --git a/cli/src/main/java/org/apache/servicecomb/toolkit/cli/CheckCompatibilityAbbr.java b/cli/src/main/java/org/apache/servicecomb/toolkit/cli/CheckCompatibilityAbbr.java new file mode 100644 index 0000000..2f14b2b --- /dev/null +++ b/cli/src/main/java/org/apache/servicecomb/toolkit/cli/CheckCompatibilityAbbr.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.servicecomb.toolkit.cli; + +import io.airlift.airline.Command; + +@Command(name = "cc", + description = "Check compatibility for two OpenAPI v3 spec yamls, right one should be semantically compatible with left one") +public class CheckCompatibilityAbbr extends CheckCompatibilityBase { + +} diff --git a/cli/src/main/java/org/apache/servicecomb/toolkit/cli/CheckCompatibilityBase.java b/cli/src/main/java/org/apache/servicecomb/toolkit/cli/CheckCompatibilityBase.java new file mode 100644 index 0000000..298132f --- /dev/null +++ b/cli/src/main/java/org/apache/servicecomb/toolkit/cli/CheckCompatibilityBase.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.servicecomb.toolkit.cli; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.StringJoiner; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.io.FileUtils; +import org.apache.servicecomb.toolkit.oasv.common.OasObjectPropertyLocation; +import org.apache.servicecomb.toolkit.oasv.compatibility.CompatibilityCheckParser; +import org.apache.servicecomb.toolkit.oasv.compatibility.factory.DefaultOasSpecDiffValidatorFactory; +import org.apache.servicecomb.toolkit.oasv.diffvalidation.api.OasDiffValidationContext; +import org.apache.servicecomb.toolkit.oasv.diffvalidation.api.OasDiffViolation; +import org.apache.servicecomb.toolkit.oasv.diffvalidation.api.OasSpecDiffValidator; +import org.apache.servicecomb.toolkit.oasv.diffvalidation.factory.OasSpecDiffValidatorFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +import io.airlift.airline.Arguments; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.parser.core.models.SwaggerParseResult; + +public class CheckCompatibilityBase implements Runnable { + + private final Logger LOGGER = LoggerFactory.getLogger(this.getClass()); + + @Arguments( + title = "files", required = true, + description = "Two OpenAPI v3 spec yamls" + ) + private List<String> filePaths; + + @Override + public void run() { + + if (filePaths.size() != 2) { + LOGGER.error("Require 2 files"); + return; + } + + OpenAPI oldOas = null; + OpenAPI newOas = null; + try { + oldOas = loadOpenApi(filePaths.get(0)); + newOas = loadOpenApi(filePaths.get(1)); + } catch (Exception e) { + LOGGER.error(e.getMessage()); + return; + } + + OasSpecDiffValidator diffValidator = createOasSpecDiffValidator(); + + List<OasDiffViolation> violations = diffValidator.validate(createContext(oldOas, newOas), oldOas, newOas); + + if (CollectionUtils.isNotEmpty(violations)) { + for (OasDiffViolation violation : violations) { + LOGGER.info("left : {}\nright : {}\nerror : {}\n------", + OasObjectPropertyLocation.toPathString(violation.getLeftLocation()), + OasObjectPropertyLocation.toPathString(violation.getRightLocation()), + violation.getError() + ); + } + return; + } + LOGGER.info("Everything is good"); + } + + private OpenAPI loadOpenApi(String filePath) throws IOException { + String yaml = loadFileContent(filePath); + SwaggerParseResult oldParseResult = CompatibilityCheckParser.parseYaml(yaml); + OpenAPI openAPI = oldParseResult.getOpenAPI(); + if (openAPI == null) { + StringJoiner errors = new StringJoiner("\n", "Parse errors:", ""); + if (CollectionUtils.isNotEmpty(oldParseResult.getMessages())) { + for (String message : oldParseResult.getMessages()) { + errors.add(message); + } + } + throw new RuntimeException(errors.toString()); + } + + return openAPI; + } + + + private OasSpecDiffValidator createOasSpecDiffValidator() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( + DefaultOasSpecDiffValidatorFactory.class.getPackage().getName()); + try { + OasSpecDiffValidatorFactory diffValidatorFactory = ctx.getBean(OasSpecDiffValidatorFactory.class); + return diffValidatorFactory.create(); + } finally { + ctx.close(); + } + } + + + private String loadFileContent(String filePath) throws IOException { + Path specPath = Paths.get(filePath); + specPath.toAbsolutePath().toString(); + return FileUtils.readFileToString(specPath.toFile()); + } + + private OasDiffValidationContext createContext(OpenAPI leftOpenAPI, OpenAPI rightOpenAPI) { + + OasDiffValidationContext context = new OasDiffValidationContext(leftOpenAPI, rightOpenAPI); + return context; + } +} diff --git a/cli/src/main/java/org/apache/servicecomb/toolkit/cli/CheckStyleBase.java b/cli/src/main/java/org/apache/servicecomb/toolkit/cli/CheckStyleBase.java index e021d9f..393d97d 100644 --- a/cli/src/main/java/org/apache/servicecomb/toolkit/cli/CheckStyleBase.java +++ b/cli/src/main/java/org/apache/servicecomb/toolkit/cli/CheckStyleBase.java @@ -24,7 +24,6 @@ import java.util.List; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.io.FileUtils; -import org.apache.servicecomb.toolkit.oasv.common.OasObjectProperty; import org.apache.servicecomb.toolkit.oasv.common.OasObjectPropertyLocation; import org.apache.servicecomb.toolkit.oasv.compliance.ComplianceCheckParser; import org.apache.servicecomb.toolkit.oasv.compliance.factory.DefaultOasSpecValidatorFactory; @@ -37,7 +36,6 @@ import org.slf4j.LoggerFactory; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import io.airlift.airline.Arguments; -import io.airlift.airline.Command; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.parser.core.models.SwaggerParseResult; @@ -79,22 +77,14 @@ public class CheckStyleBase implements Runnable { List<OasViolation> violations = oasSpecValidator.validate(createContext(openAPI), openAPI); if (CollectionUtils.isNotEmpty(violations)) { for (OasViolation violation : violations) { - LOGGER.info("{}: {}", toPathString(violation.getLocation()), violation.getError()); + LOGGER.info("path : {}\nerror : {}\n------", + OasObjectPropertyLocation.toPathString(violation.getLocation()), violation.getError()); } return; } LOGGER.info("Everything is good"); } - private String toPathString(OasObjectPropertyLocation location) { - StringBuilder sb = new StringBuilder(); - List<OasObjectProperty> path = location.getPath(); - for (OasObjectProperty property : path) { - sb.append(property.getName()).append('.'); - } - sb.deleteCharAt(sb.length() - 1); - return sb.toString(); - } private OasSpecValidator createOasSpecValidator() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( diff --git a/cli/src/main/java/org/apache/servicecomb/toolkit/cli/ToolkitMain.java b/cli/src/main/java/org/apache/servicecomb/toolkit/cli/ToolkitMain.java index 39b2477..5a75e86 100755 --- a/cli/src/main/java/org/apache/servicecomb/toolkit/cli/ToolkitMain.java +++ b/cli/src/main/java/org/apache/servicecomb/toolkit/cli/ToolkitMain.java @@ -37,7 +37,12 @@ public class ToolkitMain { builder.withDescription("Microservice development toolkit(version " + projectVersion + "). "); builder.withDefaultCommand(Help.class); - builder.withCommands(CodeGenerate.class, DocGenerate.class, CheckStyle.class, CheckStyleAbbr.class, Help.class); + builder.withCommands( + CodeGenerate.class, DocGenerate.class, + CheckStyle.class, CheckStyleAbbr.class, + CheckCompatibility.class, CheckCompatibilityAbbr.class, + Help.class + ); Runnable cmd = builder.build().parse(args); cmd.run(); diff --git a/cli/src/test/java/org/apache/servicecomb/toolkit/cli/CliTest.java b/cli/src/test/java/org/apache/servicecomb/toolkit/cli/CliTest.java index 2068ddb..5990a0b 100755 --- a/cli/src/test/java/org/apache/servicecomb/toolkit/cli/CliTest.java +++ b/cli/src/test/java/org/apache/servicecomb/toolkit/cli/CliTest.java @@ -95,7 +95,7 @@ public class CliTest { public void testCheckStyle() throws IOException { String[] args = new String[] { "checkstyle", - Paths.get("./src/test/resources/oas/parser-test.yaml").toFile().getCanonicalPath() + Paths.get("./src/test/resources/oas/style.yaml").toFile().getCanonicalPath() }; ToolkitMain.main(args); } @@ -104,9 +104,30 @@ public class CliTest { public void testCheckStyleAbbr() throws IOException { String[] args = new String[] { "cs", - Paths.get("./src/test/resources/oas/parser-test.yaml").toFile().getCanonicalPath() + Paths.get("./src/test/resources/oas/style.yaml").toFile().getCanonicalPath() }; ToolkitMain.main(args); } + @Test + public void testCheckCompatibility() throws IOException { + String[] args = new String[] { + "checkcompatibility", + Paths.get("./src/test/resources/oas/compatibility-left.yaml").toFile().getCanonicalPath(), + Paths.get("./src/test/resources/oas/compatibility-right.yaml").toFile().getCanonicalPath() + }; + ToolkitMain.main(args); + } + + @Test + public void testCheckCompatibilityAbbr() throws IOException { + String[] args = new String[] { + "cc", + Paths.get("./src/test/resources/oas/compatibility-left.yaml").toFile().getCanonicalPath(), + Paths.get("./src/test/resources/oas/compatibility-right.yaml").toFile().getCanonicalPath() + }; + ToolkitMain.main(args); + } + + } diff --git a/cli/src/test/resources/oas/parser-test.yaml b/cli/src/test/resources/oas/compatibility-left.yaml old mode 100644 new mode 100755 similarity index 94% copy from cli/src/test/resources/oas/parser-test.yaml copy to cli/src/test/resources/oas/compatibility-left.yaml index f7b88b5..ea3e0e8 --- a/cli/src/test/resources/oas/parser-test.yaml +++ b/cli/src/test/resources/oas/compatibility-left.yaml @@ -17,7 +17,11 @@ openapi: "3.0.0" info: version: 1.0.0 - title: Pet petstore + title: Swagger petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 paths: /pets: get: diff --git a/cli/src/test/resources/oas/parser-test.yaml b/cli/src/test/resources/oas/compatibility-right.yaml old mode 100644 new mode 100755 similarity index 90% copy from cli/src/test/resources/oas/parser-test.yaml copy to cli/src/test/resources/oas/compatibility-right.yaml index f7b88b5..5854b12 --- a/cli/src/test/resources/oas/parser-test.yaml +++ b/cli/src/test/resources/oas/compatibility-right.yaml @@ -17,7 +17,11 @@ openapi: "3.0.0" info: version: 1.0.0 - title: Pet petstore + title: Swagger petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 paths: /pets: get: @@ -43,6 +47,8 @@ paths: encoding: foo: contentType: 'application/octet-stream' + bar: + contentType: 'application/octet-stream' responses: '200': description: A paged array of pets diff --git a/cli/src/test/resources/oas/parser-test.yaml b/cli/src/test/resources/oas/style.yaml similarity index 100% rename from cli/src/test/resources/oas/parser-test.yaml rename to cli/src/test/resources/oas/style.yaml diff --git a/oas-validator/oas-validator-compatibility/src/test/java/org/apache/servicecomb/toolkit/oasv/compatibility/validators/encoding/EncodingAllowedReservedChangeDiffValidatorTest.java b/oas-validator/oas-validator-compatibility/src/test/java/org/apache/servicecomb/toolkit/oasv/compatibility/validators/encoding/EncodingAllowedReservedChangeDiffValidatorTest.java index d9d640f..e0e7e51 100755 --- a/oas-validator/oas-validator-compatibility/src/test/java/org/apache/servicecomb/toolkit/oasv/compatibility/validators/encoding/EncodingAllowedReservedChangeDiffValidatorTest.java +++ b/oas-validator/oas-validator-compatibility/src/test/java/org/apache/servicecomb/toolkit/oasv/compatibility/validators/encoding/EncodingAllowedReservedChangeDiffValidatorTest.java @@ -40,7 +40,6 @@ public class EncodingAllowedReservedChangeDiffValidatorTest extends OasCompatibi @Test public void validate() { OpenAPI leftOpenAPI = loadRelative("petstore-encoding-allow-reserved-a.yaml"); - System.out.println(leftOpenAPI.toString()); OpenAPI rightOpenAPI = loadRelative("petstore-encoding-allow-reserved-b.yaml"); List<OasDiffViolation> violations = oasSpecDiffValidator .validate(createContext(leftOpenAPI, rightOpenAPI), leftOpenAPI, rightOpenAPI); diff --git a/oas-validator/oas-validator-core/src/main/java/org/apache/servicecomb/toolkit/oasv/common/OasObjectPropertyLocation.java b/oas-validator/oas-validator-core/src/main/java/org/apache/servicecomb/toolkit/oasv/common/OasObjectPropertyLocation.java index 346e667..a97ef0f 100755 --- a/oas-validator/oas-validator-core/src/main/java/org/apache/servicecomb/toolkit/oasv/common/OasObjectPropertyLocation.java +++ b/oas-validator/oas-validator-core/src/main/java/org/apache/servicecomb/toolkit/oasv/common/OasObjectPropertyLocation.java @@ -117,4 +117,18 @@ public class OasObjectPropertyLocation { .add("path=" + path) .toString(); } + + public static String toPathString(OasObjectPropertyLocation location) { + if (location == null) { + return ""; + } + + StringBuilder sb = new StringBuilder(); + List<OasObjectProperty> path = location.getPath(); + for (OasObjectProperty property : path) { + sb.append(property.getName()).append('.'); + } + sb.deleteCharAt(sb.length() - 1); + return sb.toString(); + } } diff --git a/oas-validator/oas-validator-core/src/test/java/org/apache/servicecomb/toolkit/oasv/common/OasObjectPropertyLocationTest.java b/oas-validator/oas-validator-core/src/test/java/org/apache/servicecomb/toolkit/oasv/common/OasObjectPropertyLocationTest.java new file mode 100644 index 0000000..ac5bcd5 --- /dev/null +++ b/oas-validator/oas-validator-core/src/test/java/org/apache/servicecomb/toolkit/oasv/common/OasObjectPropertyLocationTest.java @@ -0,0 +1,16 @@ +package org.apache.servicecomb.toolkit.oasv.common; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class OasObjectPropertyLocationTest { + + @Test + public void toPathString() { + assertEquals("$.foo.bar", + OasObjectPropertyLocation.toPathString(OasObjectPropertyLocation.root().property("foo").property("bar"))); + + assertEquals("", OasObjectPropertyLocation.toPathString(null)); + } +}