diff --git a/boat-maven-plugin/README.md b/boat-maven-plugin/README.md index 0e340c274..98a82ef7f 100644 --- a/boat-maven-plugin/README.md +++ b/boat-maven-plugin/README.md @@ -165,17 +165,32 @@ Available parameters: showIgnoredRules (Default: false) Set this to true to show the list of ignored rules.. - writeLintReport (Default: true) - Set this to true to generate lint report. - -Example: - - - ${unversioned-filename-spec-dir}/ - ${project.build.directory}/boat-lint-reports - true - ${ignored-lint-rules} - true + writeLintReport (Default: true) + Set this to true to generate lint report. + + sourceKey + Required: false + Set this to the SourceKey for the spec being + linted. This should be set to upload spec and lint via BoatBay. + To find out how to set up a source go to BoatBay project. + + boatBayUrl + Required: false + Set to url for boat bay server, options for this are, "http://localhost:8080" to run locally for testing + purposes and https://boat-bay.proto.backbasecloud.com/ for deployment + Optionally this can be set as an enviroment variable under the key BOAT_BAY_SERVER_URL. To set this as an + enviroment variable use the command export BOAT_BAY_SERVER_URL=http://localhost:8080, or the property + may be added to the config setting of boat-maven-plugin (in the run configuration options). + + Example: + + ``` + + ${unversioned-filename-spec-dir}/ + ${project.build.directory}/boat-lint-reports + true + ${ignored-lint-rules} + true To see details and an example of inputMavenArtifact: diff --git a/boat-maven-plugin/pom.xml b/boat-maven-plugin/pom.xml index d0b163cf6..61026c46a 100644 --- a/boat-maven-plugin/pom.xml +++ b/boat-maven-plugin/pom.xml @@ -16,6 +16,11 @@ Open API Converter + + ApiClient.java,BeanValidationException.java,RFC3339DateFormat.java,ServerConfiguration.java,ServerVariable.java,StringUtil.java,Authentication.java,HttpBasicAuth.java,HttpBearerAuth.java,ApiKeyAuth.java,ApiException.java,Pair.java + 0.2.1 + 1.6.2 + 3.6.0 src/main/java/com/backbase/oss/boat/GenerateMojo.java, @@ -23,6 +28,8 @@ ${basedir}/../${aggregate.report.dir} + 1.4.2.Final + reuseReports ${project.basedir}/target/jacoco-it.exec @@ -57,7 +64,17 @@ org.apache.commons commons-collections4 - + + org.mapstruct + mapstruct + ${org.mapstruct.version} + + + org.mapstruct + mapstruct-processor + ${org.mapstruct.version} + compile + org.apache.maven @@ -76,12 +93,17 @@ org.apache.maven.shared maven-common-artifact-filters - + + org.springframework + spring-context + 4.0.6.RELEASE + org.sonatype.plexus plexus-build-api 0.0.7 + org.codehaus.plexus plexus-io @@ -136,6 +158,103 @@ test + + + io.swagger + swagger-annotations + ${swagger-annotations.version} + + + + + com.fasterxml.jackson.core + jackson-core + + + com.fasterxml.jackson.core + jackson-annotations + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + org.openapitools + jackson-databind-nullable + ${jackson-databind-nullable-version} + + + + com.google.code.findbugs + jsr305 + + + org.springframework.data + spring-data-commons + 2.4.2 + + + com.squareup.okhttp3 + okhttp + 3.14.2 + + + io.gsonfire + gson-fire + 1.8.5 + + + com.squareup.okhttp3 + logging-interceptor + 3.8.1 + + + org.springframework + spring-expression + 5.2.5.RELEASE + + + junit + junit + 4.13.1 + compile + + + org.mock-server + mockserver-netty + 5.11.1 + + + + + io.github.openfeign + feign-okhttp + 10.11 + + + io.github.openfeign + feign-gson + 10.11 + + + io.github.openfeign + feign-slf4j + 10.11 + + + io.github.openfeign.form + feign-form + 3.8.0 + + + io.github.openfeign + feign-jackson + 9.3.1 + @@ -150,6 +269,50 @@ org.apache.maven.plugins maven-plugin-plugin + + org.openapitools + openapi-generator-maven-plugin + 5.0.0 + + + + generate + + + ${project.basedir}/src/main/resources/boat-bay-api-client-temp/boat-bay-client-api.yaml + java + + true + ${boat-maven-plugin.supportingFilesToGenerate} + com.backbase.oss.boat.bay.client.model + com.backbase.oss.boat.bay.client.api + ${project.basedir}/target/generated-sources + false + feign + false + false + false + true + java8-localdatetime + src/gen/java/main + + + JsonPointer = com.fasterxml.jackson.core.JsonPointer + LocalDateTime = java.time.LocalDateTime + org.joda.time = java.time.LocalDateTime + + + + JsonPointer = com.fasterxml.jackson.core.JsonPointer + LocalDateTime = java.time.LocalDateTime + Pageable = org.springframework.data.domain.Pageable + + + + + + + org.apache.maven.plugins @@ -224,6 +387,8 @@ + + org.apache.maven.plugins maven-invoker-plugin diff --git a/boat-maven-plugin/src/it/example/boat-bay/lint-petstore-breaking/pom.xml b/boat-maven-plugin/src/it/example/boat-bay/lint-petstore-breaking/pom.xml new file mode 100644 index 000000000..1eb8d3419 --- /dev/null +++ b/boat-maven-plugin/src/it/example/boat-bay/lint-petstore-breaking/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + + com.backbase.oss.boat.example + boat-bay + 1.0.0-SNAPSHOT + + + lint-petstore-breaking + + BOAT :: Boat Bay :: Lint Spec Breaking + + + + + + pom + + + + + com.backbase.oss + boat-maven-plugin + + + lint + validate + + lint + + + ${project.basedir}/src/main/resources/petstore-new-breaking.yaml + ${project.basedir}/src/main/resources/output + repo-petstore + http://localhost:8080 + + + + + + + + + + + diff --git a/boat-maven-plugin/src/it/example/boat-bay/lint-petstore-breaking/src/main/resource/petstore-new-breaking.yaml b/boat-maven-plugin/src/it/example/boat-bay/lint-petstore-breaking/src/main/resource/petstore-new-breaking.yaml new file mode 100644 index 000000000..2e252e008 --- /dev/null +++ b/boat-maven-plugin/src/it/example/boat-bay/lint-petstore-breaking/src/main/resource/petstore-new-breaking.yaml @@ -0,0 +1,113 @@ +openapi: "3.0.0" +info: + version: 2.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /new-pets: + get: + summary: List all pets + operationId: listPets + tags: + - pets + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + format: int32 + responses: + '200': + description: A paged array of pets + headers: + x-next: + description: A link to the next page of responses + schema: + type: string + content: + application/json: + schema: + $ref: "#/components/schemas/Pets" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + summary: Create a pet + operationId: createPets + tags: + - pets + responses: + '201': + description: Null response + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /pets/{petId}: + get: + summary: Info for a specific pet + operationId: showPetById + tags: + - pets + parameters: + - name: petId + in: path + required: true + description: The id of the pet to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" +components: + schemas: + Pet: + type: object + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + tag: + type: string + new-property: + type: string + Pets: + type: array + items: + $ref: "#/components/schemas/Pet" + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string \ No newline at end of file diff --git a/boat-maven-plugin/src/it/example/boat-bay/lint-petstore-non-breaking/pom.xml b/boat-maven-plugin/src/it/example/boat-bay/lint-petstore-non-breaking/pom.xml new file mode 100644 index 000000000..62bd90bed --- /dev/null +++ b/boat-maven-plugin/src/it/example/boat-bay/lint-petstore-non-breaking/pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + + + com.backbase.oss.boat.example + boat-bay + 1.0.0-SNAPSHOT + + + lint-petstore-non-breaking + + BOAT :: Boat Bay :: Lint Non Breaking Spec + + + Example project showing the linting of a specification via boat-bay + Using a spec with non breaking changes in petstore + + + pom + + + + com.backbase.oss + boat-maven-plugin + + + lint + validate + + lint + + + ${project.basedir}/src/main/resources/petstore-new-non-breaking.yaml + ${project.basedir}/src/main/resources/output + repo-petstore + http://localhost:8080 + + + + + + + + + diff --git a/boat-maven-plugin/src/it/example/boat-bay/lint-petstore-non-breaking/src/main/resources/petstore-new-non-breaking.yaml b/boat-maven-plugin/src/it/example/boat-bay/lint-petstore-non-breaking/src/main/resources/petstore-new-non-breaking.yaml new file mode 100644 index 000000000..9f7ec3683 --- /dev/null +++ b/boat-maven-plugin/src/it/example/boat-bay/lint-petstore-non-breaking/src/main/resources/petstore-new-non-breaking.yaml @@ -0,0 +1,113 @@ +openapi: "3.0.0" +info: + version: 1.1.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /pets: + get: + summary: List all pets + operationId: listPets + tags: + - pets + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + format: int32 + responses: + '200': + description: A paged array of pets + headers: + x-next: + description: A link to the next page of responses + schema: + type: string + content: + application/json: + schema: + $ref: "#/components/schemas/Pets" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + summary: Create a pet + operationId: createPets + tags: + - pets + responses: + '201': + description: Null response + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /pets/{petId}: + get: + summary: Info for a specific pet + operationId: showPetById + tags: + - pets + parameters: + - name: petId + in: path + required: true + description: The id of the pet to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" +components: + schemas: + Pet: + type: object + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + tag: + type: string + new-property: + type: string + Pets: + type: array + items: + $ref: "#/components/schemas/Pet" + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string \ No newline at end of file diff --git a/boat-maven-plugin/src/it/example/boat-bay/lint-petstore/pom.xml b/boat-maven-plugin/src/it/example/boat-bay/lint-petstore/pom.xml new file mode 100644 index 000000000..22ad5e6c8 --- /dev/null +++ b/boat-maven-plugin/src/it/example/boat-bay/lint-petstore/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + + + com.backbase.oss.boat.example + boat-bay + 1.0.0-SNAPSHOT + + + lint-petstore + + BOAT :: Boat Bay :: Lint Spec + + + Example project showing the linting of a specification via boat-bay + + + pom + + + + + com.backbase.oss + boat-maven-plugin + + + lint + validate + + lint + + + url + ${project.basedir}/src/main/resources/petstore-v2.0.0.yaml + ${project.basedir}/src/main/resources/output + repo-petstore + http://localhost:8080 + + + + + + + + + diff --git a/boat-maven-plugin/src/it/example/boat-bay/lint-petstore/src/main/resources/petstore-v2.0.0.yaml b/boat-maven-plugin/src/it/example/boat-bay/lint-petstore/src/main/resources/petstore-v2.0.0.yaml new file mode 100644 index 000000000..137eaff93 --- /dev/null +++ b/boat-maven-plugin/src/it/example/boat-bay/lint-petstore/src/main/resources/petstore-v2.0.0.yaml @@ -0,0 +1,138 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /pets: + get: + summary: List all pets + operationId: listPets + tags: + - pets + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + format: int32 + responses: + '200': + description: A paged array of pets + headers: + x-next: + description: A link to the next page of responses + schema: + type: string + content: + application/json: + schema: + $ref: "#/components/schemas/Pets" + text/csv: + schema: + type: string + 500: + content: + application/json: + schema: + $ref: '#/components/schemas/InternalServerError' + description: InternalServerError + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + summary: Create a pet + operationId: createPets + tags: + - pets + responses: + '201': + description: Null response + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /pets/{petId}: + get: + summary: Info for a specific pet + operationId: showPetById + tags: + - pets + parameters: + - name: petId + in: path + required: true + description: The id of the pet to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /no-schema: + get: + summary: No Schema + operationId: getNoSchema + tags: + - pets + responses: + 200: + description: A response that does not specify a schema + content: + application/json: {} +components: + schemas: + Pet: + type: object + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + tag: + type: string + Pets: + type: array + items: + $ref: "#/components/schemas/Pet" + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string + InternalServerError: + type: object + required: + - message + properties: + message: + type: string \ No newline at end of file diff --git a/boat-maven-plugin/src/it/example/boat-bay/pom.xml b/boat-maven-plugin/src/it/example/boat-bay/pom.xml new file mode 100644 index 000000000..5509af49e --- /dev/null +++ b/boat-maven-plugin/src/it/example/boat-bay/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + + com.backbase.oss.boat.example + example + 1.0.0-SNAPSHOT + + + boat-bay + + BOAT :: Boat Bay + + + Example projects showing how BOAT uses Boat bay to help you lint and validate specs + + + pom + + + lint-petstore + lint-petstore-non-breaking + lint-petstore-breaking + + + diff --git a/boat-maven-plugin/src/it/example/boat-generate/pom.xml b/boat-maven-plugin/src/it/example/boat-generate/pom.xml index 63fbcf268..e74c5d361 100644 --- a/boat-maven-plugin/src/it/example/boat-generate/pom.xml +++ b/boat-maven-plugin/src/it/example/boat-generate/pom.xml @@ -22,7 +22,7 @@ angular - java-clients + java-server diff --git a/boat-maven-plugin/src/main/java/com/backbase/oss/boat/BoatBayRadio.java b/boat-maven-plugin/src/main/java/com/backbase/oss/boat/BoatBayRadio.java new file mode 100644 index 000000000..82fedbad0 --- /dev/null +++ b/boat-maven-plugin/src/main/java/com/backbase/oss/boat/BoatBayRadio.java @@ -0,0 +1,175 @@ +package com.backbase.oss.boat; + +import com.backbase.oss.boat.bay.client.ApiClient; +import com.backbase.oss.boat.bay.client.api.UploadPluginApi; +import com.backbase.oss.boat.bay.client.model.*; +import com.backbase.oss.boat.loader.OpenAPILoader; +import com.backbase.oss.boat.mapper.LintReportMapperImpl; +import com.fasterxml.jackson.databind.introspect.TypeResolutionContext.Basic; +import feign.auth.BasicAuthRequestInterceptor; +import io.swagger.v3.oas.models.OpenAPI; +import kotlin.ranges.IntRange; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.zalando.zally.rule.api.Severity; + +import java.io.File; +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +public class BoatBayRadio { + + @Parameter(name = "readTimeout", defaultValue = "null") + public Integer readTimeout; + + private final UploadPluginApi boatbayUploadSpecClient; + private final File inputSpec; + private String clientBasePath; + private LintReportMapperImpl reportMapper; + protected MavenProject project; + + + public BoatBayRadio(File inputSpec, MavenProject project, String clientBasePath) { + this.project = project; + this.reportMapper = new LintReportMapperImpl(); + this.inputSpec = inputSpec; + this.clientBasePath = clientBasePath; + + if (System.getenv().containsKey("BOAT_BAY_SERVER_URL")) + this.clientBasePath= System.getenv("BOAT_BAY_SERVER_URL"); + + boatbayUploadSpecClient = configureApiClient(this.clientBasePath).buildClient(UploadPluginApi.class); + } + + private ApiClient configureApiClient(String clientBasePath){ + + if (readTimeout == null){ + BasicAuthRequestInterceptor basicAuthRequestInterceptor = new BasicAuthRequestInterceptor("admin","admin"); + ApiClient apiClient = new ApiClient().setBasePath(clientBasePath); +// apiClient.addAuthorization("Basic",basicAuthRequestInterceptor); + return apiClient; + } + + return new ApiClient().setBasePath(clientBasePath); + } + + public List upload(String sourceKey ) { + log.debug("uploading specs for source : {}" , sourceKey); + + + List boatLintReports = boatbayUploadSpecClient.uploadSpec(sourceKey, createRequestBody()); + + log.info("\nSpecs linted.Lint reports can be found at:"); + + List lintReports= boatLintReports.stream() + .map(this::mapBoatBayLintToBoatLint) + .collect(Collectors.toList()); + + return lintReports; + } + + + private com.backbase.oss.boat.quay.model.BoatLintReport mapBoatBayLintToBoatLint(BoatLintReport bayLintReport){ + + com.backbase.oss.boat.quay.model.BoatLintReport lintReport = reportMapper.bayReportToBoatReport(bayLintReport); + lintReport.setFilePath(getFilePath(lintReport.getFilePath())); + + //link to lint report may need updating before release should perhaps + //this link structure is for testing + //be something like this: + // https://boat-bay.proto.backbasecloud.com/lint-reports/repo/digital-banking/lint-report/167 + log.info("\n\tSpec {}: {}lint-report/{}/view", + bayLintReport.getSpec().getName(), + clientBasePath, + bayLintReport.getId()); + + return lintReport; + } + + private String getFilePath(String fileName) { + File inputFile = inputSpec.toPath().resolve(fileName).toFile(); + File workingDirectory = new File("."); + Path relativize; + + try { + relativize = workingDirectory.toPath().relativize(inputFile.toPath()); + } catch (RuntimeException exception) { + log.warn("Failed to get relative path for: {} in working directory: {}", inputFile, workingDirectory); + return inputFile.toString(); + } + + return relativize.toString(); + } + + + private UploadRequestBody createRequestBody(){ + UploadRequestBody requestBody = new UploadRequestBody(); + + try { + requestBody.setSpecs(getSpecs()); + }catch (Exception e){ + throw new RuntimeException("unable to load specs", e); + } + + requestBody.projectId(project.getGroupId()); + requestBody.setArtifactId(project.getArtifactId()); + requestBody.version(project.getVersion()); + + return requestBody; + } + + private List getSpecs() throws MojoExecutionException { + File[] inputFiles; + + if (inputSpec.isDirectory()) { + inputFiles = inputSpec.listFiles(pathname -> pathname.getName().endsWith(".yaml")); + + if (inputFiles == null || inputFiles.length == 0) + throw new MojoExecutionException("No OpenAPI specs found in: " + inputSpec); + + + log.info("Found " + inputFiles.length + " specs to lint."); + } else { + inputFiles = new File[]{inputSpec}; + } + + return Arrays.stream(inputFiles).map(this::mapToUploadSpec).collect(Collectors.toList()); + } + + private UploadSpec mapToUploadSpec(File spec) { + OpenAPI openAPI; + String contents; + + try { + + contents = IOUtils.toString(spec.toURI(), Charset.defaultCharset()); + openAPI= OpenAPILoader.parse(contents); + + }catch (Exception e){ + throw new RuntimeException("unable to read api files: "+e.getMessage()); + } + + UploadSpec uploadSpec = new UploadSpec(); + uploadSpec.fileName(spec.getName()); + uploadSpec.version(openAPI.getInfo().getVersion()); + uploadSpec.openApi(contents); + + log.debug("uploading api {} with contents {}", spec.getName(),openAPI.getOpenapi()); + + uploadSpec.name(spec.getName()); + + return uploadSpec; + } + + +} diff --git a/boat-maven-plugin/src/main/java/com/backbase/oss/boat/LintMojo.java b/boat-maven-plugin/src/main/java/com/backbase/oss/boat/LintMojo.java index 0e73c4952..ba56124de 100644 --- a/boat-maven-plugin/src/main/java/com/backbase/oss/boat/LintMojo.java +++ b/boat-maven-plugin/src/main/java/com/backbase/oss/boat/LintMojo.java @@ -5,12 +5,14 @@ import com.backbase.oss.codegen.lint.BoatLintGenerator; import java.io.File; import java.util.List; + import lombok.extern.slf4j.Slf4j; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.maven.project.MavenProject; @SuppressWarnings("FieldMayBeFinal") @Mojo(name = "lint", requiresDependencyResolution = ResolutionScope.RUNTIME, threadSafe = true) @@ -32,15 +34,32 @@ public class LintMojo extends AbstractLintMojo { @Parameter(name = "writeLintReport", defaultValue = "true") private boolean writeLintReport; + @Parameter(readonly = true, required = true, defaultValue = "${project}") + protected MavenProject project; + + @Parameter(name = "boatBayUrl", property = "boat.maven.plugin.lint.boatBayUrl", defaultValue ="") + private String boatBayUrl; + + @Parameter(name = "sourceKey") + private String sourceKey; + + @Override public void execute() throws MojoExecutionException, MojoFailureException { + List boatLintReports = null; try { - boatLintReports = lint(); + if (sourceKey != null + && (System.getenv().containsKey("BOAT_BAY_SERVER_URL") + || !boatBayUrl.isEmpty())) { + boatLintReports = new BoatBayRadio(getInput(),project, boatBayUrl).upload(sourceKey); + }else { + boatLintReports = lint(); + } } catch (MojoExecutionException e) { if (failOnWarning) { - throw e; + throw new MojoExecutionException(e.getMessage()); } } if (boatLintReports == null) { @@ -68,6 +87,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { throw new MojoFailureException("Linting " + inputSpec + " failed. Please correct the found issues and try again"); } + } private void generateLintReport(boolean isSingleLint, BoatLintReport report) { @@ -91,7 +111,16 @@ private File getOutput() { return this.output; } - public void setWriteLintReport(boolean writeLintReport) { - this.writeLintReport = writeLintReport; + public File getInput(){ + if(input==null){ + input = new File(inputSpec); + } + return input; } + + public void setSourceKey(String sourceKey){ this.sourceKey = sourceKey; } + + public void setBoatBayUrl(String boatBayUrl){this.boatBayUrl = boatBayUrl;} + + public void setWriteLintReport(boolean writeLintReport) { this.writeLintReport = writeLintReport; } } diff --git a/boat-maven-plugin/src/main/java/com/backbase/oss/boat/ValidateMojo.java b/boat-maven-plugin/src/main/java/com/backbase/oss/boat/ValidateMojo.java index 75ae3e0cd..8f3f766b4 100644 --- a/boat-maven-plugin/src/main/java/com/backbase/oss/boat/ValidateMojo.java +++ b/boat-maven-plugin/src/main/java/com/backbase/oss/boat/ValidateMojo.java @@ -6,6 +6,8 @@ import io.swagger.v3.parser.core.models.SwaggerParseResult; import java.io.File; import java.util.ArrayList; + +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.maven.plugin.AbstractMojo; @@ -13,6 +15,7 @@ import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.maven.project.MavenProject; /** * Validates OpenAPI specs. @@ -27,13 +30,21 @@ public class ValidateMojo extends AbstractMojo { @Parameter(name = "failOnWarning", required = true) private boolean failOnWarning; + @Parameter(readonly = true, required = true, defaultValue = "${project}") + protected MavenProject project; + public void setInput(File input) { this.input = input; } + public void setFailOnWarning(boolean failOnWarning) { this.failOnWarning= failOnWarning; } + + + + @SneakyThrows @Override public void execute() throws MojoFailureException { diff --git a/boat-maven-plugin/src/main/java/com/backbase/oss/boat/mapper/LintReportMapper.java b/boat-maven-plugin/src/main/java/com/backbase/oss/boat/mapper/LintReportMapper.java new file mode 100644 index 000000000..715909be4 --- /dev/null +++ b/boat-maven-plugin/src/main/java/com/backbase/oss/boat/mapper/LintReportMapper.java @@ -0,0 +1,15 @@ +package com.backbase.oss.boat.mapper; +import com.backbase.oss.boat.quay.model.BoatLintReport; +import com.fasterxml.jackson.core.JsonPointer; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(componentModel = "spring") +public interface LintReportMapper { + + @Mapping(target = "title", source = "name") + @Mapping(target = "filePath", source = "spec.name") +// @Mapping(target = "availableRules", source = "") + BoatLintReport bayReportToBoatReport(com.backbase.oss.boat.bay.client.model.BoatLintReport bayReport); + +} diff --git a/boat-maven-plugin/src/main/resources/boat-bay-api-client-temp/boat-bay-client-api.yaml b/boat-maven-plugin/src/main/resources/boat-bay-api-client-temp/boat-bay-client-api.yaml new file mode 100644 index 000000000..b386c1186 --- /dev/null +++ b/boat-maven-plugin/src/main/resources/boat-bay-api-client-temp/boat-bay-client-api.yaml @@ -0,0 +1,322 @@ +openapi: 3.0.0 +info: + title: Boat Bay Upload Server + description: Endpoints for uploading Specs to boat bay + license: + name: Backbase + version: 1.0.0 +servers: +- url: http://boat-bay-server.proto.backbasecloud.com/ +tags: +- name: upload-plugin +paths: + /api/boat/boat-maven-plugin/{sourceKey}/upload: + post: + tags: + - upload-plugin + summary: upload and lint specs + operationId: uploadSpec + parameters: + - name: sourceKey + in: path + description: source identifier + required: true + style: simple + explode: false + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UploadRequestBody' + required: true + responses: + "200": + description: list of lint reports for specs + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/BoatLintReport' +components: + schemas: + BoatProduct: + type: object + properties: + portalKey: + type: string + portalName: + type: string + id: + type: integer + format: int64 + key: + type: string + name: + type: string + content: + type: string + createdOn: + $ref: '#/components/schemas/LocalDateTime' + createdBy: + type: string + lastLintReport: + $ref: '#/components/schemas/BoatLintReport' + statistics: + $ref: '#/components/schemas/BoatStatistics' + jiraProjectId: + type: string + BoatCapability: + type: object + properties: + id: + type: integer + format: int64 + key: + type: string + name: + type: string + content: + type: string + createdOn: + $ref: '#/components/schemas/LocalDateTime' + createdBy: + type: string + services: + type: array + items: + $ref: '#/components/schemas/BoatService' + lastLintReport: + $ref: '#/components/schemas/BoatLintReport' + statistics: + $ref: '#/components/schemas/BoatStatistics' + BoatService: + type: object + properties: + key: + type: string + name: + type: string + description: + type: string + icon: + type: string + color: + type: string + createdOn: + $ref: '#/components/schemas/LocalDateTime' + createdBy: + type: string + statistics: + $ref: '#/components/schemas/BoatStatistics' + capability: + $ref: '#/components/schemas/BoatCapability' + BoatSpec: + type: object + properties: + id: + type: integer + format: int64 + key: + type: string + name: + type: string + title: + type: string + description: + type: string + icon: + type: string + version: + type: string + grade: + type: string + createdOn: + $ref: '#/components/schemas/LocalDateTime' + createdBy: + type: string + statistics: + $ref: '#/components/schemas/BoatStatistics' + backwardsCompatible: + type: boolean + changes: + $ref: '#/components/schemas/Changes' + capability: + $ref: '#/components/schemas/BoatCapability' + serviceDefinition: + $ref: '#/components/schemas/BoatService' + openApi: + type: string + BoatLintReport: + type: object + properties: + id: + type: integer + format: int64 + spec: + $ref: '#/components/schemas/BoatSpec' + name: + type: string + passed: + type: boolean + lintedOn: + $ref: '#/components/schemas/LocalDateTime' + openApi: + type: string + version: + type: string + grade: + type: string + violations: + type: array + items: + $ref: '#/components/schemas/BoatViolation' + hasViolations: + type: boolean + BoatLintRule: + type: object + properties: + id: + type: integer + format: int64 + ruleId: + type: string + enabled: + type: boolean + title: + type: string + ruleSet: + type: string + severity: + $ref: '#/components/schemas/Severity' + url: + type: string + format: uri + BoatProductRelease: + type: object + properties: + id: + type: integer + format: int64 + key: + type: string + name: + type: string + version: + type: string + releaseDate: + $ref: '#/components/schemas/LocalDateTime' + Resource: + type: array + items: + type: string + format: byte + ChangedOpenApiObject: + type: object + UploadRequestBody: + type: object + properties: + specs: + type: array + items: + $ref: '#/components/schemas/UploadSpec' + projectId: + type: string + nullable: false + minLength: 1 + artifactId: + type: string + nullable: false + minLength: 1 + version: + type: string + nullable: false + minLength: 1 + LocalDateTime: + type: string + format: date-time + BoatStatistics: + type: object + properties: + updatedOn: + $ref: '#/components/schemas/LocalDateTime' + mustViolationsCount: + type: integer + format: int64 + shouldViolationsCount: + type: integer + format: int64 + mayViolationsCount: + type: integer + format: int64 + hintViolationsCount: + type: integer + format: int64 + Changes: + type: string + enum: + - INVALID_VERSION + - NOT_APPLICABLE + - ERROR_COMPARING + - UNCHANGED + - COMPATIBLE + - BREAKING + BoatViolation: + type: object + properties: + rule: + $ref: '#/components/schemas/BoatLintRule' + description: + type: string + severity: + $ref: '#/components/schemas/Severity' + lines: + $ref: '#/components/schemas/IntRange' + pointer: + $ref: '#/components/schemas/JsonPointer' + Severity: + type: string + enum: + - MUST + - SHOULD + - MAY + - HINT + UploadSpec: + type: object + properties: + fileName: + type: string + openApi: + type: string + name: + type: string + version: + type: string + JsonPointer: + type: object + properties: + separator: + type: string + default: / + EMPTY: + type: JsonPointer + _nextSegment: + type: JsonPointer + _head: + type: JsonPointer + _asString: + type: string + _matchingPropertyName: + type: string + _matchingElementIndex: + type: int + IntRange: + type: object + properties: + start: + type: integer + endInclusive: + type: integer + examples: {} diff --git a/boat-maven-plugin/src/main/resources/boat-bay-api-client-temp/boat-bay-client.yaml b/boat-maven-plugin/src/main/resources/boat-bay-api-client-temp/boat-bay-client.yaml new file mode 100644 index 000000000..055e230aa --- /dev/null +++ b/boat-maven-plugin/src/main/resources/boat-bay-api-client-temp/boat-bay-client.yaml @@ -0,0 +1,1055 @@ +openapi: 3.0.0 +info: + title: Boat Bay Client + description: Endpoints for the boat bay operations + license: + name: Backbase + version: 1.0.0 +servers: + - url: http://localhost:8080 + description: test server + - url: http://boat-bay-server.proto.backbasecloud.com/ + description: production server +tags: + - name: dashboard + - name: upload-plugin +paths: + /api/boat/portals: + get: + tags: + - dashboard + summary: get list of portals + operationId: getPortals + responses: + "200": + description: boat legacy portal + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/BoatPortal' + /api/boat/portals/{portalKey}/products: + get: + tags: + - dashboard + summary: get products for identified portal + operationId: getPortalProducts + parameters: + - name: portalKey + in: path + description: portal idenifier + required: true + style: simple + explode: false + schema: + type: string + responses: + "200": + description: list of protals products + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/BoatProduct' + /api/boat/portals/{portalKey}/products/{productKey}/capabilities: + get: + tags: + - dashboard + summary: get Portal Products Capabalities + operationId: getPortalCapabilities + parameters: + - name: pageable + in: query + required: false + style: form + explode: true + schema: + $ref: '#/components/schemas/Pageable' + - name: productKey + in: path + description: product idenifier + required: true + style: simple + explode: false + schema: + type: string + - name: portalKey + in: path + description: portal idenifier + required: true + style: simple + explode: false + schema: + type: string + responses: + "200": + description: list of capabilities for product + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/BoatCapability' + /api/boat/portals/{portalKey}/products/{productKey}/services: + get: + tags: + - dashboard + summary: get Portal services for a given product + operationId: getPortalServices + parameters: + - name: pageable + in: query + required: false + style: form + explode: true + schema: + $ref: '#/components/schemas/Pageable' + - name: productKey + in: path + description: product idenifier + required: true + style: simple + explode: false + schema: + type: string + - name: portalKey + in: path + description: portal idenifier + required: true + style: simple + explode: false + schema: + type: string + responses: + "200": + description: list of services for product + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/BoatService' + /api/boat/portals/{portalKey}/products/{productKey}/specs: + get: + tags: + - dashboard + summary: get Portal Specs for given product + operationId: getPortalSpecs + parameters: + - name: pageable + in: query + required: false + style: form + explode: true + schema: + $ref: '#/components/schemas/Pageable' + - name: productKey + in: path + description: product idenifier + required: true + style: simple + explode: false + schema: + type: string + - name: portalKey + in: path + description: portal idenifier + required: true + style: simple + explode: false + schema: + type: string + - name: capability + in: query + description: capablility idenifier + required: false + style: form + explode: true + schema: + type: array + items: + type: string + - name: release + in: query + description: product release idenifier + required: false + style: form + explode: true + schema: + type: string + - name: service + in: query + description: service idenifier + required: false + style: form + explode: true + schema: + type: array + items: + type: string + - name: grade + in: query + description: grade of spec + required: false + style: form + explode: true + schema: + type: string + - name: backwardsCompatible + in: query + description: backwards compatible indicator + required: false + style: form + explode: true + schema: + type: boolean + - name: changed + in: query + description: changed indicator + required: false + style: form + explode: true + schema: + type: boolean + responses: + "200": + description: list of specs for product + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/BoatSpec' + /api/boat/portals/{portalKey}/products/{productKey}/specs/{specId}/lint-report: + get: + tags: + - dashboard + summary: get Lint Report for spec + operationId: getLintReportForSpec + parameters: + - name: specId + in: path + description: spec idenifier + required: true + style: simple + explode: false + schema: + type: string + - name: productKey + in: path + description: product idenifier + required: true + style: simple + explode: false + schema: + type: string + - name: portalKey + in: path + description: portal idenifier + required: true + style: simple + explode: false + schema: + type: string + - name: refresh + in: query + description: refresh idicator + required: false + style: form + explode: true + schema: + type: boolean + responses: + "200": + description: lint report for spec + content: + application/json: + schema: + $ref: '#/components/schemas/BoatLintReport' + /api/boat/portals/{portalKey}/lint-rules: + get: + tags: + - dashboard + summary: get list of lint rules + operationId: getPortalLintRules + parameters: + - name: portalKey + in: path + description: portal idenifier + required: true + style: simple + explode: false + schema: + type: string + responses: + "200": + description: list of lint rules for portal + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/BoatLintRule' + /api/boat/portals/{portalKey}/products/{productKey}/releases: + get: + tags: + - dashboard + summary: get product releases + operationId: getProductReleases + parameters: + - name: productKey + in: path + description: id of product + required: true + style: simple + explode: false + schema: + type: string + - name: portalKey + in: path + description: portal idenifier + required: true + style: simple + explode: false + schema: + type: string + responses: + "200": + description: list of product releases for product + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/BoatProductRelease' + /api/boat/portals/{portalKey}/products/{productKey}/releases/{releaseKey}/specs: + get: + tags: + - dashboard + summary: get specs for product release + operationId: getProductReleaseSpecs + parameters: + - name: releaseKey + in: path + description: key for product release + required: true + style: simple + explode: false + schema: + type: string + - name: productKey + in: path + description: id of product + required: true + style: simple + explode: false + schema: + type: string + - name: portalKey + in: path + description: portal idenifier + required: true + style: simple + explode: false + schema: + type: string + responses: + "200": + description: list of specs for product release + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/BoatSpec' + /api/boat/portals/{portalKey}/lint-rules/{lintRuleId}: + post: + tags: + - dashboard + summary: update lint rule for portal + operationId: updatePortalLintRule + parameters: + - name: lintRuleId + in: path + description: id of portals lint rule + required: true + style: simple + explode: false + schema: + type: string + - name: portalKey + in: path + description: portal idenifier + required: true + style: simple + explode: false + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/BoatLintRule' + responses: + "200": + description: updated successfuly + content: {} + /api/boat/dashboard: + get: + tags: + - dashboard + summary: get list of boat portal dashboards + operationId: getDashboard + responses: + "200": + description: list of boat portal dashboards + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/BoatPortalDashboard' + /api/boat/dashboard/{projectKey}/{productKey}: + get: + tags: + - dashboard + summary: get product for dashboard project + operationId: getProductDashboard + parameters: + - name: projectKey + in: path + description: project idenifier + required: true + style: simple + explode: false + schema: + type: string + - name: productKey + in: path + description: product idenifier + required: true + style: simple + explode: false + schema: + type: string + responses: + "200": + description: product for dashboard + content: + application/json: + schema: + $ref: '#/components/schemas/BoatProduct' + /api/boat/portals/{portalKey}/products/{productKey}/tags: + get: + tags: + - dashboard + summary: get tags for product + operationId: getProductTags + parameters: + - name: portalKey + in: path + description: portal idenifier + required: true + style: simple + explode: false + schema: + type: string + - name: productKey + in: path + description: product idenifier + required: true + style: simple + explode: false + schema: + type: string + responses: + "200": + description: list of product tags + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/BoatTag' + /api/boat/portals/{portalKey}/products/{productKey}/capabilities/{capabilityKey}/services/{serviceKey}/specs/{specKey}/{version}/download: + get: + tags: + - dashboard + summary: get spec as openapi + operationId: getSpecAsOpenAPI + parameters: + - name: portalKey + in: path + description: portal idenifier + required: true + style: simple + explode: false + schema: + type: string + - name: productKey + in: path + description: product identifier + required: true + style: simple + explode: false + schema: + type: string + - name: capabilityKey + in: path + description: capability identifier + required: true + style: simple + explode: false + schema: + type: string + - name: serviceKey + in: path + description: service identifier + required: true + style: simple + explode: false + schema: + type: string + - name: specKey + in: path + description: spec identifier + required: true + style: simple + explode: false + schema: + type: string + - name: version + in: path + description: version of spec + required: true + style: simple + explode: false + schema: + type: string + responses: + "200": + description: openApi of spec + headers: + Content-Disposition: + description: name of file + style: simple + explode: false + schema: + type: string + Cache-Control: + style: simple + explode: false + schema: + type: string + Pragma: + style: simple + explode: false + schema: + type: string + Expires: + style: simple + explode: false + schema: + type: string + content: + application/vnd.oai.openapi: + schema: + $ref: '#/components/schemas/Resource' + /api/boat/portals/{portalKey}/products/{productKey}/capabilities/{capabilityKey}/services/{serviceKey}/specs/{specKey}/{version}: + get: + tags: + - dashboard + summary: download spec + operationId: downloadSpec + parameters: + - name: portalKey + in: path + description: portal idenifier + required: true + style: simple + explode: false + schema: + type: string + - name: productKey + in: path + description: product identifier + required: true + style: simple + explode: false + schema: + type: string + - name: capabilityKey + in: path + description: capability identifier + required: true + style: simple + explode: false + schema: + type: string + - name: serviceKey + in: path + description: service identifier + required: true + style: simple + explode: false + schema: + type: string + - name: specKey + in: path + description: spec identifier + required: true + style: simple + explode: false + schema: + type: string + - name: version + in: path + description: version of spec + required: true + style: simple + explode: false + schema: + type: string + responses: + "200": + description: spec with open api + content: + application/json: + schema: + $ref: '#/components/schemas/BoatSpec' + /api/boat/portals/{portalKey}/products/{productKey}/diff-report: + get: + tags: + - lint + summary: get lint report for spec + operationId: getApiChangesForSpec + parameters: + - name: portalKey + in: path + description: portal idenifier + required: true + style: simple + explode: false + schema: + type: string + - name: productKey + in: path + description: product identifier + required: true + style: simple + explode: false + schema: + type: string + - name: spec1Id + in: query + description: identifies first comparitable api + required: false + style: form + explode: true + schema: + type: string + - name: spec2Id + in: query + description: identifies second comparitable api + required: false + style: form + explode: true + schema: + type: string + responses: + "200": + description: changed openApi + content: + application/json: + schema: + $ref: '#/components/schemas/ChangedOpenApiObject' + /api/boat/portals/{portalKey}/products/{productKey}/diff-report.html: + get: + tags: + - lint + summary: get lint report for spec as html + operationId: getLintReportForSpecAsHtml + parameters: + - name: portalKey + in: path + description: portal idenifier + required: true + style: simple + explode: false + schema: + type: string + - name: productKey + in: path + description: product identifier + required: true + style: simple + explode: false + schema: + type: string + - name: spec1Id + in: query + description: identifies first comparitable api + required: false + style: form + explode: true + schema: + type: string + - name: spec2Id + in: query + description: identifies second comparitable api + required: false + style: form + explode: true + schema: + type: string + responses: + "200": + description: changed openApi as html + content: + application/json: + schema: + type: string + /api/boat/boat-maven-plugin/{sourceKey}/upload: + post: + tags: + - upload-plugin + summary: upload and lint specs + operationId: uploadSpec + parameters: + - name: sourceKey + in: path + description: source idenifier + required: true + style: simple + explode: false + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/upload-request-body' + required: true + responses: + "200": + description: list of lint reports for specs + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/BoatLintReport' +components: + schemas: + BoatPortal: + type: object + properties: + id: + type: number + key: + type: string + name: + type: string + content: + type: string + createdOn: + $ref: '#/components/schemas/LocalDateTime' + createdBy: + type: string + BoatProduct: + type: object + properties: + portalKey: + type: string + portalName: + type: string + id: + type: number + key: + type: string + name: + type: string + content: + type: string + createdOn: + $ref: '#/components/schemas/LocalDateTime' + createdBy: + type: string + lastLintReport: + $ref: '#/components/schemas/BoatLintReport' + statistics: + $ref: '#/components/schemas/BoatStatistics' + jiraProjectId: + type: string + Pageable: + type: object + properties: + page: + type: integer + size: + type: integer + description: minimal Pageable query parameters + BoatCapability: + type: object + properties: + id: + type: number + key: + type: string + name: + type: string + content: + type: string + createdOn: + $ref: '#/components/schemas/LocalDateTime' + createdBy: + type: string + services: + type: array + items: + $ref: '#/components/schemas/BoatService' + lastLintReport: + $ref: '#/components/schemas/BoatLintReport' + statistics: + $ref: '#/components/schemas/BoatStatistics' + BoatService: + type: object + properties: + key: + type: string + name: + type: string + description: + type: string + icon: + type: string + color: + type: string + createdOn: + $ref: '#/components/schemas/LocalDateTime' + createdBy: + type: string + statistics: + $ref: '#/components/schemas/BoatStatistics' + BoatSpec: + type: object + properties: + id: + type: number + key: + type: string + name: + type: string + title: + type: string + description: + type: string + icon: + type: string + version: + type: string + grade: + type: string + createdOn: + $ref: '#/components/schemas/LocalDateTime' + createdBy: + type: string + statistics: + $ref: '#/components/schemas/BoatStatistics' + backwardsCompatible: + type: boolean + changes: + $ref: '#/components/schemas/Changes' + capability: + $ref: '#/components/schemas/BoatCapability' + serviceDefinition: + $ref: '#/components/schemas/BoatService' + openApi: + type: string + BoatLintReport: + type: object + properties: + id: + type: number + spec: + $ref: '#/components/schemas/BoatSpec' + name: + type: string + passed: + type: boolean + lintedOn: + $ref: '#/components/schemas/LocalDateTime' + openApi: + type: string + version: + type: string + grade: + type: string + violations: + type: array + items: + $ref: '#/components/schemas/BoatViolation' + hasViolations: + type: boolean + BoatLintRule: + type: object + properties: + id: + type: number + ruleId: + type: string + enabled: + type: boolean + title: + type: string + ruleSet: + type: string + severity: + $ref: '#/components/schemas/Severity' + url: + type: string + format: uri + BoatProductRelease: + type: object + properties: + id: + type: number + key: + type: string + name: + type: string + version: + type: string + releaseDate: + $ref: '#/components/schemas/LocalDateTime' + BoatPortalDashboard: + type: object + properties: + portalId: + type: string + portalKey: + type: string + portalName: + type: string + productId: + type: string + productKey: + type: string + productName: + type: string + numberOfServices: + type: integer + format: int64 + numberOfCapabilities: + type: integer + format: int64 + productDescription: + type: string + lastLintReport: + $ref: '#/components/schemas/BoatLintReport' + statistics: + $ref: '#/components/schemas/BoatStatistics' + BoatTag: + type: object + properties: + name: + type: string + description: + type: string + hide: + type: boolean + color: + type: string + numberOfOccurrences: + type: integer + Resource: + type: array + items: + type: string + format: byte + ChangedOpenApiObject: + type: object + upload-request-body: + type: object + properties: + specs: + type: array + items: + $ref: '#/components/schemas/UploadSpec' + location: + type: string + projectId: + type: string + artifactId: + type: string + version: + type: string + LocalDateTime: + type: string + format: date-time + BoatStatistics: + type: object + properties: + updatedOn: + $ref: '#/components/schemas/LocalDateTime' + mustViolationsCount: + type: integer + format: int64 + shouldViolationsCount: + type: integer + format: int64 + mayViolationsCount: + type: integer + format: int64 + hintViolationsCount: + type: integer + format: int64 + Changes: + type: string + enum: + - NOT_APPLICABLE + - ERROR_COMPARING + - UNCHANGED + - COMPATIBLE + - BREAKING + BoatViolation: + type: object + properties: + rule: + $ref: '#/components/schemas/BoatLintRule' + description: + type: string + severity: + $ref: '#/components/schemas/Severity' + lines: + $ref: '#/components/schemas/IntRange' + pointer: + type: JsonPointer + Severity: + type: string + enum: + - MUST + - SHOULD + - MAY + - HINT + UploadSpec: + type: object + properties: + fileName: + type: string + openApi: + type: string + key: + type: string + name: + type: string + IntRange: + type: object + properties: + start: + type: integer + endInclusive: + type: integer + examples: {} diff --git a/boat-maven-plugin/src/test/java/com/backbase/oss/boat/BoatRadioTests.java b/boat-maven-plugin/src/test/java/com/backbase/oss/boat/BoatRadioTests.java new file mode 100644 index 000000000..86fd5e1b4 --- /dev/null +++ b/boat-maven-plugin/src/test/java/com/backbase/oss/boat/BoatRadioTests.java @@ -0,0 +1,48 @@ +package com.backbase.oss.boat; + +import static org.mockserver.integration.ClientAndServer.startClientAndServer; + +import java.io.File; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.project.MavenProject; +import org.assertj.core.util.Arrays; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockserver.configuration.ConfigurationProperties; +import org.mockserver.integration.ClientAndServer; + +public class BoatRadioTests { + private ClientAndServer boatBayMockServer; + private final String sourcekey = "repo-petstore"; + + @BeforeEach + public void setUp(){ + String initializationJsonPath = getClass().getResource("/boat-bay-mock-server/mock-upload-request-response.json").getPath(); + ConfigurationProperties.initializationJsonPath(initializationJsonPath); + boatBayMockServer = startClientAndServer(8080); + + + } + @Test + void testLintUpload() throws MojoFailureException, MojoExecutionException { + + LintMojo lintMojo = new LintMojo(); + lintMojo.project = new MavenProject(); + lintMojo.project.setGroupId("repo.backbase.com"); + lintMojo.project.setArtifactId("petstore"); + lintMojo.project.setVersion("1.0.0-SNAPSHOT"); + lintMojo.project.setFile(getFile("/oas-examples")); + lintMojo.setSourceKey(sourcekey); + lintMojo.setBoatBayUrl("http://localhost:8080/"); + lintMojo.output= new File("/Users/sophiej/Documents/Projects/opensauce/fresh-water-boat/backbase-openapi-tools/boat-maven-plugin/src/test/resources/upload-reports"); + lintMojo.setIgnoreRules(Arrays.array("219", "105", "104", "151", "134", "115")); + lintMojo.setInput(getFile("/oas-examples/petstore-v1.0.0.yaml")); + lintMojo.setFailOnWarning(false); + lintMojo.execute(); + } + private File getFile(String fileName) { + return new File(getClass().getResource(fileName).getFile()); + } + +} diff --git a/boat-maven-plugin/src/test/java/com/backbase/oss/boat/GenerateMojoTests.java b/boat-maven-plugin/src/test/java/com/backbase/oss/boat/GenerateMojoTests.java index 31457400a..b009814c7 100644 --- a/boat-maven-plugin/src/test/java/com/backbase/oss/boat/GenerateMojoTests.java +++ b/boat-maven-plugin/src/test/java/com/backbase/oss/boat/GenerateMojoTests.java @@ -94,7 +94,7 @@ void useJavaBoatForWebClientEmbedded() throws MojoExecutionException, MojoFailur private T configure(T mojo, String generatorName) { mojo.buildContext = buildContext; mojo.project = project; - mojo.inputSpec = "src/test/resources/oas-examples/petstore.yaml"; + mojo.inputSpec = "src/test/resources/oas-examples/petstore-v1.0.0.yaml"; mojo.output = new File("target/generate-mojo-tests"); mojo.generatorName = generatorName; diff --git a/boat-maven-plugin/src/test/java/com/backbase/oss/boat/GeneratorTests.java b/boat-maven-plugin/src/test/java/com/backbase/oss/boat/GeneratorTests.java index 839e21df8..00d23f2ab 100644 --- a/boat-maven-plugin/src/test/java/com/backbase/oss/boat/GeneratorTests.java +++ b/boat-maven-plugin/src/test/java/com/backbase/oss/boat/GeneratorTests.java @@ -5,14 +5,10 @@ import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.project.MavenProject; -import org.apache.maven.shared.invoker.*; import org.codehaus.plexus.logging.console.ConsoleLogger; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; -import org.junit.jupiter.params.provider.ValueSource; import org.sonatype.plexus.build.incremental.DefaultBuildContext; import java.io.File; import java.util.*; diff --git a/boat-maven-plugin/src/test/java/com/backbase/oss/boat/LintMojoTests.java b/boat-maven-plugin/src/test/java/com/backbase/oss/boat/LintMojoTests.java index 86d252f93..16e609f37 100644 --- a/boat-maven-plugin/src/test/java/com/backbase/oss/boat/LintMojoTests.java +++ b/boat-maven-plugin/src/test/java/com/backbase/oss/boat/LintMojoTests.java @@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.project.MavenProject; import org.assertj.core.util.Arrays; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import org.junit.jupiter.api.Test; @@ -86,7 +87,6 @@ void testExceptionsWithInvalidFile() { } - private File getFile(String fileName) { return new File(getClass().getResource(fileName).getFile()); } diff --git a/boat-maven-plugin/src/test/resources/boat-bay-mock-server/mock-upload-request-response.json b/boat-maven-plugin/src/test/resources/boat-bay-mock-server/mock-upload-request-response.json new file mode 100644 index 000000000..7fa8779de --- /dev/null +++ b/boat-maven-plugin/src/test/resources/boat-bay-mock-server/mock-upload-request-response.json @@ -0,0 +1,426 @@ +[ + { + "httpRequest": { + "method": "POST", + "path": "/api/boat/boat-maven-plugin/repo-petstore/upload" + }, + "httpResponse": { + "statusCode": 200, + "body": [ + { + "id": 2, + "spec": { + "id": 1, + "key": "petstore", + "name": "petstore-v1.0.0.yaml", + "title": "Swagger Petstore", + "version": "1.0.0", + "createdOn": "2021-11-17T14:45:10Z", + "createdBy": "MavenPluginUpload", + "changes": "NOT_APPLICABLE", + "capability": { + "id": 1, + "key": "backbase-com", + "name": "backbase-com" + }, + "serviceDefinition": { + "key": "petstore", + "name": "petstore", + "capability": { + "id": 1, + "key": "backbase-com", + "name": "backbase-com" + } + } + }, + "name": "petstore-v1.0.0.yaml", + "lintedOn": "2021-11-17T14:50:10Z", + "openApi": "openapi: \"3.0.0\"\ninfo:\n version: 1.0.0\n title: Swagger Petstore\n license:\n name: MIT\nservers:\n - url: http://petstore.swagger.io/v1\npaths:\n /pets:\n get:\n summary: List all pets\n operationId: listPets\n tags:\n - pets\n parameters:\n - name: limit\n in: query\n description: How many items to return at one time (max 100)\n required: false\n schema:\n type: integer\n format: int32\n responses:\n \u0027200\u0027:\n description: A paged array of pets\n headers:\n x-next:\n description: A link to the next page of responses\n schema:\n type: string\n content:\n application/json:\n schema:\n $ref: \"#/components/schemas/Pets\"\n text/csv:\n schema:\n type: string\n 500:\n content:\n application/json:\n schema:\n $ref: \u0027#/components/schemas/InternalServerError\u0027\n description: InternalServerError\n default:\n description: unexpected error\n content:\n application/json:\n schema:\n $ref: \"#/components/schemas/Error\"\n post:\n summary: Create a pet\n operationId: createPets\n tags:\n - pets\n responses:\n \u0027201\u0027:\n description: Null response\n default:\n description: unexpected error\n content:\n application/json:\n schema:\n $ref: \"#/components/schemas/Error\"\n /pets/{petId}:\n get:\n summary: Info for a specific pet\n operationId: showPetById\n tags:\n - pets\n parameters:\n - name: petId\n in: path\n required: true\n description: The id of the pet to retrieve\n schema:\n type: string\n responses:\n \u0027200\u0027:\n description: Expected response to a valid request\n content:\n application/json:\n schema:\n $ref: \"#/components/schemas/Pet\"\n default:\n description: unexpected error\n content:\n application/json:\n schema:\n $ref: \"#/components/schemas/Error\"\n /no-schema:\n get:\n summary: No Schema\n operationId: getNoSchema\n tags:\n - pets\n responses:\n 200:\n description: A response that does not specify a schema\n content:\n application/json: {}\ncomponents:\n schemas:\n Pet:\n type: object\n required:\n - id\n - name\n properties:\n id:\n type: integer\n format: int64\n name:\n type: string\n tag:\n type: string\n Pets:\n type: array\n items:\n $ref: \"#/components/schemas/Pet\"\n Error:\n type: object\n required:\n - code\n - message\n properties:\n code:\n type: integer\n format: int32\n message:\n type: string\n InternalServerError:\n type: object\n required:\n - message\n properties:\n message:\n type: string", + "version": "1.0.0", + "grade": "F", + "violations": [ + { + "rule": { + "id": 21, + "ruleId": "B007", + "enabled": true, + "title": "Check prefix for paths", + "ruleSet": "BoatRuleSet", + "severity": "MUST", + "url": "https://backbase.github.io/backbase-openapi-tools/rules.md#b007-check-prefix-for-paths" + }, + "description": "Incorrect path prefix: pets. Correct values are [client-api, service-api, integration-api]", + "severity": "MUST", + "lines": { + "first": 10, + "last": 65, + "step": 1 + }, + "pointer": { + "_nextSegment": { + "_nextSegment": { + "_asString": "", + "_matchingPropertyName": "", + "_matchingElementIndex": -1 + }, + "_asString": "/~1pets", + "_matchingPropertyName": "/pets", + "_matchingElementIndex": -1 + }, + "_asString": "/paths/~1pets", + "_matchingPropertyName": "paths", + "_matchingElementIndex": -1 + } + }, + { + "rule": { + "id": 20, + "ruleId": "B006", + "enabled": true, + "title": "Check info block description format.", + "ruleSet": "BoatRuleSet", + "severity": "MUST", + "url": "https://backbase.github.io/backbase-openapi-tools/rules.md#b006-check-info-block-description-format-" + }, + "description": "description is a required value", + "severity": "MUST", + "lines": { + "first": 1, + "last": 1, + "step": 1 + }, + "pointer": { + "_nextSegment": { + "_nextSegment": { + "_nextSegment": { + "_asString": "", + "_matchingPropertyName": "", + "_matchingElementIndex": -1 + }, + "_asString": "/description", + "_matchingPropertyName": "description", + "_matchingElementIndex": -1 + }, + "_asString": "/info/description", + "_matchingPropertyName": "info", + "_matchingElementIndex": -1 + }, + "_asString": "/openapi/info/description", + "_matchingPropertyName": "openapi", + "_matchingElementIndex": -1 + } + }, + { + "rule": { + "id": 13, + "ruleId": "B008", + "enabled": true, + "title": "Check x-icon value in the info block", + "ruleSet": "BoatRuleSet", + "severity": "SHOULD", + "url": "https://backbase.github.io/backbase-openapi-tools/rules.md#b008-check-x-icon-value-in-the-info-block" + }, + "description": "x-icon should be provided in the info block with the assigned value for the API", + "severity": "SHOULD", + "lines": { + "first": 1, + "last": 1, + "step": 1 + }, + "pointer": { + "_nextSegment": { + "_nextSegment": { + "_nextSegment": { + "_asString": "", + "_matchingPropertyName": "", + "_matchingElementIndex": -1 + }, + "_asString": "/x-icon", + "_matchingPropertyName": "x-icon", + "_matchingElementIndex": -1 + }, + "_asString": "/info/x-icon", + "_matchingPropertyName": "info", + "_matchingElementIndex": -1 + }, + "_asString": "/openapi/info/x-icon", + "_matchingPropertyName": "openapi", + "_matchingElementIndex": -1 + } + }, + { + "rule": { + "id": 18, + "ruleId": "B004", + "enabled": true, + "title": "Check info block tags allowed.", + "ruleSet": "BoatRuleSet", + "severity": "MUST", + "url": "https://backbase.github.io/backbase-openapi-tools/rules.md#b004-check-info-block-tags-allowed-" + }, + "description": "tags are required", + "severity": "MUST", + "lines": { + "first": 1, + "last": 1, + "step": 1 + }, + "pointer": { + "_nextSegment": { + "_nextSegment": { + "_nextSegment": { + "_asString": "", + "_matchingPropertyName": "", + "_matchingElementIndex": -1 + }, + "_asString": "/tags", + "_matchingPropertyName": "tags", + "_matchingElementIndex": -1 + }, + "_asString": "/info/tags", + "_matchingPropertyName": "info", + "_matchingElementIndex": -1 + }, + "_asString": "/openapi/info/tags", + "_matchingPropertyName": "openapi", + "_matchingElementIndex": -1 + } + }, + { + "rule": { + "id": 15, + "ruleId": "B001", + "enabled": true, + "title": "No license information allowed.", + "ruleSet": "BoatRuleSet", + "severity": "MUST", + "url": "https://backbase.github.io/backbase-openapi-tools/rules.md#b001-no-license-information-allowed-" + }, + "description": "OpenAPI must not contain a license because it\u0027s covered by the License Agreement we already negotiate with customers. ", + "severity": "MUST", + "lines": { + "first": 1, + "last": 1, + "step": 1 + }, + "pointer": { + "_nextSegment": { + "_nextSegment": { + "_nextSegment": { + "_asString": "", + "_matchingPropertyName": "", + "_matchingElementIndex": -1 + }, + "_asString": "/version", + "_matchingPropertyName": "version", + "_matchingElementIndex": -1 + }, + "_asString": "/info/version", + "_matchingPropertyName": "info", + "_matchingElementIndex": -1 + }, + "_asString": "/openapi/info/version", + "_matchingPropertyName": "openapi", + "_matchingElementIndex": -1 + } + }, + { + "rule": { + "id": 23, + "ruleId": "M0012", + "enabled": true, + "title": "Open API Version must be set to the correct version", + "ruleSet": "BoatRuleSet", + "severity": "MUST", + "url": "https://backbase.github.io/backbase-openapi-tools/rules.md#m0012-open-api-version-must-be-set-to-the-correct-version" + }, + "description": "OpenAPI specification version must be [3.0.3, 3.0.4]. It\u0027s now set to `3.0.0`", + "severity": "MUST", + "lines": { + "first": 1, + "last": 1, + "step": 1 + }, + "pointer": { + "_nextSegment": { + "_asString": "", + "_matchingPropertyName": "", + "_matchingElementIndex": -1 + }, + "_asString": "/openapi", + "_matchingPropertyName": "openapi", + "_matchingElementIndex": -1 + } + }, + { + "rule": { + "id": 21, + "ruleId": "B007", + "enabled": true, + "title": "Check prefix for paths", + "ruleSet": "BoatRuleSet", + "severity": "MUST", + "url": "https://backbase.github.io/backbase-openapi-tools/rules.md#b007-check-prefix-for-paths" + }, + "description": "Incorrect path prefix: pets. Correct values are [client-api, service-api, integration-api]", + "severity": "MUST", + "lines": { + "first": 65, + "last": 91, + "step": 1 + }, + "pointer": { + "_nextSegment": { + "_nextSegment": { + "_asString": "", + "_matchingPropertyName": "", + "_matchingElementIndex": -1 + }, + "_asString": "/~1pets~1{petId}", + "_matchingPropertyName": "/pets/{petId}", + "_matchingElementIndex": -1 + }, + "_asString": "/paths/~1pets~1{petId}", + "_matchingPropertyName": "paths", + "_matchingElementIndex": -1 + } + }, + { + "rule": { + "id": 21, + "ruleId": "B007", + "enabled": true, + "title": "Check prefix for paths", + "ruleSet": "BoatRuleSet", + "severity": "MUST", + "url": "https://backbase.github.io/backbase-openapi-tools/rules.md#b007-check-prefix-for-paths" + }, + "description": "Incorrect path prefix: no-schema. Correct values are [client-api, service-api, integration-api]", + "severity": "MUST", + "lines": { + "first": 91, + "last": 102, + "step": 1 + }, + "pointer": { + "_nextSegment": { + "_nextSegment": { + "_asString": "", + "_matchingPropertyName": "", + "_matchingElementIndex": -1 + }, + "_asString": "/~1no-schema", + "_matchingPropertyName": "/no-schema", + "_matchingElementIndex": -1 + }, + "_asString": "/paths/~1no-schema", + "_matchingPropertyName": "paths", + "_matchingElementIndex": -1 + } + }, + { + "rule": { + "id": 22, + "ruleId": "B009", + "enabled": true, + "title": "Check prefix for paths should contain version.", + "ruleSet": "BoatRuleSet", + "severity": "MUST", + "url": "https://backbase.github.io/backbase-openapi-tools/rules.md#b009-check-prefix-for-paths-should-contain-version-" + }, + "description": "URL should contain version number", + "severity": "MUST", + "lines": { + "first": 10, + "last": 65, + "step": 1 + }, + "pointer": { + "_nextSegment": { + "_nextSegment": { + "_asString": "", + "_matchingPropertyName": "", + "_matchingElementIndex": -1 + }, + "_asString": "/~1pets", + "_matchingPropertyName": "/pets", + "_matchingElementIndex": -1 + }, + "_asString": "/paths/~1pets", + "_matchingPropertyName": "paths", + "_matchingElementIndex": -1 + } + }, + { + "rule": { + "id": 22, + "ruleId": "B009", + "enabled": true, + "title": "Check prefix for paths should contain version.", + "ruleSet": "BoatRuleSet", + "severity": "MUST", + "url": "https://backbase.github.io/backbase-openapi-tools/rules.md#b009-check-prefix-for-paths-should-contain-version-" + }, + "description": "URL should contain version number", + "severity": "MUST", + "lines": { + "first": 65, + "last": 91, + "step": 1 + }, + "pointer": { + "_nextSegment": { + "_nextSegment": { + "_asString": "", + "_matchingPropertyName": "", + "_matchingElementIndex": -1 + }, + "_asString": "/~1pets~1{petId}", + "_matchingPropertyName": "/pets/{petId}", + "_matchingElementIndex": -1 + }, + "_asString": "/paths/~1pets~1{petId}", + "_matchingPropertyName": "paths", + "_matchingElementIndex": -1 + } + }, + { + "rule": { + "id": 22, + "ruleId": "B009", + "enabled": true, + "title": "Check prefix for paths should contain version.", + "ruleSet": "BoatRuleSet", + "severity": "MUST", + "url": "https://backbase.github.io/backbase-openapi-tools/rules.md#b009-check-prefix-for-paths-should-contain-version-" + }, + "description": "URL should contain version number", + "severity": "MUST", + "lines": { + "first": 91, + "last": 102, + "step": 1 + }, + "pointer": { + "_nextSegment": { + "_nextSegment": { + "_asString": "", + "_matchingPropertyName": "", + "_matchingElementIndex": -1 + }, + "_asString": "/~1no-schema", + "_matchingPropertyName": "/no-schema", + "_matchingElementIndex": -1 + }, + "_asString": "/paths/~1no-schema", + "_matchingPropertyName": "paths", + "_matchingElementIndex": -1 + } + } + ] + } + ] + + } + } +] \ No newline at end of file diff --git a/boat-maven-plugin/src/test/resources/oas-examples/petstore-v1.0.0.yaml b/boat-maven-plugin/src/test/resources/oas-examples/petstore-v1.0.0.yaml new file mode 100644 index 000000000..137eaff93 --- /dev/null +++ b/boat-maven-plugin/src/test/resources/oas-examples/petstore-v1.0.0.yaml @@ -0,0 +1,138 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /pets: + get: + summary: List all pets + operationId: listPets + tags: + - pets + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + format: int32 + responses: + '200': + description: A paged array of pets + headers: + x-next: + description: A link to the next page of responses + schema: + type: string + content: + application/json: + schema: + $ref: "#/components/schemas/Pets" + text/csv: + schema: + type: string + 500: + content: + application/json: + schema: + $ref: '#/components/schemas/InternalServerError' + description: InternalServerError + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + summary: Create a pet + operationId: createPets + tags: + - pets + responses: + '201': + description: Null response + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /pets/{petId}: + get: + summary: Info for a specific pet + operationId: showPetById + tags: + - pets + parameters: + - name: petId + in: path + required: true + description: The id of the pet to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /no-schema: + get: + summary: No Schema + operationId: getNoSchema + tags: + - pets + responses: + 200: + description: A response that does not specify a schema + content: + application/json: {} +components: + schemas: + Pet: + type: object + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + tag: + type: string + Pets: + type: array + items: + $ref: "#/components/schemas/Pet" + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string + InternalServerError: + type: object + required: + - message + properties: + message: + type: string \ No newline at end of file