From 116f7e9d7c2c4f43e3873d9748de9c3420c6d841 Mon Sep 17 00:00:00 2001 From: Josh Kellendonk Date: Thu, 11 Nov 2021 11:03:33 -0700 Subject: [PATCH 1/5] feat: add a maven plugin --- maven/pom.xml | 64 +++++++++++++++++ .../BackwardIncompatibilityException.java | 9 +++ .../openapidiff/maven/OpenApiDiffMojo.java | 38 +++++++++++ .../maven/OpenApiDiffMojoTest.java | 68 +++++++++++++++++++ maven/src/test/resources/newspec.yaml | 15 ++++ maven/src/test/resources/oldspec.yaml | 6 ++ pom.xml | 1 + 7 files changed, 201 insertions(+) create mode 100644 maven/pom.xml create mode 100644 maven/src/main/java/org/openapitools/openapidiff/maven/BackwardIncompatibilityException.java create mode 100644 maven/src/main/java/org/openapitools/openapidiff/maven/OpenApiDiffMojo.java create mode 100644 maven/src/test/java/org/openapitools/openapidiff/maven/OpenApiDiffMojoTest.java create mode 100644 maven/src/test/resources/newspec.yaml create mode 100644 maven/src/test/resources/oldspec.yaml 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/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..8376f48ec --- /dev/null +++ b/maven/src/main/java/org/openapitools/openapidiff/maven/OpenApiDiffMojo.java @@ -0,0 +1,38 @@ +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 = "failWhenIncompatible", defaultValue = "false") + Boolean failWhenIncompatible = false; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + try { + final ChangedOpenApi diff = OpenApiCompare.fromLocations(oldSpec, newSpec); + getLog().info(new ConsoleRender().render(diff)); + + if (failWhenIncompatible && !diff.isCompatible()) { + throw new BackwardIncompatibilityException("The API changes broke backward compatibility"); + } + } 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..915d97296 --- /dev/null +++ b/maven/src/test/java/org/openapitools/openapidiff/maven/OpenApiDiffMojoTest.java @@ -0,0 +1,68 @@ +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.failWhenIncompatible = 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.failWhenIncompatible = true; + + assertDoesNotThrow(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.failWhenIncompatible = 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..92ca4ff79 100644 --- a/pom.xml +++ b/pom.xml @@ -3,6 +3,7 @@ core cli + maven org.openapitools.openapidiff From a5c99f7a80210abd64db3fc27607ee1d3b36aaaa Mon Sep 17 00:00:00 2001 From: Josh Kellendonk Date: Sun, 14 Nov 2021 11:47:58 -0700 Subject: [PATCH 2/5] feat: add failure parameters matching the cli options --- .../openapidiff/maven/ApiChangedException.java | 9 +++++++++ .../openapidiff/maven/OpenApiDiffMojo.java | 13 ++++++++++--- .../openapidiff/maven/OpenApiDiffMojoTest.java | 16 +++++++++++++--- 3 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 maven/src/main/java/org/openapitools/openapidiff/maven/ApiChangedException.java 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/OpenApiDiffMojo.java b/maven/src/main/java/org/openapitools/openapidiff/maven/OpenApiDiffMojo.java index 8376f48ec..118274ed1 100644 --- a/maven/src/main/java/org/openapitools/openapidiff/maven/OpenApiDiffMojo.java +++ b/maven/src/main/java/org/openapitools/openapidiff/maven/OpenApiDiffMojo.java @@ -19,8 +19,11 @@ public class OpenApiDiffMojo extends AbstractMojo { @Parameter(property = "newSpec") String newSpec; - @Parameter(property = "failWhenIncompatible", defaultValue = "false") - Boolean failWhenIncompatible = false; + @Parameter(property = "failOnIncompatible", defaultValue = "false") + Boolean failOnIncompatible = false; + + @Parameter(property = "failOnChanged", defaultValue = "false") + Boolean failOnChanged = false; @Override public void execute() throws MojoExecutionException, MojoFailureException { @@ -28,9 +31,13 @@ public void execute() throws MojoExecutionException, MojoFailureException { final ChangedOpenApi diff = OpenApiCompare.fromLocations(oldSpec, newSpec); getLog().info(new ConsoleRender().render(diff)); - if (failWhenIncompatible && !diff.isCompatible()) { + if (failOnIncompatible && !diff.isCompatible()) { 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 index 915d97296..5ecc457e5 100644 --- a/maven/src/test/java/org/openapitools/openapidiff/maven/OpenApiDiffMojoTest.java +++ b/maven/src/test/java/org/openapitools/openapidiff/maven/OpenApiDiffMojoTest.java @@ -14,7 +14,7 @@ void Should_NotThrow_When_SpecHasNoChanges() { final OpenApiDiffMojo mojo = new OpenApiDiffMojo(); mojo.oldSpec = oldSpec; mojo.newSpec = oldSpec; - mojo.failWhenIncompatible = true; + mojo.failOnIncompatible = true; assertDoesNotThrow(mojo::execute); } @@ -24,11 +24,21 @@ 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.failWhenIncompatible = true; + 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(); @@ -61,7 +71,7 @@ void Should_BackwardIncompatibilityException_When_WantsExceptionAndSpecIsIncompa 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.failWhenIncompatible = true; + mojo.failOnIncompatible = true; assertThrows(BackwardIncompatibilityException.class, mojo::execute); } From d1a0d8980bd4172d081a4f079d97ecb967893fdd Mon Sep 17 00:00:00 2001 From: Josh Kellendonk Date: Sun, 14 Nov 2021 12:01:54 -0700 Subject: [PATCH 3/5] refactor: simplify the incompatibility checking --- .../org/openapitools/openapidiff/maven/OpenApiDiffMojo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maven/src/main/java/org/openapitools/openapidiff/maven/OpenApiDiffMojo.java b/maven/src/main/java/org/openapitools/openapidiff/maven/OpenApiDiffMojo.java index 118274ed1..900410420 100644 --- a/maven/src/main/java/org/openapitools/openapidiff/maven/OpenApiDiffMojo.java +++ b/maven/src/main/java/org/openapitools/openapidiff/maven/OpenApiDiffMojo.java @@ -31,7 +31,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { final ChangedOpenApi diff = OpenApiCompare.fromLocations(oldSpec, newSpec); getLog().info(new ConsoleRender().render(diff)); - if (failOnIncompatible && !diff.isCompatible()) { + if (failOnIncompatible && diff.isIncompatible()) { throw new BackwardIncompatibilityException("The API changes broke backward compatibility"); } From 59aae3af37ecf1fa9a6e72fbee1a67343c4b4100 Mon Sep 17 00:00:00 2001 From: Josh Kellendonk Date: Sun, 14 Nov 2021 12:04:50 -0700 Subject: [PATCH 4/5] docs: add maven plugin docs --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) 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 From b644eee7f2258adefae86a31c5d4489cce407ef4 Mon Sep 17 00:00:00 2001 From: Josh Kellendonk Date: Sun, 14 Nov 2021 15:09:49 -0700 Subject: [PATCH 5/5] chore: add josh kellendonk to the developer list --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index 92ca4ff79..0ae4c3d2a 100644 --- a/pom.xml +++ b/pom.xml @@ -32,6 +32,11 @@ jochen@schalanda.name https://github.com/joschi + + Josh Kellendonk + joshkellendonk@gmail.com + https://github.com/misterjoshua +