Skip to content

Commit 3575350

Browse files
nithintatikonda1Nithin Tatikonda
and
Nithin Tatikonda
authored
Option to create HTML output with all changes (#541)
Co-authored-by: Nithin Tatikonda <[email protected]>
1 parent dc6ad56 commit 3575350

File tree

3 files changed

+144
-2
lines changed

3 files changed

+144
-2
lines changed

cli/src/main/java/org/openapitools/openapidiff/cli/Main.java

+14-1
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,15 @@ public static void main(String... args) {
116116
.longOpt("html")
117117
.hasArg()
118118
.argName("file")
119-
.desc("export diff as html in given file")
119+
.desc("export diff as html in given file with incompatible changes")
120120
.build());
121+
options.addOption(
122+
Option.builder()
123+
.longOpt("html-detailed")
124+
.hasArg()
125+
.argName("file")
126+
.desc("export diff as html in given file with all changes")
127+
.build());
121128
options.addOption(
122129
Option.builder()
123130
.longOpt("text")
@@ -228,6 +235,12 @@ public static void main(String... args) {
228235
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
229236
htmlRender.render(result, outputStreamWriter);
230237
}
238+
if (line.hasOption("html-detailed")) {
239+
HtmlRender htmlRender = new HtmlRender(true);
240+
FileOutputStream outputStream = new FileOutputStream(line.getOptionValue("html-detailed"));
241+
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
242+
htmlRender.render(result, outputStreamWriter);
243+
}
231244
if (line.hasOption("markdown")) {
232245
MarkdownRender mdRender = new MarkdownRender();
233246
FileOutputStream outputStream = new FileOutputStream(line.getOptionValue("markdown"));

core/src/main/java/org/openapitools/openapidiff/core/model/ChangedOperation.java

+3
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ public DiffResult resultApiResponses() {
6363
public DiffResult resultRequestBody() {
6464
return requestBody == null ? DiffResult.NO_CHANGES : requestBody.isChanged();
6565
}
66+
public DiffResult resultSecurityRequirements() {
67+
return securityRequirements == null ? DiffResult.NO_CHANGES : securityRequirements.isChanged();
68+
}
6669

6770
public Operation getOldOperation() {
6871
return this.oldOperation;

core/src/main/java/org/openapitools/openapidiff/core/output/HtmlRender.java

+127-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import io.swagger.v3.oas.models.media.Schema;
2727
import io.swagger.v3.oas.models.parameters.Parameter;
2828
import io.swagger.v3.oas.models.responses.ApiResponse;
29+
import io.swagger.v3.oas.models.security.SecurityRequirement;
2930
import j2html.rendering.FlatHtml;
3031
import j2html.tags.ContainerTag;
3132
import j2html.tags.specialized.DivTag;
@@ -50,6 +51,8 @@
5051
import org.openapitools.openapidiff.core.model.ChangedParameters;
5152
import org.openapitools.openapidiff.core.model.ChangedResponse;
5253
import org.openapitools.openapidiff.core.model.ChangedSchema;
54+
import org.openapitools.openapidiff.core.model.ChangedSecurityRequirement;
55+
import org.openapitools.openapidiff.core.model.ChangedSecurityRequirements;
5356
import org.openapitools.openapidiff.core.model.DiffContext;
5457
import org.openapitools.openapidiff.core.model.DiffResult;
5558
import org.openapitools.openapidiff.core.model.Endpoint;
@@ -64,15 +67,27 @@ public class HtmlRender implements Render {
6467

6568
private final String title;
6669
private final String linkCss;
70+
private final boolean showAllChanges;
6771
protected ChangedOpenApi diff;
6872

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

77+
public HtmlRender(boolean showAllChanges) {
78+
this("Api Change Log", "http://deepoove.com/swagger-diff/stylesheets/demo.css", showAllChanges);
79+
}
80+
7381
public HtmlRender(String title, String linkCss) {
7482
this.title = title;
7583
this.linkCss = linkCss;
84+
this.showAllChanges = false;
85+
}
86+
87+
public HtmlRender(String title, String linkCss, boolean showAllChanges) {
88+
this.title = title;
89+
this.linkCss = linkCss;
90+
this.showAllChanges = showAllChanges;
7691
}
7792

7893
public void render(ChangedOpenApi diff, OutputStreamWriter outputStreamWriter) {
@@ -200,6 +215,11 @@ private OlTag ol_changed(List<ChangedOperation> changedOperations) {
200215
ul_detail.with(
201216
li().with(h3("Response")).with(ul_response(changedOperation.getApiResponses())));
202217
}
218+
if (showAllChanges && changedOperation.resultSecurityRequirements().isDifferent()) {
219+
ul_detail.with(
220+
li().with(h3("Security Requirements"))
221+
.with(ul_securityRequirements(changedOperation.getSecurityRequirements())));
222+
}
203223
ol.with(
204224
li().with(span(method).withClass(method))
205225
.withText(pathUrl + " ")
@@ -209,6 +229,52 @@ private OlTag ol_changed(List<ChangedOperation> changedOperations) {
209229
return ol;
210230
}
211231

232+
private UlTag ul_securityRequirements(ChangedSecurityRequirements changedSecurityRequirements) {
233+
List<SecurityRequirement> addRequirements = changedSecurityRequirements.getIncreased();
234+
List<SecurityRequirement> delRequirements = changedSecurityRequirements.getMissing();
235+
List<ChangedSecurityRequirement> changedRequirements = changedSecurityRequirements.getChanged();
236+
UlTag ul = ul().withClass("change security requirements");
237+
if (addRequirements != null) {
238+
for (SecurityRequirement addRequirement : addRequirements) {
239+
ul.with(li_addSecurityRequirement(addRequirement));
240+
}
241+
}
242+
if (delRequirements != null) {
243+
for (SecurityRequirement delRequirement : delRequirements) {
244+
ul.with(li_missingSecurityRequirement(delRequirement));
245+
}
246+
}
247+
if (changedRequirements != null) {
248+
for (ChangedSecurityRequirement changedRequirement : changedRequirements) {
249+
ul.with(li_changedSecurityRequirement(changedRequirement));
250+
}
251+
}
252+
253+
return ul;
254+
}
255+
256+
private LiTag li_addSecurityRequirement(SecurityRequirement securityRequirement) {
257+
return li().withText("New security requirement : ")
258+
.with(span(null == securityRequirement.toString() ? "" : (securityRequirement.toString())));
259+
}
260+
261+
private LiTag li_missingSecurityRequirement(SecurityRequirement securityRequirement) {
262+
return li().withText("Deleted security requirement : ")
263+
.with(span(null == securityRequirement.toString() ? "" : (securityRequirement.toString())));
264+
}
265+
266+
private LiTag li_changedSecurityRequirement(
267+
ChangedSecurityRequirement changedSecurityRequirement) {
268+
return li().withText(String.format("Changed security requirement : "))
269+
.with(
270+
span(
271+
(null == changedSecurityRequirement.getNewSecurityRequirement()
272+
|| null
273+
== changedSecurityRequirement.getNewSecurityRequirement().toString())
274+
? ""
275+
: (changedSecurityRequirement.getNewSecurityRequirement().toString())));
276+
}
277+
212278
private UlTag ul_response(ChangedApiResponse changedApiResponse) {
213279
Map<String, ApiResponse> addResponses = changedApiResponse.getIncreased();
214280
Map<String, ApiResponse> delResponses = changedApiResponse.getMissing();
@@ -279,9 +345,12 @@ private LiTag li_changedRequest(String name, ChangedMediaType request) {
279345
LiTag li =
280346
li().with(div_changedSchema(request.getSchema()))
281347
.withText(String.format("Changed body: '%s'", name));
282-
if (request.isIncompatible()) {
348+
if (request.isIncompatible() && !showAllChanges) {
283349
incompatibilities(li, request.getSchema());
284350
}
351+
else if (showAllChanges) {
352+
allChanges(li, request.getSchema());
353+
}
285354
return li;
286355
}
287356

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

363+
private void allChanges(final LiTag output, final ChangedSchema schema) {
364+
allChanges(output, "", schema);
365+
}
366+
367+
private void allChanges(
368+
final ContainerTag<?> output, String propName, final ChangedSchema schema) {
369+
String prefix = propName.isEmpty() ? "" : propName + ".";
370+
properties(
371+
output, prefix, "Missing property", schema.getMissingProperties(), schema.getContext());
372+
properties(
373+
output, prefix, "Added property", schema.getIncreasedProperties(), schema.getContext());
374+
375+
propertiesChanged(
376+
output, prefix, "Changed property", schema.getChangedProperties(), schema.getContext());
377+
if (schema.getItems() != null) {
378+
itemsAllChanges(output, propName, schema.getItems());
379+
}
380+
schema
381+
.getChangedProperties()
382+
.forEach((name, property) -> allChanges(output, prefix + name, property));
383+
}
384+
294385
private void incompatibilities(final LiTag output, final ChangedSchema schema) {
295386
incompatibilities(output, "", schema);
296387
}
@@ -316,6 +407,10 @@ private void items(ContainerTag<?> output, String propName, ChangedSchema schema
316407
incompatibilities(output, propName + "[n]", schema);
317408
}
318409

410+
private void itemsAllChanges(ContainerTag<?> output, String propName, ChangedSchema schema) {
411+
allChanges(output, propName + "[n]", schema);
412+
}
413+
319414
private void properties(
320415
ContainerTag<?> output,
321416
String propPrefix,
@@ -327,6 +422,17 @@ private void properties(
327422
}
328423
}
329424

425+
private void propertiesChanged(
426+
ContainerTag<?> output,
427+
String propPrefix,
428+
String title,
429+
Map<String, ChangedSchema> properties,
430+
DiffContext context) {
431+
if (properties != null) {
432+
properties.forEach((key, value) -> resolveProperty(output, propPrefix, key, value, title));
433+
}
434+
}
435+
330436
private void resolveProperty(
331437
ContainerTag<?> output, String propPrefix, String key, Schema<?> value, String title) {
332438
try {
@@ -336,6 +442,15 @@ private void resolveProperty(
336442
}
337443
}
338444

445+
private void resolveProperty(
446+
ContainerTag<?> output, String propPrefix, String key, ChangedSchema value, String title) {
447+
try {
448+
property(output, propPrefix + key, title, resolve(value));
449+
} catch (Exception e) {
450+
property(output, propPrefix + key, title, type(value));
451+
}
452+
}
453+
339454
protected void property(ContainerTag<?> output, String name, String title, Schema<?> schema) {
340455
property(output, name, title, type(schema));
341456
}
@@ -349,6 +464,13 @@ protected Schema<?> resolve(Schema<?> schema) {
349464
diff.getNewSpecOpenApi().getComponents(), schema, schema.get$ref());
350465
}
351466

467+
protected Schema<?> resolve(ChangedSchema schema) {
468+
return refPointer.resolveRef(
469+
diff.getNewSpecOpenApi().getComponents(),
470+
schema.getNewSchema(),
471+
schema.getNewSchema().get$ref());
472+
}
473+
352474
protected String type(Schema<?> schema) {
353475
String result = "object";
354476
if (schema == null) {
@@ -361,6 +483,10 @@ protected String type(Schema<?> schema) {
361483
return result;
362484
}
363485

486+
protected String type(ChangedSchema schema) {
487+
return type(schema.getNewSchema());
488+
}
489+
364490
private UlTag ul_param(ChangedParameters changedParameters) {
365491
List<Parameter> addParameters = changedParameters.getIncreased();
366492
List<Parameter> delParameters = changedParameters.getMissing();

0 commit comments

Comments
 (0)