Skip to content

Commit

Permalink
Merge branch 'master' into issue-501
Browse files Browse the repository at this point in the history
Conflicts:
	maven/src/main/java/org/openapitools/openapidiff/maven/OpenApiDiffMojo.java
  • Loading branch information
joschi committed Jul 25, 2023
2 parents 37b520c + 3c026ef commit c613abb
Show file tree
Hide file tree
Showing 163 changed files with 5,766 additions and 1,127 deletions.
46 changes: 19 additions & 27 deletions cli/src/main/java/org/openapitools/openapidiff/cli/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import ch.qos.logback.classic.Level;
import io.swagger.v3.parser.core.models.AuthorizationValue;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.Collections;
import java.util.List;
import org.apache.commons.cli.CommandLine;
Expand All @@ -14,7 +14,6 @@
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.openapitools.openapidiff.core.OpenApiCompare;
import org.openapitools.openapidiff.core.model.ChangedOpenApi;
Expand Down Expand Up @@ -175,29 +174,33 @@ public static void main(String... args) {
ChangedOpenApi result = OpenApiCompare.fromLocations(oldPath, newPath, auths);
ConsoleRender consoleRender = new ConsoleRender();
if (!logLevel.equals("OFF")) {
System.out.println(consoleRender.render(result));
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
consoleRender.render(result, outputStreamWriter);
System.out.println(outputStream);
}
if (line.hasOption("html")) {
HtmlRender htmlRender = new HtmlRender();
String output = htmlRender.render(result);
String outputFile = line.getOptionValue("html");
writeOutput(output, outputFile);
FileOutputStream outputStream = new FileOutputStream(line.getOptionValue("html"));
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
htmlRender.render(result, outputStreamWriter);
}
if (line.hasOption("markdown")) {
MarkdownRender mdRender = new MarkdownRender();
String output = mdRender.render(result);
String outputFile = line.getOptionValue("markdown");
writeOutput(output, outputFile);
FileOutputStream outputStream = new FileOutputStream(line.getOptionValue("markdown"));
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
mdRender.render(result, outputStreamWriter);
}
if (line.hasOption("text")) {
String output = consoleRender.render(result);
String outputFile = line.getOptionValue("text");
writeOutput(output, outputFile);
FileOutputStream outputStream = new FileOutputStream(line.getOptionValue("text"));
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
consoleRender.render(result, outputStreamWriter);
}
if (line.hasOption("json")) {
JsonRender jsonRender = new JsonRender();
String outputFile = line.getOptionValue("json");
jsonRender.renderToFile(result, outputFile);
FileOutputStream outputStream = new FileOutputStream(line.getOptionValue("json"));
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
jsonRender.render(result, outputStreamWriter);
}
if (line.hasOption("state")) {
System.out.println(result.isChanged().getValue());
Expand All @@ -222,17 +225,6 @@ public static void main(String... args) {
}
}

private static void writeOutput(String output, String outputFile) {
File file = new File(outputFile);
logger.debug("Output file: {}", file.getAbsolutePath());
try {
FileUtils.writeStringToFile(file, output, StandardCharsets.UTF_8);
} catch (IOException e) {
logger.error("Impossible to write output to file {}", outputFile, e);
System.exit(2);
}
}

public static void printHelp(Options options) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("openapi-diff <old> <new>", options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.openapidiff.core.model.Changed;
import org.openapitools.openapidiff.core.model.ChangedParameters;
import org.openapitools.openapidiff.core.model.DiffContext;
Expand Down Expand Up @@ -99,7 +100,7 @@ public boolean pathUnchangedParametersChanged(
// Speedy Check. Use the map already created in changedParameters to check if missing param is
// linked to newParam
String newParameterName = context.getParameters().get(parameter.getName());
if (newParameterName.isEmpty()) return false;
if (StringUtils.isBlank(newParameterName)) return false;

Optional<Parameter> newParameter =
changedParameters.getIncreased().stream()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.openapitools.openapidiff.core.exception;

public class RendererException extends RuntimeException {

public RendererException(Throwable cause) {
super(cause);
}

public RendererException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.openapitools.openapidiff.core.model;

import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.media.Schema;
import java.util.*;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -157,9 +156,6 @@ private DiffResult calculateCoreChanged() {
}

private boolean compatibleForRequest() {
if (PathItem.HttpMethod.PUT.equals(context.getMethod()) && !increasedProperties.isEmpty()) {
return false;
}
return (oldSchema != null || newSchema == null);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ public DiffResult isCoreChanged() {
&& !changedBearerFormat
&& !changedOpenIdConnectUrl
&& (changedScopes == null || changedScopes.getIncreased().isEmpty())) {

// TODO: Dead code removal opportunity for changedType and changedIn. It appears that
// SecuritySchemaDiff will never be given the chance to detect differences TYPE and
// IN differences because that case has already been detected and filtered out by
// SecurityRequirementsDiff and recorded as a dropped requirement in
// ChangedSecurityRequirements.

return DiffResult.COMPATIBLE;
}
return DiffResult.INCOMPATIBLE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.responses.ApiResponse;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.openapidiff.core.exception.RendererException;
import org.openapitools.openapidiff.core.model.*;
import org.openapitools.openapidiff.core.utils.RefPointer;
import org.openapitools.openapidiff.core.utils.RefType;
Expand All @@ -21,81 +24,78 @@ public class ConsoleRender implements Render {
protected ChangedOpenApi diff;

@Override
public String render(ChangedOpenApi diff) {
public void render(ChangedOpenApi diff, OutputStreamWriter outputStreamWriter) {
this.diff = diff;
StringBuilder output = new StringBuilder();
if (diff.isUnchanged()) {
output.append("No differences. Specifications are equivalents");
safelyAppend(outputStreamWriter, "No differences. Specifications are equivalents");
} else {
output
.append(bigTitle("Api Change Log"))
.append(StringUtils.center(diff.getNewSpecOpenApi().getInfo().getTitle(), LINE_LENGTH))
.append(System.lineSeparator());
safelyAppend(outputStreamWriter, bigTitle("Api Change Log"));
safelyAppend(
outputStreamWriter,
StringUtils.center(diff.getNewSpecOpenApi().getInfo().getTitle(), LINE_LENGTH));
safelyAppend(outputStreamWriter, System.lineSeparator());

List<Endpoint> newEndpoints = diff.getNewEndpoints();
String ol_newEndpoint = listEndpoints(newEndpoints, "What's New");
listEndpoints(newEndpoints, "What's New", outputStreamWriter);

List<Endpoint> missingEndpoints = diff.getMissingEndpoints();
String ol_missingEndpoint = listEndpoints(missingEndpoints, "What's Deleted");
listEndpoints(missingEndpoints, "What's Deleted", outputStreamWriter);

List<Endpoint> deprecatedEndpoints = diff.getDeprecatedEndpoints();
String ol_deprecatedEndpoint = listEndpoints(deprecatedEndpoints, "What's Deprecated");
listEndpoints(deprecatedEndpoints, "What's Deprecated", outputStreamWriter);

List<ChangedOperation> changedOperations = diff.getChangedOperations();
String ol_changed = ol_changed(changedOperations);

output
.append(renderBody(ol_newEndpoint, ol_missingEndpoint, ol_deprecatedEndpoint, ol_changed))
.append(title("Result"))
.append(
StringUtils.center(
diff.isCompatible()
? "API changes are backward compatible"
: "API changes broke backward compatibility",
LINE_LENGTH))
.append(System.lineSeparator())
.append(separator('-'));
ol_changed(changedOperations, outputStreamWriter);

safelyAppend(
outputStreamWriter,
StringUtils.center(
diff.isCompatible()
? "API changes are backward compatible"
: "API changes broke backward compatibility",
LINE_LENGTH));
safelyAppend(outputStreamWriter, System.lineSeparator());
safelyAppend(outputStreamWriter, separator('-'));
}
try {
outputStreamWriter.close();
} catch (IOException e) {
throw new RendererException(e);
}
return output.toString();
}

private String ol_changed(List<ChangedOperation> operations) {
private void ol_changed(
List<ChangedOperation> operations, OutputStreamWriter outputStreamWriter) {
if (null == operations || operations.isEmpty()) {
return "";
return;
}
StringBuilder sb = new StringBuilder();
sb.append(title("What's Changed"));
safelyAppend(outputStreamWriter, title("What's Changed"));
for (ChangedOperation operation : operations) {
String pathUrl = operation.getPathUrl();
String method = operation.getHttpMethod().toString();
String desc =
Optional.ofNullable(operation.getSummary()).map(ChangedMetadata::getRight).orElse("");

StringBuilder ul_detail = new StringBuilder();
if (result(operation.getParameters()).isDifferent()) {
ul_detail
.append(StringUtils.repeat(' ', 2))
.append("Parameter:")
.append(System.lineSeparator())
.append(ul_param(operation.getParameters()));
safelyAppend(outputStreamWriter, StringUtils.repeat(' ', 2));
safelyAppend(outputStreamWriter, "Parameter:");
safelyAppend(outputStreamWriter, System.lineSeparator());
safelyAppend(outputStreamWriter, ul_param(operation.getParameters()));
}
if (operation.resultRequestBody().isDifferent()) {
ul_detail
.append(StringUtils.repeat(' ', 2))
.append("Request:")
.append(System.lineSeparator())
.append(ul_content(operation.getRequestBody().getContent(), true));
safelyAppend(outputStreamWriter, StringUtils.repeat(' ', 2));
safelyAppend(outputStreamWriter, "Request:");
safelyAppend(outputStreamWriter, System.lineSeparator());
safelyAppend(outputStreamWriter, ul_content(operation.getRequestBody().getContent(), true));
}
if (operation.resultApiResponses().isDifferent()) {
ul_detail
.append(StringUtils.repeat(' ', 2))
.append("Return Type:")
.append(System.lineSeparator())
.append(ul_response(operation.getApiResponses()));
safelyAppend(outputStreamWriter, StringUtils.repeat(' ', 2));
safelyAppend(outputStreamWriter, "Return Type:");
safelyAppend(outputStreamWriter, System.lineSeparator());
safelyAppend(outputStreamWriter, ul_response(operation.getApiResponses()));
}
sb.append(itemEndpoint(method, pathUrl, desc)).append(ul_detail);
safelyAppend(outputStreamWriter, itemEndpoint(method, pathUrl, desc));
}
return sb.toString();
}

private String ul_response(ChangedApiResponse changedApiResponse) {
Expand Down Expand Up @@ -279,7 +279,8 @@ private String li_changedParam(ChangedParameter changeParam) {
}
}

private String listEndpoints(List<Endpoint> endpoints, String title) {
private String listEndpoints(
List<Endpoint> endpoints, String title, OutputStreamWriter outputStreamWriter) {
if (null == endpoints || endpoints.isEmpty()) {
return "";
}
Expand Down Expand Up @@ -317,8 +318,7 @@ public String title(String title, char ch) {
separator(ch), little, StringUtils.center(title, LINE_LENGTH - 4), little, separator(ch));
}

public StringBuilder separator(char ch) {
StringBuilder sb = new StringBuilder();
return sb.append(StringUtils.repeat(ch, LINE_LENGTH)).append(System.lineSeparator());
public String separator(char ch) {
return StringUtils.repeat(ch, LINE_LENGTH) + System.lineSeparator();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,20 @@
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.responses.ApiResponse;
import j2html.rendering.FlatHtml;
import j2html.tags.ContainerTag;
import j2html.tags.specialized.DivTag;
import j2html.tags.specialized.HtmlTag;
import j2html.tags.specialized.LiTag;
import j2html.tags.specialized.OlTag;
import j2html.tags.specialized.UlTag;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import org.openapitools.openapidiff.core.exception.RendererException;
import org.openapitools.openapidiff.core.model.ChangedApiResponse;
import org.openapitools.openapidiff.core.model.ChangedContent;
import org.openapitools.openapidiff.core.model.ChangedMediaType;
Expand Down Expand Up @@ -71,7 +75,7 @@ public HtmlRender(String title, String linkCss) {
this.linkCss = linkCss;
}

public String render(ChangedOpenApi diff) {
public void render(ChangedOpenApi diff, OutputStreamWriter outputStreamWriter) {
this.diff = diff;

List<Endpoint> newEndpoints = diff.getNewEndpoints();
Expand All @@ -86,10 +90,16 @@ public String render(ChangedOpenApi diff) {
List<ChangedOperation> changedOperations = diff.getChangedOperations();
OlTag ol_changed = ol_changed(changedOperations);

return renderHtml(ol_newEndpoint, ol_missingEndpoint, ol_deprecatedEndpoint, ol_changed);
renderHtml(
ol_newEndpoint, ol_missingEndpoint, ol_deprecatedEndpoint, ol_changed, outputStreamWriter);
}

public String renderHtml(OlTag ol_new, OlTag ol_miss, OlTag ol_deprec, OlTag ol_changed) {
public void renderHtml(
OlTag ol_new,
OlTag ol_miss,
OlTag ol_deprec,
OlTag ol_changed,
OutputStreamWriter outputStreamWriter) {
HtmlTag html =
html()
.attr("lang", "en")
Expand All @@ -110,7 +120,14 @@ public String renderHtml(OlTag ol_new, OlTag ol_miss, OlTag ol_deprec, OlTag ol_
div().with(h2("What's Deprecated"), hr(), ol_deprec),
div().with(h2("What's Changed"), hr(), ol_changed))));

return document().render() + html.render();
try {
FlatHtml<OutputStreamWriter> flatHtml = FlatHtml.into(outputStreamWriter);
document().render(flatHtml);
html.render(flatHtml);
outputStreamWriter.close();
} catch (IOException e) {
throw new RendererException("Problem rendering html document.", e);
}
}

private OlTag ol_newEndpoint(List<Endpoint> endpoints) {
Expand Down Expand Up @@ -400,10 +417,14 @@ private LiTag li_changedParam(ChangedParameter changeParam) {
.map(ChangedMetadata::isDifferent)
.orElse(false);
Parameter rightParam = changeParam.getNewParameter();
Parameter leftParam = changeParam.getNewParameter();
Parameter leftParam = changeParam.getOldParameter();
LiTag li = li().withText(changeParam.getName() + " in " + changeParam.getIn());
if (changeRequired) {
li.withText(" change into " + (rightParam.getRequired() ? "required" : "not required"));
li.withText(
" change into "
+ (rightParam.getRequired() != null && rightParam.getRequired()
? "required"
: "not required"));
}
if (changeDescription) {
li.withText(" Notes ")
Expand Down
Loading

0 comments on commit c613abb

Please sign in to comment.