diff --git a/README.md b/README.md index 07afff0e4..95648473e 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,35 @@ usage: openapi-diff --warn Print warning information ``` +## Maven Plugin + +Add openapi-diff to your POM to show diffs when you test your Maven project. You may opt to throw an error if you have broken backwards compatibility or if your API has changed. + +```xml + + org.openapitools.openapidiff + openapi-diff-maven + ${openapi-diff-version} + + + + diff + + + + https://petstore3.swagger.io/api/v3/openapi.json + + ${project.basedir}/target/openapi.yaml + + true + + true + + + + +``` + ## Direct Invocation ```java diff --git a/maven/pom.xml b/maven/pom.xml new file mode 100644 index 000000000..0da54d38b --- /dev/null +++ b/maven/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + + org.openapitools.openapidiff + openapi-diff-parent + 2.0.0-SNAPSHOT + + + openapi-diff-maven + jar + + openapi-diff-maven + Maven plugin for openapi-diff + + + + org.apache.maven + maven-plugin-api + 3.6.0 + provided + + + org.apache.maven + maven-core + 3.6.0 + provided + + + org.apache.maven.plugin-tools + maven-plugin-annotations + 3.4 + provided + + + + org.openapitools.openapidiff + openapi-diff-core + + + org.junit.jupiter + junit-jupiter + test + + + + + + + + org.apache.maven.plugins + maven-plugin-plugin + 3.6.0 + + + org.apache.maven.plugins + maven-site-plugin + 3.8.2 + + + + + diff --git a/maven/src/main/java/org/openapitools/openapidiff/maven/ApiChangedException.java b/maven/src/main/java/org/openapitools/openapidiff/maven/ApiChangedException.java new file mode 100644 index 000000000..da7f3ad3b --- /dev/null +++ b/maven/src/main/java/org/openapitools/openapidiff/maven/ApiChangedException.java @@ -0,0 +1,9 @@ +package org.openapitools.openapidiff.maven; + +import org.apache.maven.plugin.MojoFailureException; + +public class ApiChangedException extends MojoFailureException { + public ApiChangedException(String message) { + super(message); + } +} diff --git a/maven/src/main/java/org/openapitools/openapidiff/maven/BackwardIncompatibilityException.java b/maven/src/main/java/org/openapitools/openapidiff/maven/BackwardIncompatibilityException.java new file mode 100644 index 000000000..32c80732e --- /dev/null +++ b/maven/src/main/java/org/openapitools/openapidiff/maven/BackwardIncompatibilityException.java @@ -0,0 +1,9 @@ +package org.openapitools.openapidiff.maven; + +import org.apache.maven.plugin.MojoFailureException; + +class BackwardIncompatibilityException extends MojoFailureException { + public BackwardIncompatibilityException(String message) { + super(message); + } +} diff --git a/maven/src/main/java/org/openapitools/openapidiff/maven/OpenApiDiffMojo.java b/maven/src/main/java/org/openapitools/openapidiff/maven/OpenApiDiffMojo.java new file mode 100644 index 000000000..900410420 --- /dev/null +++ b/maven/src/main/java/org/openapitools/openapidiff/maven/OpenApiDiffMojo.java @@ -0,0 +1,45 @@ +package org.openapitools.openapidiff.maven; + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.openapitools.openapidiff.core.OpenApiCompare; +import org.openapitools.openapidiff.core.model.ChangedOpenApi; +import org.openapitools.openapidiff.core.output.ConsoleRender; + +/** A Maven Mojo that diffs two OpenAPI specifications and reports on differences. */ +@Mojo(name = "diff", defaultPhase = LifecyclePhase.TEST) +public class OpenApiDiffMojo extends AbstractMojo { + @Parameter(property = "oldSpec") + String oldSpec; + + @Parameter(property = "newSpec") + String newSpec; + + @Parameter(property = "failOnIncompatible", defaultValue = "false") + Boolean failOnIncompatible = false; + + @Parameter(property = "failOnChanged", defaultValue = "false") + Boolean failOnChanged = false; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + try { + final ChangedOpenApi diff = OpenApiCompare.fromLocations(oldSpec, newSpec); + getLog().info(new ConsoleRender().render(diff)); + + if (failOnIncompatible && diff.isIncompatible()) { + throw new BackwardIncompatibilityException("The API changes broke backward compatibility"); + } + + if (failOnChanged && diff.isDifferent()) { + throw new ApiChangedException("The API changed"); + } + } catch (RuntimeException e) { + throw new MojoExecutionException("Unexpected error", e); + } + } +} diff --git a/maven/src/test/java/org/openapitools/openapidiff/maven/OpenApiDiffMojoTest.java b/maven/src/test/java/org/openapitools/openapidiff/maven/OpenApiDiffMojoTest.java new file mode 100644 index 000000000..5ecc457e5 --- /dev/null +++ b/maven/src/test/java/org/openapitools/openapidiff/maven/OpenApiDiffMojoTest.java @@ -0,0 +1,78 @@ +package org.openapitools.openapidiff.maven; + +import static org.junit.jupiter.api.Assertions.*; + +import java.io.File; +import org.apache.maven.plugin.MojoExecutionException; +import org.junit.jupiter.api.Test; + +class OpenApiDiffMojoTest { + @Test + void Should_NotThrow_When_SpecHasNoChanges() { + final String oldSpec = new File("src/test/resources/oldspec.yaml").getAbsolutePath(); + + final OpenApiDiffMojo mojo = new OpenApiDiffMojo(); + mojo.oldSpec = oldSpec; + mojo.newSpec = oldSpec; + mojo.failOnIncompatible = true; + + assertDoesNotThrow(mojo::execute); + } + + @Test + void Should_NotThrow_When_SpecIsCompatible() { + final OpenApiDiffMojo mojo = new OpenApiDiffMojo(); + mojo.oldSpec = new File("src/test/resources/oldspec.yaml").getAbsolutePath(); + mojo.newSpec = new File("src/test/resources/newspec.yaml").getAbsolutePath(); + mojo.failOnIncompatible = true; + + assertDoesNotThrow(mojo::execute); + } + + @Test + void Should_Throw_When_SpecIsDifferent() { + final OpenApiDiffMojo mojo = new OpenApiDiffMojo(); + mojo.oldSpec = new File("src/test/resources/oldspec.yaml").getAbsolutePath(); + mojo.newSpec = new File("src/test/resources/newspec.yaml").getAbsolutePath(); + mojo.failOnChanged = true; + + assertThrows(ApiChangedException.class, mojo::execute); + } + + @Test + void Should_MojoExecutionException_When_MissingOldSpec() { + final OpenApiDiffMojo mojo = new OpenApiDiffMojo(); + mojo.oldSpec = new File("DOES_NOT_EXIST").getAbsolutePath(); + mojo.newSpec = new File("src/test/resources/newspec.yaml").getAbsolutePath(); + + assertThrows(MojoExecutionException.class, mojo::execute); + } + + @Test + void Should_MojoExecutionException_When_MissingNewSpec() { + final OpenApiDiffMojo mojo = new OpenApiDiffMojo(); + mojo.oldSpec = new File("src/test/resources/oldspec.yaml").getAbsolutePath(); + mojo.newSpec = new File("DOES_NOT_EXIST").getAbsolutePath(); + + assertThrows(MojoExecutionException.class, mojo::execute); + } + + @Test + void Should_NotThrow_When_DefaultsAndSpecIsIncompatible() { + final OpenApiDiffMojo mojo = new OpenApiDiffMojo(); + mojo.oldSpec = new File("src/test/resources/newspec.yaml").getAbsolutePath(); + mojo.newSpec = new File("src/test/resources/oldspec.yaml").getAbsolutePath(); + + assertDoesNotThrow(mojo::execute); + } + + @Test + void Should_BackwardIncompatibilityException_When_WantsExceptionAndSpecIsIncompatible() { + final OpenApiDiffMojo mojo = new OpenApiDiffMojo(); + mojo.oldSpec = new File("src/test/resources/newspec.yaml").getAbsolutePath(); + mojo.newSpec = new File("src/test/resources/oldspec.yaml").getAbsolutePath(); + mojo.failOnIncompatible = true; + + assertThrows(BackwardIncompatibilityException.class, mojo::execute); + } +} diff --git a/maven/src/test/resources/newspec.yaml b/maven/src/test/resources/newspec.yaml new file mode 100644 index 000000000..e95978f04 --- /dev/null +++ b/maven/src/test/resources/newspec.yaml @@ -0,0 +1,15 @@ +--- +openapi: 3.0.3 +info: + title: Generated API + version: "1.0" +paths: + /hello: + get: + responses: + "200": + description: OK + content: + text/plain: + schema: + type: string diff --git a/maven/src/test/resources/oldspec.yaml b/maven/src/test/resources/oldspec.yaml new file mode 100644 index 000000000..2f2735763 --- /dev/null +++ b/maven/src/test/resources/oldspec.yaml @@ -0,0 +1,6 @@ +--- +openapi: 3.0.3 +info: + title: Generated API + version: "1.0" +paths: {} diff --git a/pom.xml b/pom.xml index 1122e8e15..0ae4c3d2a 100644 --- a/pom.xml +++ b/pom.xml @@ -3,6 +3,7 @@ core cli + maven org.openapitools.openapidiff @@ -31,6 +32,11 @@ jochen@schalanda.name https://github.com/joschi + + Josh Kellendonk + joshkellendonk@gmail.com + https://github.com/misterjoshua +