Skip to content

Option to create html doc with all changes #541

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -93,8 +93,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 @@ -185,6 +192,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