diff --git a/README.md b/README.md
index c9cf9f78..60d722e7 100644
--- a/README.md
+++ b/README.md
@@ -145,6 +145,12 @@ Add openapi-diff to your POM to show diffs when you test your Maven project. You
true
true
+
+ ${project.basedir}/../maven/target/diff.txt
+
+ ${project.basedir}/../maven/target/diff.json
+
+ ${project.basedir}/../maven/target/diff.md
@@ -167,6 +173,7 @@ public class Main {
```
### Render difference
+
---
#### HTML
@@ -176,11 +183,9 @@ String html = new HtmlRender("Changelog",
.render(diff);
try {
- FileWriter fw = new FileWriter(
- "testNewApi.html");
+ FileWriter fw = new FileWriter("testNewApi.html");
fw.write(html);
fw.close();
-
} catch (IOException e) {
e.printStackTrace();
}
@@ -191,11 +196,9 @@ try {
```java
String render = new MarkdownRender().render(diff);
try {
- FileWriter fw = new FileWriter(
- "testDiff.md");
+ FileWriter fw = new FileWriter("testDiff.md");
fw.write(render);
fw.close();
-
} catch (IOException e) {
e.printStackTrace();
}
@@ -207,11 +210,9 @@ try {
```java
String render = new JsonRender().render(diff);
try {
- FileWriter fw = new FileWriter(
- "testDiff.json");
+ FileWriter fw = new FileWriter("testDiff.json");
fw.write(render);
fw.close();
-
} catch (IOException e) {
e.printStackTrace();
}
diff --git a/core/src/main/java/org/openapitools/openapidiff/core/utils/ChangedUtils.java b/core/src/main/java/org/openapitools/openapidiff/core/utils/ChangedUtils.java
index 27a5e0e2..6da806a9 100644
--- a/core/src/main/java/org/openapitools/openapidiff/core/utils/ChangedUtils.java
+++ b/core/src/main/java/org/openapitools/openapidiff/core/utils/ChangedUtils.java
@@ -5,7 +5,9 @@
public class ChangedUtils {
- private ChangedUtils() {}
+ private ChangedUtils() {
+ throw new UnsupportedOperationException("Utility class. Do not instantiate");
+ }
public static boolean isUnchanged(Changed changed) {
return changed == null || changed.isUnchanged();
diff --git a/core/src/main/java/org/openapitools/openapidiff/core/utils/Copy.java b/core/src/main/java/org/openapitools/openapidiff/core/utils/Copy.java
index 4179fd35..73c9a073 100644
--- a/core/src/main/java/org/openapitools/openapidiff/core/utils/Copy.java
+++ b/core/src/main/java/org/openapitools/openapidiff/core/utils/Copy.java
@@ -5,7 +5,9 @@
public class Copy {
- private Copy() {}
+ private Copy() {
+ throw new UnsupportedOperationException("Utility class. Do not instantiate");
+ }
public static Map copyMap(Map map) {
if (map == null) {
diff --git a/core/src/main/java/org/openapitools/openapidiff/core/utils/EndpointUtils.java b/core/src/main/java/org/openapitools/openapidiff/core/utils/EndpointUtils.java
index 749b0bdb..c749d8a5 100644
--- a/core/src/main/java/org/openapitools/openapidiff/core/utils/EndpointUtils.java
+++ b/core/src/main/java/org/openapitools/openapidiff/core/utils/EndpointUtils.java
@@ -10,7 +10,9 @@
public class EndpointUtils {
- private EndpointUtils() {}
+ private EndpointUtils() {
+ throw new UnsupportedOperationException("Utility class. Do not instantiate");
+ }
public static Collection convert2Endpoints(
String pathUrl, Map map) {
diff --git a/core/src/main/java/org/openapitools/openapidiff/core/utils/FileUtils.java b/core/src/main/java/org/openapitools/openapidiff/core/utils/FileUtils.java
new file mode 100644
index 00000000..a2c8b147
--- /dev/null
+++ b/core/src/main/java/org/openapitools/openapidiff/core/utils/FileUtils.java
@@ -0,0 +1,35 @@
+package org.openapitools.openapidiff.core.utils;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.openapitools.openapidiff.core.model.ChangedOpenApi;
+import org.openapitools.openapidiff.core.output.Render;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class FileUtils {
+ private static final Logger logger = LoggerFactory.getLogger(FileUtils.class);
+
+ private FileUtils() {
+ throw new UnsupportedOperationException("Utility class. Do not instantiate");
+ }
+
+ public static void writeToFile(
+ final Render render, final ChangedOpenApi diff, final String fileName) {
+ if (fileName == null || fileName.isEmpty()) {
+ logger.debug("File name cannot be null or empty.");
+ return;
+ }
+
+ final Path filePath = Paths.get(fileName);
+ try (final FileOutputStream outputStream = new FileOutputStream(filePath.toFile());
+ final OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream)) {
+ render.render(diff, outputStreamWriter);
+ } catch (final IOException e) {
+ logger.error("Exception while writing to file {}", fileName, e);
+ }
+ }
+}
diff --git a/core/src/main/resources/logback.xml b/core/src/main/resources/logback.xml
new file mode 100644
index 00000000..018a4277
--- /dev/null
+++ b/core/src/main/resources/logback.xml
@@ -0,0 +1,11 @@
+
+
+
+ [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/src/test/java/org/openapitools/openapidiff/core/utils/FileUtilsTest.java b/core/src/test/java/org/openapitools/openapidiff/core/utils/FileUtilsTest.java
new file mode 100644
index 00000000..5d9b4d79
--- /dev/null
+++ b/core/src/test/java/org/openapitools/openapidiff/core/utils/FileUtilsTest.java
@@ -0,0 +1,58 @@
+package org.openapitools.openapidiff.core.utils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import org.apache.commons.lang3.StringUtils;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+import org.openapitools.openapidiff.core.model.ChangedOpenApi;
+import org.openapitools.openapidiff.core.output.ConsoleRender;
+
+class FileUtilsTest {
+ private ChangedOpenApi changedOpenApi;
+
+ @BeforeEach
+ void setup() {
+ changedOpenApi = new ChangedOpenApi();
+ changedOpenApi.setChangedSchemas(Collections.emptyList());
+ changedOpenApi.setChangedOperations(Collections.emptyList());
+ changedOpenApi.setNewEndpoints(Collections.emptyList());
+ changedOpenApi.setMissingEndpoints(Collections.emptyList());
+ }
+
+ @Test
+ void writeToFile_filenameIsNull_doesNothing() {
+ assertDoesNotThrow(() -> FileUtils.writeToFile(new ConsoleRender(), changedOpenApi, null));
+ }
+
+ @Test
+ void writeToFile_filenameIsEmpty_doesNothing() {
+ assertDoesNotThrow(
+ () -> FileUtils.writeToFile(new ConsoleRender(), changedOpenApi, StringUtils.EMPTY));
+ }
+
+ @Test
+ void writeToFile_fileExists_overwrites_file(@TempDir Path tempDir) throws IOException {
+ final Path path = tempDir.resolve("output.txt");
+ Files.write(path, "Test".getBytes(StandardCharsets.UTF_8));
+
+ assertDoesNotThrow(
+ () -> FileUtils.writeToFile(new ConsoleRender(), changedOpenApi, path.toString()));
+ assertThat(path).exists().content().isNotEqualTo("Test");
+ }
+
+ @Test
+ void writeToFile_fileDoesNotExist_createsFile(@TempDir Path tempDir) {
+ final Path path = tempDir.resolve("output.txt");
+ assertDoesNotThrow(
+ () -> FileUtils.writeToFile(new ConsoleRender(), changedOpenApi, path.toString()));
+ assertThat(path).exists().content().isNotBlank();
+ }
+}
diff --git a/maven-example/pom.xml b/maven-example/pom.xml
index 46d9dda3..bb3d9c7c 100644
--- a/maven-example/pom.xml
+++ b/maven-example/pom.xml
@@ -33,6 +33,9 @@
${project.basedir}/../maven/src/test/resources/oldspec.yaml
${project.basedir}/../maven/src/test/resources/newspec.yaml
true
+ ${project.basedir}/../maven/target/diff.txt
+ ${project.basedir}/../maven/target/diff.json
+ ${project.basedir}/../maven/target/diff.md
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 af402c9f..7e0e82fb 100644
--- a/maven/src/main/java/org/openapitools/openapidiff/maven/OpenApiDiffMojo.java
+++ b/maven/src/main/java/org/openapitools/openapidiff/maven/OpenApiDiffMojo.java
@@ -1,7 +1,11 @@
package org.openapitools.openapidiff.maven;
+import static org.openapitools.openapidiff.core.utils.FileUtils.writeToFile;
+
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.io.OutputStreamWriter;
+import java.io.UncheckedIOException;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
@@ -11,10 +15,13 @@
import org.openapitools.openapidiff.core.OpenApiCompare;
import org.openapitools.openapidiff.core.model.ChangedOpenApi;
import org.openapitools.openapidiff.core.output.ConsoleRender;
+import org.openapitools.openapidiff.core.output.JsonRender;
+import org.openapitools.openapidiff.core.output.MarkdownRender;
/** 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;
@@ -30,6 +37,15 @@ public class OpenApiDiffMojo extends AbstractMojo {
@Parameter(property = "skip", defaultValue = "false")
Boolean skip = false;
+ @Parameter(property = "consoleOutputFileName")
+ String consoleOutputFileName;
+
+ @Parameter(property = "jsonOutputFileName")
+ String jsonOutputFileName;
+
+ @Parameter(property = "markdownOutputFileName")
+ String markdownOutputFileName;
+
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
if (Boolean.TRUE.equals(skip)) {
@@ -39,10 +55,18 @@ public void execute() throws MojoExecutionException, MojoFailureException {
try {
final ChangedOpenApi diff = OpenApiCompare.fromLocations(oldSpec, newSpec);
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
- new ConsoleRender().render(diff, outputStreamWriter);
- getLog().info(outputStream.toString());
+
+ try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream)) {
+ new ConsoleRender().render(diff, outputStreamWriter);
+ getLog().info(outputStream.toString());
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+
+ writeDiffAsTextToFile(diff);
+ writeDiffAsJsonToFile(diff);
+ writeDiffAsMarkdownToFile(diff);
if (failOnIncompatible && diff.isIncompatible()) {
throw new BackwardIncompatibilityException("The API changes broke backward compatibility");
@@ -55,4 +79,16 @@ public void execute() throws MojoExecutionException, MojoFailureException {
throw new MojoExecutionException("Unexpected error", e);
}
}
+
+ private void writeDiffAsTextToFile(final ChangedOpenApi diff) {
+ writeToFile(new ConsoleRender(), diff, consoleOutputFileName);
+ }
+
+ private void writeDiffAsJsonToFile(final ChangedOpenApi diff) {
+ writeToFile(new JsonRender(), diff, jsonOutputFileName);
+ }
+
+ private void writeDiffAsMarkdownToFile(final ChangedOpenApi diff) {
+ writeToFile(new MarkdownRender(), diff, markdownOutputFileName);
+ }
}
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 7deae423..10bd186e 100644
--- a/maven/src/test/java/org/openapitools/openapidiff/maven/OpenApiDiffMojoTest.java
+++ b/maven/src/test/java/org/openapitools/openapidiff/maven/OpenApiDiffMojoTest.java
@@ -1,15 +1,44 @@
package org.openapitools.openapidiff.maven;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import org.apache.maven.plugin.MojoExecutionException;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
class OpenApiDiffMojoTest {
+
+ private static final Logger logger = LoggerFactory.getLogger(OpenApiDiffMojoTest.class);
+
+ private final File oldSpecFile = new File("src/test/resources/oldspec.yaml");
+ private final File newSpecFile = new File("src/test/resources/newspec.yaml");
+
+ private final File consoleOutputfile = new File("target/diff.txt");
+ private final File markdownOutputfile = new File("target/diff.md");
+ private final File jsonOutputfile = new File("target/diff.json");
+
+ @BeforeEach
+ void setup() {
+ cleanupGeneratedFiles();
+ }
+
+ @AfterEach
+ void tearDown() {
+ cleanupGeneratedFiles();
+ }
+
@Test
void Should_NotThrow_When_SpecHasNoChanges() {
- final String oldSpec = new File("src/test/resources/oldspec.yaml").getAbsolutePath();
+ final String oldSpec = oldSpecFile.getAbsolutePath();
final OpenApiDiffMojo mojo = new OpenApiDiffMojo();
mojo.oldSpec = oldSpec;
@@ -22,8 +51,8 @@ void Should_NotThrow_When_SpecHasNoChanges() {
@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.oldSpec = oldSpecFile.getAbsolutePath();
+ mojo.newSpec = newSpecFile.getAbsolutePath();
mojo.failOnIncompatible = true;
assertDoesNotThrow(mojo::execute);
@@ -32,8 +61,8 @@ void Should_NotThrow_When_SpecIsCompatible() {
@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.oldSpec = oldSpecFile.getAbsolutePath();
+ mojo.newSpec = newSpecFile.getAbsolutePath();
mojo.failOnChanged = true;
assertThrows(ApiChangedException.class, mojo::execute);
@@ -43,7 +72,7 @@ void Should_Throw_When_SpecIsDifferent() {
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();
+ mojo.newSpec = newSpecFile.getAbsolutePath();
assertThrows(MojoExecutionException.class, mojo::execute);
}
@@ -51,7 +80,7 @@ void Should_MojoExecutionException_When_MissingOldSpec() {
@Test
void Should_MojoExecutionException_When_MissingNewSpec() {
final OpenApiDiffMojo mojo = new OpenApiDiffMojo();
- mojo.oldSpec = new File("src/test/resources/oldspec.yaml").getAbsolutePath();
+ mojo.oldSpec = oldSpecFile.getAbsolutePath();
mojo.newSpec = new File("DOES_NOT_EXIST").getAbsolutePath();
assertThrows(MojoExecutionException.class, mojo::execute);
@@ -60,8 +89,8 @@ void Should_MojoExecutionException_When_MissingNewSpec() {
@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();
+ mojo.oldSpec = newSpecFile.getAbsolutePath();
+ mojo.newSpec = oldSpecFile.getAbsolutePath();
assertDoesNotThrow(mojo::execute);
}
@@ -69,8 +98,8 @@ void Should_NotThrow_When_DefaultsAndSpecIsIncompatible() {
@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.oldSpec = newSpecFile.getAbsolutePath();
+ mojo.newSpec = oldSpecFile.getAbsolutePath();
mojo.failOnIncompatible = true;
assertThrows(BackwardIncompatibilityException.class, mojo::execute);
@@ -79,11 +108,73 @@ void Should_BackwardIncompatibilityException_When_WantsExceptionAndSpecIsIncompa
@Test
void Should_Skip_Mojo_WhenSkipIsTrue() {
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.oldSpec = newSpecFile.getAbsolutePath();
+ mojo.newSpec = oldSpecFile.getAbsolutePath();
mojo.failOnIncompatible = true;
mojo.skip = true;
assertDoesNotThrow(mojo::execute);
}
+
+ @Test
+ void Should_outputToTextFile_When_SpecIsDifferent() {
+ final OpenApiDiffMojo mojo = new OpenApiDiffMojo();
+ mojo.oldSpec = oldSpecFile.getAbsolutePath();
+ mojo.newSpec = newSpecFile.getAbsolutePath();
+
+ mojo.consoleOutputFileName = consoleOutputfile.getAbsolutePath();
+ mojo.failOnChanged = true;
+
+ assertThrows(ApiChangedException.class, mojo::execute);
+
+ assertTrue(Files.exists(consoleOutputfile.toPath()));
+ }
+
+ @Test
+ void Should_outputToMarkdownFile_When_SpecIsDifferent() {
+ final OpenApiDiffMojo mojo = new OpenApiDiffMojo();
+ mojo.oldSpec = oldSpecFile.getAbsolutePath();
+ mojo.newSpec = newSpecFile.getAbsolutePath();
+
+ mojo.markdownOutputFileName = markdownOutputfile.getAbsolutePath();
+ mojo.failOnChanged = true;
+
+ assertThrows(ApiChangedException.class, mojo::execute);
+
+ assertTrue(Files.exists(markdownOutputfile.toPath()));
+ }
+
+ @Test
+ void Should_outputToJsonFile_When_SpecIsDifferent() {
+ final OpenApiDiffMojo mojo = new OpenApiDiffMojo();
+ mojo.oldSpec = oldSpecFile.getAbsolutePath();
+ mojo.newSpec = newSpecFile.getAbsolutePath();
+
+ mojo.jsonOutputFileName = jsonOutputfile.getAbsolutePath();
+ mojo.failOnChanged = true;
+
+ assertThrows(ApiChangedException.class, mojo::execute);
+
+ assertTrue(Files.exists(jsonOutputfile.toPath()));
+ }
+
+ private void cleanupGeneratedFiles() {
+ try {
+ Files.deleteIfExists(Paths.get(consoleOutputfile.getPath()));
+ } catch (IOException ioException) {
+ logger.warn("Exception while trying to delete file {}", consoleOutputfile.getAbsolutePath());
+ }
+
+ try {
+ Files.deleteIfExists(Paths.get(markdownOutputfile.getPath()));
+ } catch (IOException ioException) {
+ logger.warn("Exception while trying to delete file {}", markdownOutputfile.getAbsolutePath());
+ }
+
+ try {
+ Files.deleteIfExists(Paths.get(jsonOutputfile.getPath()));
+ } catch (IOException ioException) {
+ logger.warn("Exception while trying to delete file {}", jsonOutputfile.getAbsolutePath());
+ }
+ }
}
diff --git a/maven/src/test/resources/logback.xml b/maven/src/test/resources/logback.xml
new file mode 100644
index 00000000..018a4277
--- /dev/null
+++ b/maven/src/test/resources/logback.xml
@@ -0,0 +1,11 @@
+
+
+
+ [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
\ No newline at end of file