Skip to content

Commit 9dc158e

Browse files
authored
Merge pull request #105 from thiagoarrais/report-missing-property
Report causes for compatibility breakage
2 parents 16f76cb + 856b426 commit 9dc158e

File tree

2 files changed

+146
-3
lines changed

2 files changed

+146
-3
lines changed

src/main/java/com/qdesrame/openapi/diff/output/ConsoleRender.java

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
import static com.qdesrame.openapi.diff.model.Changed.result;
44

55
import com.qdesrame.openapi.diff.model.*;
6+
import com.qdesrame.openapi.diff.utils.RefPointer;
7+
import com.qdesrame.openapi.diff.utils.RefType;
8+
import io.swagger.v3.oas.models.media.ArraySchema;
9+
import io.swagger.v3.oas.models.media.Schema;
610
import io.swagger.v3.oas.models.parameters.Parameter;
711
import io.swagger.v3.oas.models.responses.ApiResponse;
812
import java.util.List;
@@ -13,11 +17,14 @@
1317

1418
public class ConsoleRender implements Render {
1519
private static final int LINE_LENGTH = 74;
20+
protected static RefPointer<Schema> refPointer = new RefPointer<>(RefType.SCHEMAS);
21+
protected ChangedOpenApi diff;
1622

1723
private StringBuilder output;
1824

1925
@Override
2026
public String render(ChangedOpenApi diff) {
27+
this.diff = diff;
2128
output = new StringBuilder();
2229
if (diff.isUnchanged()) {
2330
output.append("No differences. Specifications are equivalents");
@@ -168,9 +175,73 @@ private String itemContent(
168175
.append("Schema: ")
169176
.append(changedMediaType.isCompatible() ? "Backward compatible" : "Broken compatibility")
170177
.append(System.lineSeparator());
178+
if (!changedMediaType.isCompatible()) {
179+
sb.append(incompatibilities(changedMediaType.getSchema()));
180+
}
181+
return sb.toString();
182+
}
183+
184+
private String incompatibilities(final ChangedSchema schema) {
185+
return incompatibilities("", schema);
186+
}
187+
188+
private String incompatibilities(String propName, final ChangedSchema schema) {
189+
StringBuilder sb = new StringBuilder();
190+
if (schema.getItems() != null) {
191+
sb.append(items(propName, schema.getItems()));
192+
}
193+
if (schema.isCoreChanged() == DiffResult.INCOMPATIBLE && schema.isChangedType()) {
194+
String type = type(schema.getOldSchema()) + " -> " + type(schema.getNewSchema());
195+
sb.append(property(propName, "Changed property type", type));
196+
}
197+
String prefix = propName.isEmpty() ? "" : propName + ".";
198+
sb.append(
199+
properties(prefix, "Missing property", schema.getMissingProperties(), schema.getContext()));
200+
schema
201+
.getChangedProperties()
202+
.forEach((name, property) -> sb.append(incompatibilities(prefix + name, property)));
171203
return sb.toString();
172204
}
173205

206+
private String items(String propName, ChangedSchema schema) {
207+
StringBuilder sb = new StringBuilder();
208+
sb.append(incompatibilities(propName + "[n]", schema));
209+
return sb.toString();
210+
}
211+
212+
private String properties(
213+
String propPrefix, String title, Map<String, Schema> properties, DiffContext context) {
214+
StringBuilder sb = new StringBuilder();
215+
if (properties != null) {
216+
properties.forEach(
217+
(key, value) -> sb.append(property(propPrefix + key, title, resolve(value))));
218+
}
219+
return sb.toString();
220+
}
221+
222+
protected String property(String name, String title, Schema schema) {
223+
return property(name, title, type(schema));
224+
}
225+
226+
protected String property(String name, String title, String type) {
227+
return String.format("%s%s: %s (%s)\n", StringUtils.repeat(' ', 10), title, name, type);
228+
}
229+
230+
protected Schema resolve(Schema schema) {
231+
return refPointer.resolveRef(
232+
diff.getNewSpecOpenApi().getComponents(), schema, schema.get$ref());
233+
}
234+
235+
protected String type(Schema schema) {
236+
String result = "object";
237+
if (schema instanceof ArraySchema) {
238+
result = "array";
239+
} else if (schema.getType() != null) {
240+
result = schema.getType();
241+
}
242+
return result;
243+
}
244+
174245
private String ul_param(ChangedParameters changedParameters) {
175246
List<Parameter> addParameters = changedParameters.getIncreased();
176247
List<Parameter> delParameters = changedParameters.getMissing();

src/main/java/com/qdesrame/openapi/diff/output/HtmlRender.java

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
import static j2html.TagCreator.*;
55

66
import com.qdesrame.openapi.diff.model.*;
7+
import com.qdesrame.openapi.diff.utils.RefPointer;
8+
import com.qdesrame.openapi.diff.utils.RefType;
9+
import io.swagger.v3.oas.models.media.ArraySchema;
710
import io.swagger.v3.oas.models.media.MediaType;
11+
import io.swagger.v3.oas.models.media.Schema;
812
import io.swagger.v3.oas.models.parameters.Parameter;
913
import io.swagger.v3.oas.models.responses.ApiResponse;
1014
import j2html.tags.ContainerTag;
@@ -16,6 +20,8 @@ public class HtmlRender implements Render {
1620

1721
private String title;
1822
private String linkCss;
23+
protected static RefPointer<Schema> refPointer = new RefPointer<>(RefType.SCHEMAS);
24+
protected ChangedOpenApi diff;
1925

2026
public HtmlRender() {
2127
this("Api Change Log", "http://deepoove.com/swagger-diff/stylesheets/demo.css");
@@ -27,6 +33,8 @@ public HtmlRender(String title, String linkCss) {
2733
}
2834

2935
public String render(ChangedOpenApi diff) {
36+
this.diff = diff;
37+
3038
List<Endpoint> newEndpoints = diff.getNewEndpoints();
3139
ContainerTag ol_newEndpoint = ol_newEndpoint(newEndpoints);
3240

@@ -214,16 +222,80 @@ private ContainerTag li_missingRequest(String name, MediaType request) {
214222
}
215223

216224
private ContainerTag li_changedRequest(String name, ChangedMediaType request) {
217-
return li().withText(String.format("Changed body: '%s'", name))
218-
.with(div_changedSchema(request.getSchema()));
225+
ContainerTag li =
226+
li().with(div_changedSchema(request.getSchema()))
227+
.withText(String.format("Changed body: '%s'", name));
228+
if (request.isIncompatible()) {
229+
incompatibilities(li, request.getSchema());
230+
}
231+
return li;
219232
}
220233

221234
private ContainerTag div_changedSchema(ChangedSchema schema) {
222235
ContainerTag div = div();
223-
div.with(h3("Schema"));
236+
div.with(h3("Schema" + (schema.isIncompatible() ? " incompatible" : "")));
224237
return div;
225238
}
226239

240+
private void incompatibilities(final ContainerTag output, final ChangedSchema schema) {
241+
incompatibilities(output, "", schema);
242+
}
243+
244+
private void incompatibilities(
245+
final ContainerTag output, String propName, final ChangedSchema schema) {
246+
if (schema.getItems() != null) {
247+
items(output, propName, schema.getItems());
248+
}
249+
if (schema.isCoreChanged() == DiffResult.INCOMPATIBLE && schema.isChangedType()) {
250+
String type = type(schema.getOldSchema()) + " -> " + type(schema.getNewSchema());
251+
property(output, propName, "Changed property type", type);
252+
}
253+
String prefix = propName.isEmpty() ? "" : propName + ".";
254+
properties(
255+
output, prefix, "Missing property", schema.getMissingProperties(), schema.getContext());
256+
schema
257+
.getChangedProperties()
258+
.forEach((name, property) -> incompatibilities(output, prefix + name, property));
259+
}
260+
261+
private void items(ContainerTag output, String propName, ChangedSchema schema) {
262+
incompatibilities(output, propName + "[n]", schema);
263+
}
264+
265+
private void properties(
266+
ContainerTag output,
267+
String propPrefix,
268+
String title,
269+
Map<String, Schema> properties,
270+
DiffContext context) {
271+
if (properties != null) {
272+
properties.forEach((key, value) -> property(output, propPrefix + key, title, resolve(value)));
273+
}
274+
}
275+
276+
protected void property(ContainerTag output, String name, String title, Schema schema) {
277+
property(output, name, title, type(schema));
278+
}
279+
280+
protected void property(ContainerTag output, String name, String title, String type) {
281+
output.with(p(String.format("%s: %s (%s)", title, name, type)).withClass("missing"));
282+
}
283+
284+
protected Schema resolve(Schema schema) {
285+
return refPointer.resolveRef(
286+
diff.getNewSpecOpenApi().getComponents(), schema, schema.get$ref());
287+
}
288+
289+
protected String type(Schema schema) {
290+
String result = "object";
291+
if (schema instanceof ArraySchema) {
292+
result = "array";
293+
} else if (schema.getType() != null) {
294+
result = schema.getType();
295+
}
296+
return result;
297+
}
298+
227299
private ContainerTag ul_param(ChangedParameters changedParameters) {
228300
List<Parameter> addParameters = changedParameters.getIncreased();
229301
List<Parameter> delParameters = changedParameters.getMissing();

0 commit comments

Comments
 (0)