@@ -32,6 +32,8 @@ type SpecAnalyser struct {
3232 urlMethods2 URLMethods
3333 Definitions1 spec.Definitions
3434 Definitions2 spec.Definitions
35+ Info1 * spec.Info
36+ Info2 * spec.Info
3537 ReferencedDefinitions map [string ]bool
3638
3739 schemasCompared map [string ]struct {}
@@ -50,6 +52,8 @@ func (sd *SpecAnalyser) Analyse(spec1, spec2 *spec.Swagger) error {
5052 sd .schemasCompared = make (map [string ]struct {})
5153 sd .Definitions1 = spec1 .Definitions
5254 sd .Definitions2 = spec2 .Definitions
55+ sd .Info1 = spec1 .Info
56+ sd .Info2 = spec2 .Info
5357 sd .urlMethods1 = getURLMethodsFor (spec1 )
5458 sd .urlMethods2 = getURLMethodsFor (spec2 )
5559
@@ -58,6 +62,7 @@ func (sd *SpecAnalyser) Analyse(spec1, spec2 *spec.Swagger) error {
5862 sd .analyseRequestParams ()
5963 sd .analyseEndpointData ()
6064 sd .analyseResponseParams ()
65+ sd .analyseExtensions (spec1 , spec2 )
6166 sd .AnalyseDefinitions ()
6267
6368 return nil
@@ -231,7 +236,6 @@ func (sd *SpecAnalyser) analyseResponseParams() {
231236 }
232237 // Added updated Response Codes
233238 for code2 , op2Response := range op2Responses {
234-
235239 if op1Response , ok := op1Responses [code2 ]; ok {
236240 op1Headers := op1Response .ResponseProps .Headers
237241 headerRootNode := getNameOnlyDiffNode ("Headers" )
@@ -284,6 +288,163 @@ func (sd *SpecAnalyser) analyseResponseParams() {
284288 }
285289}
286290
291+ func (sd * SpecAnalyser ) analyseExtensions (spec1 , spec2 * spec.Swagger ) {
292+ // root
293+ specLoc := DifferenceLocation {Node : & Node {Field : "Spec" }}
294+ sd .checkAddedExtensions (spec1 .Extensions , spec2 .Extensions , specLoc , "" )
295+ sd .checkDeletedExtensions (spec1 .Extensions , spec2 .Extensions , specLoc , "" )
296+
297+ sd .analyzeInfoExtensions ()
298+ sd .analyzeTagExtensions (spec1 , spec2 )
299+ sd .analyzeSecurityDefinitionExtensions (spec1 , spec2 )
300+
301+ sd .analyzeOperationExtensions ()
302+ }
303+
304+ func (sd * SpecAnalyser ) analyzeOperationExtensions () {
305+ for urlMethod , op2 := range sd .urlMethods2 {
306+ pathAndMethodLoc := DifferenceLocation {URL : urlMethod .Path , Method : urlMethod .Method }
307+ if op1 , ok := sd .urlMethods1 [urlMethod ]; ok {
308+ sd .checkAddedExtensions (op1 .Extensions , op2 .Extensions , DifferenceLocation {URL : urlMethod .Path }, "" )
309+ sd .checkAddedExtensions (op1 .Operation .Responses .Extensions , op2 .Operation .Responses .Extensions , pathAndMethodLoc , "Responses" )
310+ sd .checkAddedExtensions (op1 .Operation .Extensions , op2 .Operation .Extensions , pathAndMethodLoc , "" )
311+
312+ for code , resp := range op1 .Operation .Responses .StatusCodeResponses {
313+ for hdr , h := range resp .Headers {
314+ op2StatusCode , ok := op2 .Operation .Responses .StatusCodeResponses [code ]
315+ if ok {
316+ if _ , ok = op2StatusCode .Headers [hdr ]; ok {
317+ sd .checkAddedExtensions (h .Extensions , op2StatusCode .Headers [hdr ].Extensions , DifferenceLocation {URL : urlMethod .Path , Method : urlMethod .Method , Node : getNameOnlyDiffNode ("Headers" )}, hdr )
318+ }
319+ }
320+ }
321+
322+ resp2 := op2 .Operation .Responses .StatusCodeResponses [code ]
323+ sd .analyzeSchemaExtensions (resp .Schema , resp2 .Schema , code , urlMethod )
324+ }
325+
326+ }
327+ }
328+
329+ for urlMethod , op1 := range sd .urlMethods1 {
330+ pathAndMethodLoc := DifferenceLocation {URL : urlMethod .Path , Method : urlMethod .Method }
331+ if op2 , ok := sd .urlMethods2 [urlMethod ]; ok {
332+ sd .checkDeletedExtensions (op1 .Extensions , op2 .Extensions , DifferenceLocation {URL : urlMethod .Path }, "" )
333+ sd .checkDeletedExtensions (op1 .Operation .Responses .Extensions , op2 .Operation .Responses .Extensions , pathAndMethodLoc , "Responses" )
334+ sd .checkDeletedExtensions (op1 .Operation .Extensions , op2 .Operation .Extensions , pathAndMethodLoc , "" )
335+ for code , resp := range op1 .Operation .Responses .StatusCodeResponses {
336+ for hdr , h := range resp .Headers {
337+ op2StatusCode , ok := op2 .Operation .Responses .StatusCodeResponses [code ]
338+ if ok {
339+ if _ , ok = op2StatusCode .Headers [hdr ]; ok {
340+ sd .checkDeletedExtensions (h .Extensions , op2StatusCode .Headers [hdr ].Extensions , DifferenceLocation {URL : urlMethod .Path , Method : urlMethod .Method , Node : getNameOnlyDiffNode ("Headers" )}, hdr )
341+ }
342+ }
343+ }
344+ }
345+ }
346+ }
347+ }
348+
349+ func (sd * SpecAnalyser ) analyzeSecurityDefinitionExtensions (spec1 * spec.Swagger , spec2 * spec.Swagger ) {
350+ securityDefLoc := DifferenceLocation {Node : & Node {Field : "Security Definitions" }}
351+ for key , securityDef := range spec1 .SecurityDefinitions {
352+ if securityDef2 , ok := spec2 .SecurityDefinitions [key ]; ok {
353+ sd .checkAddedExtensions (securityDef .Extensions , securityDef2 .Extensions , securityDefLoc , "" )
354+ }
355+ }
356+
357+ for key , securityDef := range spec2 .SecurityDefinitions {
358+ if securityDef1 , ok := spec1 .SecurityDefinitions [key ]; ok {
359+ sd .checkDeletedExtensions (securityDef1 .Extensions , securityDef .Extensions , securityDefLoc , "" )
360+ }
361+ }
362+ }
363+
364+ func (sd * SpecAnalyser ) analyzeSchemaExtensions (schema1 , schema2 * spec.Schema , code int , urlMethod URLMethod ) {
365+ if schema1 != nil && schema2 != nil {
366+ diffLoc := DifferenceLocation {Response : code , URL : urlMethod .Path , Method : urlMethod .Method , Node : getSchemaDiffNode ("Body" , schema2 )}
367+ sd .checkAddedExtensions (schema1 .Extensions , schema2 .Extensions , diffLoc , "" )
368+ sd .checkDeletedExtensions (schema1 .Extensions , schema2 .Extensions , diffLoc , "" )
369+ if schema1 .Items != nil && schema2 .Items != nil {
370+ sd .analyzeSchemaExtensions (schema1 .Items .Schema , schema2 .Items .Schema , code , urlMethod )
371+ for i := range schema1 .Items .Schemas {
372+ s1 := schema1 .Items .Schemas [i ]
373+ for j := range schema2 .Items .Schemas {
374+ s2 := schema2 .Items .Schemas [j ]
375+ sd .analyzeSchemaExtensions (& s1 , & s2 , code , urlMethod )
376+ }
377+ }
378+ }
379+ }
380+ }
381+
382+ func (sd * SpecAnalyser ) analyzeInfoExtensions () {
383+ if sd .Info1 != nil && sd .Info2 != nil {
384+ diffLocation := DifferenceLocation {Node : & Node {Field : "Spec Info" }}
385+ sd .checkAddedExtensions (sd .Info1 .Extensions , sd .Info2 .Extensions , diffLocation , "" )
386+ sd .checkDeletedExtensions (sd .Info1 .Extensions , sd .Info2 .Extensions , diffLocation , "" )
387+ if sd .Info1 .Contact != nil && sd .Info2 .Contact != nil {
388+ diffLocation = DifferenceLocation {Node : & Node {Field : "Spec Info.Contact" }}
389+ sd .checkAddedExtensions (sd .Info1 .Contact .Extensions , sd .Info2 .Contact .Extensions , diffLocation , "" )
390+ sd .checkDeletedExtensions (sd .Info1 .Contact .Extensions , sd .Info2 .Contact .Extensions , diffLocation , "" )
391+ }
392+ if sd .Info1 .License != nil && sd .Info2 .License != nil {
393+ diffLocation = DifferenceLocation {Node : & Node {Field : "Spec Info.License" }}
394+ sd .checkAddedExtensions (sd .Info1 .License .Extensions , sd .Info2 .License .Extensions , diffLocation , "" )
395+ sd .checkDeletedExtensions (sd .Info1 .License .Extensions , sd .Info2 .License .Extensions , diffLocation , "" )
396+ }
397+ }
398+ }
399+
400+ func (sd * SpecAnalyser ) analyzeTagExtensions (spec1 * spec.Swagger , spec2 * spec.Swagger ) {
401+ diffLocation := DifferenceLocation {Node : & Node {Field : "Spec Tags" }}
402+ for _ , spec2Tag := range spec2 .Tags {
403+ for _ , spec1Tag := range spec1 .Tags {
404+ if spec2Tag .Name == spec1Tag .Name {
405+ sd .checkAddedExtensions (spec1Tag .Extensions , spec2Tag .Extensions , diffLocation , "" )
406+ }
407+ }
408+ }
409+ for _ , spec1Tag := range spec1 .Tags {
410+ for _ , spec2Tag := range spec2 .Tags {
411+ if spec1Tag .Name == spec2Tag .Name {
412+ sd .checkDeletedExtensions (spec1Tag .Extensions , spec2Tag .Extensions , diffLocation , "" )
413+ }
414+ }
415+ }
416+ }
417+
418+ func (sd * SpecAnalyser ) checkAddedExtensions (extensions1 spec.Extensions , extensions2 spec.Extensions , diffLocation DifferenceLocation , fieldPrefix string ) {
419+ for extKey := range extensions2 {
420+ if _ , ok := extensions1 [extKey ]; ! ok {
421+ if fieldPrefix != "" {
422+ extKey = fmt .Sprintf ("%s.%s" , fieldPrefix , extKey )
423+ }
424+ sd .Diffs = sd .Diffs .addDiff (SpecDifference {
425+ DifferenceLocation : diffLocation .AddNode (& Node {Field : extKey }),
426+ Code : AddedExtension ,
427+ Compatibility : Warning , // this could potentially be a breaking change
428+ })
429+ }
430+ }
431+ }
432+
433+ func (sd * SpecAnalyser ) checkDeletedExtensions (extensions1 spec.Extensions , extensions2 spec.Extensions , diffLocation DifferenceLocation , fieldPrefix string ) {
434+ for extKey := range extensions1 {
435+ if _ , ok := extensions2 [extKey ]; ! ok {
436+ if fieldPrefix != "" {
437+ extKey = fmt .Sprintf ("%s.%s" , fieldPrefix , extKey )
438+ }
439+ sd .Diffs = sd .Diffs .addDiff (SpecDifference {
440+ DifferenceLocation : diffLocation .AddNode (& Node {Field : extKey }),
441+ Code : DeletedExtension ,
442+ Compatibility : Warning , // this could potentially be a breaking change
443+ })
444+ }
445+ }
446+ }
447+
287448func addTypeDiff (diffs []TypeDiff , diff TypeDiff ) []TypeDiff {
288449 if diff .Change != NoChangeDetected {
289450 diffs = append (diffs , diff )
@@ -370,9 +531,7 @@ func (sd *SpecAnalyser) compareParams(urlMethod URLMethod, location string, name
370531 sd .addDiffs (childLocation , diffs )
371532 }
372533
373- if & param1 .SimpleSchema != nil && & param2 .SimpleSchema != nil {
374- sd .compareSimpleSchema (childLocation , & param1 .SimpleSchema , & param2 .SimpleSchema )
375- }
534+ sd .compareSimpleSchema (childLocation , & param1 .SimpleSchema , & param2 .SimpleSchema )
376535}
377536
378537func (sd * SpecAnalyser ) addTypeDiff (location DifferenceLocation , diff * TypeDiff ) {
@@ -483,21 +642,23 @@ func (sd *SpecAnalyser) compareSimpleSchema(location DifferenceLocation, schema1
483642 }
484643
485644 if schema1 .Default != schema2 .Default {
486- if schema1 .Default == nil && schema2 .Default != nil {
645+ switch {
646+ case schema1 .Default == nil && schema2 .Default != nil :
487647 sd .addDiffs (location , addTypeDiff ([]TypeDiff {}, TypeDiff {Change : AddedDefault , FromType : getSchemaTypeStr (schema1 ), ToType : getSchemaTypeStr (schema2 )}))
488- } else if schema1 .Default != nil && schema2 .Default == nil {
648+ case schema1 .Default != nil && schema2 .Default == nil :
489649 sd .addDiffs (location , addTypeDiff ([]TypeDiff {}, TypeDiff {Change : DeletedDefault , FromType : getSchemaTypeStr (schema1 ), ToType : getSchemaTypeStr (schema2 )}))
490- } else {
650+ default :
491651 sd .addDiffs (location , addTypeDiff ([]TypeDiff {}, TypeDiff {Change : ChangedDefault , FromType : getSchemaTypeStr (schema1 ), ToType : getSchemaTypeStr (schema2 )}))
492652 }
493653 }
494654
495655 if schema1 .Example != schema2 .Example {
496- if schema1 .Example == nil && schema2 .Example != nil {
656+ switch {
657+ case schema1 .Example == nil && schema2 .Example != nil :
497658 sd .addDiffs (location , addTypeDiff ([]TypeDiff {}, TypeDiff {Change : AddedExample , FromType : getSchemaTypeStr (schema1 ), ToType : getSchemaTypeStr (schema2 )}))
498- } else if schema1 .Example != nil && schema2 .Example == nil {
659+ case schema1 .Example != nil && schema2 .Example == nil :
499660 sd .addDiffs (location , addTypeDiff ([]TypeDiff {}, TypeDiff {Change : DeletedExample , FromType : getSchemaTypeStr (schema1 ), ToType : getSchemaTypeStr (schema2 )}))
500- } else {
661+ default :
501662 sd .addDiffs (location , addTypeDiff ([]TypeDiff {}, TypeDiff {Change : ChangedExample , FromType : getSchemaTypeStr (schema1 ), ToType : getSchemaTypeStr (schema2 )}))
502663 }
503664 }
0 commit comments