Skip to content

Commit

Permalink
Option to create HTML output with all changes (#541)
Browse files Browse the repository at this point in the history
Co-authored-by: Nithin Tatikonda <[email protected]>
  • Loading branch information
nithintatikonda1 and Nithin Tatikonda authored Dec 16, 2023
1 parent dc6ad56 commit 3575350
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 2 deletions.
15 changes: 14 additions & 1 deletion cli/src/main/java/org/openapitools/openapidiff/cli/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,15 @@ public static void main(String... args) {
.longOpt("html")
.hasArg()
.argName("file")
.desc("export diff as html in given file")
.desc("export diff as html in given file with incompatible changes")
.build());
options.addOption(
Option.builder()
.longOpt("html-detailed")
.hasArg()
.argName("file")
.desc("export diff as html in given file with all changes")
.build());
options.addOption(
Option.builder()
.longOpt("text")
Expand Down Expand Up @@ -228,6 +235,12 @@ public static void main(String... args) {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
htmlRender.render(result, outputStreamWriter);
}
if (line.hasOption("html-detailed")) {
HtmlRender htmlRender = new HtmlRender(true);
FileOutputStream outputStream = new FileOutputStream(line.getOptionValue("html-detailed"));
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
htmlRender.render(result, outputStreamWriter);
}
if (line.hasOption("markdown")) {
MarkdownRender mdRender = new MarkdownRender();
FileOutputStream outputStream = new FileOutputStream(line.getOptionValue("markdown"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ public DiffResult resultApiResponses() {
public DiffResult resultRequestBody() {
return requestBody == null ? DiffResult.NO_CHANGES : requestBody.isChanged();
}
public DiffResult resultSecurityRequirements() {
return securityRequirements == null ? DiffResult.NO_CHANGES : securityRequirements.isChanged();
}

public Operation getOldOperation() {
return this.oldOperation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
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 io.swagger.v3.oas.models.security.SecurityRequirement;
import j2html.rendering.FlatHtml;
import j2html.tags.ContainerTag;
import j2html.tags.specialized.DivTag;
Expand All @@ -50,6 +51,8 @@
import org.openapitools.openapidiff.core.model.ChangedParameters;
import org.openapitools.openapidiff.core.model.ChangedResponse;
import org.openapitools.openapidiff.core.model.ChangedSchema;
import org.openapitools.openapidiff.core.model.ChangedSecurityRequirement;
import org.openapitools.openapidiff.core.model.ChangedSecurityRequirements;
import org.openapitools.openapidiff.core.model.DiffContext;
import org.openapitools.openapidiff.core.model.DiffResult;
import org.openapitools.openapidiff.core.model.Endpoint;
Expand All @@ -64,15 +67,27 @@ public class HtmlRender implements Render {

private final String title;
private final String linkCss;
private final boolean showAllChanges;
protected ChangedOpenApi diff;

public HtmlRender() {
this("Api Change Log", "http://deepoove.com/swagger-diff/stylesheets/demo.css");
}

public HtmlRender(boolean showAllChanges) {
this("Api Change Log", "http://deepoove.com/swagger-diff/stylesheets/demo.css", showAllChanges);
}

public HtmlRender(String title, String linkCss) {
this.title = title;
this.linkCss = linkCss;
this.showAllChanges = false;
}

public HtmlRender(String title, String linkCss, boolean showAllChanges) {
this.title = title;
this.linkCss = linkCss;
this.showAllChanges = showAllChanges;
}

public void render(ChangedOpenApi diff, OutputStreamWriter outputStreamWriter) {
Expand Down Expand Up @@ -200,6 +215,11 @@ private OlTag ol_changed(List<ChangedOperation> changedOperations) {
ul_detail.with(
li().with(h3("Response")).with(ul_response(changedOperation.getApiResponses())));
}
if (showAllChanges && changedOperation.resultSecurityRequirements().isDifferent()) {
ul_detail.with(
li().with(h3("Security Requirements"))
.with(ul_securityRequirements(changedOperation.getSecurityRequirements())));
}
ol.with(
li().with(span(method).withClass(method))
.withText(pathUrl + " ")
Expand All @@ -209,6 +229,52 @@ private OlTag ol_changed(List<ChangedOperation> changedOperations) {
return ol;
}

private UlTag ul_securityRequirements(ChangedSecurityRequirements changedSecurityRequirements) {
List<SecurityRequirement> addRequirements = changedSecurityRequirements.getIncreased();
List<SecurityRequirement> delRequirements = changedSecurityRequirements.getMissing();
List<ChangedSecurityRequirement> changedRequirements = changedSecurityRequirements.getChanged();
UlTag ul = ul().withClass("change security requirements");
if (addRequirements != null) {
for (SecurityRequirement addRequirement : addRequirements) {
ul.with(li_addSecurityRequirement(addRequirement));
}
}
if (delRequirements != null) {
for (SecurityRequirement delRequirement : delRequirements) {
ul.with(li_missingSecurityRequirement(delRequirement));
}
}
if (changedRequirements != null) {
for (ChangedSecurityRequirement changedRequirement : changedRequirements) {
ul.with(li_changedSecurityRequirement(changedRequirement));
}
}

return ul;
}

private LiTag li_addSecurityRequirement(SecurityRequirement securityRequirement) {
return li().withText("New security requirement : ")
.with(span(null == securityRequirement.toString() ? "" : (securityRequirement.toString())));
}

private LiTag li_missingSecurityRequirement(SecurityRequirement securityRequirement) {
return li().withText("Deleted security requirement : ")
.with(span(null == securityRequirement.toString() ? "" : (securityRequirement.toString())));
}

private LiTag li_changedSecurityRequirement(
ChangedSecurityRequirement changedSecurityRequirement) {
return li().withText(String.format("Changed security requirement : "))
.with(
span(
(null == changedSecurityRequirement.getNewSecurityRequirement()
|| null
== changedSecurityRequirement.getNewSecurityRequirement().toString())
? ""
: (changedSecurityRequirement.getNewSecurityRequirement().toString())));
}

private UlTag ul_response(ChangedApiResponse changedApiResponse) {
Map<String, ApiResponse> addResponses = changedApiResponse.getIncreased();
Map<String, ApiResponse> delResponses = changedApiResponse.getMissing();
Expand Down Expand Up @@ -279,9 +345,12 @@ private LiTag li_changedRequest(String name, ChangedMediaType request) {
LiTag li =
li().with(div_changedSchema(request.getSchema()))
.withText(String.format("Changed body: '%s'", name));
if (request.isIncompatible()) {
if (request.isIncompatible() && !showAllChanges) {
incompatibilities(li, request.getSchema());
}
else if (showAllChanges) {
allChanges(li, request.getSchema());
}
return li;
}

Expand All @@ -291,6 +360,28 @@ private DivTag div_changedSchema(ChangedSchema schema) {
return div;
}

private void allChanges(final LiTag output, final ChangedSchema schema) {
allChanges(output, "", schema);
}

private void allChanges(
final ContainerTag<?> output, String propName, final ChangedSchema schema) {
String prefix = propName.isEmpty() ? "" : propName + ".";
properties(
output, prefix, "Missing property", schema.getMissingProperties(), schema.getContext());
properties(
output, prefix, "Added property", schema.getIncreasedProperties(), schema.getContext());

propertiesChanged(
output, prefix, "Changed property", schema.getChangedProperties(), schema.getContext());
if (schema.getItems() != null) {
itemsAllChanges(output, propName, schema.getItems());
}
schema
.getChangedProperties()
.forEach((name, property) -> allChanges(output, prefix + name, property));
}

private void incompatibilities(final LiTag output, final ChangedSchema schema) {
incompatibilities(output, "", schema);
}
Expand All @@ -316,6 +407,10 @@ private void items(ContainerTag<?> output, String propName, ChangedSchema schema
incompatibilities(output, propName + "[n]", schema);
}

private void itemsAllChanges(ContainerTag<?> output, String propName, ChangedSchema schema) {
allChanges(output, propName + "[n]", schema);
}

private void properties(
ContainerTag<?> output,
String propPrefix,
Expand All @@ -327,6 +422,17 @@ private void properties(
}
}

private void propertiesChanged(
ContainerTag<?> output,
String propPrefix,
String title,
Map<String, ChangedSchema> properties,
DiffContext context) {
if (properties != null) {
properties.forEach((key, value) -> resolveProperty(output, propPrefix, key, value, title));
}
}

private void resolveProperty(
ContainerTag<?> output, String propPrefix, String key, Schema<?> value, String title) {
try {
Expand All @@ -336,6 +442,15 @@ private void resolveProperty(
}
}

private void resolveProperty(
ContainerTag<?> output, String propPrefix, String key, ChangedSchema value, String title) {
try {
property(output, propPrefix + key, title, resolve(value));
} catch (Exception e) {
property(output, propPrefix + key, title, type(value));
}
}

protected void property(ContainerTag<?> output, String name, String title, Schema<?> schema) {
property(output, name, title, type(schema));
}
Expand All @@ -349,6 +464,13 @@ protected Schema<?> resolve(Schema<?> schema) {
diff.getNewSpecOpenApi().getComponents(), schema, schema.get$ref());
}

protected Schema<?> resolve(ChangedSchema schema) {
return refPointer.resolveRef(
diff.getNewSpecOpenApi().getComponents(),
schema.getNewSchema(),
schema.getNewSchema().get$ref());
}

protected String type(Schema<?> schema) {
String result = "object";
if (schema == null) {
Expand All @@ -361,6 +483,10 @@ protected String type(Schema<?> schema) {
return result;
}

protected String type(ChangedSchema schema) {
return type(schema.getNewSchema());
}

private UlTag ul_param(ChangedParameters changedParameters) {
List<Parameter> addParameters = changedParameters.getIncreased();
List<Parameter> delParameters = changedParameters.getMissing();
Expand Down

0 comments on commit 3575350

Please sign in to comment.