@@ -2,6 +2,7 @@ package diff
22
33import (
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
304306func (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+
349393func (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+
433498func (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