Skip to content

Commit baebacf

Browse files
author
Ahmad Moudani
committed
fix: 1) adds supports for Diff to report on changed extension values #2984 and 2) detects request param extension changes #2983
Signed-off-by: Ahmad Moudani <ahmad.moudani@crowdstrike.com>
1 parent b9afd59 commit baebacf

File tree

3 files changed

+77
-5
lines changed

3 files changed

+77
-5
lines changed

diff/compatibility.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ func init() {
3636
AddedConstraint: NonBreaking,
3737
DeletedExtension: Warning,
3838
AddedExtension: Warning,
39+
ChangedExtensionValue: Warning,
3940
},
4041
ForRequest: map[SpecChangeCode]Compatibility{
4142
AddedRequiredProperty: Breaking,
@@ -70,6 +71,7 @@ func init() {
7071
ChangedCollectionFormat: Breaking,
7172
DeletedExtension: Warning,
7273
AddedExtension: Warning,
74+
ChangedExtensionValue: Warning,
7375
},
7476
ForChange: map[SpecChangeCode]Compatibility{
7577
NoChangeDetected: NonBreaking,
@@ -96,6 +98,7 @@ func init() {
9698
DeletedDefinition: NonBreaking,
9799
DeletedExtension: Warning,
98100
AddedExtension: Warning,
101+
ChangedExtensionValue: Warning,
99102
},
100103
}
101104
}

diff/difftypes.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ const (
117117
DeletedExtension
118118
// AddedExtension added an extension
119119
AddedExtension
120+
// ChangedExtensionValue changed an extension value
121+
ChangedExtensionValue
120122
)
121123

122124
var toLongStringSpecChangeCode = map[SpecChangeCode]string{
@@ -173,6 +175,7 @@ var toLongStringSpecChangeCode = map[SpecChangeCode]string{
173175
ChangedCollectionFormat: "Changed collection format",
174176
DeletedExtension: "Deleted Extension",
175177
AddedExtension: "Added Extension",
178+
ChangedExtensionValue: "Changed Extension Value",
176179
}
177180

178181
var toStringSpecChangeCode = map[SpecChangeCode]string{
@@ -229,6 +232,7 @@ var toStringSpecChangeCode = map[SpecChangeCode]string{
229232
ChangedCollectionFormat: "ChangedCollectionFormat",
230233
DeletedExtension: "DeletedExtension",
231234
AddedExtension: "AddedExtension",
235+
ChangedExtensionValue: "ChangedExtensionValue",
232236
}
233237

234238
var toIDSpecChangeCode = map[string]SpecChangeCode{}

diff/spec_analyser.go

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package diff
22

33
import (
44
"fmt"
5+
"reflect"
56
"strings"
67

78
"github.com/go-openapi/spec"
@@ -293,6 +294,7 @@ func (sd *SpecAnalyser) analyseExtensions(spec1, spec2 *spec.Swagger) {
293294
specLoc := DifferenceLocation{Node: &Node{Field: "Spec"}}
294295
sd.checkAddedExtensions(spec1.Extensions, spec2.Extensions, specLoc, "")
295296
sd.checkDeletedExtensions(spec1.Extensions, spec2.Extensions, specLoc, "")
297+
sd.checkChangedExtensions(spec1.Extensions, spec2.Extensions, specLoc, "")
296298

297299
sd.analyzeInfoExtensions()
298300
sd.analyzeTagExtensions(spec1, spec2)
@@ -302,19 +304,27 @@ func (sd *SpecAnalyser) analyseExtensions(spec1, spec2 *spec.Swagger) {
302304
}
303305

304306
func (sd *SpecAnalyser) analyzeOperationExtensions() {
307+
pathsIterated := make(map[string]struct{})
305308
for urlMethod, op2 := range sd.urlMethods2 {
306309
pathAndMethodLoc := DifferenceLocation{URL: urlMethod.Path, Method: urlMethod.Method}
307310
if op1, ok := sd.urlMethods1[urlMethod]; ok {
308-
sd.checkAddedExtensions(op1.Extensions, op2.Extensions, DifferenceLocation{URL: urlMethod.Path}, "")
311+
if _, ok := pathsIterated[urlMethod.Path]; !ok {
312+
sd.checkAddedExtensions(op1.Extensions, op2.Extensions, DifferenceLocation{URL: urlMethod.Path}, "")
313+
sd.checkChangedExtensions(op1.Extensions, op2.Extensions, DifferenceLocation{URL: urlMethod.Path}, "")
314+
pathsIterated[urlMethod.Path] = struct{}{}
315+
}
309316
sd.checkAddedExtensions(op1.Operation.Responses.Extensions, op2.Operation.Responses.Extensions, pathAndMethodLoc, "Responses")
317+
sd.checkChangedExtensions(op1.Operation.Responses.Extensions, op2.Operation.Responses.Extensions, pathAndMethodLoc, "Responses")
310318
sd.checkAddedExtensions(op1.Operation.Extensions, op2.Operation.Extensions, pathAndMethodLoc, "")
311-
319+
sd.checkChangedExtensions(op1.Operation.Extensions, op2.Operation.Extensions, pathAndMethodLoc, "")
320+
sd.checkParamExtensions(op1, op2, urlMethod)
312321
for code, resp := range op1.Operation.Responses.StatusCodeResponses {
313322
for hdr, h := range resp.Headers {
314323
op2StatusCode, ok := op2.Operation.Responses.StatusCodeResponses[code]
315324
if ok {
316325
if _, ok = op2StatusCode.Headers[hdr]; ok {
317326
sd.checkAddedExtensions(h.Extensions, op2StatusCode.Headers[hdr].Extensions, DifferenceLocation{URL: urlMethod.Path, Method: urlMethod.Method, Node: getNameOnlyDiffNode("Headers")}, hdr)
327+
sd.checkChangedExtensions(h.Extensions, op2StatusCode.Headers[hdr].Extensions, DifferenceLocation{URL: urlMethod.Path, Method: urlMethod.Method, Node: getNameOnlyDiffNode("Headers")}, hdr)
318328
}
319329
}
320330
}
@@ -326,10 +336,14 @@ func (sd *SpecAnalyser) analyzeOperationExtensions() {
326336
}
327337
}
328338

339+
pathsIterated = make(map[string]struct{})
329340
for urlMethod, op1 := range sd.urlMethods1 {
330341
pathAndMethodLoc := DifferenceLocation{URL: urlMethod.Path, Method: urlMethod.Method}
331342
if op2, ok := sd.urlMethods2[urlMethod]; ok {
332-
sd.checkDeletedExtensions(op1.Extensions, op2.Extensions, DifferenceLocation{URL: urlMethod.Path}, "")
343+
if _, ok := pathsIterated[urlMethod.Path]; !ok {
344+
sd.checkDeletedExtensions(op1.Extensions, op2.Extensions, DifferenceLocation{URL: urlMethod.Path}, "")
345+
pathsIterated[urlMethod.Path] = struct{}{}
346+
}
333347
sd.checkDeletedExtensions(op1.Operation.Responses.Extensions, op2.Operation.Responses.Extensions, pathAndMethodLoc, "Responses")
334348
sd.checkDeletedExtensions(op1.Operation.Extensions, op2.Operation.Extensions, pathAndMethodLoc, "")
335349
for code, resp := range op1.Operation.Responses.StatusCodeResponses {
@@ -346,11 +360,42 @@ func (sd *SpecAnalyser) analyzeOperationExtensions() {
346360
}
347361
}
348362

363+
func (sd *SpecAnalyser) checkParamExtensions(op1 *PathItemOp, op2 *PathItemOp, urlMethod URLMethod) {
364+
locations := []string{"query", "path", "body", "header", "formData"}
365+
titles := []string{"Query", "Path", "Body", "Header", "FormData"}
366+
367+
for i, paramLocation := range locations {
368+
rootNode := getNameOnlyDiffNode(titles[i])
369+
params1 := getParams(op1.ParentPathItem.Parameters, op1.Operation.Parameters, paramLocation)
370+
params2 := getParams(op2.ParentPathItem.Parameters, op2.Operation.Parameters, paramLocation)
371+
372+
location := DifferenceLocation{URL: urlMethod.Path, Method: urlMethod.Method, Node: rootNode}
373+
// detect deleted param extensions
374+
for paramName1, param1 := range params1 {
375+
if param2, ok := params2[paramName1]; ok {
376+
childLocation := location.AddNode(getSchemaDiffNode(paramName1, &param1.SimpleSchema))
377+
sd.checkDeletedExtensions(param1.Extensions, param2.Extensions, childLocation, "")
378+
}
379+
}
380+
381+
// detect added changed params
382+
for paramName2, param2 := range params2 {
383+
// changed?
384+
if param1, ok := params1[paramName2]; ok {
385+
childLocation := location.AddNode(getSchemaDiffNode(paramName2, &param1.SimpleSchema))
386+
sd.checkAddedExtensions(param1.Extensions, param2.Extensions, childLocation, "")
387+
sd.checkChangedExtensions(param1.Extensions, param2.Extensions, childLocation, "")
388+
}
389+
}
390+
}
391+
}
392+
349393
func (sd *SpecAnalyser) analyzeSecurityDefinitionExtensions(spec1 *spec.Swagger, spec2 *spec.Swagger) {
350394
securityDefLoc := DifferenceLocation{Node: &Node{Field: "Security Definitions"}}
351-
for key, securityDef := range spec1.SecurityDefinitions {
395+
for key, securityDef1 := range spec1.SecurityDefinitions {
352396
if securityDef2, ok := spec2.SecurityDefinitions[key]; ok {
353-
sd.checkAddedExtensions(securityDef.Extensions, securityDef2.Extensions, securityDefLoc, "")
397+
sd.checkAddedExtensions(securityDef1.Extensions, securityDef2.Extensions, securityDefLoc, "")
398+
sd.checkChangedExtensions(securityDef1.Extensions, securityDef2.Extensions, securityDefLoc, "")
354399
}
355400
}
356401

@@ -365,6 +410,7 @@ func (sd *SpecAnalyser) analyzeSchemaExtensions(schema1, schema2 *spec.Schema, c
365410
if schema1 != nil && schema2 != nil {
366411
diffLoc := DifferenceLocation{Response: code, URL: urlMethod.Path, Method: urlMethod.Method, Node: getSchemaDiffNode("Body", schema2)}
367412
sd.checkAddedExtensions(schema1.Extensions, schema2.Extensions, diffLoc, "")
413+
sd.checkChangedExtensions(schema1.Extensions, schema2.Extensions, diffLoc, "")
368414
sd.checkDeletedExtensions(schema1.Extensions, schema2.Extensions, diffLoc, "")
369415
if schema1.Items != nil && schema2.Items != nil {
370416
sd.analyzeSchemaExtensions(schema1.Items.Schema, schema2.Items.Schema, code, urlMethod)
@@ -384,15 +430,18 @@ func (sd *SpecAnalyser) analyzeInfoExtensions() {
384430
diffLocation := DifferenceLocation{Node: &Node{Field: "Spec Info"}}
385431
sd.checkAddedExtensions(sd.Info1.Extensions, sd.Info2.Extensions, diffLocation, "")
386432
sd.checkDeletedExtensions(sd.Info1.Extensions, sd.Info2.Extensions, diffLocation, "")
433+
sd.checkChangedExtensions(sd.Info1.Extensions, sd.Info2.Extensions, diffLocation, "")
387434
if sd.Info1.Contact != nil && sd.Info2.Contact != nil {
388435
diffLocation = DifferenceLocation{Node: &Node{Field: "Spec Info.Contact"}}
389436
sd.checkAddedExtensions(sd.Info1.Contact.Extensions, sd.Info2.Contact.Extensions, diffLocation, "")
390437
sd.checkDeletedExtensions(sd.Info1.Contact.Extensions, sd.Info2.Contact.Extensions, diffLocation, "")
438+
sd.checkChangedExtensions(sd.Info1.Contact.Extensions, sd.Info2.Contact.Extensions, diffLocation, "")
391439
}
392440
if sd.Info1.License != nil && sd.Info2.License != nil {
393441
diffLocation = DifferenceLocation{Node: &Node{Field: "Spec Info.License"}}
394442
sd.checkAddedExtensions(sd.Info1.License.Extensions, sd.Info2.License.Extensions, diffLocation, "")
395443
sd.checkDeletedExtensions(sd.Info1.License.Extensions, sd.Info2.License.Extensions, diffLocation, "")
444+
sd.checkChangedExtensions(sd.Info1.License.Extensions, sd.Info2.License.Extensions, diffLocation, "")
396445
}
397446
}
398447
}
@@ -403,6 +452,7 @@ func (sd *SpecAnalyser) analyzeTagExtensions(spec1 *spec.Swagger, spec2 *spec.Sw
403452
for _, spec1Tag := range spec1.Tags {
404453
if spec2Tag.Name == spec1Tag.Name {
405454
sd.checkAddedExtensions(spec1Tag.Extensions, spec2Tag.Extensions, diffLocation, "")
455+
sd.checkChangedExtensions(spec1Tag.Extensions, spec2Tag.Extensions, diffLocation, "")
406456
}
407457
}
408458
}
@@ -430,6 +480,21 @@ func (sd *SpecAnalyser) checkAddedExtensions(extensions1 spec.Extensions, extens
430480
}
431481
}
432482

483+
func (sd *SpecAnalyser) checkChangedExtensions(extensions1 spec.Extensions, extensions2 spec.Extensions, diffLocation DifferenceLocation, fieldPrefix string) {
484+
for extKey, ext2Val := range extensions2 {
485+
if ext1Val, ok := extensions1[extKey]; ok && !reflect.DeepEqual(ext1Val, ext2Val) {
486+
if fieldPrefix != "" {
487+
extKey = fmt.Sprintf("%s.%s", fieldPrefix, extKey)
488+
}
489+
sd.Diffs = sd.Diffs.addDiff(SpecDifference{
490+
DifferenceLocation: diffLocation.AddNode(&Node{Field: extKey}),
491+
Code: ChangedExtensionValue,
492+
Compatibility: Warning, // this could potentially be a breaking change
493+
})
494+
}
495+
}
496+
}
497+
433498
func (sd *SpecAnalyser) checkDeletedExtensions(extensions1 spec.Extensions, extensions2 spec.Extensions, diffLocation DifferenceLocation, fieldPrefix string) {
434499
for extKey := range extensions1 {
435500
if _, ok := extensions2[extKey]; !ok {

0 commit comments

Comments
 (0)