mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-09 20:47:44 +00:00
Moved what-changed PropertyChanges to a pointer in all models.
No breaking changes, gofmt seems to have gone a little nuts for some reason, but this is an internal change that moves everything to a pointer, for better reflection use down the chain.
This commit is contained in:
@@ -4,97 +4,97 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CallbackChanges represents all changes made between two Callback OpenAPI objects.
|
// CallbackChanges represents all changes made between two Callback OpenAPI objects.
|
||||||
type CallbackChanges struct {
|
type CallbackChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ExpressionChanges map[string]*PathItemChanges `json:"expressions,omitempty" yaml:"expressions,omitempty"`
|
ExpressionChanges map[string]*PathItemChanges `json:"expressions,omitempty" yaml:"expressions,omitempty"`
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns a total count of all changes made between Callback objects
|
// TotalChanges returns a total count of all changes made between Callback objects
|
||||||
func (c *CallbackChanges) TotalChanges() int {
|
func (c *CallbackChanges) TotalChanges() int {
|
||||||
d := c.PropertyChanges.TotalChanges()
|
d := c.PropertyChanges.TotalChanges()
|
||||||
for k := range c.ExpressionChanges {
|
for k := range c.ExpressionChanges {
|
||||||
d += c.ExpressionChanges[k].TotalChanges()
|
d += c.ExpressionChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
if c.ExtensionChanges != nil {
|
if c.ExtensionChanges != nil {
|
||||||
d += c.ExtensionChanges.TotalChanges()
|
d += c.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns a total count of all changes made between Callback objects
|
// TotalBreakingChanges returns a total count of all changes made between Callback objects
|
||||||
func (c *CallbackChanges) TotalBreakingChanges() int {
|
func (c *CallbackChanges) TotalBreakingChanges() int {
|
||||||
d := c.PropertyChanges.TotalBreakingChanges()
|
d := c.PropertyChanges.TotalBreakingChanges()
|
||||||
for k := range c.ExpressionChanges {
|
for k := range c.ExpressionChanges {
|
||||||
d += c.ExpressionChanges[k].TotalBreakingChanges()
|
d += c.ExpressionChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
if c.ExtensionChanges != nil {
|
if c.ExtensionChanges != nil {
|
||||||
d += c.ExtensionChanges.TotalBreakingChanges()
|
d += c.ExtensionChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareCallback will compare two Callback objects and return a pointer to CallbackChanges with all the things
|
// CompareCallback will compare two Callback objects and return a pointer to CallbackChanges with all the things
|
||||||
// that have changed between them.
|
// that have changed between them.
|
||||||
func CompareCallback(l, r *v3.Callback) *CallbackChanges {
|
func CompareCallback(l, r *v3.Callback) *CallbackChanges {
|
||||||
|
|
||||||
cc := new(CallbackChanges)
|
cc := new(CallbackChanges)
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
|
|
||||||
lHashes := make(map[string]string)
|
lHashes := make(map[string]string)
|
||||||
rHashes := make(map[string]string)
|
rHashes := make(map[string]string)
|
||||||
|
|
||||||
lValues := make(map[string]low.ValueReference[*v3.PathItem])
|
lValues := make(map[string]low.ValueReference[*v3.PathItem])
|
||||||
rValues := make(map[string]low.ValueReference[*v3.PathItem])
|
rValues := make(map[string]low.ValueReference[*v3.PathItem])
|
||||||
|
|
||||||
for k := range l.Expression.Value {
|
for k := range l.Expression.Value {
|
||||||
lHashes[k.Value] = low.GenerateHashString(l.Expression.Value[k].Value)
|
lHashes[k.Value] = low.GenerateHashString(l.Expression.Value[k].Value)
|
||||||
lValues[k.Value] = l.Expression.Value[k]
|
lValues[k.Value] = l.Expression.Value[k]
|
||||||
}
|
}
|
||||||
|
|
||||||
for k := range r.Expression.Value {
|
for k := range r.Expression.Value {
|
||||||
rHashes[k.Value] = low.GenerateHashString(r.Expression.Value[k].Value)
|
rHashes[k.Value] = low.GenerateHashString(r.Expression.Value[k].Value)
|
||||||
rValues[k.Value] = r.Expression.Value[k]
|
rValues[k.Value] = r.Expression.Value[k]
|
||||||
}
|
}
|
||||||
|
|
||||||
expChanges := make(map[string]*PathItemChanges)
|
expChanges := make(map[string]*PathItemChanges)
|
||||||
|
|
||||||
// check left path item hashes
|
// check left path item hashes
|
||||||
for k := range lHashes {
|
for k := range lHashes {
|
||||||
rhash := rHashes[k]
|
rhash := rHashes[k]
|
||||||
if rhash == "" {
|
if rhash == "" {
|
||||||
CreateChange(&changes, ObjectRemoved, k,
|
CreateChange(&changes, ObjectRemoved, k,
|
||||||
lValues[k].GetValueNode(), nil, true,
|
lValues[k].GetValueNode(), nil, true,
|
||||||
lValues[k].GetValue(), nil)
|
lValues[k].GetValue(), nil)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if lHashes[k] == rHashes[k] {
|
if lHashes[k] == rHashes[k] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// run comparison.
|
// run comparison.
|
||||||
expChanges[k] = ComparePathItems(lValues[k].Value, rValues[k].Value)
|
expChanges[k] = ComparePathItems(lValues[k].Value, rValues[k].Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
//check right path item hashes
|
//check right path item hashes
|
||||||
for k := range rHashes {
|
for k := range rHashes {
|
||||||
lhash := lHashes[k]
|
lhash := lHashes[k]
|
||||||
if lhash == "" {
|
if lhash == "" {
|
||||||
CreateChange(&changes, ObjectAdded, k,
|
CreateChange(&changes, ObjectAdded, k,
|
||||||
nil, rValues[k].GetValueNode(), false,
|
nil, rValues[k].GetValueNode(), false,
|
||||||
nil, rValues[k].GetValue())
|
nil, rValues[k].GetValue())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cc.ExpressionChanges = expChanges
|
cc.ExpressionChanges = expChanges
|
||||||
cc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
cc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||||
cc.Changes = changes
|
cc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
if cc.TotalChanges() <= 0 {
|
if cc.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return cc
|
return cc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,42 +4,42 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Definitions of the possible changes between two items
|
// Definitions of the possible changes between two items
|
||||||
const (
|
const (
|
||||||
|
|
||||||
// Modified means that was a modification of a value was made
|
// Modified means that was a modification of a value was made
|
||||||
Modified = iota + 1
|
Modified = iota + 1
|
||||||
|
|
||||||
// PropertyAdded means that a new property to an object was added
|
// PropertyAdded means that a new property to an object was added
|
||||||
PropertyAdded
|
PropertyAdded
|
||||||
|
|
||||||
// ObjectAdded means that a new object was added to a parent object
|
// ObjectAdded means that a new object was added to a parent object
|
||||||
ObjectAdded
|
ObjectAdded
|
||||||
|
|
||||||
// ObjectRemoved means that an object was removed from a parent object
|
// ObjectRemoved means that an object was removed from a parent object
|
||||||
ObjectRemoved
|
ObjectRemoved
|
||||||
|
|
||||||
// PropertyRemoved means that a property of an object was removed
|
// PropertyRemoved means that a property of an object was removed
|
||||||
PropertyRemoved
|
PropertyRemoved
|
||||||
)
|
)
|
||||||
|
|
||||||
// WhatChanged is a summary object that contains a high level summary of everything changed.
|
// WhatChanged is a summary object that contains a high level summary of everything changed.
|
||||||
type WhatChanged struct {
|
type WhatChanged struct {
|
||||||
Added int `json:"added,omitempty" yaml:"added,omitempty"`
|
Added int `json:"added,omitempty" yaml:"added,omitempty"`
|
||||||
Removed int `json:"removed,omitempty" yaml:"removed,omitempty"`
|
Removed int `json:"removed,omitempty" yaml:"removed,omitempty"`
|
||||||
Modified int `json:"modified,omitempty" yaml:"modified,omitempty"`
|
Modified int `json:"modified,omitempty" yaml:"modified,omitempty"`
|
||||||
TotalChanges int `json:"total,omitempty" yaml:"total,omitempty"`
|
TotalChanges int `json:"total,omitempty" yaml:"total,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChangeContext holds a reference to the line and column positions of original and new change.
|
// ChangeContext holds a reference to the line and column positions of original and new change.
|
||||||
type ChangeContext struct {
|
type ChangeContext struct {
|
||||||
OriginalLine *int `json:"originalLine,omitempty" yaml:"originalLine,omitempty"`
|
OriginalLine *int `json:"originalLine,omitempty" yaml:"originalLine,omitempty"`
|
||||||
OriginalColumn *int `json:"originalColumn,omitempty" yaml:"originalColumn,omitempty"`
|
OriginalColumn *int `json:"originalColumn,omitempty" yaml:"originalColumn,omitempty"`
|
||||||
NewLine *int `json:"newLine,omitempty" yaml:"newLine,omitempty"`
|
NewLine *int `json:"newLine,omitempty" yaml:"newLine,omitempty"`
|
||||||
NewColumn *int `json:"newColumn,omitempty" yaml:"newColumn,omitempty"`
|
NewColumn *int `json:"newColumn,omitempty" yaml:"newColumn,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasChanged determines if the line and column numbers of the original and new values have changed.
|
// HasChanged determines if the line and column numbers of the original and new values have changed.
|
||||||
@@ -47,66 +47,70 @@ type ChangeContext struct {
|
|||||||
// It's worth noting that there is no guarantee to the positions of anything in either left or right, so
|
// It's worth noting that there is no guarantee to the positions of anything in either left or right, so
|
||||||
// considering these values as 'changes' is going to add a considerable amount of noise to results.
|
// considering these values as 'changes' is going to add a considerable amount of noise to results.
|
||||||
func (c *ChangeContext) HasChanged() bool {
|
func (c *ChangeContext) HasChanged() bool {
|
||||||
if c.NewLine != nil && c.OriginalLine != nil && *c.NewLine != *c.OriginalLine {
|
if c.NewLine != nil && c.OriginalLine != nil && *c.NewLine != *c.OriginalLine {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if c.NewColumn != nil && c.OriginalColumn != nil && *c.NewColumn != *c.OriginalColumn {
|
if c.NewColumn != nil && c.OriginalColumn != nil && *c.NewColumn != *c.OriginalColumn {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if (c.NewLine == nil && c.OriginalLine != nil) || (c.NewLine != nil && c.OriginalLine == nil) {
|
if (c.NewLine == nil && c.OriginalLine != nil) || (c.NewLine != nil && c.OriginalLine == nil) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if (c.NewColumn == nil && c.OriginalColumn != nil) || (c.NewColumn != nil && c.OriginalColumn == nil) {
|
if (c.NewColumn == nil && c.OriginalColumn != nil) || (c.NewColumn != nil && c.OriginalColumn == nil) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change represents a change between two different elements inside an OpenAPI specification.
|
// Change represents a change between two different elements inside an OpenAPI specification.
|
||||||
type Change struct {
|
type Change struct {
|
||||||
|
|
||||||
// Context represents the lines and column numbers of the original and new values
|
// Context represents the lines and column numbers of the original and new values
|
||||||
// It's worth noting that these values may frequently be different and are not used to calculate
|
// It's worth noting that these values may frequently be different and are not used to calculate
|
||||||
// a change. If the positions change, but values do not, then no change is recorded.
|
// a change. If the positions change, but values do not, then no change is recorded.
|
||||||
Context *ChangeContext `json:"context,omitempty" yaml:"context,omitempty"`
|
Context *ChangeContext `json:"context,omitempty" yaml:"context,omitempty"`
|
||||||
|
|
||||||
// ChangeType represents the type of change that occurred. stored as an integer, defined by constants above.
|
// ChangeType represents the type of change that occurred. stored as an integer, defined by constants above.
|
||||||
ChangeType int `json:"change,omitempty" yaml:"change,omitempty"`
|
ChangeType int `json:"change,omitempty" yaml:"change,omitempty"`
|
||||||
|
|
||||||
// Property is the property name key being changed.
|
// Property is the property name key being changed.
|
||||||
Property string `json:"property,omitempty" yaml:"property,omitempty"`
|
Property string `json:"property,omitempty" yaml:"property,omitempty"`
|
||||||
|
|
||||||
// Original is the original value represented as a string.
|
// Original is the original value represented as a string.
|
||||||
Original string `json:"original,omitempty" yaml:"original,omitempty"`
|
Original string `json:"original,omitempty" yaml:"original,omitempty"`
|
||||||
|
|
||||||
// New is the new value represented as a string.
|
// New is the new value represented as a string.
|
||||||
New string `json:"new,omitempty" yaml:"new,omitempty"`
|
New string `json:"new,omitempty" yaml:"new,omitempty"`
|
||||||
|
|
||||||
// Breaking determines if the change is a breaking one or not.
|
// Breaking determines if the change is a breaking one or not.
|
||||||
Breaking bool `json:"breaking" yaml:"breaking"`
|
Breaking bool `json:"breaking" yaml:"breaking"`
|
||||||
|
|
||||||
// OriginalObject represents the original object that was changed.
|
// OriginalObject represents the original object that was changed.
|
||||||
OriginalObject any `json:"-" yaml:"-"`
|
OriginalObject any `json:"-" yaml:"-"`
|
||||||
|
|
||||||
// NewObject represents the new object that has been modified.
|
// NewObject represents the new object that has been modified.
|
||||||
NewObject any `json:"-" yaml:"-"`
|
NewObject any `json:"-" yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PropertyChanges holds a slice of Change pointers
|
// PropertyChanges holds a slice of Change pointers
|
||||||
type PropertyChanges struct {
|
type PropertyChanges struct {
|
||||||
//Total *int `json:"total,omitempty" yaml:"total,omitempty"`
|
//Total *int `json:"total,omitempty" yaml:"total,omitempty"`
|
||||||
//Breaking *int `json:"breaking,omitempty" yaml:"breaking,omitempty"`
|
//Breaking *int `json:"breaking,omitempty" yaml:"breaking,omitempty"`
|
||||||
Changes []*Change `json:"changes,omitempty" yaml:"changes,omitempty"`
|
Changes []*Change `json:"changes,omitempty" yaml:"changes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns the total number of property changes made.
|
// TotalChanges returns the total number of property changes made.
|
||||||
func (p PropertyChanges) TotalChanges() int {
|
func (p PropertyChanges) TotalChanges() int {
|
||||||
return len(p.Changes)
|
return len(p.Changes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the total number of property breaking changes made.
|
// TotalBreakingChanges returns the total number of property breaking changes made.
|
||||||
func (p PropertyChanges) TotalBreakingChanges() int {
|
func (p PropertyChanges) TotalBreakingChanges() int {
|
||||||
return CountBreakingChanges(p.Changes)
|
return CountBreakingChanges(p.Changes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPropertyChanges(changes []*Change) *PropertyChanges {
|
||||||
|
return &PropertyChanges{Changes: changes}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SortByChangeType will order changes by the types of change they represent,
|
// SortByChangeType will order changes by the types of change they represent,
|
||||||
@@ -120,24 +124,24 @@ func (p PropertyChanges) TotalBreakingChanges() int {
|
|||||||
// PropertyCheck is used by functions to check the state of left and right values.
|
// PropertyCheck is used by functions to check the state of left and right values.
|
||||||
type PropertyCheck struct {
|
type PropertyCheck struct {
|
||||||
|
|
||||||
// Original is the property we're checking on the left
|
// Original is the property we're checking on the left
|
||||||
Original any
|
Original any
|
||||||
|
|
||||||
// New is s the property we're checking on the right
|
// New is s the property we're checking on the right
|
||||||
New any
|
New any
|
||||||
|
|
||||||
// Label is the identifier we're looking for on the left and right hand sides
|
// Label is the identifier we're looking for on the left and right hand sides
|
||||||
Label string
|
Label string
|
||||||
|
|
||||||
// LeftNode is the yaml.Node pointer that holds the original node structure of the value
|
// LeftNode is the yaml.Node pointer that holds the original node structure of the value
|
||||||
LeftNode *yaml.Node
|
LeftNode *yaml.Node
|
||||||
|
|
||||||
// RightNode is the yaml.Node pointer that holds the new node structure of the value
|
// RightNode is the yaml.Node pointer that holds the new node structure of the value
|
||||||
RightNode *yaml.Node
|
RightNode *yaml.Node
|
||||||
|
|
||||||
// Breaking determines if the check is a breaking change (modifications or removals etc.)
|
// Breaking determines if the check is a breaking change (modifications or removals etc.)
|
||||||
Breaking bool
|
Breaking bool
|
||||||
|
|
||||||
// Changes represents a pointer to the slice to contain all changes found.
|
// Changes represents a pointer to the slice to contain all changes found.
|
||||||
Changes *[]*Change
|
Changes *[]*Change
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ComponentsChanges represents changes made to both OpenAPI and Swagger documents. This model is based on OpenAPI 3
|
// ComponentsChanges represents changes made to both OpenAPI and Swagger documents. This model is based on OpenAPI 3
|
||||||
@@ -35,228 +35,228 @@ import (
|
|||||||
// modifications are not checked, these checks occur in-place by implementing objects as they are autp-resolved
|
// modifications are not checked, these checks occur in-place by implementing objects as they are autp-resolved
|
||||||
// when the model is built.
|
// when the model is built.
|
||||||
type ComponentsChanges struct {
|
type ComponentsChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
SchemaChanges map[string]*SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
SchemaChanges map[string]*SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||||
SecuritySchemeChanges map[string]*SecuritySchemeChanges `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"`
|
SecuritySchemeChanges map[string]*SecuritySchemeChanges `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"`
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareComponents will compare OpenAPI components for any changes. Accepts Swagger Definition objects
|
// CompareComponents will compare OpenAPI components for any changes. Accepts Swagger Definition objects
|
||||||
// like ParameterDefinitions or Definitions etc.
|
// like ParameterDefinitions or Definitions etc.
|
||||||
func CompareComponents(l, r any) *ComponentsChanges {
|
func CompareComponents(l, r any) *ComponentsChanges {
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
|
|
||||||
cc := new(ComponentsChanges)
|
cc := new(ComponentsChanges)
|
||||||
|
|
||||||
// Swagger Parameters
|
// Swagger Parameters
|
||||||
if reflect.TypeOf(&v2.ParameterDefinitions{}) == reflect.TypeOf(l) &&
|
if reflect.TypeOf(&v2.ParameterDefinitions{}) == reflect.TypeOf(l) &&
|
||||||
reflect.TypeOf(&v2.ParameterDefinitions{}) == reflect.TypeOf(r) {
|
reflect.TypeOf(&v2.ParameterDefinitions{}) == reflect.TypeOf(r) {
|
||||||
lDef := l.(*v2.ParameterDefinitions)
|
lDef := l.(*v2.ParameterDefinitions)
|
||||||
rDef := r.(*v2.ParameterDefinitions)
|
rDef := r.(*v2.ParameterDefinitions)
|
||||||
var a, b map[low.KeyReference[string]]low.ValueReference[*v2.Parameter]
|
var a, b map[low.KeyReference[string]]low.ValueReference[*v2.Parameter]
|
||||||
if lDef != nil {
|
if lDef != nil {
|
||||||
a = lDef.Definitions
|
a = lDef.Definitions
|
||||||
}
|
}
|
||||||
if rDef != nil {
|
if rDef != nil {
|
||||||
b = rDef.Definitions
|
b = rDef.Definitions
|
||||||
}
|
}
|
||||||
CheckMapForAdditionRemoval(a, b, &changes, v3.ParametersLabel)
|
CheckMapForAdditionRemoval(a, b, &changes, v3.ParametersLabel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swagger Responses
|
// Swagger Responses
|
||||||
if reflect.TypeOf(&v2.ResponsesDefinitions{}) == reflect.TypeOf(l) &&
|
if reflect.TypeOf(&v2.ResponsesDefinitions{}) == reflect.TypeOf(l) &&
|
||||||
reflect.TypeOf(&v2.ResponsesDefinitions{}) == reflect.TypeOf(r) {
|
reflect.TypeOf(&v2.ResponsesDefinitions{}) == reflect.TypeOf(r) {
|
||||||
lDef := l.(*v2.ResponsesDefinitions)
|
lDef := l.(*v2.ResponsesDefinitions)
|
||||||
rDef := r.(*v2.ResponsesDefinitions)
|
rDef := r.(*v2.ResponsesDefinitions)
|
||||||
var a, b map[low.KeyReference[string]]low.ValueReference[*v2.Response]
|
var a, b map[low.KeyReference[string]]low.ValueReference[*v2.Response]
|
||||||
if lDef != nil {
|
if lDef != nil {
|
||||||
a = lDef.Definitions
|
a = lDef.Definitions
|
||||||
}
|
}
|
||||||
if rDef != nil {
|
if rDef != nil {
|
||||||
b = rDef.Definitions
|
b = rDef.Definitions
|
||||||
}
|
}
|
||||||
CheckMapForAdditionRemoval(a, b, &changes, v3.ResponsesLabel)
|
CheckMapForAdditionRemoval(a, b, &changes, v3.ResponsesLabel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swagger Schemas
|
// Swagger Schemas
|
||||||
if reflect.TypeOf(&v2.Definitions{}) == reflect.TypeOf(l) &&
|
if reflect.TypeOf(&v2.Definitions{}) == reflect.TypeOf(l) &&
|
||||||
reflect.TypeOf(&v2.Definitions{}) == reflect.TypeOf(r) {
|
reflect.TypeOf(&v2.Definitions{}) == reflect.TypeOf(r) {
|
||||||
lDef := l.(*v2.Definitions)
|
lDef := l.(*v2.Definitions)
|
||||||
rDef := r.(*v2.Definitions)
|
rDef := r.(*v2.Definitions)
|
||||||
var a, b map[low.KeyReference[string]]low.ValueReference[*base.SchemaProxy]
|
var a, b map[low.KeyReference[string]]low.ValueReference[*base.SchemaProxy]
|
||||||
if lDef != nil {
|
if lDef != nil {
|
||||||
a = lDef.Schemas
|
a = lDef.Schemas
|
||||||
}
|
}
|
||||||
if rDef != nil {
|
if rDef != nil {
|
||||||
b = rDef.Schemas
|
b = rDef.Schemas
|
||||||
}
|
}
|
||||||
cc.SchemaChanges = CheckMapForChanges(a, b, &changes, v2.DefinitionsLabel, CompareSchemas)
|
cc.SchemaChanges = CheckMapForChanges(a, b, &changes, v2.DefinitionsLabel, CompareSchemas)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swagger Security Definitions
|
// Swagger Security Definitions
|
||||||
if reflect.TypeOf(&v2.SecurityDefinitions{}) == reflect.TypeOf(l) &&
|
if reflect.TypeOf(&v2.SecurityDefinitions{}) == reflect.TypeOf(l) &&
|
||||||
reflect.TypeOf(&v2.SecurityDefinitions{}) == reflect.TypeOf(r) {
|
reflect.TypeOf(&v2.SecurityDefinitions{}) == reflect.TypeOf(r) {
|
||||||
lDef := l.(*v2.SecurityDefinitions)
|
lDef := l.(*v2.SecurityDefinitions)
|
||||||
rDef := r.(*v2.SecurityDefinitions)
|
rDef := r.(*v2.SecurityDefinitions)
|
||||||
var a, b map[low.KeyReference[string]]low.ValueReference[*v2.SecurityScheme]
|
var a, b map[low.KeyReference[string]]low.ValueReference[*v2.SecurityScheme]
|
||||||
if lDef != nil {
|
if lDef != nil {
|
||||||
a = lDef.Definitions
|
a = lDef.Definitions
|
||||||
}
|
}
|
||||||
if rDef != nil {
|
if rDef != nil {
|
||||||
b = rDef.Definitions
|
b = rDef.Definitions
|
||||||
}
|
}
|
||||||
cc.SecuritySchemeChanges = CheckMapForChanges(a, b, &changes,
|
cc.SecuritySchemeChanges = CheckMapForChanges(a, b, &changes,
|
||||||
v3.SecurityDefinitionLabel, CompareSecuritySchemesV2)
|
v3.SecurityDefinitionLabel, CompareSecuritySchemesV2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenAPI Components
|
// OpenAPI Components
|
||||||
if reflect.TypeOf(&v3.Components{}) == reflect.TypeOf(l) &&
|
if reflect.TypeOf(&v3.Components{}) == reflect.TypeOf(l) &&
|
||||||
reflect.TypeOf(&v3.Components{}) == reflect.TypeOf(r) {
|
reflect.TypeOf(&v3.Components{}) == reflect.TypeOf(r) {
|
||||||
|
|
||||||
lComponents := l.(*v3.Components)
|
lComponents := l.(*v3.Components)
|
||||||
rComponents := r.(*v3.Components)
|
rComponents := r.(*v3.Components)
|
||||||
|
|
||||||
//if low.AreEqual(lComponents, rComponents) {
|
//if low.AreEqual(lComponents, rComponents) {
|
||||||
// return nil
|
// return nil
|
||||||
//}
|
//}
|
||||||
|
|
||||||
doneChan := make(chan componentComparison)
|
doneChan := make(chan componentComparison)
|
||||||
comparisons := 0
|
comparisons := 0
|
||||||
|
|
||||||
// run as fast as we can, thread all the things.
|
// run as fast as we can, thread all the things.
|
||||||
if !lComponents.Schemas.IsEmpty() || !rComponents.Schemas.IsEmpty() {
|
if !lComponents.Schemas.IsEmpty() || !rComponents.Schemas.IsEmpty() {
|
||||||
comparisons++
|
comparisons++
|
||||||
go runComparison(lComponents.Schemas.Value, rComponents.Schemas.Value,
|
go runComparison(lComponents.Schemas.Value, rComponents.Schemas.Value,
|
||||||
&changes, v3.SchemasLabel, CompareSchemas, doneChan)
|
&changes, v3.SchemasLabel, CompareSchemas, doneChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !lComponents.Responses.IsEmpty() || !rComponents.Responses.IsEmpty() {
|
if !lComponents.Responses.IsEmpty() || !rComponents.Responses.IsEmpty() {
|
||||||
comparisons++
|
comparisons++
|
||||||
go runComparison(lComponents.Responses.Value, rComponents.Responses.Value,
|
go runComparison(lComponents.Responses.Value, rComponents.Responses.Value,
|
||||||
&changes, v3.ResponsesLabel, CompareResponseV3, doneChan)
|
&changes, v3.ResponsesLabel, CompareResponseV3, doneChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !lComponents.Parameters.IsEmpty() || !rComponents.Parameters.IsEmpty() {
|
if !lComponents.Parameters.IsEmpty() || !rComponents.Parameters.IsEmpty() {
|
||||||
comparisons++
|
comparisons++
|
||||||
go runComparison(lComponents.Parameters.Value, rComponents.Parameters.Value,
|
go runComparison(lComponents.Parameters.Value, rComponents.Parameters.Value,
|
||||||
&changes, v3.ParametersLabel, CompareParametersV3, doneChan)
|
&changes, v3.ParametersLabel, CompareParametersV3, doneChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !lComponents.Examples.IsEmpty() || !rComponents.Examples.IsEmpty() {
|
if !lComponents.Examples.IsEmpty() || !rComponents.Examples.IsEmpty() {
|
||||||
comparisons++
|
comparisons++
|
||||||
go runComparison(lComponents.Examples.Value, rComponents.Examples.Value,
|
go runComparison(lComponents.Examples.Value, rComponents.Examples.Value,
|
||||||
&changes, v3.ExamplesLabel, CompareExamples, doneChan)
|
&changes, v3.ExamplesLabel, CompareExamples, doneChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !lComponents.RequestBodies.IsEmpty() || !rComponents.RequestBodies.IsEmpty() {
|
if !lComponents.RequestBodies.IsEmpty() || !rComponents.RequestBodies.IsEmpty() {
|
||||||
comparisons++
|
comparisons++
|
||||||
go runComparison(lComponents.RequestBodies.Value, rComponents.RequestBodies.Value,
|
go runComparison(lComponents.RequestBodies.Value, rComponents.RequestBodies.Value,
|
||||||
&changes, v3.RequestBodiesLabel, CompareRequestBodies, doneChan)
|
&changes, v3.RequestBodiesLabel, CompareRequestBodies, doneChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !lComponents.Headers.IsEmpty() || !rComponents.Headers.IsEmpty() {
|
if !lComponents.Headers.IsEmpty() || !rComponents.Headers.IsEmpty() {
|
||||||
comparisons++
|
comparisons++
|
||||||
go runComparison(lComponents.Headers.Value, rComponents.Headers.Value,
|
go runComparison(lComponents.Headers.Value, rComponents.Headers.Value,
|
||||||
&changes, v3.HeadersLabel, CompareHeadersV3, doneChan)
|
&changes, v3.HeadersLabel, CompareHeadersV3, doneChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !lComponents.SecuritySchemes.IsEmpty() || !rComponents.SecuritySchemes.IsEmpty() {
|
if !lComponents.SecuritySchemes.IsEmpty() || !rComponents.SecuritySchemes.IsEmpty() {
|
||||||
comparisons++
|
comparisons++
|
||||||
go runComparison(lComponents.SecuritySchemes.Value, rComponents.SecuritySchemes.Value,
|
go runComparison(lComponents.SecuritySchemes.Value, rComponents.SecuritySchemes.Value,
|
||||||
&changes, v3.SecuritySchemesLabel, CompareSecuritySchemesV3, doneChan)
|
&changes, v3.SecuritySchemesLabel, CompareSecuritySchemesV3, doneChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !lComponents.Links.IsEmpty() || !rComponents.Links.IsEmpty() {
|
if !lComponents.Links.IsEmpty() || !rComponents.Links.IsEmpty() {
|
||||||
comparisons++
|
comparisons++
|
||||||
go runComparison(lComponents.Links.Value, rComponents.Links.Value,
|
go runComparison(lComponents.Links.Value, rComponents.Links.Value,
|
||||||
&changes, v3.LinksLabel, CompareLinks, doneChan)
|
&changes, v3.LinksLabel, CompareLinks, doneChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !lComponents.Callbacks.IsEmpty() || !rComponents.Callbacks.IsEmpty() {
|
if !lComponents.Callbacks.IsEmpty() || !rComponents.Callbacks.IsEmpty() {
|
||||||
comparisons++
|
comparisons++
|
||||||
go runComparison(lComponents.Callbacks.Value, rComponents.Callbacks.Value,
|
go runComparison(lComponents.Callbacks.Value, rComponents.Callbacks.Value,
|
||||||
&changes, v3.CallbacksLabel, CompareCallback, doneChan)
|
&changes, v3.CallbacksLabel, CompareCallback, doneChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
cc.ExtensionChanges = CompareExtensions(lComponents.Extensions, rComponents.Extensions)
|
cc.ExtensionChanges = CompareExtensions(lComponents.Extensions, rComponents.Extensions)
|
||||||
|
|
||||||
completedComponents := 0
|
completedComponents := 0
|
||||||
for completedComponents < comparisons {
|
for completedComponents < comparisons {
|
||||||
select {
|
select {
|
||||||
case res := <-doneChan:
|
case res := <-doneChan:
|
||||||
switch res.prop {
|
switch res.prop {
|
||||||
case v3.SchemasLabel:
|
case v3.SchemasLabel:
|
||||||
completedComponents++
|
completedComponents++
|
||||||
cc.SchemaChanges = res.result.(map[string]*SchemaChanges)
|
cc.SchemaChanges = res.result.(map[string]*SchemaChanges)
|
||||||
break
|
break
|
||||||
case v3.SecuritySchemesLabel:
|
case v3.SecuritySchemesLabel:
|
||||||
completedComponents++
|
completedComponents++
|
||||||
cc.SecuritySchemeChanges = res.result.(map[string]*SecuritySchemeChanges)
|
cc.SecuritySchemeChanges = res.result.(map[string]*SecuritySchemeChanges)
|
||||||
break
|
break
|
||||||
case v3.ResponsesLabel, v3.ParametersLabel, v3.ExamplesLabel, v3.RequestBodiesLabel, v3.HeadersLabel,
|
case v3.ResponsesLabel, v3.ParametersLabel, v3.ExamplesLabel, v3.RequestBodiesLabel, v3.HeadersLabel,
|
||||||
v3.LinksLabel, v3.CallbacksLabel:
|
v3.LinksLabel, v3.CallbacksLabel:
|
||||||
completedComponents++
|
completedComponents++
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cc.Changes = changes
|
cc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
if cc.TotalChanges() <= 0 {
|
if cc.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return cc
|
return cc
|
||||||
}
|
}
|
||||||
|
|
||||||
type componentComparison struct {
|
type componentComparison struct {
|
||||||
prop string
|
prop string
|
||||||
result any
|
result any
|
||||||
}
|
}
|
||||||
|
|
||||||
// run a generic comparison in a thread which in turn splits checks into further threads.
|
// run a generic comparison in a thread which in turn splits checks into further threads.
|
||||||
func runComparison[T any, R any](l, r map[low.KeyReference[string]]low.ValueReference[T],
|
func runComparison[T any, R any](l, r map[low.KeyReference[string]]low.ValueReference[T],
|
||||||
changes *[]*Change, label string, compareFunc func(l, r T) R, doneChan chan componentComparison) {
|
changes *[]*Change, label string, compareFunc func(l, r T) R, doneChan chan componentComparison) {
|
||||||
|
|
||||||
// for schemas
|
// for schemas
|
||||||
if label == v3.SchemasLabel || label == v2.DefinitionsLabel || label == v3.SecuritySchemesLabel {
|
if label == v3.SchemasLabel || label == v2.DefinitionsLabel || label == v3.SecuritySchemesLabel {
|
||||||
doneChan <- componentComparison{
|
doneChan <- componentComparison{
|
||||||
prop: label,
|
prop: label,
|
||||||
result: CheckMapForChanges(l, r, changes, label, compareFunc),
|
result: CheckMapForChanges(l, r, changes, label, compareFunc),
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
doneChan <- componentComparison{
|
doneChan <- componentComparison{
|
||||||
prop: label,
|
prop: label,
|
||||||
result: CheckMapForAdditionRemoval(l, r, changes, label),
|
result: CheckMapForAdditionRemoval(l, r, changes, label),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns total changes for all Components and Definitions
|
// TotalChanges returns total changes for all Components and Definitions
|
||||||
func (c *ComponentsChanges) TotalChanges() int {
|
func (c *ComponentsChanges) TotalChanges() int {
|
||||||
v := c.PropertyChanges.TotalChanges()
|
v := c.PropertyChanges.TotalChanges()
|
||||||
for k := range c.SchemaChanges {
|
for k := range c.SchemaChanges {
|
||||||
v += c.SchemaChanges[k].TotalChanges()
|
v += c.SchemaChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
for k := range c.SecuritySchemeChanges {
|
for k := range c.SecuritySchemeChanges {
|
||||||
v += c.SecuritySchemeChanges[k].TotalChanges()
|
v += c.SecuritySchemeChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
if c.ExtensionChanges != nil {
|
if c.ExtensionChanges != nil {
|
||||||
v += c.ExtensionChanges.TotalChanges()
|
v += c.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns all breaking changes found for all Components and Definitions
|
// TotalBreakingChanges returns all breaking changes found for all Components and Definitions
|
||||||
func (c *ComponentsChanges) TotalBreakingChanges() int {
|
func (c *ComponentsChanges) TotalBreakingChanges() int {
|
||||||
v := c.PropertyChanges.TotalBreakingChanges()
|
v := c.PropertyChanges.TotalBreakingChanges()
|
||||||
for k := range c.SchemaChanges {
|
for k := range c.SchemaChanges {
|
||||||
v += c.SchemaChanges[k].TotalBreakingChanges()
|
v += c.SchemaChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
for k := range c.SecuritySchemeChanges {
|
for k := range c.SecuritySchemeChanges {
|
||||||
v += c.SecuritySchemeChanges[k].TotalBreakingChanges()
|
v += c.SecuritySchemeChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,23 +4,23 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContactChanges Represent changes to a Contact object that is a child of Info, part of an OpenAPI document.
|
// ContactChanges Represent changes to a Contact object that is a child of Info, part of an OpenAPI document.
|
||||||
type ContactChanges struct {
|
type ContactChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges represents the total number of changes that have occurred to a Contact object
|
// TotalChanges represents the total number of changes that have occurred to a Contact object
|
||||||
func (c *ContactChanges) TotalChanges() int {
|
func (c *ContactChanges) TotalChanges() int {
|
||||||
return c.PropertyChanges.TotalChanges()
|
return c.PropertyChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges always returns 0 for Contact objects, they are non-binding.
|
// TotalBreakingChanges always returns 0 for Contact objects, they are non-binding.
|
||||||
func (c *ContactChanges) TotalBreakingChanges() int {
|
func (c *ContactChanges) TotalBreakingChanges() int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareContact will check a left (original) and right (new) Contact object for any changes. If there
|
// CompareContact will check a left (original) and right (new) Contact object for any changes. If there
|
||||||
@@ -28,49 +28,49 @@ func (c *ContactChanges) TotalBreakingChanges() int {
|
|||||||
// returns nil.
|
// returns nil.
|
||||||
func CompareContact(l, r *base.Contact) *ContactChanges {
|
func CompareContact(l, r *base.Contact) *ContactChanges {
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
// check URL
|
// check URL
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.URL.ValueNode,
|
LeftNode: l.URL.ValueNode,
|
||||||
RightNode: r.URL.ValueNode,
|
RightNode: r.URL.ValueNode,
|
||||||
Label: v3.URLLabel,
|
Label: v3.URLLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// check name
|
// check name
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Name.ValueNode,
|
LeftNode: l.Name.ValueNode,
|
||||||
RightNode: r.Name.ValueNode,
|
RightNode: r.Name.ValueNode,
|
||||||
Label: v3.NameLabel,
|
Label: v3.NameLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// check email
|
// check email
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Email.ValueNode,
|
LeftNode: l.Email.ValueNode,
|
||||||
RightNode: r.Email.ValueNode,
|
RightNode: r.Email.ValueNode,
|
||||||
Label: v3.EmailLabel,
|
Label: v3.EmailLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// check everything.
|
// check everything.
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
|
|
||||||
dc := new(ContactChanges)
|
dc := new(ContactChanges)
|
||||||
dc.Changes = changes
|
dc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
if dc.TotalChanges() <= 0 {
|
if dc.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return dc
|
return dc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,83 +4,83 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DiscriminatorChanges represents changes made to a Discriminator OpenAPI object
|
// DiscriminatorChanges represents changes made to a Discriminator OpenAPI object
|
||||||
type DiscriminatorChanges struct {
|
type DiscriminatorChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
MappingChanges []*Change `json:"mappings,omitempty" yaml:"mappings,omitempty"`
|
MappingChanges []*Change `json:"mappings,omitempty" yaml:"mappings,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns a count of everything changed within the Discriminator object
|
// TotalChanges returns a count of everything changed within the Discriminator object
|
||||||
func (d *DiscriminatorChanges) TotalChanges() int {
|
func (d *DiscriminatorChanges) TotalChanges() int {
|
||||||
l := 0
|
l := 0
|
||||||
if k := d.PropertyChanges.TotalChanges(); k > 0 {
|
if k := d.PropertyChanges.TotalChanges(); k > 0 {
|
||||||
l += k
|
l += k
|
||||||
}
|
}
|
||||||
if k := len(d.MappingChanges); k > 0 {
|
if k := len(d.MappingChanges); k > 0 {
|
||||||
l += k
|
l += k
|
||||||
}
|
}
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the number of breaking changes made by the Discriminator
|
// TotalBreakingChanges returns the number of breaking changes made by the Discriminator
|
||||||
func (d *DiscriminatorChanges) TotalBreakingChanges() int {
|
func (d *DiscriminatorChanges) TotalBreakingChanges() int {
|
||||||
return d.PropertyChanges.TotalBreakingChanges() + CountBreakingChanges(d.MappingChanges)
|
return d.PropertyChanges.TotalBreakingChanges() + CountBreakingChanges(d.MappingChanges)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareDiscriminator will check a left (original) and right (new) Discriminator object for changes
|
// CompareDiscriminator will check a left (original) and right (new) Discriminator object for changes
|
||||||
// and will return a pointer to DiscriminatorChanges
|
// and will return a pointer to DiscriminatorChanges
|
||||||
func CompareDiscriminator(l, r *base.Discriminator) *DiscriminatorChanges {
|
func CompareDiscriminator(l, r *base.Discriminator) *DiscriminatorChanges {
|
||||||
dc := new(DiscriminatorChanges)
|
dc := new(DiscriminatorChanges)
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
var mappingChanges []*Change
|
var mappingChanges []*Change
|
||||||
|
|
||||||
// Name (breaking change)
|
// Name (breaking change)
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.PropertyName.ValueNode,
|
LeftNode: l.PropertyName.ValueNode,
|
||||||
RightNode: r.PropertyName.ValueNode,
|
RightNode: r.PropertyName.ValueNode,
|
||||||
Label: v3.PropertyNameLabel,
|
Label: v3.PropertyNameLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// check properties
|
// check properties
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
|
|
||||||
// flatten maps
|
// flatten maps
|
||||||
lMap := FlattenLowLevelMap[string](l.Mapping)
|
lMap := FlattenLowLevelMap[string](l.Mapping)
|
||||||
rMap := FlattenLowLevelMap[string](r.Mapping)
|
rMap := FlattenLowLevelMap[string](r.Mapping)
|
||||||
|
|
||||||
// check for removals, modifications and moves
|
// check for removals, modifications and moves
|
||||||
for i := range lMap {
|
for i := range lMap {
|
||||||
CheckForObjectAdditionOrRemoval[string](lMap, rMap, i, &mappingChanges, false, true)
|
CheckForObjectAdditionOrRemoval[string](lMap, rMap, i, &mappingChanges, false, true)
|
||||||
// if the existing tag exists, let's check it.
|
// if the existing tag exists, let's check it.
|
||||||
if rMap[i] != nil {
|
if rMap[i] != nil {
|
||||||
if lMap[i].Value != rMap[i].Value {
|
if lMap[i].Value != rMap[i].Value {
|
||||||
CreateChange(&mappingChanges, Modified, i, lMap[i].GetValueNode(),
|
CreateChange(&mappingChanges, Modified, i, lMap[i].GetValueNode(),
|
||||||
rMap[i].GetValueNode(), true, lMap[i].GetValue(), rMap[i].GetValue())
|
rMap[i].GetValueNode(), true, lMap[i].GetValue(), rMap[i].GetValue())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range rMap {
|
for i := range rMap {
|
||||||
if lMap[i] == nil {
|
if lMap[i] == nil {
|
||||||
CreateChange(&mappingChanges, ObjectAdded, i, nil,
|
CreateChange(&mappingChanges, ObjectAdded, i, nil,
|
||||||
rMap[i].GetValueNode(), false, nil, rMap[i].GetValue())
|
rMap[i].GetValueNode(), false, nil, rMap[i].GetValue())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dc.Changes = changes
|
dc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
dc.MappingChanges = mappingChanges
|
dc.MappingChanges = mappingChanges
|
||||||
if dc.TotalChanges() <= 0 {
|
if dc.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return dc
|
return dc
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,278 +11,279 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DocumentChanges represents all the changes made to an OpenAPI document.
|
// DocumentChanges represents all the changes made to an OpenAPI document.
|
||||||
type DocumentChanges struct {
|
type DocumentChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
InfoChanges *InfoChanges `json:"info,omitempty" yaml:"info,omitempty"`
|
InfoChanges *InfoChanges `json:"info,omitempty" yaml:"info,omitempty"`
|
||||||
PathsChanges *PathsChanges `json:"paths,omitempty" yaml:"paths,omitempty"`
|
PathsChanges *PathsChanges `json:"paths,omitempty" yaml:"paths,omitempty"`
|
||||||
TagChanges []*TagChanges `json:"tags,omitempty" yaml:"tags,omitempty"`
|
TagChanges []*TagChanges `json:"tags,omitempty" yaml:"tags,omitempty"`
|
||||||
ExternalDocChanges *ExternalDocChanges `json:"externalDoc,omitempty" yaml:"externalDoc,omitempty"`
|
ExternalDocChanges *ExternalDocChanges `json:"externalDoc,omitempty" yaml:"externalDoc,omitempty"`
|
||||||
WebhookChanges map[string]*PathItemChanges `json:"webhooks,omitempty" yaml:"webhooks,omitempty"`
|
WebhookChanges map[string]*PathItemChanges `json:"webhooks,omitempty" yaml:"webhooks,omitempty"`
|
||||||
ServerChanges []*ServerChanges `json:"servers,omitempty" yaml:"servers,omitempty"`
|
ServerChanges []*ServerChanges `json:"servers,omitempty" yaml:"servers,omitempty"`
|
||||||
SecurityRequirementChanges []*SecurityRequirementChanges `json:"securityRequirements,omitempty" yaml:"securityRequirements,omitempty"`
|
SecurityRequirementChanges []*SecurityRequirementChanges `json:"securityRequirements,omitempty" yaml:"securityRequirements,omitempty"`
|
||||||
ComponentsChanges *ComponentsChanges `json:"components,omitempty" yaml:"components,omitempty"`
|
ComponentsChanges *ComponentsChanges `json:"components,omitempty" yaml:"components,omitempty"`
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns a total count of all changes made in the Document
|
// TotalChanges returns a total count of all changes made in the Document
|
||||||
func (d *DocumentChanges) TotalChanges() int {
|
func (d *DocumentChanges) TotalChanges() int {
|
||||||
c := d.PropertyChanges.TotalChanges()
|
c := d.PropertyChanges.TotalChanges()
|
||||||
if d.InfoChanges != nil {
|
if d.InfoChanges != nil {
|
||||||
c += d.InfoChanges.TotalChanges()
|
c += d.InfoChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
if d.PathsChanges != nil {
|
if d.PathsChanges != nil {
|
||||||
c += d.PathsChanges.TotalChanges()
|
c += d.PathsChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
for k := range d.TagChanges {
|
for k := range d.TagChanges {
|
||||||
c += d.TagChanges[k].TotalChanges()
|
c += d.TagChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
if d.ExternalDocChanges != nil {
|
if d.ExternalDocChanges != nil {
|
||||||
c += d.ExternalDocChanges.TotalChanges()
|
c += d.ExternalDocChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
for k := range d.WebhookChanges {
|
for k := range d.WebhookChanges {
|
||||||
c += d.WebhookChanges[k].TotalChanges()
|
c += d.WebhookChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
for k := range d.ServerChanges {
|
for k := range d.ServerChanges {
|
||||||
c += d.ServerChanges[k].TotalChanges()
|
c += d.ServerChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
for k := range d.SecurityRequirementChanges {
|
for k := range d.SecurityRequirementChanges {
|
||||||
c += d.SecurityRequirementChanges[k].TotalChanges()
|
c += d.SecurityRequirementChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
if d.ComponentsChanges != nil {
|
if d.ComponentsChanges != nil {
|
||||||
c += d.ComponentsChanges.TotalChanges()
|
c += d.ComponentsChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
if d.ExtensionChanges != nil {
|
if d.ExtensionChanges != nil {
|
||||||
c += d.ExtensionChanges.TotalChanges()
|
c += d.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns a total count of all breaking changes made in the Document
|
// TotalBreakingChanges returns a total count of all breaking changes made in the Document
|
||||||
func (d *DocumentChanges) TotalBreakingChanges() int {
|
func (d *DocumentChanges) TotalBreakingChanges() int {
|
||||||
c := d.PropertyChanges.TotalBreakingChanges()
|
c := d.PropertyChanges.TotalBreakingChanges()
|
||||||
if d.InfoChanges != nil {
|
if d.InfoChanges != nil {
|
||||||
c += d.InfoChanges.TotalBreakingChanges()
|
c += d.InfoChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
if d.PathsChanges != nil {
|
if d.PathsChanges != nil {
|
||||||
c += d.PathsChanges.TotalBreakingChanges()
|
c += d.PathsChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
for k := range d.TagChanges {
|
for k := range d.TagChanges {
|
||||||
c += d.TagChanges[k].TotalBreakingChanges()
|
c += d.TagChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
if d.ExternalDocChanges != nil {
|
if d.ExternalDocChanges != nil {
|
||||||
c += d.ExternalDocChanges.TotalBreakingChanges()
|
c += d.ExternalDocChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
for k := range d.WebhookChanges {
|
for k := range d.WebhookChanges {
|
||||||
c += d.WebhookChanges[k].TotalBreakingChanges()
|
c += d.WebhookChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
for k := range d.ServerChanges {
|
for k := range d.ServerChanges {
|
||||||
c += d.ServerChanges[k].TotalBreakingChanges()
|
c += d.ServerChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
for k := range d.SecurityRequirementChanges {
|
for k := range d.SecurityRequirementChanges {
|
||||||
c += d.SecurityRequirementChanges[k].TotalBreakingChanges()
|
c += d.SecurityRequirementChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
if d.ComponentsChanges != nil {
|
if d.ComponentsChanges != nil {
|
||||||
c += d.ComponentsChanges.TotalBreakingChanges()
|
c += d.ComponentsChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareDocuments will compare any two OpenAPI documents (either Swagger or OpenAPI) and return a pointer to
|
// CompareDocuments will compare any two OpenAPI documents (either Swagger or OpenAPI) and return a pointer to
|
||||||
// DocumentChanges that outlines everything that was found to have changed.
|
// DocumentChanges that outlines everything that was found to have changed.
|
||||||
func CompareDocuments(l, r any) *DocumentChanges {
|
func CompareDocuments(l, r any) *DocumentChanges {
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
dc := new(DocumentChanges)
|
dc := new(DocumentChanges)
|
||||||
|
|
||||||
if reflect.TypeOf(&v2.Swagger{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Swagger{}) == reflect.TypeOf(r) {
|
if reflect.TypeOf(&v2.Swagger{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Swagger{}) == reflect.TypeOf(r) {
|
||||||
lDoc := l.(*v2.Swagger)
|
lDoc := l.(*v2.Swagger)
|
||||||
rDoc := r.(*v2.Swagger)
|
rDoc := r.(*v2.Swagger)
|
||||||
|
|
||||||
// version
|
// version
|
||||||
addPropertyCheck(&props, lDoc.Swagger.ValueNode, rDoc.Swagger.ValueNode,
|
addPropertyCheck(&props, lDoc.Swagger.ValueNode, rDoc.Swagger.ValueNode,
|
||||||
lDoc.Swagger.Value, rDoc.Swagger.Value, &changes, v3.SwaggerLabel, true)
|
lDoc.Swagger.Value, rDoc.Swagger.Value, &changes, v3.SwaggerLabel, true)
|
||||||
|
|
||||||
// host
|
// host
|
||||||
addPropertyCheck(&props, lDoc.Host.ValueNode, rDoc.Host.ValueNode,
|
addPropertyCheck(&props, lDoc.Host.ValueNode, rDoc.Host.ValueNode,
|
||||||
lDoc.Host.Value, rDoc.Host.Value, &changes, v3.HostLabel, true)
|
lDoc.Host.Value, rDoc.Host.Value, &changes, v3.HostLabel, true)
|
||||||
|
|
||||||
// base path
|
// base path
|
||||||
addPropertyCheck(&props, lDoc.BasePath.ValueNode, rDoc.BasePath.ValueNode,
|
addPropertyCheck(&props, lDoc.BasePath.ValueNode, rDoc.BasePath.ValueNode,
|
||||||
lDoc.BasePath.Value, rDoc.BasePath.Value, &changes, v3.BasePathLabel, true)
|
lDoc.BasePath.Value, rDoc.BasePath.Value, &changes, v3.BasePathLabel, true)
|
||||||
|
|
||||||
// schemes
|
// schemes
|
||||||
if len(lDoc.Schemes.Value) > 0 || len(lDoc.Schemes.Value) > 0 {
|
if len(lDoc.Schemes.Value) > 0 || len(lDoc.Schemes.Value) > 0 {
|
||||||
ExtractStringValueSliceChanges(lDoc.Schemes.Value, rDoc.Schemes.Value,
|
ExtractStringValueSliceChanges(lDoc.Schemes.Value, rDoc.Schemes.Value,
|
||||||
&changes, v3.SchemesLabel, true)
|
&changes, v3.SchemesLabel, true)
|
||||||
}
|
}
|
||||||
// consumes
|
// consumes
|
||||||
if len(lDoc.Consumes.Value) > 0 || len(lDoc.Consumes.Value) > 0 {
|
if len(lDoc.Consumes.Value) > 0 || len(lDoc.Consumes.Value) > 0 {
|
||||||
ExtractStringValueSliceChanges(lDoc.Consumes.Value, rDoc.Consumes.Value,
|
ExtractStringValueSliceChanges(lDoc.Consumes.Value, rDoc.Consumes.Value,
|
||||||
&changes, v3.ConsumesLabel, true)
|
&changes, v3.ConsumesLabel, true)
|
||||||
}
|
}
|
||||||
// produces
|
// produces
|
||||||
if len(lDoc.Produces.Value) > 0 || len(lDoc.Produces.Value) > 0 {
|
if len(lDoc.Produces.Value) > 0 || len(lDoc.Produces.Value) > 0 {
|
||||||
ExtractStringValueSliceChanges(lDoc.Produces.Value, rDoc.Produces.Value,
|
ExtractStringValueSliceChanges(lDoc.Produces.Value, rDoc.Produces.Value,
|
||||||
&changes, v3.ProducesLabel, true)
|
&changes, v3.ProducesLabel, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// tags
|
// tags
|
||||||
dc.TagChanges = CompareTags(lDoc.Tags.Value, rDoc.Tags.Value)
|
dc.TagChanges = CompareTags(lDoc.Tags.Value, rDoc.Tags.Value)
|
||||||
|
|
||||||
// paths
|
// paths
|
||||||
if !lDoc.Paths.IsEmpty() || !rDoc.Paths.IsEmpty() {
|
if !lDoc.Paths.IsEmpty() || !rDoc.Paths.IsEmpty() {
|
||||||
dc.PathsChanges = ComparePaths(lDoc.Paths.Value, rDoc.Paths.Value)
|
dc.PathsChanges = ComparePaths(lDoc.Paths.Value, rDoc.Paths.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// external docs
|
// external docs
|
||||||
compareDocumentExternalDocs(lDoc, rDoc, dc, &changes)
|
compareDocumentExternalDocs(lDoc, rDoc, dc, &changes)
|
||||||
|
|
||||||
// info
|
// info
|
||||||
compareDocumentInfo(&lDoc.Info, &rDoc.Info, dc, &changes)
|
compareDocumentInfo(&lDoc.Info, &rDoc.Info, dc, &changes)
|
||||||
|
|
||||||
// security
|
// security
|
||||||
if !lDoc.Security.IsEmpty() || !rDoc.Security.IsEmpty() {
|
if !lDoc.Security.IsEmpty() || !rDoc.Security.IsEmpty() {
|
||||||
checkSecurity(lDoc.Security, rDoc.Security, &changes, dc)
|
checkSecurity(lDoc.Security, rDoc.Security, &changes, dc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// components / definitions
|
// components / definitions
|
||||||
// swagger (damn you) decided to put all this stuff at the document root, rather than cleanly
|
// swagger (damn you) decided to put all this stuff at the document root, rather than cleanly
|
||||||
// placing it under a parent, like they did with OpenAPI. This means picking through each definition
|
// placing it under a parent, like they did with OpenAPI. This means picking through each definition
|
||||||
// creating a new set of changes and then morphing them into a single changes object.
|
// creating a new set of changes and then morphing them into a single changes object.
|
||||||
cc := new(ComponentsChanges)
|
cc := new(ComponentsChanges)
|
||||||
if n := CompareComponents(lDoc.Definitions.Value, rDoc.Definitions.Value); n != nil {
|
cc.PropertyChanges = new(PropertyChanges)
|
||||||
cc.SchemaChanges = n.SchemaChanges
|
if n := CompareComponents(lDoc.Definitions.Value, rDoc.Definitions.Value); n != nil {
|
||||||
}
|
cc.SchemaChanges = n.SchemaChanges
|
||||||
if n := CompareComponents(lDoc.SecurityDefinitions.Value, rDoc.SecurityDefinitions.Value); n != nil {
|
}
|
||||||
cc.SecuritySchemeChanges = n.SecuritySchemeChanges
|
if n := CompareComponents(lDoc.SecurityDefinitions.Value, rDoc.SecurityDefinitions.Value); n != nil {
|
||||||
}
|
cc.SecuritySchemeChanges = n.SecuritySchemeChanges
|
||||||
if n := CompareComponents(lDoc.Parameters.Value, rDoc.Parameters.Value); n != nil {
|
}
|
||||||
cc.Changes = append(cc.Changes, n.Changes...)
|
if n := CompareComponents(lDoc.Parameters.Value, rDoc.Parameters.Value); n != nil {
|
||||||
}
|
cc.PropertyChanges.Changes = append(cc.PropertyChanges.Changes, n.Changes...)
|
||||||
if n := CompareComponents(lDoc.Responses.Value, rDoc.Responses.Value); n != nil {
|
}
|
||||||
cc.Changes = append(cc.Changes, n.Changes...)
|
if n := CompareComponents(lDoc.Responses.Value, rDoc.Responses.Value); n != nil {
|
||||||
}
|
cc.Changes = append(cc.Changes, n.Changes...)
|
||||||
dc.ExtensionChanges = CompareExtensions(lDoc.Extensions, rDoc.Extensions)
|
}
|
||||||
if cc.TotalChanges() > 0 {
|
dc.ExtensionChanges = CompareExtensions(lDoc.Extensions, rDoc.Extensions)
|
||||||
dc.ComponentsChanges = cc
|
if cc.TotalChanges() > 0 {
|
||||||
}
|
dc.ComponentsChanges = cc
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if reflect.TypeOf(&v3.Document{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Document{}) == reflect.TypeOf(r) {
|
if reflect.TypeOf(&v3.Document{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Document{}) == reflect.TypeOf(r) {
|
||||||
lDoc := l.(*v3.Document)
|
lDoc := l.(*v3.Document)
|
||||||
rDoc := r.(*v3.Document)
|
rDoc := r.(*v3.Document)
|
||||||
|
|
||||||
// version
|
// version
|
||||||
addPropertyCheck(&props, lDoc.Version.ValueNode, rDoc.Version.ValueNode,
|
addPropertyCheck(&props, lDoc.Version.ValueNode, rDoc.Version.ValueNode,
|
||||||
lDoc.Version.Value, rDoc.Version.Value, &changes, v3.OpenAPILabel, true)
|
lDoc.Version.Value, rDoc.Version.Value, &changes, v3.OpenAPILabel, true)
|
||||||
|
|
||||||
// schema dialect
|
// schema dialect
|
||||||
addPropertyCheck(&props, lDoc.JsonSchemaDialect.ValueNode, rDoc.JsonSchemaDialect.ValueNode,
|
addPropertyCheck(&props, lDoc.JsonSchemaDialect.ValueNode, rDoc.JsonSchemaDialect.ValueNode,
|
||||||
lDoc.JsonSchemaDialect.Value, rDoc.JsonSchemaDialect.Value, &changes, v3.JSONSchemaDialectLabel, true)
|
lDoc.JsonSchemaDialect.Value, rDoc.JsonSchemaDialect.Value, &changes, v3.JSONSchemaDialectLabel, true)
|
||||||
|
|
||||||
// tags
|
// tags
|
||||||
dc.TagChanges = CompareTags(lDoc.Tags.Value, rDoc.Tags.Value)
|
dc.TagChanges = CompareTags(lDoc.Tags.Value, rDoc.Tags.Value)
|
||||||
|
|
||||||
// paths
|
// paths
|
||||||
if !lDoc.Paths.IsEmpty() || !rDoc.Paths.IsEmpty() {
|
if !lDoc.Paths.IsEmpty() || !rDoc.Paths.IsEmpty() {
|
||||||
dc.PathsChanges = ComparePaths(lDoc.Paths.Value, rDoc.Paths.Value)
|
dc.PathsChanges = ComparePaths(lDoc.Paths.Value, rDoc.Paths.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// external docs
|
// external docs
|
||||||
compareDocumentExternalDocs(lDoc, rDoc, dc, &changes)
|
compareDocumentExternalDocs(lDoc, rDoc, dc, &changes)
|
||||||
|
|
||||||
// info
|
// info
|
||||||
compareDocumentInfo(&lDoc.Info, &rDoc.Info, dc, &changes)
|
compareDocumentInfo(&lDoc.Info, &rDoc.Info, dc, &changes)
|
||||||
|
|
||||||
// security
|
// security
|
||||||
if !lDoc.Security.IsEmpty() || !rDoc.Security.IsEmpty() {
|
if !lDoc.Security.IsEmpty() || !rDoc.Security.IsEmpty() {
|
||||||
checkSecurity(lDoc.Security, rDoc.Security, &changes, dc)
|
checkSecurity(lDoc.Security, rDoc.Security, &changes, dc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// compare components.
|
// compare components.
|
||||||
if !lDoc.Components.IsEmpty() && !rDoc.Components.IsEmpty() {
|
if !lDoc.Components.IsEmpty() && !rDoc.Components.IsEmpty() {
|
||||||
if n := CompareComponents(lDoc.Components.Value, rDoc.Components.Value); n != nil {
|
if n := CompareComponents(lDoc.Components.Value, rDoc.Components.Value); n != nil {
|
||||||
dc.ComponentsChanges = n
|
dc.ComponentsChanges = n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !lDoc.Components.IsEmpty() && rDoc.Components.IsEmpty() {
|
if !lDoc.Components.IsEmpty() && rDoc.Components.IsEmpty() {
|
||||||
CreateChange(&changes, PropertyRemoved, v3.ComponentsLabel,
|
CreateChange(&changes, PropertyRemoved, v3.ComponentsLabel,
|
||||||
lDoc.Components.ValueNode, nil, true, lDoc.Components.Value, nil)
|
lDoc.Components.ValueNode, nil, true, lDoc.Components.Value, nil)
|
||||||
}
|
}
|
||||||
if lDoc.Components.IsEmpty() && !rDoc.Components.IsEmpty() {
|
if lDoc.Components.IsEmpty() && !rDoc.Components.IsEmpty() {
|
||||||
CreateChange(&changes, PropertyAdded, v3.ComponentsLabel,
|
CreateChange(&changes, PropertyAdded, v3.ComponentsLabel,
|
||||||
rDoc.Components.ValueNode, nil, false, nil, lDoc.Components.Value)
|
rDoc.Components.ValueNode, nil, false, nil, lDoc.Components.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// compare servers
|
// compare servers
|
||||||
if n := checkServers(lDoc.Servers, rDoc.Servers); n != nil {
|
if n := checkServers(lDoc.Servers, rDoc.Servers); n != nil {
|
||||||
dc.ServerChanges = n
|
dc.ServerChanges = n
|
||||||
}
|
}
|
||||||
|
|
||||||
// compare webhooks
|
// compare webhooks
|
||||||
dc.WebhookChanges = CheckMapForChanges(lDoc.Webhooks.Value, rDoc.Webhooks.Value, &changes,
|
dc.WebhookChanges = CheckMapForChanges(lDoc.Webhooks.Value, rDoc.Webhooks.Value, &changes,
|
||||||
v3.WebhooksLabel, ComparePathItemsV3)
|
v3.WebhooksLabel, ComparePathItemsV3)
|
||||||
|
|
||||||
// extensions
|
// extensions
|
||||||
dc.ExtensionChanges = CompareExtensions(lDoc.Extensions, rDoc.Extensions)
|
dc.ExtensionChanges = CompareExtensions(lDoc.Extensions, rDoc.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
dc.Changes = changes
|
dc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
if dc.TotalChanges() <= 0 {
|
if dc.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return dc
|
return dc
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareDocumentExternalDocs(l, r low.HasExternalDocs, dc *DocumentChanges, changes *[]*Change) {
|
func compareDocumentExternalDocs(l, r low.HasExternalDocs, dc *DocumentChanges, changes *[]*Change) {
|
||||||
// external docs
|
// external docs
|
||||||
if !l.GetExternalDocs().IsEmpty() && !r.GetExternalDocs().IsEmpty() {
|
if !l.GetExternalDocs().IsEmpty() && !r.GetExternalDocs().IsEmpty() {
|
||||||
lExtDoc := l.GetExternalDocs().Value.(*base.ExternalDoc)
|
lExtDoc := l.GetExternalDocs().Value.(*base.ExternalDoc)
|
||||||
rExtDoc := r.GetExternalDocs().Value.(*base.ExternalDoc)
|
rExtDoc := r.GetExternalDocs().Value.(*base.ExternalDoc)
|
||||||
if !low.AreEqual(lExtDoc, rExtDoc) {
|
if !low.AreEqual(lExtDoc, rExtDoc) {
|
||||||
dc.ExternalDocChanges = CompareExternalDocs(lExtDoc, rExtDoc)
|
dc.ExternalDocChanges = CompareExternalDocs(lExtDoc, rExtDoc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if l.GetExternalDocs().IsEmpty() && !r.GetExternalDocs().IsEmpty() {
|
if l.GetExternalDocs().IsEmpty() && !r.GetExternalDocs().IsEmpty() {
|
||||||
CreateChange(changes, PropertyAdded, v3.ExternalDocsLabel,
|
CreateChange(changes, PropertyAdded, v3.ExternalDocsLabel,
|
||||||
nil, r.GetExternalDocs().ValueNode, false, nil,
|
nil, r.GetExternalDocs().ValueNode, false, nil,
|
||||||
r.GetExternalDocs().Value)
|
r.GetExternalDocs().Value)
|
||||||
}
|
}
|
||||||
if !l.GetExternalDocs().IsEmpty() && r.GetExternalDocs().IsEmpty() {
|
if !l.GetExternalDocs().IsEmpty() && r.GetExternalDocs().IsEmpty() {
|
||||||
CreateChange(changes, PropertyRemoved, v3.ExternalDocsLabel,
|
CreateChange(changes, PropertyRemoved, v3.ExternalDocsLabel,
|
||||||
l.GetExternalDocs().ValueNode, nil, false, l.GetExternalDocs().Value,
|
l.GetExternalDocs().ValueNode, nil, false, l.GetExternalDocs().Value,
|
||||||
nil)
|
nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareDocumentInfo(l, r *low.NodeReference[*base.Info], dc *DocumentChanges, changes *[]*Change) {
|
func compareDocumentInfo(l, r *low.NodeReference[*base.Info], dc *DocumentChanges, changes *[]*Change) {
|
||||||
// info
|
// info
|
||||||
if !l.IsEmpty() && !r.IsEmpty() {
|
if !l.IsEmpty() && !r.IsEmpty() {
|
||||||
lInfo := l.Value
|
lInfo := l.Value
|
||||||
rInfo := r.Value
|
rInfo := r.Value
|
||||||
if !low.AreEqual(lInfo, rInfo) {
|
if !low.AreEqual(lInfo, rInfo) {
|
||||||
dc.InfoChanges = CompareInfo(lInfo, rInfo)
|
dc.InfoChanges = CompareInfo(lInfo, rInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if l.IsEmpty() && !r.IsEmpty() {
|
if l.IsEmpty() && !r.IsEmpty() {
|
||||||
CreateChange(changes, PropertyAdded, v3.InfoLabel,
|
CreateChange(changes, PropertyAdded, v3.InfoLabel,
|
||||||
nil, r.ValueNode, false, nil,
|
nil, r.ValueNode, false, nil,
|
||||||
r.Value)
|
r.Value)
|
||||||
}
|
}
|
||||||
if !l.IsEmpty() && r.IsEmpty() {
|
if !l.IsEmpty() && r.IsEmpty() {
|
||||||
CreateChange(changes, PropertyRemoved, v3.InfoLabel,
|
CreateChange(changes, PropertyRemoved, v3.InfoLabel,
|
||||||
l.ValueNode, nil, false, l.Value,
|
l.ValueNode, nil, false, l.Value,
|
||||||
nil)
|
nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,86 +4,86 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EncodingChanges represent all the changes made to an Encoding object
|
// EncodingChanges represent all the changes made to an Encoding object
|
||||||
type EncodingChanges struct {
|
type EncodingChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
HeaderChanges map[string]*HeaderChanges `json:"headers,omitempty" yaml:"headers,omitempty"`
|
HeaderChanges map[string]*HeaderChanges `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns the total number of changes made between two Encoding objects
|
// TotalChanges returns the total number of changes made between two Encoding objects
|
||||||
func (e *EncodingChanges) TotalChanges() int {
|
func (e *EncodingChanges) TotalChanges() int {
|
||||||
c := e.PropertyChanges.TotalChanges()
|
c := e.PropertyChanges.TotalChanges()
|
||||||
if e.HeaderChanges != nil {
|
if e.HeaderChanges != nil {
|
||||||
for i := range e.HeaderChanges {
|
for i := range e.HeaderChanges {
|
||||||
c += e.HeaderChanges[i].TotalChanges()
|
c += e.HeaderChanges[i].TotalChanges()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the number of changes made between two Encoding objects that were breaking.
|
// TotalBreakingChanges returns the number of changes made between two Encoding objects that were breaking.
|
||||||
func (e *EncodingChanges) TotalBreakingChanges() int {
|
func (e *EncodingChanges) TotalBreakingChanges() int {
|
||||||
c := e.PropertyChanges.TotalBreakingChanges()
|
c := e.PropertyChanges.TotalBreakingChanges()
|
||||||
if e.HeaderChanges != nil {
|
if e.HeaderChanges != nil {
|
||||||
for i := range e.HeaderChanges {
|
for i := range e.HeaderChanges {
|
||||||
c += e.HeaderChanges[i].TotalBreakingChanges()
|
c += e.HeaderChanges[i].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareEncoding returns a pointer to *EncodingChanges that contain all changes made between a left and right
|
// CompareEncoding returns a pointer to *EncodingChanges that contain all changes made between a left and right
|
||||||
// set of Encoding objects.
|
// set of Encoding objects.
|
||||||
func CompareEncoding(l, r *v3.Encoding) *EncodingChanges {
|
func CompareEncoding(l, r *v3.Encoding) *EncodingChanges {
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
// ContentType
|
// ContentType
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.ContentType.ValueNode,
|
LeftNode: l.ContentType.ValueNode,
|
||||||
RightNode: r.ContentType.ValueNode,
|
RightNode: r.ContentType.ValueNode,
|
||||||
Label: v3.ContentTypeLabel,
|
Label: v3.ContentTypeLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Explode
|
// Explode
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Explode.ValueNode,
|
LeftNode: l.Explode.ValueNode,
|
||||||
RightNode: r.Explode.ValueNode,
|
RightNode: r.Explode.ValueNode,
|
||||||
Label: v3.ExplodeLabel,
|
Label: v3.ExplodeLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// AllowReserved
|
// AllowReserved
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.AllowReserved.ValueNode,
|
LeftNode: l.AllowReserved.ValueNode,
|
||||||
RightNode: r.AllowReserved.ValueNode,
|
RightNode: r.AllowReserved.ValueNode,
|
||||||
Label: v3.AllowReservedLabel,
|
Label: v3.AllowReservedLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// check everything.
|
// check everything.
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
ec := new(EncodingChanges)
|
ec := new(EncodingChanges)
|
||||||
|
|
||||||
// headers
|
// headers
|
||||||
ec.HeaderChanges = CheckMapForChanges(l.Headers.Value, r.Headers.Value, &changes, v3.HeadersLabel, CompareHeadersV3)
|
ec.HeaderChanges = CheckMapForChanges(l.Headers.Value, r.Headers.Value, &changes, v3.HeadersLabel, CompareHeadersV3)
|
||||||
ec.Changes = changes
|
ec.PropertyChanges = NewPropertyChanges(changes)
|
||||||
if ec.TotalChanges() <= 0 {
|
if ec.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return ec
|
return ec
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
// ExampleChanges represent changes to an Example object, part of an OpenAPI specification.
|
// ExampleChanges represent changes to an Example object, part of an OpenAPI specification.
|
||||||
type ExampleChanges struct {
|
type ExampleChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +174,7 @@ func CompareExamples(l, r *base.Example) *ExampleChanges {
|
|||||||
|
|
||||||
// check extensions
|
// check extensions
|
||||||
ec.ExtensionChanges = CheckExtensions(l, r)
|
ec.ExtensionChanges = CheckExtensions(l, r)
|
||||||
ec.Changes = changes
|
ec.PropertyChanges = NewPropertyChanges(changes)
|
||||||
if ec.TotalChanges() <= 0 {
|
if ec.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
// ExamplesChanges represents changes made between Swagger Examples objects (Not OpenAPI 3).
|
// ExamplesChanges represents changes made between Swagger Examples objects (Not OpenAPI 3).
|
||||||
type ExamplesChanges struct {
|
type ExamplesChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges represents the total number of changes made between Example instances.
|
// TotalChanges represents the total number of changes made between Example instances.
|
||||||
@@ -73,7 +73,7 @@ func CompareExamplesV2(l, r *v2.Examples) *ExamplesChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ex := new(ExamplesChanges)
|
ex := new(ExamplesChanges)
|
||||||
ex.Changes = changes
|
ex.PropertyChanges = NewPropertyChanges(changes)
|
||||||
if ex.TotalChanges() <= 0 {
|
if ex.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,23 +4,23 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExtensionChanges represents any changes to custom extensions defined for an OpenAPI object.
|
// ExtensionChanges represents any changes to custom extensions defined for an OpenAPI object.
|
||||||
type ExtensionChanges struct {
|
type ExtensionChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns the total number of object extensions that were made.
|
// TotalChanges returns the total number of object extensions that were made.
|
||||||
func (e *ExtensionChanges) TotalChanges() int {
|
func (e *ExtensionChanges) TotalChanges() int {
|
||||||
return e.PropertyChanges.TotalChanges()
|
return e.PropertyChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges always returns 0 for Extension objects, they are non-binding.
|
// TotalBreakingChanges always returns 0 for Extension objects, they are non-binding.
|
||||||
func (e *ExtensionChanges) TotalBreakingChanges() int {
|
func (e *ExtensionChanges) TotalBreakingChanges() int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareExtensions will compare a left and right map of Key/ValueReference models for any changes to
|
// CompareExtensions will compare a left and right map of Key/ValueReference models for any changes to
|
||||||
@@ -31,62 +31,62 @@ func (e *ExtensionChanges) TotalBreakingChanges() int {
|
|||||||
// there is currently no support for knowing anything changed - so it is ignored.
|
// there is currently no support for knowing anything changed - so it is ignored.
|
||||||
func CompareExtensions(l, r map[low.KeyReference[string]]low.ValueReference[any]) *ExtensionChanges {
|
func CompareExtensions(l, r map[low.KeyReference[string]]low.ValueReference[any]) *ExtensionChanges {
|
||||||
|
|
||||||
// look at the original and then look through the new.
|
// look at the original and then look through the new.
|
||||||
seenLeft := make(map[string]*low.ValueReference[any])
|
seenLeft := make(map[string]*low.ValueReference[any])
|
||||||
seenRight := make(map[string]*low.ValueReference[any])
|
seenRight := make(map[string]*low.ValueReference[any])
|
||||||
for i := range l {
|
for i := range l {
|
||||||
h := l[i]
|
h := l[i]
|
||||||
seenLeft[strings.ToLower(i.Value)] = &h
|
seenLeft[strings.ToLower(i.Value)] = &h
|
||||||
}
|
}
|
||||||
for i := range r {
|
for i := range r {
|
||||||
h := r[i]
|
h := r[i]
|
||||||
seenRight[strings.ToLower(i.Value)] = &h
|
seenRight[strings.ToLower(i.Value)] = &h
|
||||||
}
|
}
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
for i := range seenLeft {
|
for i := range seenLeft {
|
||||||
|
|
||||||
CheckForObjectAdditionOrRemoval[any](seenLeft, seenRight, i, &changes, false, true)
|
CheckForObjectAdditionOrRemoval[any](seenLeft, seenRight, i, &changes, false, true)
|
||||||
|
|
||||||
if seenRight[i] != nil {
|
if seenRight[i] != nil {
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: seenLeft[i].ValueNode,
|
LeftNode: seenLeft[i].ValueNode,
|
||||||
RightNode: seenRight[i].ValueNode,
|
RightNode: seenRight[i].ValueNode,
|
||||||
Label: i,
|
Label: i,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: seenLeft[i].Value,
|
Original: seenLeft[i].Value,
|
||||||
New: seenRight[i].Value,
|
New: seenRight[i].Value,
|
||||||
})
|
})
|
||||||
|
|
||||||
// check properties
|
// check properties
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := range seenRight {
|
for i := range seenRight {
|
||||||
if seenLeft[i] == nil {
|
if seenLeft[i] == nil {
|
||||||
CheckForObjectAdditionOrRemoval[any](seenLeft, seenRight, i, &changes, false, true)
|
CheckForObjectAdditionOrRemoval[any](seenLeft, seenRight, i, &changes, false, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ex := new(ExtensionChanges)
|
ex := new(ExtensionChanges)
|
||||||
ex.Changes = changes
|
ex.PropertyChanges = NewPropertyChanges(changes)
|
||||||
if ex.TotalChanges() <= 0 {
|
if ex.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return ex
|
return ex
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckExtensions is a helper method to un-pack a left and right model that contains extensions. Once unpacked
|
// CheckExtensions is a helper method to un-pack a left and right model that contains extensions. Once unpacked
|
||||||
// the extensions are compared and returns a pointer to ExtensionChanges. If nothing changed, nil is returned.
|
// the extensions are compared and returns a pointer to ExtensionChanges. If nothing changed, nil is returned.
|
||||||
func CheckExtensions[T low.HasExtensions[T]](l, r T) *ExtensionChanges {
|
func CheckExtensions[T low.HasExtensions[T]](l, r T) *ExtensionChanges {
|
||||||
var lExt, rExt map[low.KeyReference[string]]low.ValueReference[any]
|
var lExt, rExt map[low.KeyReference[string]]low.ValueReference[any]
|
||||||
if len(l.GetExtensions()) > 0 {
|
if len(l.GetExtensions()) > 0 {
|
||||||
lExt = l.GetExtensions()
|
lExt = l.GetExtensions()
|
||||||
}
|
}
|
||||||
if len(r.GetExtensions()) > 0 {
|
if len(r.GetExtensions()) > 0 {
|
||||||
rExt = r.GetExtensions()
|
rExt = r.GetExtensions()
|
||||||
}
|
}
|
||||||
return CompareExtensions(lExt, rExt)
|
return CompareExtensions(lExt, rExt)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,69 +4,69 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExternalDocChanges represents changes made to any ExternalDoc object from an OpenAPI document.
|
// ExternalDocChanges represents changes made to any ExternalDoc object from an OpenAPI document.
|
||||||
type ExternalDocChanges struct {
|
type ExternalDocChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns a count of everything that changed
|
// TotalChanges returns a count of everything that changed
|
||||||
func (e *ExternalDocChanges) TotalChanges() int {
|
func (e *ExternalDocChanges) TotalChanges() int {
|
||||||
c := e.PropertyChanges.TotalChanges()
|
c := e.PropertyChanges.TotalChanges()
|
||||||
if e.ExtensionChanges != nil {
|
if e.ExtensionChanges != nil {
|
||||||
c += e.ExtensionChanges.TotalChanges()
|
c += e.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges always returns 0 for ExternalDoc objects, they are non-binding.
|
// TotalBreakingChanges always returns 0 for ExternalDoc objects, they are non-binding.
|
||||||
func (e *ExternalDocChanges) TotalBreakingChanges() int {
|
func (e *ExternalDocChanges) TotalBreakingChanges() int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareExternalDocs will compare a left (original) and a right (new) slice of ValueReference
|
// CompareExternalDocs will compare a left (original) and a right (new) slice of ValueReference
|
||||||
// nodes for any changes between them. If there are changes, then a pointer to ExternalDocChanges
|
// nodes for any changes between them. If there are changes, then a pointer to ExternalDocChanges
|
||||||
// is returned, otherwise if nothing changed - then nil is returned.
|
// is returned, otherwise if nothing changed - then nil is returned.
|
||||||
func CompareExternalDocs(l, r *base.ExternalDoc) *ExternalDocChanges {
|
func CompareExternalDocs(l, r *base.ExternalDoc) *ExternalDocChanges {
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
// URL
|
// URL
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.URL.ValueNode,
|
LeftNode: l.URL.ValueNode,
|
||||||
RightNode: r.URL.ValueNode,
|
RightNode: r.URL.ValueNode,
|
||||||
Label: v3.URLLabel,
|
Label: v3.URLLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// description.
|
// description.
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Description.ValueNode,
|
LeftNode: l.Description.ValueNode,
|
||||||
RightNode: r.Description.ValueNode,
|
RightNode: r.Description.ValueNode,
|
||||||
Label: v3.DescriptionLabel,
|
Label: v3.DescriptionLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// check everything.
|
// check everything.
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
|
|
||||||
dc := new(ExternalDocChanges)
|
dc := new(ExternalDocChanges)
|
||||||
dc.Changes = changes
|
dc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
|
|
||||||
// check extensions
|
// check extensions
|
||||||
dc.ExtensionChanges = CheckExtensions(l, r)
|
dc.ExtensionChanges = CheckExtensions(l, r)
|
||||||
if dc.TotalChanges() <= 0 {
|
if dc.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return dc
|
return dc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,255 +4,255 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HeaderChanges represents changes made between two Header objects. Supports both Swagger and OpenAPI header
|
// HeaderChanges represents changes made between two Header objects. Supports both Swagger and OpenAPI header
|
||||||
// objects, V2 only property Items is broken out into its own.
|
// objects, V2 only property Items is broken out into its own.
|
||||||
type HeaderChanges struct {
|
type HeaderChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||||
ExamplesChanges map[string]*ExampleChanges `json:"examples,omitempty" yaml:"examples,omitempty"`
|
ExamplesChanges map[string]*ExampleChanges `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||||
ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"`
|
ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"`
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
|
|
||||||
// Items only supported by Swagger (V2)
|
// Items only supported by Swagger (V2)
|
||||||
ItemsChanges *ItemsChanges `json:"items,omitempty" yaml:"items,omitempty"`
|
ItemsChanges *ItemsChanges `json:"items,omitempty" yaml:"items,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns the total number of changes made between two Header objects.
|
// TotalChanges returns the total number of changes made between two Header objects.
|
||||||
func (h *HeaderChanges) TotalChanges() int {
|
func (h *HeaderChanges) TotalChanges() int {
|
||||||
c := h.PropertyChanges.TotalChanges()
|
c := h.PropertyChanges.TotalChanges()
|
||||||
for k := range h.ExamplesChanges {
|
for k := range h.ExamplesChanges {
|
||||||
c += h.ExamplesChanges[k].TotalChanges()
|
c += h.ExamplesChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
for k := range h.ContentChanges {
|
for k := range h.ContentChanges {
|
||||||
c += h.ContentChanges[k].TotalChanges()
|
c += h.ContentChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
if h.ExtensionChanges != nil {
|
if h.ExtensionChanges != nil {
|
||||||
c += h.ExtensionChanges.TotalChanges()
|
c += h.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
if h.SchemaChanges != nil {
|
if h.SchemaChanges != nil {
|
||||||
c += h.SchemaChanges.TotalChanges()
|
c += h.SchemaChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
if h.ItemsChanges != nil {
|
if h.ItemsChanges != nil {
|
||||||
c += h.ItemsChanges.TotalChanges()
|
c += h.ItemsChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the total number of breaking changes made between two Header instances.
|
// TotalBreakingChanges returns the total number of breaking changes made between two Header instances.
|
||||||
func (h *HeaderChanges) TotalBreakingChanges() int {
|
func (h *HeaderChanges) TotalBreakingChanges() int {
|
||||||
c := h.PropertyChanges.TotalBreakingChanges()
|
c := h.PropertyChanges.TotalBreakingChanges()
|
||||||
for k := range h.ContentChanges {
|
for k := range h.ContentChanges {
|
||||||
c += h.ContentChanges[k].TotalBreakingChanges()
|
c += h.ContentChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
if h.ItemsChanges != nil {
|
if h.ItemsChanges != nil {
|
||||||
c += h.ItemsChanges.TotalBreakingChanges()
|
c += h.ItemsChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
if h.SchemaChanges != nil {
|
if h.SchemaChanges != nil {
|
||||||
c += h.SchemaChanges.TotalBreakingChanges()
|
c += h.SchemaChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// shared header properties
|
// shared header properties
|
||||||
func addOpenAPIHeaderProperties(left, right low.OpenAPIHeader, changes *[]*Change) []*PropertyCheck {
|
func addOpenAPIHeaderProperties(left, right low.OpenAPIHeader, changes *[]*Change) []*PropertyCheck {
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
// style
|
// style
|
||||||
addPropertyCheck(&props, left.GetStyle().ValueNode, right.GetStyle().ValueNode,
|
addPropertyCheck(&props, left.GetStyle().ValueNode, right.GetStyle().ValueNode,
|
||||||
left.GetStyle(), right.GetStyle(), changes, v3.StyleLabel, false)
|
left.GetStyle(), right.GetStyle(), changes, v3.StyleLabel, false)
|
||||||
|
|
||||||
// allow reserved
|
// allow reserved
|
||||||
addPropertyCheck(&props, left.GetAllowReserved().ValueNode, right.GetAllowReserved().ValueNode,
|
addPropertyCheck(&props, left.GetAllowReserved().ValueNode, right.GetAllowReserved().ValueNode,
|
||||||
left.GetAllowReserved(), right.GetAllowReserved(), changes, v3.AllowReservedLabel, false)
|
left.GetAllowReserved(), right.GetAllowReserved(), changes, v3.AllowReservedLabel, false)
|
||||||
|
|
||||||
// allow empty value
|
// allow empty value
|
||||||
addPropertyCheck(&props, left.GetAllowEmptyValue().ValueNode, right.GetAllowEmptyValue().ValueNode,
|
addPropertyCheck(&props, left.GetAllowEmptyValue().ValueNode, right.GetAllowEmptyValue().ValueNode,
|
||||||
left.GetAllowEmptyValue(), right.GetAllowEmptyValue(), changes, v3.AllowEmptyValueLabel, true)
|
left.GetAllowEmptyValue(), right.GetAllowEmptyValue(), changes, v3.AllowEmptyValueLabel, true)
|
||||||
|
|
||||||
// explode
|
// explode
|
||||||
addPropertyCheck(&props, left.GetExplode().ValueNode, right.GetExplode().ValueNode,
|
addPropertyCheck(&props, left.GetExplode().ValueNode, right.GetExplode().ValueNode,
|
||||||
left.GetExplode(), right.GetExplode(), changes, v3.ExplodeLabel, false)
|
left.GetExplode(), right.GetExplode(), changes, v3.ExplodeLabel, false)
|
||||||
|
|
||||||
// example
|
// example
|
||||||
addPropertyCheck(&props, left.GetExample().ValueNode, right.GetExample().ValueNode,
|
addPropertyCheck(&props, left.GetExample().ValueNode, right.GetExample().ValueNode,
|
||||||
left.GetExample(), right.GetExample(), changes, v3.ExampleLabel, false)
|
left.GetExample(), right.GetExample(), changes, v3.ExampleLabel, false)
|
||||||
|
|
||||||
// deprecated
|
// deprecated
|
||||||
addPropertyCheck(&props, left.GetDeprecated().ValueNode, right.GetDeprecated().ValueNode,
|
addPropertyCheck(&props, left.GetDeprecated().ValueNode, right.GetDeprecated().ValueNode,
|
||||||
left.GetDeprecated(), right.GetDeprecated(), changes, v3.DeprecatedLabel, false)
|
left.GetDeprecated(), right.GetDeprecated(), changes, v3.DeprecatedLabel, false)
|
||||||
|
|
||||||
// required
|
// required
|
||||||
addPropertyCheck(&props, left.GetRequired().ValueNode, right.GetRequired().ValueNode,
|
addPropertyCheck(&props, left.GetRequired().ValueNode, right.GetRequired().ValueNode,
|
||||||
left.GetRequired(), right.GetRequired(), changes, v3.RequiredLabel, true)
|
left.GetRequired(), right.GetRequired(), changes, v3.RequiredLabel, true)
|
||||||
|
|
||||||
return props
|
return props
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger only properties
|
// swagger only properties
|
||||||
func addSwaggerHeaderProperties(left, right low.SwaggerHeader, changes *[]*Change) []*PropertyCheck {
|
func addSwaggerHeaderProperties(left, right low.SwaggerHeader, changes *[]*Change) []*PropertyCheck {
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
// type
|
// type
|
||||||
addPropertyCheck(&props, left.GetType().ValueNode, right.GetType().ValueNode,
|
addPropertyCheck(&props, left.GetType().ValueNode, right.GetType().ValueNode,
|
||||||
left.GetType(), right.GetType(), changes, v3.TypeLabel, true)
|
left.GetType(), right.GetType(), changes, v3.TypeLabel, true)
|
||||||
|
|
||||||
// format
|
// format
|
||||||
addPropertyCheck(&props, left.GetFormat().ValueNode, right.GetFormat().ValueNode,
|
addPropertyCheck(&props, left.GetFormat().ValueNode, right.GetFormat().ValueNode,
|
||||||
left.GetFormat(), right.GetFormat(), changes, v3.FormatLabel, true)
|
left.GetFormat(), right.GetFormat(), changes, v3.FormatLabel, true)
|
||||||
|
|
||||||
// collection format
|
// collection format
|
||||||
addPropertyCheck(&props, left.GetCollectionFormat().ValueNode, right.GetCollectionFormat().ValueNode,
|
addPropertyCheck(&props, left.GetCollectionFormat().ValueNode, right.GetCollectionFormat().ValueNode,
|
||||||
left.GetCollectionFormat(), right.GetCollectionFormat(), changes, v3.CollectionFormatLabel, true)
|
left.GetCollectionFormat(), right.GetCollectionFormat(), changes, v3.CollectionFormatLabel, true)
|
||||||
|
|
||||||
// maximum
|
// maximum
|
||||||
addPropertyCheck(&props, left.GetMaximum().ValueNode, right.GetMaximum().ValueNode,
|
addPropertyCheck(&props, left.GetMaximum().ValueNode, right.GetMaximum().ValueNode,
|
||||||
left.GetMaximum(), right.GetMaximum(), changes, v3.MaximumLabel, true)
|
left.GetMaximum(), right.GetMaximum(), changes, v3.MaximumLabel, true)
|
||||||
|
|
||||||
// minimum
|
// minimum
|
||||||
addPropertyCheck(&props, left.GetMinimum().ValueNode, right.GetMinimum().ValueNode,
|
addPropertyCheck(&props, left.GetMinimum().ValueNode, right.GetMinimum().ValueNode,
|
||||||
left.GetMinimum(), right.GetMinimum(), changes, v3.MinimumLabel, true)
|
left.GetMinimum(), right.GetMinimum(), changes, v3.MinimumLabel, true)
|
||||||
|
|
||||||
// exclusive maximum
|
// exclusive maximum
|
||||||
addPropertyCheck(&props, left.GetExclusiveMaximum().ValueNode, right.GetExclusiveMaximum().ValueNode,
|
addPropertyCheck(&props, left.GetExclusiveMaximum().ValueNode, right.GetExclusiveMaximum().ValueNode,
|
||||||
left.GetExclusiveMaximum(), right.GetExclusiveMaximum(), changes, v3.ExclusiveMaximumLabel, true)
|
left.GetExclusiveMaximum(), right.GetExclusiveMaximum(), changes, v3.ExclusiveMaximumLabel, true)
|
||||||
|
|
||||||
// exclusive minimum
|
// exclusive minimum
|
||||||
addPropertyCheck(&props, left.GetExclusiveMinimum().ValueNode, right.GetExclusiveMinimum().ValueNode,
|
addPropertyCheck(&props, left.GetExclusiveMinimum().ValueNode, right.GetExclusiveMinimum().ValueNode,
|
||||||
left.GetExclusiveMinimum(), right.GetExclusiveMinimum(), changes, v3.ExclusiveMinimumLabel, true)
|
left.GetExclusiveMinimum(), right.GetExclusiveMinimum(), changes, v3.ExclusiveMinimumLabel, true)
|
||||||
|
|
||||||
// max length
|
// max length
|
||||||
addPropertyCheck(&props, left.GetMaxLength().ValueNode, right.GetMaxLength().ValueNode,
|
addPropertyCheck(&props, left.GetMaxLength().ValueNode, right.GetMaxLength().ValueNode,
|
||||||
left.GetMaxLength(), right.GetMaxLength(), changes, v3.MaxLengthLabel, true)
|
left.GetMaxLength(), right.GetMaxLength(), changes, v3.MaxLengthLabel, true)
|
||||||
|
|
||||||
// min length
|
// min length
|
||||||
addPropertyCheck(&props, left.GetMinLength().ValueNode, right.GetMinLength().ValueNode,
|
addPropertyCheck(&props, left.GetMinLength().ValueNode, right.GetMinLength().ValueNode,
|
||||||
left.GetMinLength(), right.GetMinLength(), changes, v3.MinLengthLabel, true)
|
left.GetMinLength(), right.GetMinLength(), changes, v3.MinLengthLabel, true)
|
||||||
|
|
||||||
// pattern
|
// pattern
|
||||||
addPropertyCheck(&props, left.GetPattern().ValueNode, right.GetPattern().ValueNode,
|
addPropertyCheck(&props, left.GetPattern().ValueNode, right.GetPattern().ValueNode,
|
||||||
left.GetPattern(), right.GetPattern(), changes, v3.PatternLabel, true)
|
left.GetPattern(), right.GetPattern(), changes, v3.PatternLabel, true)
|
||||||
|
|
||||||
// max items
|
// max items
|
||||||
addPropertyCheck(&props, left.GetMaxItems().ValueNode, right.GetMaxItems().ValueNode,
|
addPropertyCheck(&props, left.GetMaxItems().ValueNode, right.GetMaxItems().ValueNode,
|
||||||
left.GetMaxItems(), right.GetMaxItems(), changes, v3.MaxItemsLabel, true)
|
left.GetMaxItems(), right.GetMaxItems(), changes, v3.MaxItemsLabel, true)
|
||||||
|
|
||||||
// min items
|
// min items
|
||||||
addPropertyCheck(&props, left.GetMinItems().ValueNode, right.GetMinItems().ValueNode,
|
addPropertyCheck(&props, left.GetMinItems().ValueNode, right.GetMinItems().ValueNode,
|
||||||
left.GetMinItems(), right.GetMinItems(), changes, v3.MinItemsLabel, true)
|
left.GetMinItems(), right.GetMinItems(), changes, v3.MinItemsLabel, true)
|
||||||
|
|
||||||
// unique items
|
// unique items
|
||||||
addPropertyCheck(&props, left.GetUniqueItems().ValueNode, right.GetUniqueItems().ValueNode,
|
addPropertyCheck(&props, left.GetUniqueItems().ValueNode, right.GetUniqueItems().ValueNode,
|
||||||
left.GetUniqueItems(), right.GetUniqueItems(), changes, v3.UniqueItemsLabel, true)
|
left.GetUniqueItems(), right.GetUniqueItems(), changes, v3.UniqueItemsLabel, true)
|
||||||
|
|
||||||
// multiple of
|
// multiple of
|
||||||
addPropertyCheck(&props, left.GetMultipleOf().ValueNode, right.GetMultipleOf().ValueNode,
|
addPropertyCheck(&props, left.GetMultipleOf().ValueNode, right.GetMultipleOf().ValueNode,
|
||||||
left.GetMultipleOf(), right.GetMultipleOf(), changes, v3.MultipleOfLabel, true)
|
left.GetMultipleOf(), right.GetMultipleOf(), changes, v3.MultipleOfLabel, true)
|
||||||
|
|
||||||
return props
|
return props
|
||||||
}
|
}
|
||||||
|
|
||||||
// common header properties
|
// common header properties
|
||||||
func addCommonHeaderProperties(left, right low.HasDescription, changes *[]*Change) []*PropertyCheck {
|
func addCommonHeaderProperties(left, right low.HasDescription, changes *[]*Change) []*PropertyCheck {
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
// description
|
// description
|
||||||
addPropertyCheck(&props, left.GetDescription().ValueNode, right.GetDescription().ValueNode,
|
addPropertyCheck(&props, left.GetDescription().ValueNode, right.GetDescription().ValueNode,
|
||||||
left.GetDescription(), right.GetDescription(), changes, v3.DescriptionLabel, false)
|
left.GetDescription(), right.GetDescription(), changes, v3.DescriptionLabel, false)
|
||||||
|
|
||||||
return props
|
return props
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareHeadersV2 is a Swagger compatible, typed signature used for other generic functions. It simply
|
// CompareHeadersV2 is a Swagger compatible, typed signature used for other generic functions. It simply
|
||||||
// wraps CompareHeaders and provides nothing other that a typed interface.
|
// wraps CompareHeaders and provides nothing other that a typed interface.
|
||||||
func CompareHeadersV2(l, r *v2.Header) *HeaderChanges {
|
func CompareHeadersV2(l, r *v2.Header) *HeaderChanges {
|
||||||
return CompareHeaders(l, r)
|
return CompareHeaders(l, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareHeadersV3 is an OpenAPI 3+ compatible, typed signature used for other generic functions. It simply
|
// CompareHeadersV3 is an OpenAPI 3+ compatible, typed signature used for other generic functions. It simply
|
||||||
// wraps CompareHeaders and provides nothing other that a typed interface.
|
// wraps CompareHeaders and provides nothing other that a typed interface.
|
||||||
func CompareHeadersV3(l, r *v3.Header) *HeaderChanges {
|
func CompareHeadersV3(l, r *v3.Header) *HeaderChanges {
|
||||||
return CompareHeaders(l, r)
|
return CompareHeaders(l, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareHeaders will compare left and right Header objects (any version of Swagger or OpenAPI) and return
|
// CompareHeaders will compare left and right Header objects (any version of Swagger or OpenAPI) and return
|
||||||
// a pointer to HeaderChanges with anything that has changed, or nil if nothing changed.
|
// a pointer to HeaderChanges with anything that has changed, or nil if nothing changed.
|
||||||
func CompareHeaders(l, r any) *HeaderChanges {
|
func CompareHeaders(l, r any) *HeaderChanges {
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
hc := new(HeaderChanges)
|
hc := new(HeaderChanges)
|
||||||
|
|
||||||
// handle swagger.
|
// handle swagger.
|
||||||
if reflect.TypeOf(&v2.Header{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Header{}) == reflect.TypeOf(r) {
|
if reflect.TypeOf(&v2.Header{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Header{}) == reflect.TypeOf(r) {
|
||||||
lHeader := l.(*v2.Header)
|
lHeader := l.(*v2.Header)
|
||||||
rHeader := r.(*v2.Header)
|
rHeader := r.(*v2.Header)
|
||||||
|
|
||||||
// perform hash check to avoid further processing
|
// perform hash check to avoid further processing
|
||||||
if low.AreEqual(lHeader, rHeader) {
|
if low.AreEqual(lHeader, rHeader) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
props = append(props, addCommonHeaderProperties(lHeader, rHeader, &changes)...)
|
props = append(props, addCommonHeaderProperties(lHeader, rHeader, &changes)...)
|
||||||
props = append(props, addSwaggerHeaderProperties(lHeader, rHeader, &changes)...)
|
props = append(props, addSwaggerHeaderProperties(lHeader, rHeader, &changes)...)
|
||||||
|
|
||||||
// enum
|
// enum
|
||||||
if len(lHeader.Enum.Value) > 0 || len(rHeader.Enum.Value) > 0 {
|
if len(lHeader.Enum.Value) > 0 || len(rHeader.Enum.Value) > 0 {
|
||||||
ExtractRawValueSliceChanges(lHeader.Enum.Value, rHeader.Enum.Value, &changes, v3.EnumLabel, true)
|
ExtractRawValueSliceChanges(lHeader.Enum.Value, rHeader.Enum.Value, &changes, v3.EnumLabel, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// items
|
// items
|
||||||
if !lHeader.Items.IsEmpty() && !rHeader.Items.IsEmpty() {
|
if !lHeader.Items.IsEmpty() && !rHeader.Items.IsEmpty() {
|
||||||
if !low.AreEqual(lHeader.Items.Value, rHeader.Items.Value) {
|
if !low.AreEqual(lHeader.Items.Value, rHeader.Items.Value) {
|
||||||
hc.ItemsChanges = CompareItems(lHeader.Items.Value, rHeader.Items.Value)
|
hc.ItemsChanges = CompareItems(lHeader.Items.Value, rHeader.Items.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if lHeader.Items.IsEmpty() && !rHeader.Items.IsEmpty() {
|
if lHeader.Items.IsEmpty() && !rHeader.Items.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectAdded, v3.ItemsLabel, nil,
|
CreateChange(&changes, ObjectAdded, v3.ItemsLabel, nil,
|
||||||
rHeader.Items.ValueNode, true, nil, rHeader.Items.Value)
|
rHeader.Items.ValueNode, true, nil, rHeader.Items.Value)
|
||||||
}
|
}
|
||||||
if !lHeader.Items.IsEmpty() && rHeader.Items.IsEmpty() {
|
if !lHeader.Items.IsEmpty() && rHeader.Items.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.SchemaLabel, lHeader.Items.ValueNode,
|
CreateChange(&changes, ObjectRemoved, v3.SchemaLabel, lHeader.Items.ValueNode,
|
||||||
nil, true, lHeader.Items.Value, nil)
|
nil, true, lHeader.Items.Value, nil)
|
||||||
}
|
}
|
||||||
hc.ExtensionChanges = CompareExtensions(lHeader.Extensions, rHeader.Extensions)
|
hc.ExtensionChanges = CompareExtensions(lHeader.Extensions, rHeader.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle OpenAPI
|
// handle OpenAPI
|
||||||
if reflect.TypeOf(&v3.Header{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Header{}) == reflect.TypeOf(r) {
|
if reflect.TypeOf(&v3.Header{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Header{}) == reflect.TypeOf(r) {
|
||||||
lHeader := l.(*v3.Header)
|
lHeader := l.(*v3.Header)
|
||||||
rHeader := r.(*v3.Header)
|
rHeader := r.(*v3.Header)
|
||||||
|
|
||||||
// perform hash check to avoid further processing
|
// perform hash check to avoid further processing
|
||||||
if low.AreEqual(lHeader, rHeader) {
|
if low.AreEqual(lHeader, rHeader) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
props = append(props, addCommonHeaderProperties(lHeader, rHeader, &changes)...)
|
props = append(props, addCommonHeaderProperties(lHeader, rHeader, &changes)...)
|
||||||
props = append(props, addOpenAPIHeaderProperties(lHeader, rHeader, &changes)...)
|
props = append(props, addOpenAPIHeaderProperties(lHeader, rHeader, &changes)...)
|
||||||
|
|
||||||
// header
|
// header
|
||||||
if !lHeader.Schema.IsEmpty() || !rHeader.Schema.IsEmpty() {
|
if !lHeader.Schema.IsEmpty() || !rHeader.Schema.IsEmpty() {
|
||||||
hc.SchemaChanges = CompareSchemas(lHeader.Schema.Value, rHeader.Schema.Value)
|
hc.SchemaChanges = CompareSchemas(lHeader.Schema.Value, rHeader.Schema.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// examples
|
// examples
|
||||||
hc.ExamplesChanges = CheckMapForChanges(lHeader.Examples.Value, rHeader.Examples.Value,
|
hc.ExamplesChanges = CheckMapForChanges(lHeader.Examples.Value, rHeader.Examples.Value,
|
||||||
&changes, v3.ExamplesLabel, CompareExamples)
|
&changes, v3.ExamplesLabel, CompareExamples)
|
||||||
|
|
||||||
// content
|
// content
|
||||||
hc.ContentChanges = CheckMapForChanges(lHeader.Content.Value, rHeader.Content.Value,
|
hc.ContentChanges = CheckMapForChanges(lHeader.Content.Value, rHeader.Content.Value,
|
||||||
&changes, v3.ContentLabel, CompareMediaTypes)
|
&changes, v3.ContentLabel, CompareMediaTypes)
|
||||||
|
|
||||||
hc.ExtensionChanges = CompareExtensions(lHeader.Extensions, rHeader.Extensions)
|
hc.ExtensionChanges = CompareExtensions(lHeader.Extensions, rHeader.Extensions)
|
||||||
|
|
||||||
}
|
}
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
hc.Changes = changes
|
hc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
return hc
|
return hc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,32 +4,32 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InfoChanges represents the number of changes to an Info object. Part of an OpenAPI document
|
// InfoChanges represents the number of changes to an Info object. Part of an OpenAPI document
|
||||||
type InfoChanges struct {
|
type InfoChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ContactChanges *ContactChanges `json:"contact,omitempty" yaml:"contact,omitempty"`
|
ContactChanges *ContactChanges `json:"contact,omitempty" yaml:"contact,omitempty"`
|
||||||
LicenseChanges *LicenseChanges `json:"license,omitempty" yaml:"license,omitempty"`
|
LicenseChanges *LicenseChanges `json:"license,omitempty" yaml:"license,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges represents the total number of changes made to an Info object.
|
// TotalChanges represents the total number of changes made to an Info object.
|
||||||
func (i *InfoChanges) TotalChanges() int {
|
func (i *InfoChanges) TotalChanges() int {
|
||||||
t := i.PropertyChanges.TotalChanges()
|
t := i.PropertyChanges.TotalChanges()
|
||||||
if i.ContactChanges != nil {
|
if i.ContactChanges != nil {
|
||||||
t += i.ContactChanges.TotalChanges()
|
t += i.ContactChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
if i.LicenseChanges != nil {
|
if i.LicenseChanges != nil {
|
||||||
t += i.LicenseChanges.TotalChanges()
|
t += i.LicenseChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges always returns 0 for Info objects, they are non-binding.
|
// TotalBreakingChanges always returns 0 for Info objects, they are non-binding.
|
||||||
func (i *InfoChanges) TotalBreakingChanges() int {
|
func (i *InfoChanges) TotalBreakingChanges() int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareInfo will compare a left (original) and a right (new) Info object. Any changes
|
// CompareInfo will compare a left (original) and a right (new) Info object. Any changes
|
||||||
@@ -37,88 +37,88 @@ func (i *InfoChanges) TotalBreakingChanges() int {
|
|||||||
// returned instead.
|
// returned instead.
|
||||||
func CompareInfo(l, r *base.Info) *InfoChanges {
|
func CompareInfo(l, r *base.Info) *InfoChanges {
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Title.ValueNode,
|
LeftNode: l.Title.ValueNode,
|
||||||
RightNode: r.Title.ValueNode,
|
RightNode: r.Title.ValueNode,
|
||||||
Label: v3.TitleLabel,
|
Label: v3.TitleLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Description
|
// Description
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Description.ValueNode,
|
LeftNode: l.Description.ValueNode,
|
||||||
RightNode: r.Description.ValueNode,
|
RightNode: r.Description.ValueNode,
|
||||||
Label: v3.DescriptionLabel,
|
Label: v3.DescriptionLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// TermsOfService
|
// TermsOfService
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.TermsOfService.ValueNode,
|
LeftNode: l.TermsOfService.ValueNode,
|
||||||
RightNode: r.TermsOfService.ValueNode,
|
RightNode: r.TermsOfService.ValueNode,
|
||||||
Label: v3.TermsOfServiceLabel,
|
Label: v3.TermsOfServiceLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Version
|
// Version
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Version.ValueNode,
|
LeftNode: l.Version.ValueNode,
|
||||||
RightNode: r.Version.ValueNode,
|
RightNode: r.Version.ValueNode,
|
||||||
Label: v3.VersionLabel,
|
Label: v3.VersionLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// check properties
|
// check properties
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
|
|
||||||
i := new(InfoChanges)
|
i := new(InfoChanges)
|
||||||
|
|
||||||
// compare contact.
|
// compare contact.
|
||||||
if l.Contact.Value != nil && r.Contact.Value != nil {
|
if l.Contact.Value != nil && r.Contact.Value != nil {
|
||||||
i.ContactChanges = CompareContact(l.Contact.Value, r.Contact.Value)
|
i.ContactChanges = CompareContact(l.Contact.Value, r.Contact.Value)
|
||||||
} else {
|
} else {
|
||||||
if l.Contact.Value == nil && r.Contact.Value != nil {
|
if l.Contact.Value == nil && r.Contact.Value != nil {
|
||||||
CreateChange(&changes, ObjectAdded, v3.ContactLabel,
|
CreateChange(&changes, ObjectAdded, v3.ContactLabel,
|
||||||
nil, r.Contact.ValueNode, false, nil, r.Contact.Value)
|
nil, r.Contact.ValueNode, false, nil, r.Contact.Value)
|
||||||
}
|
}
|
||||||
if l.Contact.Value != nil && r.Contact.Value == nil {
|
if l.Contact.Value != nil && r.Contact.Value == nil {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.ContactLabel,
|
CreateChange(&changes, ObjectRemoved, v3.ContactLabel,
|
||||||
l.Contact.ValueNode, nil, false, l.Contact.Value, nil)
|
l.Contact.ValueNode, nil, false, l.Contact.Value, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// compare license.
|
// compare license.
|
||||||
if l.License.Value != nil && r.License.Value != nil {
|
if l.License.Value != nil && r.License.Value != nil {
|
||||||
i.LicenseChanges = CompareLicense(l.License.Value, r.License.Value)
|
i.LicenseChanges = CompareLicense(l.License.Value, r.License.Value)
|
||||||
} else {
|
} else {
|
||||||
if l.License.Value == nil && r.License.Value != nil {
|
if l.License.Value == nil && r.License.Value != nil {
|
||||||
CreateChange(&changes, ObjectAdded, v3.LicenseLabel,
|
CreateChange(&changes, ObjectAdded, v3.LicenseLabel,
|
||||||
nil, r.License.ValueNode, false, nil, r.License.Value)
|
nil, r.License.ValueNode, false, nil, r.License.Value)
|
||||||
}
|
}
|
||||||
if l.License.Value != nil && r.License.Value == nil {
|
if l.License.Value != nil && r.License.Value == nil {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.LicenseLabel,
|
CreateChange(&changes, ObjectRemoved, v3.LicenseLabel,
|
||||||
l.License.ValueNode, nil, false, r.License.Value, nil)
|
l.License.ValueNode, nil, false, r.License.Value, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i.Changes = changes
|
i.PropertyChanges = NewPropertyChanges(changes)
|
||||||
if i.TotalChanges() <= 0 {
|
if i.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,35 +4,35 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ItemsChanges represent changes found between a left (original) and right (modified) object. Items is only
|
// ItemsChanges represent changes found between a left (original) and right (modified) object. Items is only
|
||||||
// used by Swagger documents.
|
// used by Swagger documents.
|
||||||
type ItemsChanges struct {
|
type ItemsChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ItemsChanges *ItemsChanges `json:"items,omitempty" yaml:"items,omitempty"`
|
ItemsChanges *ItemsChanges `json:"items,omitempty" yaml:"items,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns the total number of changes found between two Items objects
|
// TotalChanges returns the total number of changes found between two Items objects
|
||||||
// This is a recursive function because Items can contain Items. Be careful!
|
// This is a recursive function because Items can contain Items. Be careful!
|
||||||
func (i *ItemsChanges) TotalChanges() int {
|
func (i *ItemsChanges) TotalChanges() int {
|
||||||
c := i.PropertyChanges.TotalChanges()
|
c := i.PropertyChanges.TotalChanges()
|
||||||
if i.ItemsChanges != nil {
|
if i.ItemsChanges != nil {
|
||||||
c += i.ItemsChanges.TotalChanges()
|
c += i.ItemsChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the total number of breaking changes found between two Swagger Items objects
|
// TotalBreakingChanges returns the total number of breaking changes found between two Swagger Items objects
|
||||||
// This is a recursive method, Items are recursive, be careful!
|
// This is a recursive method, Items are recursive, be careful!
|
||||||
func (i *ItemsChanges) TotalBreakingChanges() int {
|
func (i *ItemsChanges) TotalBreakingChanges() int {
|
||||||
c := i.PropertyChanges.TotalBreakingChanges()
|
c := i.PropertyChanges.TotalBreakingChanges()
|
||||||
if i.ItemsChanges != nil {
|
if i.ItemsChanges != nil {
|
||||||
c += i.ItemsChanges.TotalBreakingChanges()
|
c += i.ItemsChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareItems compares two sets of Swagger Item objects. If there are any changes found then a pointer to
|
// CompareItems compares two sets of Swagger Item objects. If there are any changes found then a pointer to
|
||||||
@@ -42,37 +42,37 @@ func (i *ItemsChanges) TotalBreakingChanges() int {
|
|||||||
// runaway code if not using the resolver's circular reference checking.
|
// runaway code if not using the resolver's circular reference checking.
|
||||||
func CompareItems(l, r *v2.Items) *ItemsChanges {
|
func CompareItems(l, r *v2.Items) *ItemsChanges {
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
ic := new(ItemsChanges)
|
ic := new(ItemsChanges)
|
||||||
|
|
||||||
// header is identical to items, except for a description.
|
// header is identical to items, except for a description.
|
||||||
props = append(props, addSwaggerHeaderProperties(l, r, &changes)...)
|
props = append(props, addSwaggerHeaderProperties(l, r, &changes)...)
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
|
|
||||||
if !l.Items.IsEmpty() && !r.Items.IsEmpty() {
|
if !l.Items.IsEmpty() && !r.Items.IsEmpty() {
|
||||||
// inline, check hashes, if they don't match, compare.
|
// inline, check hashes, if they don't match, compare.
|
||||||
if l.Items.Value.Hash() != r.Items.Value.Hash() {
|
if l.Items.Value.Hash() != r.Items.Value.Hash() {
|
||||||
// compare.
|
// compare.
|
||||||
ic.ItemsChanges = CompareItems(l.Items.Value, r.Items.Value)
|
ic.ItemsChanges = CompareItems(l.Items.Value, r.Items.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if l.Items.IsEmpty() && !r.Items.IsEmpty() {
|
if l.Items.IsEmpty() && !r.Items.IsEmpty() {
|
||||||
// added items
|
// added items
|
||||||
CreateChange(&changes, PropertyAdded, v3.ItemsLabel,
|
CreateChange(&changes, PropertyAdded, v3.ItemsLabel,
|
||||||
nil, r.Items.GetValueNode(), true, nil, r.Items.GetValue())
|
nil, r.Items.GetValueNode(), true, nil, r.Items.GetValue())
|
||||||
}
|
}
|
||||||
if !l.Items.IsEmpty() && r.Items.IsEmpty() {
|
if !l.Items.IsEmpty() && r.Items.IsEmpty() {
|
||||||
// removed items
|
// removed items
|
||||||
CreateChange(&changes, PropertyRemoved, v3.ItemsLabel,
|
CreateChange(&changes, PropertyRemoved, v3.ItemsLabel,
|
||||||
l.Items.GetValueNode(), nil, true, l.Items.GetValue(),
|
l.Items.GetValueNode(), nil, true, l.Items.GetValue(),
|
||||||
nil)
|
nil)
|
||||||
}
|
}
|
||||||
ic.Changes = changes
|
ic.PropertyChanges = NewPropertyChanges(changes)
|
||||||
if ic.TotalChanges() <= 0 {
|
if ic.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return ic
|
return ic
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,23 +4,23 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LicenseChanges represent changes to a License object that is a child of Info object. Part of an OpenAPI document
|
// LicenseChanges represent changes to a License object that is a child of Info object. Part of an OpenAPI document
|
||||||
type LicenseChanges struct {
|
type LicenseChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges represents the total number of changes made to a License instance.
|
// TotalChanges represents the total number of changes made to a License instance.
|
||||||
func (l *LicenseChanges) TotalChanges() int {
|
func (l *LicenseChanges) TotalChanges() int {
|
||||||
return l.PropertyChanges.TotalChanges()
|
return l.PropertyChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges always returns 0 for License objects, they are non-binding.
|
// TotalBreakingChanges always returns 0 for License objects, they are non-binding.
|
||||||
func (l *LicenseChanges) TotalBreakingChanges() int {
|
func (l *LicenseChanges) TotalBreakingChanges() int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareLicense will check a left (original) and right (new) License object for any changes. If there
|
// CompareLicense will check a left (original) and right (new) License object for any changes. If there
|
||||||
@@ -28,38 +28,38 @@ func (l *LicenseChanges) TotalBreakingChanges() int {
|
|||||||
// returns nil.
|
// returns nil.
|
||||||
func CompareLicense(l, r *base.License) *LicenseChanges {
|
func CompareLicense(l, r *base.License) *LicenseChanges {
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
// check URL
|
// check URL
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.URL.ValueNode,
|
LeftNode: l.URL.ValueNode,
|
||||||
RightNode: r.URL.ValueNode,
|
RightNode: r.URL.ValueNode,
|
||||||
Label: v3.URLLabel,
|
Label: v3.URLLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// check name
|
// check name
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Name.ValueNode,
|
LeftNode: l.Name.ValueNode,
|
||||||
RightNode: r.Name.ValueNode,
|
RightNode: r.Name.ValueNode,
|
||||||
Label: v3.NameLabel,
|
Label: v3.NameLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// check everything.
|
// check everything.
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
|
|
||||||
lc := new(LicenseChanges)
|
lc := new(LicenseChanges)
|
||||||
lc.Changes = changes
|
lc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
if lc.TotalChanges() <= 0 {
|
if lc.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return lc
|
return lc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,144 +4,144 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LinkChanges represent changes made between two OpenAPI Link Objects.
|
// LinkChanges represent changes made between two OpenAPI Link Objects.
|
||||||
type LinkChanges struct {
|
type LinkChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
ServerChanges *ServerChanges `json:"server,omitempty" yaml:"server,omitempty"`
|
ServerChanges *ServerChanges `json:"server,omitempty" yaml:"server,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns the total changes made between OpenAPI Link objects
|
// TotalChanges returns the total changes made between OpenAPI Link objects
|
||||||
func (l *LinkChanges) TotalChanges() int {
|
func (l *LinkChanges) TotalChanges() int {
|
||||||
c := l.PropertyChanges.TotalChanges()
|
c := l.PropertyChanges.TotalChanges()
|
||||||
if l.ExtensionChanges != nil {
|
if l.ExtensionChanges != nil {
|
||||||
c += l.ExtensionChanges.TotalChanges()
|
c += l.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
if l.ServerChanges != nil {
|
if l.ServerChanges != nil {
|
||||||
c += l.ServerChanges.TotalChanges()
|
c += l.ServerChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the number of breaking changes made between two OpenAPI Link Objects
|
// TotalBreakingChanges returns the number of breaking changes made between two OpenAPI Link Objects
|
||||||
func (l *LinkChanges) TotalBreakingChanges() int {
|
func (l *LinkChanges) TotalBreakingChanges() int {
|
||||||
c := l.PropertyChanges.TotalBreakingChanges()
|
c := l.PropertyChanges.TotalBreakingChanges()
|
||||||
if l.ServerChanges != nil {
|
if l.ServerChanges != nil {
|
||||||
c += l.ServerChanges.TotalBreakingChanges()
|
c += l.ServerChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareLinks checks a left and right OpenAPI Link for any changes. If they are found, returns a pointer to
|
// CompareLinks checks a left and right OpenAPI Link for any changes. If they are found, returns a pointer to
|
||||||
// LinkChanges, and returns nil if nothing is found.
|
// LinkChanges, and returns nil if nothing is found.
|
||||||
func CompareLinks(l, r *v3.Link) *LinkChanges {
|
func CompareLinks(l, r *v3.Link) *LinkChanges {
|
||||||
if low.AreEqual(l, r) {
|
if low.AreEqual(l, r) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
|
|
||||||
// operation ref
|
// operation ref
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.OperationRef.ValueNode,
|
LeftNode: l.OperationRef.ValueNode,
|
||||||
RightNode: r.OperationRef.ValueNode,
|
RightNode: r.OperationRef.ValueNode,
|
||||||
Label: v3.OperationRefLabel,
|
Label: v3.OperationRefLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// operation id
|
// operation id
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.OperationId.ValueNode,
|
LeftNode: l.OperationId.ValueNode,
|
||||||
RightNode: r.OperationId.ValueNode,
|
RightNode: r.OperationId.ValueNode,
|
||||||
Label: v3.OperationIdLabel,
|
Label: v3.OperationIdLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// request body
|
// request body
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.RequestBody.ValueNode,
|
LeftNode: l.RequestBody.ValueNode,
|
||||||
RightNode: r.RequestBody.ValueNode,
|
RightNode: r.RequestBody.ValueNode,
|
||||||
Label: v3.RequestBodyLabel,
|
Label: v3.RequestBodyLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// description
|
// description
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Description.ValueNode,
|
LeftNode: l.Description.ValueNode,
|
||||||
RightNode: r.Description.ValueNode,
|
RightNode: r.Description.ValueNode,
|
||||||
Label: v3.DescriptionLabel,
|
Label: v3.DescriptionLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
lc := new(LinkChanges)
|
lc := new(LinkChanges)
|
||||||
lc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
lc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||||
|
|
||||||
// server
|
// server
|
||||||
if !l.Server.IsEmpty() && !r.Server.IsEmpty() {
|
if !l.Server.IsEmpty() && !r.Server.IsEmpty() {
|
||||||
if !low.AreEqual(l.Server.Value, r.Server.Value) {
|
if !low.AreEqual(l.Server.Value, r.Server.Value) {
|
||||||
lc.ServerChanges = CompareServers(l.Server.Value, r.Server.Value)
|
lc.ServerChanges = CompareServers(l.Server.Value, r.Server.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !l.Server.IsEmpty() && r.Server.IsEmpty() {
|
if !l.Server.IsEmpty() && r.Server.IsEmpty() {
|
||||||
CreateChange(&changes, PropertyRemoved, v3.ServerLabel,
|
CreateChange(&changes, PropertyRemoved, v3.ServerLabel,
|
||||||
l.Server.ValueNode, nil, true,
|
l.Server.ValueNode, nil, true,
|
||||||
l.Server.Value, nil)
|
l.Server.Value, nil)
|
||||||
}
|
}
|
||||||
if l.Server.IsEmpty() && !r.Server.IsEmpty() {
|
if l.Server.IsEmpty() && !r.Server.IsEmpty() {
|
||||||
CreateChange(&changes, PropertyAdded, v3.ServerLabel,
|
CreateChange(&changes, PropertyAdded, v3.ServerLabel,
|
||||||
nil, r.Server.ValueNode, true,
|
nil, r.Server.ValueNode, true,
|
||||||
nil, r.Server.Value)
|
nil, r.Server.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parameters
|
// parameters
|
||||||
lValues := make(map[string]low.ValueReference[string])
|
lValues := make(map[string]low.ValueReference[string])
|
||||||
rValues := make(map[string]low.ValueReference[string])
|
rValues := make(map[string]low.ValueReference[string])
|
||||||
for i := range l.Parameters {
|
for i := range l.Parameters {
|
||||||
lValues[i.Value] = l.Parameters[i]
|
lValues[i.Value] = l.Parameters[i]
|
||||||
}
|
}
|
||||||
for i := range r.Parameters {
|
for i := range r.Parameters {
|
||||||
rValues[i.Value] = r.Parameters[i]
|
rValues[i.Value] = r.Parameters[i]
|
||||||
}
|
}
|
||||||
for k := range lValues {
|
for k := range lValues {
|
||||||
if _, ok := rValues[k]; !ok {
|
if _, ok := rValues[k]; !ok {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.ParametersLabel,
|
CreateChange(&changes, ObjectRemoved, v3.ParametersLabel,
|
||||||
lValues[k].ValueNode, nil, true,
|
lValues[k].ValueNode, nil, true,
|
||||||
k, nil)
|
k, nil)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if lValues[k].Value != rValues[k].Value {
|
if lValues[k].Value != rValues[k].Value {
|
||||||
CreateChange(&changes, Modified, v3.ParametersLabel,
|
CreateChange(&changes, Modified, v3.ParametersLabel,
|
||||||
lValues[k].ValueNode, rValues[k].ValueNode, true,
|
lValues[k].ValueNode, rValues[k].ValueNode, true,
|
||||||
k, k)
|
k, k)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
for k := range rValues {
|
for k := range rValues {
|
||||||
if _, ok := lValues[k]; !ok {
|
if _, ok := lValues[k]; !ok {
|
||||||
CreateChange(&changes, ObjectAdded, v3.ParametersLabel,
|
CreateChange(&changes, ObjectAdded, v3.ParametersLabel,
|
||||||
nil, rValues[k].ValueNode, true,
|
nil, rValues[k].ValueNode, true,
|
||||||
nil, k)
|
nil, k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lc.Changes = changes
|
lc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
return lc
|
return lc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
|
|
||||||
// MediaTypeChanges represent changes made between two OpenAPI MediaType instances.
|
// MediaTypeChanges represent changes made between two OpenAPI MediaType instances.
|
||||||
type MediaTypeChanges struct {
|
type MediaTypeChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
ExampleChanges map[string]*ExampleChanges `json:"examples,omitempty" yaml:"examples,omitempty"`
|
ExampleChanges map[string]*ExampleChanges `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||||
@@ -130,7 +130,7 @@ func CompareMediaTypes(l, r *v3.MediaType) *MediaTypeChanges {
|
|||||||
&changes, v3.EncodingLabel, CompareEncoding)
|
&changes, v3.EncodingLabel, CompareEncoding)
|
||||||
|
|
||||||
mc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
mc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||||
mc.Changes = changes
|
mc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
|
|
||||||
if mc.TotalChanges() <= 0 {
|
if mc.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -4,222 +4,222 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OAuthFlowsChanges represents changes found between two OpenAPI OAuthFlows objects.
|
// OAuthFlowsChanges represents changes found between two OpenAPI OAuthFlows objects.
|
||||||
type OAuthFlowsChanges struct {
|
type OAuthFlowsChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ImplicitChanges *OAuthFlowChanges `json:"implicit,omitempty" yaml:"implicit,omitempty"`
|
ImplicitChanges *OAuthFlowChanges `json:"implicit,omitempty" yaml:"implicit,omitempty"`
|
||||||
PasswordChanges *OAuthFlowChanges `json:"password,omitempty" yaml:"password,omitempty"`
|
PasswordChanges *OAuthFlowChanges `json:"password,omitempty" yaml:"password,omitempty"`
|
||||||
ClientCredentialsChanges *OAuthFlowChanges `json:"clientCredentials,omitempty" yaml:"clientCredentials,omitempty"`
|
ClientCredentialsChanges *OAuthFlowChanges `json:"clientCredentials,omitempty" yaml:"clientCredentials,omitempty"`
|
||||||
AuthorizationCodeChanges *OAuthFlowChanges `json:"authCode,omitempty" yaml:"authCode,omitempty"`
|
AuthorizationCodeChanges *OAuthFlowChanges `json:"authCode,omitempty" yaml:"authCode,omitempty"`
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns the number of changes made between two OAuthFlows instances.
|
// TotalChanges returns the number of changes made between two OAuthFlows instances.
|
||||||
func (o *OAuthFlowsChanges) TotalChanges() int {
|
func (o *OAuthFlowsChanges) TotalChanges() int {
|
||||||
c := o.PropertyChanges.TotalChanges()
|
c := o.PropertyChanges.TotalChanges()
|
||||||
if o.ImplicitChanges != nil {
|
if o.ImplicitChanges != nil {
|
||||||
c += o.ImplicitChanges.TotalChanges()
|
c += o.ImplicitChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
if o.PasswordChanges != nil {
|
if o.PasswordChanges != nil {
|
||||||
c += o.PasswordChanges.TotalChanges()
|
c += o.PasswordChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
if o.ClientCredentialsChanges != nil {
|
if o.ClientCredentialsChanges != nil {
|
||||||
c += o.ClientCredentialsChanges.TotalChanges()
|
c += o.ClientCredentialsChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
if o.AuthorizationCodeChanges != nil {
|
if o.AuthorizationCodeChanges != nil {
|
||||||
c += o.AuthorizationCodeChanges.TotalChanges()
|
c += o.AuthorizationCodeChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
if o.ExtensionChanges != nil {
|
if o.ExtensionChanges != nil {
|
||||||
c += o.ExtensionChanges.TotalChanges()
|
c += o.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the number of breaking changes made between two OAuthFlows objects.
|
// TotalBreakingChanges returns the number of breaking changes made between two OAuthFlows objects.
|
||||||
func (o *OAuthFlowsChanges) TotalBreakingChanges() int {
|
func (o *OAuthFlowsChanges) TotalBreakingChanges() int {
|
||||||
c := o.PropertyChanges.TotalBreakingChanges()
|
c := o.PropertyChanges.TotalBreakingChanges()
|
||||||
if o.ImplicitChanges != nil {
|
if o.ImplicitChanges != nil {
|
||||||
c += o.ImplicitChanges.TotalBreakingChanges()
|
c += o.ImplicitChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
if o.PasswordChanges != nil {
|
if o.PasswordChanges != nil {
|
||||||
c += o.PasswordChanges.TotalBreakingChanges()
|
c += o.PasswordChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
if o.ClientCredentialsChanges != nil {
|
if o.ClientCredentialsChanges != nil {
|
||||||
c += o.ClientCredentialsChanges.TotalBreakingChanges()
|
c += o.ClientCredentialsChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
if o.AuthorizationCodeChanges != nil {
|
if o.AuthorizationCodeChanges != nil {
|
||||||
c += o.AuthorizationCodeChanges.TotalBreakingChanges()
|
c += o.AuthorizationCodeChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareOAuthFlows compares a left and right OAuthFlows object. If changes are found a pointer to *OAuthFlowsChanges
|
// CompareOAuthFlows compares a left and right OAuthFlows object. If changes are found a pointer to *OAuthFlowsChanges
|
||||||
// is returned, otherwise nil is returned.
|
// is returned, otherwise nil is returned.
|
||||||
func CompareOAuthFlows(l, r *v3.OAuthFlows) *OAuthFlowsChanges {
|
func CompareOAuthFlows(l, r *v3.OAuthFlows) *OAuthFlowsChanges {
|
||||||
if low.AreEqual(l, r) {
|
if low.AreEqual(l, r) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
oa := new(OAuthFlowsChanges)
|
oa := new(OAuthFlowsChanges)
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
|
|
||||||
// client credentials
|
// client credentials
|
||||||
if !l.ClientCredentials.IsEmpty() && !r.ClientCredentials.IsEmpty() {
|
if !l.ClientCredentials.IsEmpty() && !r.ClientCredentials.IsEmpty() {
|
||||||
oa.ClientCredentialsChanges = CompareOAuthFlow(l.ClientCredentials.Value, r.ClientCredentials.Value)
|
oa.ClientCredentialsChanges = CompareOAuthFlow(l.ClientCredentials.Value, r.ClientCredentials.Value)
|
||||||
}
|
}
|
||||||
if !l.ClientCredentials.IsEmpty() && r.ClientCredentials.IsEmpty() {
|
if !l.ClientCredentials.IsEmpty() && r.ClientCredentials.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.ClientCredentialsLabel,
|
CreateChange(&changes, ObjectRemoved, v3.ClientCredentialsLabel,
|
||||||
l.ClientCredentials.ValueNode, nil, true,
|
l.ClientCredentials.ValueNode, nil, true,
|
||||||
l.ClientCredentials.Value, nil)
|
l.ClientCredentials.Value, nil)
|
||||||
}
|
}
|
||||||
if l.ClientCredentials.IsEmpty() && !r.ClientCredentials.IsEmpty() {
|
if l.ClientCredentials.IsEmpty() && !r.ClientCredentials.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectAdded, v3.ClientCredentialsLabel,
|
CreateChange(&changes, ObjectAdded, v3.ClientCredentialsLabel,
|
||||||
nil, r.ClientCredentials.ValueNode, false,
|
nil, r.ClientCredentials.ValueNode, false,
|
||||||
nil, r.ClientCredentials.Value)
|
nil, r.ClientCredentials.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// implicit
|
// implicit
|
||||||
if !l.Implicit.IsEmpty() && !r.Implicit.IsEmpty() {
|
if !l.Implicit.IsEmpty() && !r.Implicit.IsEmpty() {
|
||||||
oa.ImplicitChanges = CompareOAuthFlow(l.Implicit.Value, r.Implicit.Value)
|
oa.ImplicitChanges = CompareOAuthFlow(l.Implicit.Value, r.Implicit.Value)
|
||||||
}
|
}
|
||||||
if !l.Implicit.IsEmpty() && r.Implicit.IsEmpty() {
|
if !l.Implicit.IsEmpty() && r.Implicit.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.ImplicitLabel,
|
CreateChange(&changes, ObjectRemoved, v3.ImplicitLabel,
|
||||||
l.Implicit.ValueNode, nil, true,
|
l.Implicit.ValueNode, nil, true,
|
||||||
l.Implicit.Value, nil)
|
l.Implicit.Value, nil)
|
||||||
}
|
}
|
||||||
if l.Implicit.IsEmpty() && !r.Implicit.IsEmpty() {
|
if l.Implicit.IsEmpty() && !r.Implicit.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectAdded, v3.ImplicitLabel,
|
CreateChange(&changes, ObjectAdded, v3.ImplicitLabel,
|
||||||
nil, r.Implicit.ValueNode, false,
|
nil, r.Implicit.ValueNode, false,
|
||||||
nil, r.Implicit.Value)
|
nil, r.Implicit.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// password
|
// password
|
||||||
if !l.Password.IsEmpty() && !r.Password.IsEmpty() {
|
if !l.Password.IsEmpty() && !r.Password.IsEmpty() {
|
||||||
oa.PasswordChanges = CompareOAuthFlow(l.Password.Value, r.Password.Value)
|
oa.PasswordChanges = CompareOAuthFlow(l.Password.Value, r.Password.Value)
|
||||||
}
|
}
|
||||||
if !l.Password.IsEmpty() && r.Password.IsEmpty() {
|
if !l.Password.IsEmpty() && r.Password.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.PasswordLabel,
|
CreateChange(&changes, ObjectRemoved, v3.PasswordLabel,
|
||||||
l.Password.ValueNode, nil, true,
|
l.Password.ValueNode, nil, true,
|
||||||
l.Password.Value, nil)
|
l.Password.Value, nil)
|
||||||
}
|
}
|
||||||
if l.Password.IsEmpty() && !r.Password.IsEmpty() {
|
if l.Password.IsEmpty() && !r.Password.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectAdded, v3.PasswordLabel,
|
CreateChange(&changes, ObjectAdded, v3.PasswordLabel,
|
||||||
nil, r.Password.ValueNode, false,
|
nil, r.Password.ValueNode, false,
|
||||||
nil, r.Password.Value)
|
nil, r.Password.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// auth code
|
// auth code
|
||||||
if !l.AuthorizationCode.IsEmpty() && !r.AuthorizationCode.IsEmpty() {
|
if !l.AuthorizationCode.IsEmpty() && !r.AuthorizationCode.IsEmpty() {
|
||||||
oa.AuthorizationCodeChanges = CompareOAuthFlow(l.AuthorizationCode.Value, r.AuthorizationCode.Value)
|
oa.AuthorizationCodeChanges = CompareOAuthFlow(l.AuthorizationCode.Value, r.AuthorizationCode.Value)
|
||||||
}
|
}
|
||||||
if !l.AuthorizationCode.IsEmpty() && r.AuthorizationCode.IsEmpty() {
|
if !l.AuthorizationCode.IsEmpty() && r.AuthorizationCode.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.AuthorizationCodeLabel,
|
CreateChange(&changes, ObjectRemoved, v3.AuthorizationCodeLabel,
|
||||||
l.AuthorizationCode.ValueNode, nil, true,
|
l.AuthorizationCode.ValueNode, nil, true,
|
||||||
l.AuthorizationCode.Value, nil)
|
l.AuthorizationCode.Value, nil)
|
||||||
}
|
}
|
||||||
if l.AuthorizationCode.IsEmpty() && !r.AuthorizationCode.IsEmpty() {
|
if l.AuthorizationCode.IsEmpty() && !r.AuthorizationCode.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectAdded, v3.AuthorizationCodeLabel,
|
CreateChange(&changes, ObjectAdded, v3.AuthorizationCodeLabel,
|
||||||
nil, r.AuthorizationCode.ValueNode, false,
|
nil, r.AuthorizationCode.ValueNode, false,
|
||||||
nil, r.AuthorizationCode.Value)
|
nil, r.AuthorizationCode.Value)
|
||||||
}
|
}
|
||||||
oa.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
oa.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||||
oa.Changes = changes
|
oa.PropertyChanges = NewPropertyChanges(changes)
|
||||||
return oa
|
return oa
|
||||||
}
|
}
|
||||||
|
|
||||||
// OAuthFlowChanges represents an OpenAPI OAuthFlow object.
|
// OAuthFlowChanges represents an OpenAPI OAuthFlow object.
|
||||||
type OAuthFlowChanges struct {
|
type OAuthFlowChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns the total number of changes made between two OAuthFlow objects
|
// TotalChanges returns the total number of changes made between two OAuthFlow objects
|
||||||
func (o *OAuthFlowChanges) TotalChanges() int {
|
func (o *OAuthFlowChanges) TotalChanges() int {
|
||||||
c := o.PropertyChanges.TotalChanges()
|
c := o.PropertyChanges.TotalChanges()
|
||||||
if o.ExtensionChanges != nil {
|
if o.ExtensionChanges != nil {
|
||||||
c += o.ExtensionChanges.TotalChanges()
|
c += o.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the total number of breaking changes made between two OAuthFlow objects
|
// TotalBreakingChanges returns the total number of breaking changes made between two OAuthFlow objects
|
||||||
func (o *OAuthFlowChanges) TotalBreakingChanges() int {
|
func (o *OAuthFlowChanges) TotalBreakingChanges() int {
|
||||||
return o.PropertyChanges.TotalBreakingChanges()
|
return o.PropertyChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareOAuthFlow checks a left and a right OAuthFlow object for changes. If found, returns a pointer to
|
// CompareOAuthFlow checks a left and a right OAuthFlow object for changes. If found, returns a pointer to
|
||||||
// an OAuthFlowChanges instance, or nil if nothing is found.
|
// an OAuthFlowChanges instance, or nil if nothing is found.
|
||||||
func CompareOAuthFlow(l, r *v3.OAuthFlow) *OAuthFlowChanges {
|
func CompareOAuthFlow(l, r *v3.OAuthFlow) *OAuthFlowChanges {
|
||||||
if low.AreEqual(l, r) {
|
if low.AreEqual(l, r) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
// authorization url
|
// authorization url
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.AuthorizationUrl.ValueNode,
|
LeftNode: l.AuthorizationUrl.ValueNode,
|
||||||
RightNode: r.AuthorizationUrl.ValueNode,
|
RightNode: r.AuthorizationUrl.ValueNode,
|
||||||
Label: v3.AuthorizationUrlLabel,
|
Label: v3.AuthorizationUrlLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// token url
|
// token url
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.TokenUrl.ValueNode,
|
LeftNode: l.TokenUrl.ValueNode,
|
||||||
RightNode: r.TokenUrl.ValueNode,
|
RightNode: r.TokenUrl.ValueNode,
|
||||||
Label: v3.TokenUrlLabel,
|
Label: v3.TokenUrlLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// refresh url
|
// refresh url
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.RefreshUrl.ValueNode,
|
LeftNode: l.RefreshUrl.ValueNode,
|
||||||
RightNode: r.RefreshUrl.ValueNode,
|
RightNode: r.RefreshUrl.ValueNode,
|
||||||
Label: v3.RefreshUrlLabel,
|
Label: v3.RefreshUrlLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
|
|
||||||
for v := range l.Scopes.Value {
|
for v := range l.Scopes.Value {
|
||||||
if r != nil && r.FindScope(v.Value) == nil {
|
if r != nil && r.FindScope(v.Value) == nil {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.Scopes,
|
CreateChange(&changes, ObjectRemoved, v3.Scopes,
|
||||||
l.Scopes.Value[v].ValueNode, nil, true,
|
l.Scopes.Value[v].ValueNode, nil, true,
|
||||||
v.Value, nil)
|
v.Value, nil)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if r != nil && r.FindScope(v.Value) != nil {
|
if r != nil && r.FindScope(v.Value) != nil {
|
||||||
if l.Scopes.Value[v].Value != r.FindScope(v.Value).Value {
|
if l.Scopes.Value[v].Value != r.FindScope(v.Value).Value {
|
||||||
CreateChange(&changes, Modified, v3.Scopes,
|
CreateChange(&changes, Modified, v3.Scopes,
|
||||||
l.Scopes.Value[v].ValueNode, r.FindScope(v.Value).ValueNode, true,
|
l.Scopes.Value[v].ValueNode, r.FindScope(v.Value).ValueNode, true,
|
||||||
l.Scopes.Value[v].Value, r.FindScope(v.Value).Value)
|
l.Scopes.Value[v].Value, r.FindScope(v.Value).Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for v := range r.Scopes.Value {
|
for v := range r.Scopes.Value {
|
||||||
if l != nil && l.FindScope(v.Value) == nil {
|
if l != nil && l.FindScope(v.Value) == nil {
|
||||||
CreateChange(&changes, ObjectAdded, v3.Scopes,
|
CreateChange(&changes, ObjectAdded, v3.Scopes,
|
||||||
nil, r.Scopes.Value[v].ValueNode, false,
|
nil, r.Scopes.Value[v].ValueNode, false,
|
||||||
nil, v.Value)
|
nil, v.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
oa := new(OAuthFlowChanges)
|
oa := new(OAuthFlowChanges)
|
||||||
oa.Changes = changes
|
oa.PropertyChanges = NewPropertyChanges(changes)
|
||||||
oa.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
oa.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||||
return oa
|
return oa
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,155 +4,154 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OperationChanges represent changes made between two Swagger or OpenAPI Operation objects.
|
// OperationChanges represent changes made between two Swagger or OpenAPI Operation objects.
|
||||||
type OperationChanges struct {
|
type OperationChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ExternalDocChanges *ExternalDocChanges `json:"externalDoc,omitempty" yaml:"externalDoc,omitempty"`
|
ExternalDocChanges *ExternalDocChanges `json:"externalDoc,omitempty" yaml:"externalDoc,omitempty"`
|
||||||
ParameterChanges []*ParameterChanges `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
ParameterChanges []*ParameterChanges `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||||
ResponsesChanges *ResponsesChanges `json:"responses,omitempty" yaml:"responses,omitempty"`
|
ResponsesChanges *ResponsesChanges `json:"responses,omitempty" yaml:"responses,omitempty"`
|
||||||
SecurityRequirementChanges []*SecurityRequirementChanges `json:"securityRequirements,omitempty" yaml:"securityRequirements,omitempty"`
|
SecurityRequirementChanges []*SecurityRequirementChanges `json:"securityRequirements,omitempty" yaml:"securityRequirements,omitempty"`
|
||||||
|
|
||||||
// OpenAPI 3+ only changes
|
// OpenAPI 3+ only changes
|
||||||
RequestBodyChanges *RequestBodyChanges `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"`
|
RequestBodyChanges *RequestBodyChanges `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"`
|
||||||
ServerChanges []*ServerChanges `json:"servers,omitempty" yaml:"servers,omitempty"`
|
ServerChanges []*ServerChanges `json:"servers,omitempty" yaml:"servers,omitempty"`
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
CallbackChanges map[string]*CallbackChanges `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
|
CallbackChanges map[string]*CallbackChanges `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns the total number of changes made between two Swagger or OpenAPI Operation objects.
|
// TotalChanges returns the total number of changes made between two Swagger or OpenAPI Operation objects.
|
||||||
func (o *OperationChanges) TotalChanges() int {
|
func (o *OperationChanges) TotalChanges() int {
|
||||||
c := o.PropertyChanges.TotalChanges()
|
c := o.PropertyChanges.TotalChanges()
|
||||||
if o.ExternalDocChanges != nil {
|
if o.ExternalDocChanges != nil {
|
||||||
c += o.ExternalDocChanges.TotalChanges()
|
c += o.ExternalDocChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
for k := range o.ParameterChanges {
|
for k := range o.ParameterChanges {
|
||||||
c += o.ParameterChanges[k].TotalChanges()
|
c += o.ParameterChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
if o.ResponsesChanges != nil {
|
if o.ResponsesChanges != nil {
|
||||||
c += o.ResponsesChanges.TotalChanges()
|
c += o.ResponsesChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
for k := range o.SecurityRequirementChanges {
|
for k := range o.SecurityRequirementChanges {
|
||||||
c += o.SecurityRequirementChanges[k].TotalChanges()
|
c += o.SecurityRequirementChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
if o.RequestBodyChanges != nil {
|
if o.RequestBodyChanges != nil {
|
||||||
c += o.RequestBodyChanges.TotalChanges()
|
c += o.RequestBodyChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
for k := range o.ServerChanges {
|
for k := range o.ServerChanges {
|
||||||
c += o.ServerChanges[k].TotalChanges()
|
c += o.ServerChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
for k := range o.CallbackChanges {
|
for k := range o.CallbackChanges {
|
||||||
c += o.CallbackChanges[k].TotalChanges()
|
c += o.CallbackChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
if o.ExtensionChanges != nil {
|
if o.ExtensionChanges != nil {
|
||||||
c += o.ExtensionChanges.TotalChanges()
|
c += o.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the total number of breaking changes made between two Swagger
|
// TotalBreakingChanges returns the total number of breaking changes made between two Swagger
|
||||||
// or OpenAPI Operation objects.
|
// or OpenAPI Operation objects.
|
||||||
func (o *OperationChanges) TotalBreakingChanges() int {
|
func (o *OperationChanges) TotalBreakingChanges() int {
|
||||||
c := o.PropertyChanges.TotalBreakingChanges()
|
c := o.PropertyChanges.TotalBreakingChanges()
|
||||||
if o.ExternalDocChanges != nil {
|
if o.ExternalDocChanges != nil {
|
||||||
c += o.ExternalDocChanges.TotalBreakingChanges()
|
c += o.ExternalDocChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
for k := range o.ParameterChanges {
|
for k := range o.ParameterChanges {
|
||||||
c += o.ParameterChanges[k].TotalBreakingChanges()
|
c += o.ParameterChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
if o.ResponsesChanges != nil {
|
if o.ResponsesChanges != nil {
|
||||||
c += o.ResponsesChanges.TotalBreakingChanges()
|
c += o.ResponsesChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
for k := range o.SecurityRequirementChanges {
|
for k := range o.SecurityRequirementChanges {
|
||||||
c += o.SecurityRequirementChanges[k].TotalBreakingChanges()
|
c += o.SecurityRequirementChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
for k := range o.CallbackChanges {
|
for k := range o.CallbackChanges {
|
||||||
c += o.CallbackChanges[k].TotalBreakingChanges()
|
c += o.CallbackChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
if o.RequestBodyChanges != nil {
|
if o.RequestBodyChanges != nil {
|
||||||
c += o.RequestBodyChanges.TotalBreakingChanges()
|
c += o.RequestBodyChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
for k := range o.ServerChanges {
|
for k := range o.ServerChanges {
|
||||||
c += o.ServerChanges[k].TotalBreakingChanges()
|
c += o.ServerChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
// todo: add callbacks in here.
|
return c
|
||||||
return c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for properties shared between operations objects.
|
// check for properties shared between operations objects.
|
||||||
func addSharedOperationProperties(left, right low.SharedOperations, changes *[]*Change) []*PropertyCheck {
|
func addSharedOperationProperties(left, right low.SharedOperations, changes *[]*Change) []*PropertyCheck {
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
// tags
|
// tags
|
||||||
if len(left.GetTags().Value) > 0 || len(right.GetTags().Value) > 0 {
|
if len(left.GetTags().Value) > 0 || len(right.GetTags().Value) > 0 {
|
||||||
ExtractStringValueSliceChanges(left.GetTags().Value, right.GetTags().Value,
|
ExtractStringValueSliceChanges(left.GetTags().Value, right.GetTags().Value,
|
||||||
changes, v3.TagsLabel, false)
|
changes, v3.TagsLabel, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// summary
|
// summary
|
||||||
addPropertyCheck(&props, left.GetSummary().ValueNode, right.GetSummary().ValueNode,
|
addPropertyCheck(&props, left.GetSummary().ValueNode, right.GetSummary().ValueNode,
|
||||||
left.GetSummary(), right.GetSummary(), changes, v3.SummaryLabel, false)
|
left.GetSummary(), right.GetSummary(), changes, v3.SummaryLabel, false)
|
||||||
|
|
||||||
// description
|
// description
|
||||||
addPropertyCheck(&props, left.GetDescription().ValueNode, right.GetDescription().ValueNode,
|
addPropertyCheck(&props, left.GetDescription().ValueNode, right.GetDescription().ValueNode,
|
||||||
left.GetDescription(), right.GetDescription(), changes, v3.DescriptionLabel, false)
|
left.GetDescription(), right.GetDescription(), changes, v3.DescriptionLabel, false)
|
||||||
|
|
||||||
// deprecated
|
// deprecated
|
||||||
addPropertyCheck(&props, left.GetDeprecated().ValueNode, right.GetDeprecated().ValueNode,
|
addPropertyCheck(&props, left.GetDeprecated().ValueNode, right.GetDeprecated().ValueNode,
|
||||||
left.GetDeprecated(), right.GetDeprecated(), changes, v3.DeprecatedLabel, false)
|
left.GetDeprecated(), right.GetDeprecated(), changes, v3.DeprecatedLabel, false)
|
||||||
|
|
||||||
// operation id
|
// operation id
|
||||||
addPropertyCheck(&props, left.GetOperationId().ValueNode, right.GetOperationId().ValueNode,
|
addPropertyCheck(&props, left.GetOperationId().ValueNode, right.GetOperationId().ValueNode,
|
||||||
left.GetOperationId(), right.GetOperationId(), changes, v3.OperationIdLabel, true)
|
left.GetOperationId(), right.GetOperationId(), changes, v3.OperationIdLabel, true)
|
||||||
|
|
||||||
return props
|
return props
|
||||||
}
|
}
|
||||||
|
|
||||||
// check shared objects
|
// check shared objects
|
||||||
func compareSharedOperationObjects(l, r low.SharedOperations, changes *[]*Change, opChanges *OperationChanges) {
|
func compareSharedOperationObjects(l, r low.SharedOperations, changes *[]*Change, opChanges *OperationChanges) {
|
||||||
|
|
||||||
// external docs
|
// external docs
|
||||||
if !l.GetExternalDocs().IsEmpty() && !r.GetExternalDocs().IsEmpty() {
|
if !l.GetExternalDocs().IsEmpty() && !r.GetExternalDocs().IsEmpty() {
|
||||||
lExtDoc := l.GetExternalDocs().Value.(*base.ExternalDoc)
|
lExtDoc := l.GetExternalDocs().Value.(*base.ExternalDoc)
|
||||||
rExtDoc := r.GetExternalDocs().Value.(*base.ExternalDoc)
|
rExtDoc := r.GetExternalDocs().Value.(*base.ExternalDoc)
|
||||||
if !low.AreEqual(lExtDoc, rExtDoc) {
|
if !low.AreEqual(lExtDoc, rExtDoc) {
|
||||||
opChanges.ExternalDocChanges = CompareExternalDocs(lExtDoc, rExtDoc)
|
opChanges.ExternalDocChanges = CompareExternalDocs(lExtDoc, rExtDoc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if l.GetExternalDocs().IsEmpty() && !r.GetExternalDocs().IsEmpty() {
|
if l.GetExternalDocs().IsEmpty() && !r.GetExternalDocs().IsEmpty() {
|
||||||
CreateChange(changes, PropertyAdded, v3.ExternalDocsLabel,
|
CreateChange(changes, PropertyAdded, v3.ExternalDocsLabel,
|
||||||
nil, r.GetExternalDocs().ValueNode, false, nil,
|
nil, r.GetExternalDocs().ValueNode, false, nil,
|
||||||
r.GetExternalDocs().Value)
|
r.GetExternalDocs().Value)
|
||||||
}
|
}
|
||||||
if !l.GetExternalDocs().IsEmpty() && r.GetExternalDocs().IsEmpty() {
|
if !l.GetExternalDocs().IsEmpty() && r.GetExternalDocs().IsEmpty() {
|
||||||
CreateChange(changes, PropertyRemoved, v3.ExternalDocsLabel,
|
CreateChange(changes, PropertyRemoved, v3.ExternalDocsLabel,
|
||||||
l.GetExternalDocs().ValueNode, nil, false, l.GetExternalDocs().Value,
|
l.GetExternalDocs().ValueNode, nil, false, l.GetExternalDocs().Value,
|
||||||
nil)
|
nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// responses
|
// responses
|
||||||
if !l.GetResponses().IsEmpty() && !r.GetResponses().IsEmpty() {
|
if !l.GetResponses().IsEmpty() && !r.GetResponses().IsEmpty() {
|
||||||
opChanges.ResponsesChanges = CompareResponses(l.GetResponses().Value, r.GetResponses().Value)
|
opChanges.ResponsesChanges = CompareResponses(l.GetResponses().Value, r.GetResponses().Value)
|
||||||
}
|
}
|
||||||
if l.GetResponses().IsEmpty() && !r.GetResponses().IsEmpty() {
|
if l.GetResponses().IsEmpty() && !r.GetResponses().IsEmpty() {
|
||||||
CreateChange(changes, PropertyAdded, v3.ResponsesLabel,
|
CreateChange(changes, PropertyAdded, v3.ResponsesLabel,
|
||||||
nil, r.GetResponses().ValueNode, false, nil,
|
nil, r.GetResponses().ValueNode, false, nil,
|
||||||
r.GetResponses().Value)
|
r.GetResponses().Value)
|
||||||
}
|
}
|
||||||
if !l.GetResponses().IsEmpty() && r.GetResponses().IsEmpty() {
|
if !l.GetResponses().IsEmpty() && r.GetResponses().IsEmpty() {
|
||||||
CreateChange(changes, PropertyRemoved, v3.ResponsesLabel,
|
CreateChange(changes, PropertyRemoved, v3.ResponsesLabel,
|
||||||
l.GetResponses().ValueNode, nil, true, l.GetResponses().Value,
|
l.GetResponses().ValueNode, nil, true, l.GetResponses().Value,
|
||||||
nil)
|
nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,371 +159,371 @@ func compareSharedOperationObjects(l, r low.SharedOperations, changes *[]*Change
|
|||||||
// a pointer to an OperationChanges instance, or nil if nothing is found.
|
// a pointer to an OperationChanges instance, or nil if nothing is found.
|
||||||
func CompareOperations(l, r any) *OperationChanges {
|
func CompareOperations(l, r any) *OperationChanges {
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
oc := new(OperationChanges)
|
oc := new(OperationChanges)
|
||||||
|
|
||||||
// Swagger
|
// Swagger
|
||||||
if reflect.TypeOf(&v2.Operation{}) == reflect.TypeOf(l) &&
|
if reflect.TypeOf(&v2.Operation{}) == reflect.TypeOf(l) &&
|
||||||
reflect.TypeOf(&v2.Operation{}) == reflect.TypeOf(r) {
|
reflect.TypeOf(&v2.Operation{}) == reflect.TypeOf(r) {
|
||||||
|
|
||||||
lOperation := l.(*v2.Operation)
|
lOperation := l.(*v2.Operation)
|
||||||
rOperation := r.(*v2.Operation)
|
rOperation := r.(*v2.Operation)
|
||||||
|
|
||||||
// perform hash check to avoid further processing
|
// perform hash check to avoid further processing
|
||||||
if low.AreEqual(lOperation, rOperation) {
|
if low.AreEqual(lOperation, rOperation) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
props = append(props, addSharedOperationProperties(lOperation, rOperation, &changes)...)
|
props = append(props, addSharedOperationProperties(lOperation, rOperation, &changes)...)
|
||||||
|
|
||||||
compareSharedOperationObjects(lOperation, rOperation, &changes, oc)
|
compareSharedOperationObjects(lOperation, rOperation, &changes, oc)
|
||||||
|
|
||||||
// parameters
|
// parameters
|
||||||
lParamsUntyped := lOperation.GetParameters()
|
lParamsUntyped := lOperation.GetParameters()
|
||||||
rParamsUntyped := rOperation.GetParameters()
|
rParamsUntyped := rOperation.GetParameters()
|
||||||
if !lParamsUntyped.IsEmpty() && !rParamsUntyped.IsEmpty() {
|
if !lParamsUntyped.IsEmpty() && !rParamsUntyped.IsEmpty() {
|
||||||
lParams := lParamsUntyped.Value.([]low.ValueReference[*v2.Parameter])
|
lParams := lParamsUntyped.Value.([]low.ValueReference[*v2.Parameter])
|
||||||
rParams := rParamsUntyped.Value.([]low.ValueReference[*v2.Parameter])
|
rParams := rParamsUntyped.Value.([]low.ValueReference[*v2.Parameter])
|
||||||
|
|
||||||
lv := make(map[string]*v2.Parameter, len(lParams))
|
lv := make(map[string]*v2.Parameter, len(lParams))
|
||||||
rv := make(map[string]*v2.Parameter, len(rParams))
|
rv := make(map[string]*v2.Parameter, len(rParams))
|
||||||
|
|
||||||
for i := range lParams {
|
for i := range lParams {
|
||||||
s := lParams[i].Value.Name.Value
|
s := lParams[i].Value.Name.Value
|
||||||
lv[s] = lParams[i].Value
|
lv[s] = lParams[i].Value
|
||||||
}
|
}
|
||||||
for i := range rParams {
|
for i := range rParams {
|
||||||
s := rParams[i].Value.Name.Value
|
s := rParams[i].Value.Name.Value
|
||||||
rv[s] = rParams[i].Value
|
rv[s] = rParams[i].Value
|
||||||
}
|
}
|
||||||
|
|
||||||
var paramChanges []*ParameterChanges
|
var paramChanges []*ParameterChanges
|
||||||
for n := range lv {
|
for n := range lv {
|
||||||
if _, ok := rv[n]; ok {
|
if _, ok := rv[n]; ok {
|
||||||
if !low.AreEqual(lv[n], rv[n]) {
|
if !low.AreEqual(lv[n], rv[n]) {
|
||||||
ch := CompareParameters(lv[n], rv[n])
|
ch := CompareParameters(lv[n], rv[n])
|
||||||
if ch != nil {
|
if ch != nil {
|
||||||
paramChanges = append(paramChanges, ch)
|
paramChanges = append(paramChanges, ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
CreateChange(&changes, ObjectRemoved, v3.ParametersLabel,
|
CreateChange(&changes, ObjectRemoved, v3.ParametersLabel,
|
||||||
lv[n].Name.ValueNode, nil, true, lv[n].Name.Value,
|
lv[n].Name.ValueNode, nil, true, lv[n].Name.Value,
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
}
|
}
|
||||||
for n := range rv {
|
for n := range rv {
|
||||||
if _, ok := lv[n]; !ok {
|
if _, ok := lv[n]; !ok {
|
||||||
CreateChange(&changes, ObjectAdded, v3.ParametersLabel,
|
CreateChange(&changes, ObjectAdded, v3.ParametersLabel,
|
||||||
nil, rv[n].Name.ValueNode, true, nil,
|
nil, rv[n].Name.ValueNode, true, nil,
|
||||||
rv[n].Name.Value)
|
rv[n].Name.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
oc.ParameterChanges = paramChanges
|
oc.ParameterChanges = paramChanges
|
||||||
}
|
}
|
||||||
if !lParamsUntyped.IsEmpty() && rParamsUntyped.IsEmpty() {
|
if !lParamsUntyped.IsEmpty() && rParamsUntyped.IsEmpty() {
|
||||||
CreateChange(&changes, PropertyRemoved, v3.ParametersLabel,
|
CreateChange(&changes, PropertyRemoved, v3.ParametersLabel,
|
||||||
lParamsUntyped.ValueNode, nil, true, lParamsUntyped.Value,
|
lParamsUntyped.ValueNode, nil, true, lParamsUntyped.Value,
|
||||||
nil)
|
nil)
|
||||||
}
|
}
|
||||||
if lParamsUntyped.IsEmpty() && !rParamsUntyped.IsEmpty() {
|
if lParamsUntyped.IsEmpty() && !rParamsUntyped.IsEmpty() {
|
||||||
CreateChange(&changes, PropertyAdded, v3.ParametersLabel,
|
CreateChange(&changes, PropertyAdded, v3.ParametersLabel,
|
||||||
nil, rParamsUntyped.ValueNode, true, nil,
|
nil, rParamsUntyped.ValueNode, true, nil,
|
||||||
rParamsUntyped.Value)
|
rParamsUntyped.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// security
|
// security
|
||||||
if !lOperation.Security.IsEmpty() || !rOperation.Security.IsEmpty() {
|
if !lOperation.Security.IsEmpty() || !rOperation.Security.IsEmpty() {
|
||||||
checkSecurity(lOperation.Security, rOperation.Security, &changes, oc)
|
checkSecurity(lOperation.Security, rOperation.Security, &changes, oc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// produces
|
// produces
|
||||||
if len(lOperation.Produces.Value) > 0 || len(rOperation.Produces.Value) > 0 {
|
if len(lOperation.Produces.Value) > 0 || len(rOperation.Produces.Value) > 0 {
|
||||||
ExtractStringValueSliceChanges(lOperation.Produces.Value, rOperation.Produces.Value,
|
ExtractStringValueSliceChanges(lOperation.Produces.Value, rOperation.Produces.Value,
|
||||||
&changes, v3.ProducesLabel, true)
|
&changes, v3.ProducesLabel, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// consumes
|
// consumes
|
||||||
if len(lOperation.Consumes.Value) > 0 || len(rOperation.Consumes.Value) > 0 {
|
if len(lOperation.Consumes.Value) > 0 || len(rOperation.Consumes.Value) > 0 {
|
||||||
ExtractStringValueSliceChanges(lOperation.Consumes.Value, rOperation.Consumes.Value,
|
ExtractStringValueSliceChanges(lOperation.Consumes.Value, rOperation.Consumes.Value,
|
||||||
&changes, v3.ConsumesLabel, true)
|
&changes, v3.ConsumesLabel, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// schemes
|
// schemes
|
||||||
if len(lOperation.Schemes.Value) > 0 || len(rOperation.Schemes.Value) > 0 {
|
if len(lOperation.Schemes.Value) > 0 || len(rOperation.Schemes.Value) > 0 {
|
||||||
ExtractStringValueSliceChanges(lOperation.Schemes.Value, rOperation.Schemes.Value,
|
ExtractStringValueSliceChanges(lOperation.Schemes.Value, rOperation.Schemes.Value,
|
||||||
&changes, v3.SchemesLabel, true)
|
&changes, v3.SchemesLabel, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
oc.ExtensionChanges = CompareExtensions(lOperation.Extensions, rOperation.Extensions)
|
oc.ExtensionChanges = CompareExtensions(lOperation.Extensions, rOperation.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenAPI
|
// OpenAPI
|
||||||
if reflect.TypeOf(&v3.Operation{}) == reflect.TypeOf(l) &&
|
if reflect.TypeOf(&v3.Operation{}) == reflect.TypeOf(l) &&
|
||||||
reflect.TypeOf(&v3.Operation{}) == reflect.TypeOf(r) {
|
reflect.TypeOf(&v3.Operation{}) == reflect.TypeOf(r) {
|
||||||
|
|
||||||
lOperation := l.(*v3.Operation)
|
lOperation := l.(*v3.Operation)
|
||||||
rOperation := r.(*v3.Operation)
|
rOperation := r.(*v3.Operation)
|
||||||
|
|
||||||
// perform hash check to avoid further processing
|
// perform hash check to avoid further processing
|
||||||
if low.AreEqual(lOperation, rOperation) {
|
if low.AreEqual(lOperation, rOperation) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
props = append(props, addSharedOperationProperties(lOperation, rOperation, &changes)...)
|
props = append(props, addSharedOperationProperties(lOperation, rOperation, &changes)...)
|
||||||
compareSharedOperationObjects(lOperation, rOperation, &changes, oc)
|
compareSharedOperationObjects(lOperation, rOperation, &changes, oc)
|
||||||
|
|
||||||
// parameters
|
// parameters
|
||||||
lParamsUntyped := lOperation.GetParameters()
|
lParamsUntyped := lOperation.GetParameters()
|
||||||
rParamsUntyped := rOperation.GetParameters()
|
rParamsUntyped := rOperation.GetParameters()
|
||||||
if !lParamsUntyped.IsEmpty() && !rParamsUntyped.IsEmpty() {
|
if !lParamsUntyped.IsEmpty() && !rParamsUntyped.IsEmpty() {
|
||||||
lParams := lParamsUntyped.Value.([]low.ValueReference[*v3.Parameter])
|
lParams := lParamsUntyped.Value.([]low.ValueReference[*v3.Parameter])
|
||||||
rParams := rParamsUntyped.Value.([]low.ValueReference[*v3.Parameter])
|
rParams := rParamsUntyped.Value.([]low.ValueReference[*v3.Parameter])
|
||||||
|
|
||||||
lv := make(map[string]*v3.Parameter, len(lParams))
|
lv := make(map[string]*v3.Parameter, len(lParams))
|
||||||
rv := make(map[string]*v3.Parameter, len(rParams))
|
rv := make(map[string]*v3.Parameter, len(rParams))
|
||||||
|
|
||||||
for i := range lParams {
|
for i := range lParams {
|
||||||
s := lParams[i].Value.Name.Value
|
s := lParams[i].Value.Name.Value
|
||||||
lv[s] = lParams[i].Value
|
lv[s] = lParams[i].Value
|
||||||
}
|
}
|
||||||
for i := range rParams {
|
for i := range rParams {
|
||||||
s := rParams[i].Value.Name.Value
|
s := rParams[i].Value.Name.Value
|
||||||
rv[s] = rParams[i].Value
|
rv[s] = rParams[i].Value
|
||||||
}
|
}
|
||||||
|
|
||||||
var paramChanges []*ParameterChanges
|
var paramChanges []*ParameterChanges
|
||||||
for n := range lv {
|
for n := range lv {
|
||||||
if _, ok := rv[n]; ok {
|
if _, ok := rv[n]; ok {
|
||||||
if !low.AreEqual(lv[n], rv[n]) {
|
if !low.AreEqual(lv[n], rv[n]) {
|
||||||
ch := CompareParameters(lv[n], rv[n])
|
ch := CompareParameters(lv[n], rv[n])
|
||||||
if ch != nil {
|
if ch != nil {
|
||||||
paramChanges = append(paramChanges, ch)
|
paramChanges = append(paramChanges, ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
CreateChange(&changes, ObjectRemoved, v3.ParametersLabel,
|
CreateChange(&changes, ObjectRemoved, v3.ParametersLabel,
|
||||||
lv[n].Name.ValueNode, nil, true, lv[n].Name.Value,
|
lv[n].Name.ValueNode, nil, true, lv[n].Name.Value,
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
}
|
}
|
||||||
for n := range rv {
|
for n := range rv {
|
||||||
if _, ok := lv[n]; !ok {
|
if _, ok := lv[n]; !ok {
|
||||||
CreateChange(&changes, ObjectAdded, v3.ParametersLabel,
|
CreateChange(&changes, ObjectAdded, v3.ParametersLabel,
|
||||||
nil, rv[n].Name.ValueNode, true, nil,
|
nil, rv[n].Name.ValueNode, true, nil,
|
||||||
rv[n].Name.Value)
|
rv[n].Name.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
oc.ParameterChanges = paramChanges
|
oc.ParameterChanges = paramChanges
|
||||||
}
|
}
|
||||||
if !lParamsUntyped.IsEmpty() && rParamsUntyped.IsEmpty() {
|
if !lParamsUntyped.IsEmpty() && rParamsUntyped.IsEmpty() {
|
||||||
CreateChange(&changes, PropertyRemoved, v3.ParametersLabel,
|
CreateChange(&changes, PropertyRemoved, v3.ParametersLabel,
|
||||||
lParamsUntyped.ValueNode, nil, true, lParamsUntyped.Value,
|
lParamsUntyped.ValueNode, nil, true, lParamsUntyped.Value,
|
||||||
nil)
|
nil)
|
||||||
}
|
}
|
||||||
if lParamsUntyped.IsEmpty() && !rParamsUntyped.IsEmpty() {
|
if lParamsUntyped.IsEmpty() && !rParamsUntyped.IsEmpty() {
|
||||||
CreateChange(&changes, PropertyAdded, v3.ParametersLabel,
|
CreateChange(&changes, PropertyAdded, v3.ParametersLabel,
|
||||||
nil, rParamsUntyped.ValueNode, true, nil,
|
nil, rParamsUntyped.ValueNode, true, nil,
|
||||||
rParamsUntyped.Value)
|
rParamsUntyped.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// security
|
// security
|
||||||
if !lOperation.Security.IsEmpty() && !lOperation.Security.IsEmpty() {
|
if !lOperation.Security.IsEmpty() && !lOperation.Security.IsEmpty() {
|
||||||
checkSecurity(lOperation.Security, rOperation.Security, &changes, oc)
|
checkSecurity(lOperation.Security, rOperation.Security, &changes, oc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// request body
|
// request body
|
||||||
if !lOperation.RequestBody.IsEmpty() && !rOperation.RequestBody.IsEmpty() {
|
if !lOperation.RequestBody.IsEmpty() && !rOperation.RequestBody.IsEmpty() {
|
||||||
if !low.AreEqual(lOperation.RequestBody.Value, rOperation.RequestBody.Value) {
|
if !low.AreEqual(lOperation.RequestBody.Value, rOperation.RequestBody.Value) {
|
||||||
oc.RequestBodyChanges = CompareRequestBodies(lOperation.RequestBody.Value, rOperation.RequestBody.Value)
|
oc.RequestBodyChanges = CompareRequestBodies(lOperation.RequestBody.Value, rOperation.RequestBody.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !lOperation.RequestBody.IsEmpty() && rOperation.RequestBody.IsEmpty() {
|
if !lOperation.RequestBody.IsEmpty() && rOperation.RequestBody.IsEmpty() {
|
||||||
CreateChange(&changes, PropertyRemoved, v3.RequestBodyLabel,
|
CreateChange(&changes, PropertyRemoved, v3.RequestBodyLabel,
|
||||||
lOperation.RequestBody.ValueNode, nil, true, lOperation.RequestBody.Value,
|
lOperation.RequestBody.ValueNode, nil, true, lOperation.RequestBody.Value,
|
||||||
nil)
|
nil)
|
||||||
}
|
}
|
||||||
if lOperation.RequestBody.IsEmpty() && !rOperation.RequestBody.IsEmpty() {
|
if lOperation.RequestBody.IsEmpty() && !rOperation.RequestBody.IsEmpty() {
|
||||||
CreateChange(&changes, PropertyAdded, v3.RequestBodyLabel,
|
CreateChange(&changes, PropertyAdded, v3.RequestBodyLabel,
|
||||||
nil, rOperation.RequestBody.ValueNode, true, nil,
|
nil, rOperation.RequestBody.ValueNode, true, nil,
|
||||||
rOperation.RequestBody.Value)
|
rOperation.RequestBody.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// callbacks
|
// callbacks
|
||||||
if !lOperation.GetCallbacks().IsEmpty() && !rOperation.GetCallbacks().IsEmpty() {
|
if !lOperation.GetCallbacks().IsEmpty() && !rOperation.GetCallbacks().IsEmpty() {
|
||||||
oc.CallbackChanges = CheckMapForChanges(lOperation.Callbacks.Value, rOperation.Callbacks.Value, &changes,
|
oc.CallbackChanges = CheckMapForChanges(lOperation.Callbacks.Value, rOperation.Callbacks.Value, &changes,
|
||||||
v3.CallbacksLabel, CompareCallback)
|
v3.CallbacksLabel, CompareCallback)
|
||||||
}
|
}
|
||||||
if !lOperation.GetCallbacks().IsEmpty() && rOperation.GetCallbacks().IsEmpty() {
|
if !lOperation.GetCallbacks().IsEmpty() && rOperation.GetCallbacks().IsEmpty() {
|
||||||
CreateChange(&changes, PropertyRemoved, v3.CallbacksLabel,
|
CreateChange(&changes, PropertyRemoved, v3.CallbacksLabel,
|
||||||
lOperation.Callbacks.ValueNode, nil, true, lOperation.Callbacks.Value,
|
lOperation.Callbacks.ValueNode, nil, true, lOperation.Callbacks.Value,
|
||||||
nil)
|
nil)
|
||||||
}
|
}
|
||||||
if lOperation.Callbacks.IsEmpty() && !rOperation.Callbacks.IsEmpty() {
|
if lOperation.Callbacks.IsEmpty() && !rOperation.Callbacks.IsEmpty() {
|
||||||
CreateChange(&changes, PropertyAdded, v3.CallbacksLabel,
|
CreateChange(&changes, PropertyAdded, v3.CallbacksLabel,
|
||||||
nil, rOperation.Callbacks.ValueNode, true, nil,
|
nil, rOperation.Callbacks.ValueNode, true, nil,
|
||||||
rOperation.Callbacks.Value)
|
rOperation.Callbacks.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// servers
|
// servers
|
||||||
oc.ServerChanges = checkServers(lOperation.Servers, rOperation.Servers)
|
oc.ServerChanges = checkServers(lOperation.Servers, rOperation.Servers)
|
||||||
oc.ExtensionChanges = CompareExtensions(lOperation.Extensions, rOperation.Extensions)
|
oc.ExtensionChanges = CompareExtensions(lOperation.Extensions, rOperation.Extensions)
|
||||||
|
|
||||||
// todo: callbacks
|
// todo: callbacks
|
||||||
}
|
}
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
oc.Changes = changes
|
oc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
return oc
|
return oc
|
||||||
}
|
}
|
||||||
|
|
||||||
// check servers property
|
// check servers property
|
||||||
func checkServers(lServers, rServers low.NodeReference[[]low.ValueReference[*v3.Server]]) []*ServerChanges {
|
func checkServers(lServers, rServers low.NodeReference[[]low.ValueReference[*v3.Server]]) []*ServerChanges {
|
||||||
|
|
||||||
var serverChanges []*ServerChanges
|
var serverChanges []*ServerChanges
|
||||||
|
|
||||||
if !lServers.IsEmpty() && !rServers.IsEmpty() {
|
if !lServers.IsEmpty() && !rServers.IsEmpty() {
|
||||||
|
|
||||||
lv := make(map[string]low.ValueReference[*v3.Server], len(lServers.Value))
|
lv := make(map[string]low.ValueReference[*v3.Server], len(lServers.Value))
|
||||||
rv := make(map[string]low.ValueReference[*v3.Server], len(rServers.Value))
|
rv := make(map[string]low.ValueReference[*v3.Server], len(rServers.Value))
|
||||||
|
|
||||||
for i := range lServers.Value {
|
for i := range lServers.Value {
|
||||||
var s string
|
var s string
|
||||||
if !lServers.Value[i].Value.URL.IsEmpty() {
|
if !lServers.Value[i].Value.URL.IsEmpty() {
|
||||||
s = lServers.Value[i].Value.URL.Value
|
s = lServers.Value[i].Value.URL.Value
|
||||||
} else {
|
} else {
|
||||||
s = low.GenerateHashString(lServers.Value[i].Value)
|
s = low.GenerateHashString(lServers.Value[i].Value)
|
||||||
}
|
}
|
||||||
lv[s] = lServers.Value[i]
|
lv[s] = lServers.Value[i]
|
||||||
}
|
}
|
||||||
for i := range rServers.Value {
|
for i := range rServers.Value {
|
||||||
var s string
|
var s string
|
||||||
if !rServers.Value[i].Value.URL.IsEmpty() {
|
if !rServers.Value[i].Value.URL.IsEmpty() {
|
||||||
s = rServers.Value[i].Value.URL.Value
|
s = rServers.Value[i].Value.URL.Value
|
||||||
} else {
|
} else {
|
||||||
s = low.GenerateHashString(rServers.Value[i].Value)
|
s = low.GenerateHashString(rServers.Value[i].Value)
|
||||||
}
|
}
|
||||||
rv[s] = rServers.Value[i]
|
rv[s] = rServers.Value[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
for k := range lv {
|
for k := range lv {
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
|
|
||||||
if _, ok := rv[k]; ok {
|
if _, ok := rv[k]; ok {
|
||||||
if !low.AreEqual(lv[k].Value, rv[k].Value) {
|
if !low.AreEqual(lv[k].Value, rv[k].Value) {
|
||||||
serverChanges = append(serverChanges, CompareServers(lv[k].Value, rv[k].Value))
|
serverChanges = append(serverChanges, CompareServers(lv[k].Value, rv[k].Value))
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
lv[k].ValueNode.Value = lv[k].Value.URL.Value
|
lv[k].ValueNode.Value = lv[k].Value.URL.Value
|
||||||
CreateChange(&changes, ObjectRemoved, v3.ServersLabel,
|
CreateChange(&changes, ObjectRemoved, v3.ServersLabel,
|
||||||
lv[k].ValueNode, nil, true, lv[k].Value.URL.Value,
|
lv[k].ValueNode, nil, true, lv[k].Value.URL.Value,
|
||||||
nil)
|
nil)
|
||||||
sc := new(ServerChanges)
|
sc := new(ServerChanges)
|
||||||
sc.Changes = changes
|
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
serverChanges = append(serverChanges, sc)
|
serverChanges = append(serverChanges, sc)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for k := range rv {
|
for k := range rv {
|
||||||
|
|
||||||
if _, ok := lv[k]; !ok {
|
if _, ok := lv[k]; !ok {
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
rv[k].ValueNode.Value = rv[k].Value.URL.Value
|
rv[k].ValueNode.Value = rv[k].Value.URL.Value
|
||||||
CreateChange(&changes, ObjectAdded, v3.ServersLabel,
|
CreateChange(&changes, ObjectAdded, v3.ServersLabel,
|
||||||
nil, rv[k].ValueNode, false, nil,
|
nil, rv[k].ValueNode, false, nil,
|
||||||
rv[k].Value.URL.Value)
|
rv[k].Value.URL.Value)
|
||||||
|
|
||||||
sc := new(ServerChanges)
|
sc := new(ServerChanges)
|
||||||
sc.Changes = changes
|
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
serverChanges = append(serverChanges, sc)
|
serverChanges = append(serverChanges, sc)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
sc := new(ServerChanges)
|
sc := new(ServerChanges)
|
||||||
if !lServers.IsEmpty() && rServers.IsEmpty() {
|
if !lServers.IsEmpty() && rServers.IsEmpty() {
|
||||||
CreateChange(&changes, PropertyRemoved, v3.ServersLabel,
|
CreateChange(&changes, PropertyRemoved, v3.ServersLabel,
|
||||||
lServers.ValueNode, nil, true, lServers.Value,
|
lServers.ValueNode, nil, true, lServers.Value,
|
||||||
nil)
|
nil)
|
||||||
}
|
}
|
||||||
if lServers.IsEmpty() && !rServers.IsEmpty() {
|
if lServers.IsEmpty() && !rServers.IsEmpty() {
|
||||||
CreateChange(&changes, PropertyAdded, v3.ServersLabel,
|
CreateChange(&changes, PropertyAdded, v3.ServersLabel,
|
||||||
nil, rServers.ValueNode, false, nil,
|
nil, rServers.ValueNode, false, nil,
|
||||||
rServers.Value)
|
rServers.Value)
|
||||||
}
|
}
|
||||||
sc.Changes = changes
|
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
if len(changes) > 0 {
|
if len(changes) > 0 {
|
||||||
serverChanges = append(serverChanges, sc)
|
serverChanges = append(serverChanges, sc)
|
||||||
}
|
}
|
||||||
if len(serverChanges) <= 0 {
|
if len(serverChanges) <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return serverChanges
|
return serverChanges
|
||||||
}
|
}
|
||||||
|
|
||||||
// check security property.
|
// check security property.
|
||||||
func checkSecurity(lSecurity, rSecurity low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]],
|
func checkSecurity(lSecurity, rSecurity low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]],
|
||||||
changes *[]*Change, oc any) {
|
changes *[]*Change, oc any) {
|
||||||
|
|
||||||
lv := make(map[string]*base.SecurityRequirement, len(lSecurity.Value))
|
lv := make(map[string]*base.SecurityRequirement, len(lSecurity.Value))
|
||||||
rv := make(map[string]*base.SecurityRequirement, len(rSecurity.Value))
|
rv := make(map[string]*base.SecurityRequirement, len(rSecurity.Value))
|
||||||
lvn := make(map[string]*yaml.Node, len(lSecurity.Value))
|
lvn := make(map[string]*yaml.Node, len(lSecurity.Value))
|
||||||
rvn := make(map[string]*yaml.Node, len(rSecurity.Value))
|
rvn := make(map[string]*yaml.Node, len(rSecurity.Value))
|
||||||
|
|
||||||
for i := range lSecurity.Value {
|
for i := range lSecurity.Value {
|
||||||
keys := lSecurity.Value[i].Value.GetKeys()
|
keys := lSecurity.Value[i].Value.GetKeys()
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
s := strings.Join(keys, "|")
|
s := strings.Join(keys, "|")
|
||||||
lv[s] = lSecurity.Value[i].Value
|
lv[s] = lSecurity.Value[i].Value
|
||||||
lvn[s] = lSecurity.Value[i].ValueNode
|
lvn[s] = lSecurity.Value[i].ValueNode
|
||||||
|
|
||||||
}
|
}
|
||||||
for i := range rSecurity.Value {
|
for i := range rSecurity.Value {
|
||||||
keys := rSecurity.Value[i].Value.GetKeys()
|
keys := rSecurity.Value[i].Value.GetKeys()
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
s := strings.Join(keys, "|")
|
s := strings.Join(keys, "|")
|
||||||
rv[s] = rSecurity.Value[i].Value
|
rv[s] = rSecurity.Value[i].Value
|
||||||
rvn[s] = rSecurity.Value[i].ValueNode
|
rvn[s] = rSecurity.Value[i].ValueNode
|
||||||
}
|
}
|
||||||
|
|
||||||
var secChanges []*SecurityRequirementChanges
|
var secChanges []*SecurityRequirementChanges
|
||||||
for n := range lv {
|
for n := range lv {
|
||||||
if _, ok := rv[n]; ok {
|
if _, ok := rv[n]; ok {
|
||||||
if !low.AreEqual(lv[n], rv[n]) {
|
if !low.AreEqual(lv[n], rv[n]) {
|
||||||
ch := CompareSecurityRequirement(lv[n], rv[n])
|
ch := CompareSecurityRequirement(lv[n], rv[n])
|
||||||
if ch != nil {
|
if ch != nil {
|
||||||
secChanges = append(secChanges, ch)
|
secChanges = append(secChanges, ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
lvn[n].Value = strings.Join(lv[n].GetKeys(), ", ")
|
lvn[n].Value = strings.Join(lv[n].GetKeys(), ", ")
|
||||||
CreateChange(changes, ObjectRemoved, v3.SecurityLabel,
|
CreateChange(changes, ObjectRemoved, v3.SecurityLabel,
|
||||||
lvn[n], nil, true, lv[n],
|
lvn[n], nil, true, lv[n],
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
}
|
}
|
||||||
for n := range rv {
|
for n := range rv {
|
||||||
if _, ok := lv[n]; !ok {
|
if _, ok := lv[n]; !ok {
|
||||||
rvn[n].Value = strings.Join(rv[n].GetKeys(), ", ")
|
rvn[n].Value = strings.Join(rv[n].GetKeys(), ", ")
|
||||||
CreateChange(changes, ObjectAdded, v3.SecurityLabel,
|
CreateChange(changes, ObjectAdded, v3.SecurityLabel,
|
||||||
nil, rvn[n], false, nil,
|
nil, rvn[n], false, nil,
|
||||||
rv[n])
|
rv[n])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle different change types.
|
// handle different change types.
|
||||||
if reflect.TypeOf(&OperationChanges{}) == reflect.TypeOf(oc) {
|
if reflect.TypeOf(&OperationChanges{}) == reflect.TypeOf(oc) {
|
||||||
oc.(*OperationChanges).SecurityRequirementChanges = secChanges
|
oc.(*OperationChanges).SecurityRequirementChanges = secChanges
|
||||||
}
|
}
|
||||||
if reflect.TypeOf(&DocumentChanges{}) == reflect.TypeOf(oc) {
|
if reflect.TypeOf(&DocumentChanges{}) == reflect.TypeOf(oc) {
|
||||||
oc.(*DocumentChanges).SecurityRequirementChanges = secChanges
|
oc.(*DocumentChanges).SecurityRequirementChanges = secChanges
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,332 +4,332 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
v2 "github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ParameterChanges represents changes found between Swagger or OpenAPI Parameter objects.
|
// ParameterChanges represents changes found between Swagger or OpenAPI Parameter objects.
|
||||||
type ParameterChanges struct {
|
type ParameterChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
|
|
||||||
// Swagger supports Items.
|
// Swagger supports Items.
|
||||||
ItemsChanges *ItemsChanges `json:"items,omitempty" yaml:"items,omitempty"`
|
ItemsChanges *ItemsChanges `json:"items,omitempty" yaml:"items,omitempty"`
|
||||||
|
|
||||||
// OpenAPI supports examples and content types.
|
// OpenAPI supports examples and content types.
|
||||||
ExamplesChanges map[string]*ExampleChanges `json:"examples,omitempty" yaml:"examples,omitempty"`
|
ExamplesChanges map[string]*ExampleChanges `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||||
ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"`
|
ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns a count of everything that changed
|
// TotalChanges returns a count of everything that changed
|
||||||
func (p *ParameterChanges) TotalChanges() int {
|
func (p *ParameterChanges) TotalChanges() int {
|
||||||
c := p.PropertyChanges.TotalChanges()
|
c := p.PropertyChanges.TotalChanges()
|
||||||
if p.SchemaChanges != nil {
|
if p.SchemaChanges != nil {
|
||||||
c += p.SchemaChanges.TotalChanges()
|
c += p.SchemaChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
for i := range p.ExamplesChanges {
|
for i := range p.ExamplesChanges {
|
||||||
c += p.ExamplesChanges[i].TotalChanges()
|
c += p.ExamplesChanges[i].TotalChanges()
|
||||||
}
|
}
|
||||||
if p.ItemsChanges != nil {
|
if p.ItemsChanges != nil {
|
||||||
c += p.ItemsChanges.TotalChanges()
|
c += p.ItemsChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
if p.ExtensionChanges != nil {
|
if p.ExtensionChanges != nil {
|
||||||
c += p.ExtensionChanges.TotalChanges()
|
c += p.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
for i := range p.ContentChanges {
|
for i := range p.ContentChanges {
|
||||||
c += p.ContentChanges[i].TotalChanges()
|
c += p.ContentChanges[i].TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges always returns 0 for ExternalDoc objects, they are non-binding.
|
// TotalBreakingChanges always returns 0 for ExternalDoc objects, they are non-binding.
|
||||||
func (p *ParameterChanges) TotalBreakingChanges() int {
|
func (p *ParameterChanges) TotalBreakingChanges() int {
|
||||||
c := p.PropertyChanges.TotalBreakingChanges()
|
c := p.PropertyChanges.TotalBreakingChanges()
|
||||||
if p.SchemaChanges != nil {
|
if p.SchemaChanges != nil {
|
||||||
c += p.SchemaChanges.TotalBreakingChanges()
|
c += p.SchemaChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
if p.ItemsChanges != nil {
|
if p.ItemsChanges != nil {
|
||||||
c += p.ItemsChanges.TotalBreakingChanges()
|
c += p.ItemsChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
for i := range p.ContentChanges {
|
for i := range p.ContentChanges {
|
||||||
c += p.ContentChanges[i].TotalBreakingChanges()
|
c += p.ContentChanges[i].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func addPropertyCheck(props *[]*PropertyCheck,
|
func addPropertyCheck(props *[]*PropertyCheck,
|
||||||
lvn, rvn *yaml.Node, lv, rv any, changes *[]*Change, label string, breaking bool) {
|
lvn, rvn *yaml.Node, lv, rv any, changes *[]*Change, label string, breaking bool) {
|
||||||
*props = append(*props, &PropertyCheck{
|
*props = append(*props, &PropertyCheck{
|
||||||
LeftNode: lvn,
|
LeftNode: lvn,
|
||||||
RightNode: rvn,
|
RightNode: rvn,
|
||||||
Label: label,
|
Label: label,
|
||||||
Changes: changes,
|
Changes: changes,
|
||||||
Breaking: breaking,
|
Breaking: breaking,
|
||||||
Original: lv,
|
Original: lv,
|
||||||
New: rv,
|
New: rv,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func addOpenAPIParameterProperties(left, right low.OpenAPIParameter, changes *[]*Change) []*PropertyCheck {
|
func addOpenAPIParameterProperties(left, right low.OpenAPIParameter, changes *[]*Change) []*PropertyCheck {
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
// style
|
// style
|
||||||
addPropertyCheck(&props, left.GetStyle().ValueNode, right.GetStyle().ValueNode,
|
addPropertyCheck(&props, left.GetStyle().ValueNode, right.GetStyle().ValueNode,
|
||||||
left.GetStyle(), right.GetStyle(), changes, v3.StyleLabel, false)
|
left.GetStyle(), right.GetStyle(), changes, v3.StyleLabel, false)
|
||||||
|
|
||||||
// allow reserved
|
// allow reserved
|
||||||
addPropertyCheck(&props, left.GetAllowReserved().ValueNode, right.GetAllowReserved().ValueNode,
|
addPropertyCheck(&props, left.GetAllowReserved().ValueNode, right.GetAllowReserved().ValueNode,
|
||||||
left.GetAllowReserved(), right.GetAllowReserved(), changes, v3.AllowReservedLabel, true)
|
left.GetAllowReserved(), right.GetAllowReserved(), changes, v3.AllowReservedLabel, true)
|
||||||
|
|
||||||
// explode
|
// explode
|
||||||
addPropertyCheck(&props, left.GetExplode().ValueNode, right.GetExplode().ValueNode,
|
addPropertyCheck(&props, left.GetExplode().ValueNode, right.GetExplode().ValueNode,
|
||||||
left.GetExplode(), right.GetExplode(), changes, v3.ExplodeLabel, false)
|
left.GetExplode(), right.GetExplode(), changes, v3.ExplodeLabel, false)
|
||||||
|
|
||||||
// deprecated
|
// deprecated
|
||||||
addPropertyCheck(&props, left.GetDeprecated().ValueNode, right.GetDeprecated().ValueNode,
|
addPropertyCheck(&props, left.GetDeprecated().ValueNode, right.GetDeprecated().ValueNode,
|
||||||
left.GetDeprecated(), right.GetDeprecated(), changes, v3.DeprecatedLabel, false)
|
left.GetDeprecated(), right.GetDeprecated(), changes, v3.DeprecatedLabel, false)
|
||||||
|
|
||||||
// example
|
// example
|
||||||
addPropertyCheck(&props, left.GetExample().ValueNode, right.GetExample().ValueNode,
|
addPropertyCheck(&props, left.GetExample().ValueNode, right.GetExample().ValueNode,
|
||||||
left.GetExample(), right.GetExample(), changes, v3.ExampleLabel, false)
|
left.GetExample(), right.GetExample(), changes, v3.ExampleLabel, false)
|
||||||
|
|
||||||
return props
|
return props
|
||||||
}
|
}
|
||||||
|
|
||||||
func addSwaggerParameterProperties(left, right low.SwaggerParameter, changes *[]*Change) []*PropertyCheck {
|
func addSwaggerParameterProperties(left, right low.SwaggerParameter, changes *[]*Change) []*PropertyCheck {
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
// type
|
// type
|
||||||
addPropertyCheck(&props, left.GetType().ValueNode, right.GetType().ValueNode,
|
addPropertyCheck(&props, left.GetType().ValueNode, right.GetType().ValueNode,
|
||||||
left.GetType(), right.GetType(), changes, v3.TypeLabel, true)
|
left.GetType(), right.GetType(), changes, v3.TypeLabel, true)
|
||||||
|
|
||||||
// format
|
// format
|
||||||
addPropertyCheck(&props, left.GetFormat().ValueNode, right.GetFormat().ValueNode,
|
addPropertyCheck(&props, left.GetFormat().ValueNode, right.GetFormat().ValueNode,
|
||||||
left.GetFormat(), right.GetFormat(), changes, v3.FormatLabel, true)
|
left.GetFormat(), right.GetFormat(), changes, v3.FormatLabel, true)
|
||||||
|
|
||||||
// collection format
|
// collection format
|
||||||
addPropertyCheck(&props, left.GetCollectionFormat().ValueNode, right.GetCollectionFormat().ValueNode,
|
addPropertyCheck(&props, left.GetCollectionFormat().ValueNode, right.GetCollectionFormat().ValueNode,
|
||||||
left.GetCollectionFormat(), right.GetCollectionFormat(), changes, v3.CollectionFormatLabel, true)
|
left.GetCollectionFormat(), right.GetCollectionFormat(), changes, v3.CollectionFormatLabel, true)
|
||||||
|
|
||||||
// maximum
|
// maximum
|
||||||
addPropertyCheck(&props, left.GetMaximum().ValueNode, right.GetMaximum().ValueNode,
|
addPropertyCheck(&props, left.GetMaximum().ValueNode, right.GetMaximum().ValueNode,
|
||||||
left.GetMaximum(), right.GetMaximum(), changes, v3.MaximumLabel, true)
|
left.GetMaximum(), right.GetMaximum(), changes, v3.MaximumLabel, true)
|
||||||
|
|
||||||
// minimum
|
// minimum
|
||||||
addPropertyCheck(&props, left.GetMinimum().ValueNode, right.GetMinimum().ValueNode,
|
addPropertyCheck(&props, left.GetMinimum().ValueNode, right.GetMinimum().ValueNode,
|
||||||
left.GetMinimum(), right.GetMinimum(), changes, v3.MinimumLabel, true)
|
left.GetMinimum(), right.GetMinimum(), changes, v3.MinimumLabel, true)
|
||||||
|
|
||||||
// exclusive maximum
|
// exclusive maximum
|
||||||
addPropertyCheck(&props, left.GetExclusiveMaximum().ValueNode, right.GetExclusiveMaximum().ValueNode,
|
addPropertyCheck(&props, left.GetExclusiveMaximum().ValueNode, right.GetExclusiveMaximum().ValueNode,
|
||||||
left.GetExclusiveMaximum(), right.GetExclusiveMaximum(), changes, v3.ExclusiveMaximumLabel, true)
|
left.GetExclusiveMaximum(), right.GetExclusiveMaximum(), changes, v3.ExclusiveMaximumLabel, true)
|
||||||
|
|
||||||
// exclusive minimum
|
// exclusive minimum
|
||||||
addPropertyCheck(&props, left.GetExclusiveMinimum().ValueNode, right.GetExclusiveMinimum().ValueNode,
|
addPropertyCheck(&props, left.GetExclusiveMinimum().ValueNode, right.GetExclusiveMinimum().ValueNode,
|
||||||
left.GetExclusiveMinimum(), right.GetExclusiveMinimum(), changes, v3.ExclusiveMinimumLabel, true)
|
left.GetExclusiveMinimum(), right.GetExclusiveMinimum(), changes, v3.ExclusiveMinimumLabel, true)
|
||||||
|
|
||||||
// max length
|
// max length
|
||||||
addPropertyCheck(&props, left.GetMaxLength().ValueNode, right.GetMaxLength().ValueNode,
|
addPropertyCheck(&props, left.GetMaxLength().ValueNode, right.GetMaxLength().ValueNode,
|
||||||
left.GetMaxLength(), right.GetMaxLength(), changes, v3.MaxLengthLabel, true)
|
left.GetMaxLength(), right.GetMaxLength(), changes, v3.MaxLengthLabel, true)
|
||||||
|
|
||||||
// min length
|
// min length
|
||||||
addPropertyCheck(&props, left.GetMinLength().ValueNode, right.GetMinLength().ValueNode,
|
addPropertyCheck(&props, left.GetMinLength().ValueNode, right.GetMinLength().ValueNode,
|
||||||
left.GetMinLength(), right.GetMinLength(), changes, v3.MinLengthLabel, true)
|
left.GetMinLength(), right.GetMinLength(), changes, v3.MinLengthLabel, true)
|
||||||
|
|
||||||
// pattern
|
// pattern
|
||||||
addPropertyCheck(&props, left.GetPattern().ValueNode, right.GetPattern().ValueNode,
|
addPropertyCheck(&props, left.GetPattern().ValueNode, right.GetPattern().ValueNode,
|
||||||
left.GetPattern(), right.GetPattern(), changes, v3.PatternLabel, true)
|
left.GetPattern(), right.GetPattern(), changes, v3.PatternLabel, true)
|
||||||
|
|
||||||
// max items
|
// max items
|
||||||
addPropertyCheck(&props, left.GetMaxItems().ValueNode, right.GetMaxItems().ValueNode,
|
addPropertyCheck(&props, left.GetMaxItems().ValueNode, right.GetMaxItems().ValueNode,
|
||||||
left.GetMaxItems(), right.GetMaxItems(), changes, v3.MaxItemsLabel, true)
|
left.GetMaxItems(), right.GetMaxItems(), changes, v3.MaxItemsLabel, true)
|
||||||
|
|
||||||
// min items
|
// min items
|
||||||
addPropertyCheck(&props, left.GetMinItems().ValueNode, right.GetMinItems().ValueNode,
|
addPropertyCheck(&props, left.GetMinItems().ValueNode, right.GetMinItems().ValueNode,
|
||||||
left.GetMinItems(), right.GetMinItems(), changes, v3.MinItemsLabel, true)
|
left.GetMinItems(), right.GetMinItems(), changes, v3.MinItemsLabel, true)
|
||||||
|
|
||||||
// unique items
|
// unique items
|
||||||
addPropertyCheck(&props, left.GetUniqueItems().ValueNode, right.GetUniqueItems().ValueNode,
|
addPropertyCheck(&props, left.GetUniqueItems().ValueNode, right.GetUniqueItems().ValueNode,
|
||||||
left.GetUniqueItems(), right.GetUniqueItems(), changes, v3.UniqueItemsLabel, true)
|
left.GetUniqueItems(), right.GetUniqueItems(), changes, v3.UniqueItemsLabel, true)
|
||||||
|
|
||||||
// default
|
// default
|
||||||
addPropertyCheck(&props, left.GetDefault().ValueNode, right.GetDefault().ValueNode,
|
addPropertyCheck(&props, left.GetDefault().ValueNode, right.GetDefault().ValueNode,
|
||||||
left.GetDefault(), right.GetDefault(), changes, v3.DefaultLabel, true)
|
left.GetDefault(), right.GetDefault(), changes, v3.DefaultLabel, true)
|
||||||
|
|
||||||
// multiple of
|
// multiple of
|
||||||
addPropertyCheck(&props, left.GetMultipleOf().ValueNode, right.GetMultipleOf().ValueNode,
|
addPropertyCheck(&props, left.GetMultipleOf().ValueNode, right.GetMultipleOf().ValueNode,
|
||||||
left.GetMultipleOf(), right.GetMultipleOf(), changes, v3.MultipleOfLabel, true)
|
left.GetMultipleOf(), right.GetMultipleOf(), changes, v3.MultipleOfLabel, true)
|
||||||
|
|
||||||
return props
|
return props
|
||||||
}
|
}
|
||||||
|
|
||||||
func addCommonParameterProperties(left, right low.SharedParameters, changes *[]*Change) []*PropertyCheck {
|
func addCommonParameterProperties(left, right low.SharedParameters, changes *[]*Change) []*PropertyCheck {
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
addPropertyCheck(&props, left.GetName().ValueNode, right.GetName().ValueNode,
|
addPropertyCheck(&props, left.GetName().ValueNode, right.GetName().ValueNode,
|
||||||
left.GetName(), right.GetName(), changes, v3.NameLabel, true)
|
left.GetName(), right.GetName(), changes, v3.NameLabel, true)
|
||||||
|
|
||||||
// in
|
// in
|
||||||
addPropertyCheck(&props, left.GetIn().ValueNode, right.GetIn().ValueNode,
|
addPropertyCheck(&props, left.GetIn().ValueNode, right.GetIn().ValueNode,
|
||||||
left.GetIn(), right.GetIn(), changes, v3.InLabel, true)
|
left.GetIn(), right.GetIn(), changes, v3.InLabel, true)
|
||||||
|
|
||||||
// description
|
// description
|
||||||
addPropertyCheck(&props, left.GetDescription().ValueNode, right.GetDescription().ValueNode,
|
addPropertyCheck(&props, left.GetDescription().ValueNode, right.GetDescription().ValueNode,
|
||||||
left.GetDescription(), right.GetDescription(), changes, v3.DescriptionLabel, false)
|
left.GetDescription(), right.GetDescription(), changes, v3.DescriptionLabel, false)
|
||||||
|
|
||||||
// required
|
// required
|
||||||
addPropertyCheck(&props, left.GetRequired().ValueNode, right.GetRequired().ValueNode,
|
addPropertyCheck(&props, left.GetRequired().ValueNode, right.GetRequired().ValueNode,
|
||||||
left.GetRequired(), right.GetRequired(), changes, v3.RequiredLabel, true)
|
left.GetRequired(), right.GetRequired(), changes, v3.RequiredLabel, true)
|
||||||
|
|
||||||
// allow empty value
|
// allow empty value
|
||||||
addPropertyCheck(&props, left.GetAllowEmptyValue().ValueNode, right.GetAllowEmptyValue().ValueNode,
|
addPropertyCheck(&props, left.GetAllowEmptyValue().ValueNode, right.GetAllowEmptyValue().ValueNode,
|
||||||
left.GetAllowEmptyValue(), right.GetAllowEmptyValue(), changes, v3.AllowEmptyValueLabel, true)
|
left.GetAllowEmptyValue(), right.GetAllowEmptyValue(), changes, v3.AllowEmptyValueLabel, true)
|
||||||
|
|
||||||
return props
|
return props
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareParametersV3 is amn OpenAPI type safe proxy for CompareParameters
|
// CompareParametersV3 is amn OpenAPI type safe proxy for CompareParameters
|
||||||
func CompareParametersV3(l, r *v3.Parameter) *ParameterChanges {
|
func CompareParametersV3(l, r *v3.Parameter) *ParameterChanges {
|
||||||
return CompareParameters(l, r)
|
return CompareParameters(l, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareParameters compares a left and right Swagger or OpenAPI Parameter object for any changes. If found returns
|
// CompareParameters compares a left and right Swagger or OpenAPI Parameter object for any changes. If found returns
|
||||||
// a pointer to ParameterChanges. If nothing is found, returns nil.
|
// a pointer to ParameterChanges. If nothing is found, returns nil.
|
||||||
func CompareParameters(l, r any) *ParameterChanges {
|
func CompareParameters(l, r any) *ParameterChanges {
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
pc := new(ParameterChanges)
|
pc := new(ParameterChanges)
|
||||||
var lSchema *base.SchemaProxy
|
var lSchema *base.SchemaProxy
|
||||||
var rSchema *base.SchemaProxy
|
var rSchema *base.SchemaProxy
|
||||||
var lext, rext map[low.KeyReference[string]]low.ValueReference[any]
|
var lext, rext map[low.KeyReference[string]]low.ValueReference[any]
|
||||||
|
|
||||||
if reflect.TypeOf(&v2.Parameter{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Parameter{}) == reflect.TypeOf(r) {
|
if reflect.TypeOf(&v2.Parameter{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Parameter{}) == reflect.TypeOf(r) {
|
||||||
lParam := l.(*v2.Parameter)
|
lParam := l.(*v2.Parameter)
|
||||||
rParam := r.(*v2.Parameter)
|
rParam := r.(*v2.Parameter)
|
||||||
|
|
||||||
// perform hash check to avoid further processing
|
// perform hash check to avoid further processing
|
||||||
if low.AreEqual(lParam, rParam) {
|
if low.AreEqual(lParam, rParam) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
props = append(props, addSwaggerParameterProperties(lParam, rParam, &changes)...)
|
props = append(props, addSwaggerParameterProperties(lParam, rParam, &changes)...)
|
||||||
props = append(props, addCommonParameterProperties(lParam, rParam, &changes)...)
|
props = append(props, addCommonParameterProperties(lParam, rParam, &changes)...)
|
||||||
|
|
||||||
// extract schema
|
// extract schema
|
||||||
if lParam != nil {
|
if lParam != nil {
|
||||||
lSchema = lParam.Schema.Value
|
lSchema = lParam.Schema.Value
|
||||||
lext = lParam.Extensions
|
lext = lParam.Extensions
|
||||||
}
|
}
|
||||||
if rParam != nil {
|
if rParam != nil {
|
||||||
rext = rParam.Extensions
|
rext = rParam.Extensions
|
||||||
rSchema = rParam.Schema.Value
|
rSchema = rParam.Schema.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
// items
|
// items
|
||||||
if !lParam.Items.IsEmpty() && !rParam.Items.IsEmpty() {
|
if !lParam.Items.IsEmpty() && !rParam.Items.IsEmpty() {
|
||||||
if lParam.Items.Value.Hash() != rParam.Items.Value.Hash() {
|
if lParam.Items.Value.Hash() != rParam.Items.Value.Hash() {
|
||||||
pc.ItemsChanges = CompareItems(lParam.Items.Value, rParam.Items.Value)
|
pc.ItemsChanges = CompareItems(lParam.Items.Value, rParam.Items.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if lParam.Items.IsEmpty() && !rParam.Items.IsEmpty() {
|
if lParam.Items.IsEmpty() && !rParam.Items.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectAdded, v3.ItemsLabel,
|
CreateChange(&changes, ObjectAdded, v3.ItemsLabel,
|
||||||
nil, rParam.Items.ValueNode, true, nil,
|
nil, rParam.Items.ValueNode, true, nil,
|
||||||
rParam.Items.Value)
|
rParam.Items.Value)
|
||||||
}
|
}
|
||||||
if !lParam.Items.IsEmpty() && rParam.Items.IsEmpty() {
|
if !lParam.Items.IsEmpty() && rParam.Items.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.ItemsLabel,
|
CreateChange(&changes, ObjectRemoved, v3.ItemsLabel,
|
||||||
lParam.Items.ValueNode, nil, true, lParam.Items.Value,
|
lParam.Items.ValueNode, nil, true, lParam.Items.Value,
|
||||||
nil)
|
nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// enum
|
// enum
|
||||||
if len(lParam.Enum.Value) > 0 || len(rParam.Enum.Value) > 0 {
|
if len(lParam.Enum.Value) > 0 || len(rParam.Enum.Value) > 0 {
|
||||||
ExtractRawValueSliceChanges(lParam.Enum.Value, rParam.Enum.Value, &changes, v3.EnumLabel, true)
|
ExtractRawValueSliceChanges(lParam.Enum.Value, rParam.Enum.Value, &changes, v3.EnumLabel, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenAPI
|
// OpenAPI
|
||||||
if reflect.TypeOf(&v3.Parameter{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Parameter{}) == reflect.TypeOf(r) {
|
if reflect.TypeOf(&v3.Parameter{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Parameter{}) == reflect.TypeOf(r) {
|
||||||
|
|
||||||
lParam := l.(*v3.Parameter)
|
lParam := l.(*v3.Parameter)
|
||||||
rParam := r.(*v3.Parameter)
|
rParam := r.(*v3.Parameter)
|
||||||
|
|
||||||
// perform hash check to avoid further processing
|
// perform hash check to avoid further processing
|
||||||
if low.AreEqual(lParam, rParam) {
|
if low.AreEqual(lParam, rParam) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
props = append(props, addOpenAPIParameterProperties(lParam, rParam, &changes)...)
|
props = append(props, addOpenAPIParameterProperties(lParam, rParam, &changes)...)
|
||||||
props = append(props, addCommonParameterProperties(lParam, rParam, &changes)...)
|
props = append(props, addCommonParameterProperties(lParam, rParam, &changes)...)
|
||||||
if lParam != nil {
|
if lParam != nil {
|
||||||
lext = lParam.Extensions
|
lext = lParam.Extensions
|
||||||
lSchema = lParam.Schema.Value
|
lSchema = lParam.Schema.Value
|
||||||
}
|
}
|
||||||
if rParam != nil {
|
if rParam != nil {
|
||||||
rext = rParam.Extensions
|
rext = rParam.Extensions
|
||||||
rSchema = rParam.Schema.Value
|
rSchema = rParam.Schema.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
// example
|
// example
|
||||||
checkParameterExample(lParam.Example, rParam.Example, changes)
|
checkParameterExample(lParam.Example, rParam.Example, changes)
|
||||||
|
|
||||||
// examples
|
// examples
|
||||||
pc.ExamplesChanges = CheckMapForChanges(lParam.Examples.Value, rParam.Examples.Value,
|
pc.ExamplesChanges = CheckMapForChanges(lParam.Examples.Value, rParam.Examples.Value,
|
||||||
&changes, v3.ExamplesLabel, CompareExamples)
|
&changes, v3.ExamplesLabel, CompareExamples)
|
||||||
|
|
||||||
// content
|
// content
|
||||||
pc.ContentChanges = CheckMapForChanges(lParam.Content.Value, rParam.Content.Value,
|
pc.ContentChanges = CheckMapForChanges(lParam.Content.Value, rParam.Content.Value,
|
||||||
&changes, v3.ContentLabel, CompareMediaTypes)
|
&changes, v3.ContentLabel, CompareMediaTypes)
|
||||||
}
|
}
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
|
|
||||||
if lSchema != nil && rSchema != nil {
|
if lSchema != nil && rSchema != nil {
|
||||||
pc.SchemaChanges = CompareSchemas(lSchema, rSchema)
|
pc.SchemaChanges = CompareSchemas(lSchema, rSchema)
|
||||||
}
|
}
|
||||||
if lSchema != nil && rSchema == nil {
|
if lSchema != nil && rSchema == nil {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.SchemaLabel,
|
CreateChange(&changes, ObjectRemoved, v3.SchemaLabel,
|
||||||
lSchema.GetValueNode(), nil, true, lSchema,
|
lSchema.GetValueNode(), nil, true, lSchema,
|
||||||
nil)
|
nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if lSchema == nil && rSchema != nil {
|
if lSchema == nil && rSchema != nil {
|
||||||
CreateChange(&changes, ObjectAdded, v3.SchemaLabel,
|
CreateChange(&changes, ObjectAdded, v3.SchemaLabel,
|
||||||
nil, rSchema.GetValueNode(), true, nil,
|
nil, rSchema.GetValueNode(), true, nil,
|
||||||
rSchema)
|
rSchema)
|
||||||
}
|
}
|
||||||
|
|
||||||
pc.Changes = changes
|
pc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
pc.ExtensionChanges = CompareExtensions(lext, rext)
|
pc.ExtensionChanges = CompareExtensions(lext, rext)
|
||||||
if pc.TotalChanges() <= 0 {
|
if pc.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return pc
|
return pc
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkParameterExample(expLeft, expRight low.NodeReference[any], changes []*Change) {
|
func checkParameterExample(expLeft, expRight low.NodeReference[any], changes []*Change) {
|
||||||
if !expLeft.IsEmpty() && !expRight.IsEmpty() {
|
if !expLeft.IsEmpty() && !expRight.IsEmpty() {
|
||||||
if low.GenerateHashString(expLeft.GetValue()) != low.GenerateHashString(expRight.GetValue()) {
|
if low.GenerateHashString(expLeft.GetValue()) != low.GenerateHashString(expRight.GetValue()) {
|
||||||
CreateChange(&changes, Modified, v3.ExampleLabel,
|
CreateChange(&changes, Modified, v3.ExampleLabel,
|
||||||
expLeft.GetValueNode(), expRight.GetValueNode(), false,
|
expLeft.GetValueNode(), expRight.GetValueNode(), false,
|
||||||
expLeft.GetValue(), expRight.GetValue())
|
expLeft.GetValue(), expRight.GetValue())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if expLeft.Value == nil && expRight.Value != nil {
|
if expLeft.Value == nil && expRight.Value != nil {
|
||||||
CreateChange(&changes, PropertyAdded, v3.ExampleLabel,
|
CreateChange(&changes, PropertyAdded, v3.ExampleLabel,
|
||||||
nil, expRight.GetValueNode(), false,
|
nil, expRight.GetValueNode(), false,
|
||||||
nil, expRight.GetValue())
|
nil, expRight.GetValue())
|
||||||
|
|
||||||
}
|
}
|
||||||
if expLeft.Value != nil && expRight.Value == nil {
|
if expLeft.Value != nil && expRight.Value == nil {
|
||||||
CreateChange(&changes, PropertyRemoved, v3.ExampleLabel,
|
CreateChange(&changes, PropertyRemoved, v3.ExampleLabel,
|
||||||
expLeft.GetValueNode(), nil, false,
|
expLeft.GetValueNode(), nil, false,
|
||||||
expLeft.GetValue(), nil)
|
expLeft.GetValue(), nil)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4,190 +4,190 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PathsChanges represents changes found between two Swagger or OpenAPI Paths Objects.
|
// PathsChanges represents changes found between two Swagger or OpenAPI Paths Objects.
|
||||||
type PathsChanges struct {
|
type PathsChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
PathItemsChanges map[string]*PathItemChanges `json:"pathItems,omitempty" yaml:"pathItems,omitempty"`
|
PathItemsChanges map[string]*PathItemChanges `json:"pathItems,omitempty" yaml:"pathItems,omitempty"`
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns the total number of changes between two Swagger or OpenAPI Paths Objects
|
// TotalChanges returns the total number of changes between two Swagger or OpenAPI Paths Objects
|
||||||
func (p *PathsChanges) TotalChanges() int {
|
func (p *PathsChanges) TotalChanges() int {
|
||||||
c := p.PropertyChanges.TotalChanges()
|
c := p.PropertyChanges.TotalChanges()
|
||||||
for k := range p.PathItemsChanges {
|
for k := range p.PathItemsChanges {
|
||||||
c += p.PathItemsChanges[k].TotalChanges()
|
c += p.PathItemsChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
if p.ExtensionChanges != nil {
|
if p.ExtensionChanges != nil {
|
||||||
c += p.ExtensionChanges.TotalChanges()
|
c += p.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns tht total number of changes found between two Swagger or OpenAPI Path Objects
|
// TotalBreakingChanges returns tht total number of changes found between two Swagger or OpenAPI Path Objects
|
||||||
func (p *PathsChanges) TotalBreakingChanges() int {
|
func (p *PathsChanges) TotalBreakingChanges() int {
|
||||||
c := p.PropertyChanges.TotalBreakingChanges()
|
c := p.PropertyChanges.TotalBreakingChanges()
|
||||||
for k := range p.PathItemsChanges {
|
for k := range p.PathItemsChanges {
|
||||||
c += p.PathItemsChanges[k].TotalBreakingChanges()
|
c += p.PathItemsChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// ComparePaths compares a left and right Swagger or OpenAPI Paths Object for changes. If found, returns a pointer
|
// ComparePaths compares a left and right Swagger or OpenAPI Paths Object for changes. If found, returns a pointer
|
||||||
// to a PathsChanges instance. Returns nil if nothing is found.
|
// to a PathsChanges instance. Returns nil if nothing is found.
|
||||||
func ComparePaths(l, r any) *PathsChanges {
|
func ComparePaths(l, r any) *PathsChanges {
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
|
|
||||||
pc := new(PathsChanges)
|
pc := new(PathsChanges)
|
||||||
pathChanges := make(map[string]*PathItemChanges)
|
pathChanges := make(map[string]*PathItemChanges)
|
||||||
|
|
||||||
// Swagger
|
// Swagger
|
||||||
if reflect.TypeOf(&v2.Paths{}) == reflect.TypeOf(l) &&
|
if reflect.TypeOf(&v2.Paths{}) == reflect.TypeOf(l) &&
|
||||||
reflect.TypeOf(&v2.Paths{}) == reflect.TypeOf(r) {
|
reflect.TypeOf(&v2.Paths{}) == reflect.TypeOf(r) {
|
||||||
|
|
||||||
lPath := l.(*v2.Paths)
|
lPath := l.(*v2.Paths)
|
||||||
rPath := r.(*v2.Paths)
|
rPath := r.(*v2.Paths)
|
||||||
|
|
||||||
// perform hash check to avoid further processing
|
// perform hash check to avoid further processing
|
||||||
if low.AreEqual(lPath, rPath) {
|
if low.AreEqual(lPath, rPath) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
lKeys := make(map[string]low.ValueReference[*v2.PathItem])
|
lKeys := make(map[string]low.ValueReference[*v2.PathItem])
|
||||||
rKeys := make(map[string]low.ValueReference[*v2.PathItem])
|
rKeys := make(map[string]low.ValueReference[*v2.PathItem])
|
||||||
for k := range lPath.PathItems {
|
for k := range lPath.PathItems {
|
||||||
lKeys[k.Value] = lPath.PathItems[k]
|
lKeys[k.Value] = lPath.PathItems[k]
|
||||||
}
|
}
|
||||||
for k := range rPath.PathItems {
|
for k := range rPath.PathItems {
|
||||||
rKeys[k.Value] = rPath.PathItems[k]
|
rKeys[k.Value] = rPath.PathItems[k]
|
||||||
}
|
}
|
||||||
|
|
||||||
// run every comparison in a thread.
|
// run every comparison in a thread.
|
||||||
var mLock sync.Mutex
|
var mLock sync.Mutex
|
||||||
compare := func(path string, pChanges map[string]*PathItemChanges, l, r *v2.PathItem, doneChan chan bool) {
|
compare := func(path string, pChanges map[string]*PathItemChanges, l, r *v2.PathItem, doneChan chan bool) {
|
||||||
if !low.AreEqual(l, r) {
|
if !low.AreEqual(l, r) {
|
||||||
mLock.Lock()
|
mLock.Lock()
|
||||||
pathChanges[path] = ComparePathItems(l, r)
|
pathChanges[path] = ComparePathItems(l, r)
|
||||||
mLock.Unlock()
|
mLock.Unlock()
|
||||||
}
|
}
|
||||||
doneChan <- true
|
doneChan <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
doneChan := make(chan bool)
|
doneChan := make(chan bool)
|
||||||
pathsChecked := 0
|
pathsChecked := 0
|
||||||
|
|
||||||
for k := range lKeys {
|
for k := range lKeys {
|
||||||
if _, ok := rKeys[k]; ok {
|
if _, ok := rKeys[k]; ok {
|
||||||
go compare(k, pathChanges, lKeys[k].Value, rKeys[k].Value, doneChan)
|
go compare(k, pathChanges, lKeys[k].Value, rKeys[k].Value, doneChan)
|
||||||
pathsChecked++
|
pathsChecked++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
g, p := lPath.FindPathAndKey(k)
|
g, p := lPath.FindPathAndKey(k)
|
||||||
CreateChange(&changes, ObjectRemoved, v3.PathLabel,
|
CreateChange(&changes, ObjectRemoved, v3.PathLabel,
|
||||||
g.KeyNode, nil, true,
|
g.KeyNode, nil, true,
|
||||||
p.Value, nil)
|
p.Value, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
for k := range rKeys {
|
for k := range rKeys {
|
||||||
if _, ok := lKeys[k]; !ok {
|
if _, ok := lKeys[k]; !ok {
|
||||||
g, p := rPath.FindPathAndKey(k)
|
g, p := rPath.FindPathAndKey(k)
|
||||||
CreateChange(&changes, ObjectAdded, v3.PathLabel,
|
CreateChange(&changes, ObjectAdded, v3.PathLabel,
|
||||||
nil, g.KeyNode, false,
|
nil, g.KeyNode, false,
|
||||||
nil, p.Value)
|
nil, p.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for the things to be done.
|
// wait for the things to be done.
|
||||||
completedChecks := 0
|
completedChecks := 0
|
||||||
for completedChecks < pathsChecked {
|
for completedChecks < pathsChecked {
|
||||||
select {
|
select {
|
||||||
case <-doneChan:
|
case <-doneChan:
|
||||||
completedChecks++
|
completedChecks++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(pathChanges) > 0 {
|
if len(pathChanges) > 0 {
|
||||||
pc.PathItemsChanges = pathChanges
|
pc.PathItemsChanges = pathChanges
|
||||||
}
|
}
|
||||||
|
|
||||||
pc.ExtensionChanges = CompareExtensions(lPath.Extensions, rPath.Extensions)
|
pc.ExtensionChanges = CompareExtensions(lPath.Extensions, rPath.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenAPI
|
// OpenAPI
|
||||||
if reflect.TypeOf(&v3.Paths{}) == reflect.TypeOf(l) &&
|
if reflect.TypeOf(&v3.Paths{}) == reflect.TypeOf(l) &&
|
||||||
reflect.TypeOf(&v3.Paths{}) == reflect.TypeOf(r) {
|
reflect.TypeOf(&v3.Paths{}) == reflect.TypeOf(r) {
|
||||||
|
|
||||||
lPath := l.(*v3.Paths)
|
lPath := l.(*v3.Paths)
|
||||||
rPath := r.(*v3.Paths)
|
rPath := r.(*v3.Paths)
|
||||||
|
|
||||||
// perform hash check to avoid further processing
|
// perform hash check to avoid further processing
|
||||||
if low.AreEqual(lPath, rPath) {
|
if low.AreEqual(lPath, rPath) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
lKeys := make(map[string]low.ValueReference[*v3.PathItem])
|
lKeys := make(map[string]low.ValueReference[*v3.PathItem])
|
||||||
rKeys := make(map[string]low.ValueReference[*v3.PathItem])
|
rKeys := make(map[string]low.ValueReference[*v3.PathItem])
|
||||||
for k := range lPath.PathItems {
|
for k := range lPath.PathItems {
|
||||||
lKeys[k.Value] = lPath.PathItems[k]
|
lKeys[k.Value] = lPath.PathItems[k]
|
||||||
}
|
}
|
||||||
for k := range rPath.PathItems {
|
for k := range rPath.PathItems {
|
||||||
rKeys[k.Value] = rPath.PathItems[k]
|
rKeys[k.Value] = rPath.PathItems[k]
|
||||||
}
|
}
|
||||||
|
|
||||||
// run every comparison in a thread.
|
// run every comparison in a thread.
|
||||||
var mLock sync.Mutex
|
var mLock sync.Mutex
|
||||||
compare := func(path string, pChanges map[string]*PathItemChanges, l, r *v3.PathItem, doneChan chan bool) {
|
compare := func(path string, pChanges map[string]*PathItemChanges, l, r *v3.PathItem, doneChan chan bool) {
|
||||||
if !low.AreEqual(l, r) {
|
if !low.AreEqual(l, r) {
|
||||||
mLock.Lock()
|
mLock.Lock()
|
||||||
pathChanges[path] = ComparePathItems(l, r)
|
pathChanges[path] = ComparePathItems(l, r)
|
||||||
mLock.Unlock()
|
mLock.Unlock()
|
||||||
}
|
}
|
||||||
doneChan <- true
|
doneChan <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
doneChan := make(chan bool)
|
doneChan := make(chan bool)
|
||||||
pathsChecked := 0
|
pathsChecked := 0
|
||||||
|
|
||||||
for k := range lKeys {
|
for k := range lKeys {
|
||||||
if _, ok := rKeys[k]; ok {
|
if _, ok := rKeys[k]; ok {
|
||||||
go compare(k, pathChanges, lKeys[k].Value, rKeys[k].Value, doneChan)
|
go compare(k, pathChanges, lKeys[k].Value, rKeys[k].Value, doneChan)
|
||||||
pathsChecked++
|
pathsChecked++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
g, p := lPath.FindPathAndKey(k)
|
g, p := lPath.FindPathAndKey(k)
|
||||||
CreateChange(&changes, ObjectRemoved, v3.PathLabel,
|
CreateChange(&changes, ObjectRemoved, v3.PathLabel,
|
||||||
g.KeyNode, nil, true,
|
g.KeyNode, nil, true,
|
||||||
p.Value, nil)
|
p.Value, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
for k := range rKeys {
|
for k := range rKeys {
|
||||||
if _, ok := lKeys[k]; !ok {
|
if _, ok := lKeys[k]; !ok {
|
||||||
g, p := rPath.FindPathAndKey(k)
|
g, p := rPath.FindPathAndKey(k)
|
||||||
CreateChange(&changes, ObjectAdded, v3.PathLabel,
|
CreateChange(&changes, ObjectAdded, v3.PathLabel,
|
||||||
nil, g.KeyNode, false,
|
nil, g.KeyNode, false,
|
||||||
nil, p.Value)
|
nil, p.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// wait for the things to be done.
|
// wait for the things to be done.
|
||||||
completedChecks := 0
|
completedChecks := 0
|
||||||
for completedChecks < pathsChecked {
|
for completedChecks < pathsChecked {
|
||||||
select {
|
select {
|
||||||
case <-doneChan:
|
case <-doneChan:
|
||||||
completedChecks++
|
completedChecks++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(pathChanges) > 0 {
|
if len(pathChanges) > 0 {
|
||||||
pc.PathItemsChanges = pathChanges
|
pc.PathItemsChanges = pathChanges
|
||||||
}
|
}
|
||||||
|
|
||||||
pc.ExtensionChanges = CompareExtensions(lPath.Extensions, rPath.Extensions)
|
pc.ExtensionChanges = CompareExtensions(lPath.Extensions, rPath.Extensions)
|
||||||
}
|
}
|
||||||
pc.Changes = changes
|
pc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
return pc
|
return pc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,77 +4,77 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RequestBodyChanges represents changes made between two OpenAPI RequestBody Objects
|
// RequestBodyChanges represents changes made between two OpenAPI RequestBody Objects
|
||||||
type RequestBodyChanges struct {
|
type RequestBodyChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"`
|
ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"`
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns the total number of changes found between two OpenAPI RequestBody objects
|
// TotalChanges returns the total number of changes found between two OpenAPI RequestBody objects
|
||||||
func (rb *RequestBodyChanges) TotalChanges() int {
|
func (rb *RequestBodyChanges) TotalChanges() int {
|
||||||
c := rb.PropertyChanges.TotalChanges()
|
c := rb.PropertyChanges.TotalChanges()
|
||||||
for k := range rb.ContentChanges {
|
for k := range rb.ContentChanges {
|
||||||
c += rb.ContentChanges[k].TotalChanges()
|
c += rb.ContentChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
if rb.ExtensionChanges != nil {
|
if rb.ExtensionChanges != nil {
|
||||||
c += rb.ExtensionChanges.TotalChanges()
|
c += rb.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the total number of breaking changes found between OpenAPI RequestBody objects
|
// TotalBreakingChanges returns the total number of breaking changes found between OpenAPI RequestBody objects
|
||||||
func (rb *RequestBodyChanges) TotalBreakingChanges() int {
|
func (rb *RequestBodyChanges) TotalBreakingChanges() int {
|
||||||
c := rb.PropertyChanges.TotalBreakingChanges()
|
c := rb.PropertyChanges.TotalBreakingChanges()
|
||||||
for k := range rb.ContentChanges {
|
for k := range rb.ContentChanges {
|
||||||
c += rb.ContentChanges[k].TotalBreakingChanges()
|
c += rb.ContentChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareRequestBodies compares a left and right OpenAPI RequestBody object for changes. If found returns a pointer
|
// CompareRequestBodies compares a left and right OpenAPI RequestBody object for changes. If found returns a pointer
|
||||||
// to a RequestBodyChanges instance. Returns nil if nothing was found.
|
// to a RequestBodyChanges instance. Returns nil if nothing was found.
|
||||||
func CompareRequestBodies(l, r *v3.RequestBody) *RequestBodyChanges {
|
func CompareRequestBodies(l, r *v3.RequestBody) *RequestBodyChanges {
|
||||||
if low.AreEqual(l, r) {
|
if low.AreEqual(l, r) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
// description
|
// description
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Description.ValueNode,
|
LeftNode: l.Description.ValueNode,
|
||||||
RightNode: r.Description.ValueNode,
|
RightNode: r.Description.ValueNode,
|
||||||
Label: v3.DescriptionLabel,
|
Label: v3.DescriptionLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// required
|
// required
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Required.ValueNode,
|
LeftNode: l.Required.ValueNode,
|
||||||
RightNode: r.Required.ValueNode,
|
RightNode: r.Required.ValueNode,
|
||||||
Label: v3.RequiredLabel,
|
Label: v3.RequiredLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
|
|
||||||
rbc := new(RequestBodyChanges)
|
rbc := new(RequestBodyChanges)
|
||||||
rbc.ContentChanges = CheckMapForChanges(l.Content.Value, r.Content.Value,
|
rbc.ContentChanges = CheckMapForChanges(l.Content.Value, r.Content.Value,
|
||||||
&changes, v3.ContentLabel, CompareMediaTypes)
|
&changes, v3.ContentLabel, CompareMediaTypes)
|
||||||
rbc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
rbc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||||
rbc.Changes = changes
|
rbc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
|
|
||||||
return rbc
|
return rbc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,172 +4,172 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResponseChanges represents changes found between two Swagger or OpenAPI Response objects.
|
// ResponseChanges represents changes found between two Swagger or OpenAPI Response objects.
|
||||||
type ResponseChanges struct {
|
type ResponseChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
HeadersChanges map[string]*HeaderChanges `json:"headers,omitempty" yaml:"headers,omitempty"`
|
HeadersChanges map[string]*HeaderChanges `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||||
|
|
||||||
// Swagger Response Properties.
|
// Swagger Response Properties.
|
||||||
SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
SchemaChanges *SchemaChanges `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||||
ExamplesChanges *ExamplesChanges `json:"examples,omitempty" yaml:"examples,omitempty"`
|
ExamplesChanges *ExamplesChanges `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||||
|
|
||||||
// OpenAPI Response Properties.
|
// OpenAPI Response Properties.
|
||||||
ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"`
|
ContentChanges map[string]*MediaTypeChanges `json:"content,omitempty" yaml:"content,omitempty"`
|
||||||
LinkChanges map[string]*LinkChanges `json:"links,omitempty" yaml:"links,omitempty"`
|
LinkChanges map[string]*LinkChanges `json:"links,omitempty" yaml:"links,omitempty"`
|
||||||
ServerChanges *ServerChanges `json:"server,omitempty" yaml:"server,omitempty"`
|
ServerChanges *ServerChanges `json:"server,omitempty" yaml:"server,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns the total number of changes found between two Swagger or OpenAPI Response Objects
|
// TotalChanges returns the total number of changes found between two Swagger or OpenAPI Response Objects
|
||||||
func (r *ResponseChanges) TotalChanges() int {
|
func (r *ResponseChanges) TotalChanges() int {
|
||||||
c := r.PropertyChanges.TotalChanges()
|
c := r.PropertyChanges.TotalChanges()
|
||||||
if r.ExtensionChanges != nil {
|
if r.ExtensionChanges != nil {
|
||||||
c += r.ExtensionChanges.TotalChanges()
|
c += r.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
if r.SchemaChanges != nil {
|
if r.SchemaChanges != nil {
|
||||||
c += r.SchemaChanges.TotalChanges()
|
c += r.SchemaChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
if r.ExamplesChanges != nil {
|
if r.ExamplesChanges != nil {
|
||||||
c += r.ExamplesChanges.TotalChanges()
|
c += r.ExamplesChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
for k := range r.HeadersChanges {
|
for k := range r.HeadersChanges {
|
||||||
c += r.HeadersChanges[k].TotalChanges()
|
c += r.HeadersChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
for k := range r.ContentChanges {
|
for k := range r.ContentChanges {
|
||||||
c += r.ContentChanges[k].TotalChanges()
|
c += r.ContentChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
for k := range r.LinkChanges {
|
for k := range r.LinkChanges {
|
||||||
c += r.LinkChanges[k].TotalChanges()
|
c += r.LinkChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the total number of breaking changes found between two swagger or OpenAPI
|
// TotalBreakingChanges returns the total number of breaking changes found between two swagger or OpenAPI
|
||||||
// Response Objects
|
// Response Objects
|
||||||
func (r *ResponseChanges) TotalBreakingChanges() int {
|
func (r *ResponseChanges) TotalBreakingChanges() int {
|
||||||
c := r.PropertyChanges.TotalBreakingChanges()
|
c := r.PropertyChanges.TotalBreakingChanges()
|
||||||
if r.SchemaChanges != nil {
|
if r.SchemaChanges != nil {
|
||||||
c += r.SchemaChanges.TotalBreakingChanges()
|
c += r.SchemaChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
for k := range r.HeadersChanges {
|
for k := range r.HeadersChanges {
|
||||||
c += r.HeadersChanges[k].TotalBreakingChanges()
|
c += r.HeadersChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
for k := range r.ContentChanges {
|
for k := range r.ContentChanges {
|
||||||
c += r.ContentChanges[k].TotalBreakingChanges()
|
c += r.ContentChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
for k := range r.LinkChanges {
|
for k := range r.LinkChanges {
|
||||||
c += r.LinkChanges[k].TotalBreakingChanges()
|
c += r.LinkChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareResponseV2 is a Swagger type safe proxy for CompareResponse
|
// CompareResponseV2 is a Swagger type safe proxy for CompareResponse
|
||||||
func CompareResponseV2(l, r *v2.Response) *ResponseChanges {
|
func CompareResponseV2(l, r *v2.Response) *ResponseChanges {
|
||||||
return CompareResponse(l, r)
|
return CompareResponse(l, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareResponseV3 is an OpenAPI type safe proxy for CompareResponse
|
// CompareResponseV3 is an OpenAPI type safe proxy for CompareResponse
|
||||||
func CompareResponseV3(l, r *v3.Response) *ResponseChanges {
|
func CompareResponseV3(l, r *v3.Response) *ResponseChanges {
|
||||||
return CompareResponse(l, r)
|
return CompareResponse(l, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareResponse compares a left and right Swagger or OpenAPI Response object. If anything is found
|
// CompareResponse compares a left and right Swagger or OpenAPI Response object. If anything is found
|
||||||
// a pointer to a ResponseChanges is returned, otherwise it returns nil.
|
// a pointer to a ResponseChanges is returned, otherwise it returns nil.
|
||||||
func CompareResponse(l, r any) *ResponseChanges {
|
func CompareResponse(l, r any) *ResponseChanges {
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
rc := new(ResponseChanges)
|
rc := new(ResponseChanges)
|
||||||
|
|
||||||
if reflect.TypeOf(&v2.Response{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Response{}) == reflect.TypeOf(r) {
|
if reflect.TypeOf(&v2.Response{}) == reflect.TypeOf(l) && reflect.TypeOf(&v2.Response{}) == reflect.TypeOf(r) {
|
||||||
|
|
||||||
lResponse := l.(*v2.Response)
|
lResponse := l.(*v2.Response)
|
||||||
rResponse := r.(*v2.Response)
|
rResponse := r.(*v2.Response)
|
||||||
|
|
||||||
// perform hash check to avoid further processing
|
// perform hash check to avoid further processing
|
||||||
if low.AreEqual(lResponse, rResponse) {
|
if low.AreEqual(lResponse, rResponse) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// description
|
// description
|
||||||
addPropertyCheck(&props, lResponse.Description.ValueNode, rResponse.Description.ValueNode,
|
addPropertyCheck(&props, lResponse.Description.ValueNode, rResponse.Description.ValueNode,
|
||||||
lResponse.Description.Value, rResponse.Description.Value, &changes, v3.DescriptionLabel, false)
|
lResponse.Description.Value, rResponse.Description.Value, &changes, v3.DescriptionLabel, false)
|
||||||
|
|
||||||
if !lResponse.Schema.IsEmpty() && !rResponse.Schema.IsEmpty() {
|
if !lResponse.Schema.IsEmpty() && !rResponse.Schema.IsEmpty() {
|
||||||
rc.SchemaChanges = CompareSchemas(lResponse.Schema.Value, rResponse.Schema.Value)
|
rc.SchemaChanges = CompareSchemas(lResponse.Schema.Value, rResponse.Schema.Value)
|
||||||
}
|
}
|
||||||
if !lResponse.Schema.IsEmpty() && rResponse.Schema.IsEmpty() {
|
if !lResponse.Schema.IsEmpty() && rResponse.Schema.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.SchemaLabel,
|
CreateChange(&changes, ObjectRemoved, v3.SchemaLabel,
|
||||||
lResponse.Schema.ValueNode, nil, true,
|
lResponse.Schema.ValueNode, nil, true,
|
||||||
lResponse.Schema.Value, nil)
|
lResponse.Schema.Value, nil)
|
||||||
}
|
}
|
||||||
if lResponse.Schema.IsEmpty() && !rResponse.Schema.IsEmpty() {
|
if lResponse.Schema.IsEmpty() && !rResponse.Schema.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectAdded, v3.SchemaLabel,
|
CreateChange(&changes, ObjectAdded, v3.SchemaLabel,
|
||||||
nil, rResponse.Schema.ValueNode, true,
|
nil, rResponse.Schema.ValueNode, true,
|
||||||
nil, rResponse.Schema.Value)
|
nil, rResponse.Schema.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
rc.HeadersChanges =
|
rc.HeadersChanges =
|
||||||
CheckMapForChanges(lResponse.Headers.Value, rResponse.Headers.Value,
|
CheckMapForChanges(lResponse.Headers.Value, rResponse.Headers.Value,
|
||||||
&changes, v3.HeadersLabel, CompareHeadersV2)
|
&changes, v3.HeadersLabel, CompareHeadersV2)
|
||||||
|
|
||||||
if !lResponse.Examples.IsEmpty() && !rResponse.Examples.IsEmpty() {
|
if !lResponse.Examples.IsEmpty() && !rResponse.Examples.IsEmpty() {
|
||||||
rc.ExamplesChanges = CompareExamplesV2(lResponse.Examples.Value, rResponse.Examples.Value)
|
rc.ExamplesChanges = CompareExamplesV2(lResponse.Examples.Value, rResponse.Examples.Value)
|
||||||
}
|
}
|
||||||
if !lResponse.Examples.IsEmpty() && rResponse.Examples.IsEmpty() {
|
if !lResponse.Examples.IsEmpty() && rResponse.Examples.IsEmpty() {
|
||||||
CreateChange(&changes, PropertyRemoved, v3.ExamplesLabel,
|
CreateChange(&changes, PropertyRemoved, v3.ExamplesLabel,
|
||||||
lResponse.Schema.ValueNode, nil, false,
|
lResponse.Schema.ValueNode, nil, false,
|
||||||
lResponse.Schema.Value, nil)
|
lResponse.Schema.Value, nil)
|
||||||
}
|
}
|
||||||
if lResponse.Examples.IsEmpty() && !rResponse.Examples.IsEmpty() {
|
if lResponse.Examples.IsEmpty() && !rResponse.Examples.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectAdded, v3.ExamplesLabel,
|
CreateChange(&changes, ObjectAdded, v3.ExamplesLabel,
|
||||||
nil, rResponse.Schema.ValueNode, false,
|
nil, rResponse.Schema.ValueNode, false,
|
||||||
nil, lResponse.Schema.Value)
|
nil, lResponse.Schema.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
rc.ExtensionChanges = CompareExtensions(lResponse.Extensions, rResponse.Extensions)
|
rc.ExtensionChanges = CompareExtensions(lResponse.Extensions, rResponse.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
if reflect.TypeOf(&v3.Response{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Response{}) == reflect.TypeOf(r) {
|
if reflect.TypeOf(&v3.Response{}) == reflect.TypeOf(l) && reflect.TypeOf(&v3.Response{}) == reflect.TypeOf(r) {
|
||||||
|
|
||||||
lResponse := l.(*v3.Response)
|
lResponse := l.(*v3.Response)
|
||||||
rResponse := r.(*v3.Response)
|
rResponse := r.(*v3.Response)
|
||||||
|
|
||||||
// perform hash check to avoid further processing
|
// perform hash check to avoid further processing
|
||||||
if low.AreEqual(lResponse, rResponse) {
|
if low.AreEqual(lResponse, rResponse) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// description
|
// description
|
||||||
addPropertyCheck(&props, lResponse.Description.ValueNode, rResponse.Description.ValueNode,
|
addPropertyCheck(&props, lResponse.Description.ValueNode, rResponse.Description.ValueNode,
|
||||||
lResponse.Description.Value, lResponse.Description.Value, &changes, v3.DescriptionLabel, false)
|
lResponse.Description.Value, lResponse.Description.Value, &changes, v3.DescriptionLabel, false)
|
||||||
|
|
||||||
rc.HeadersChanges =
|
rc.HeadersChanges =
|
||||||
CheckMapForChanges(lResponse.Headers.Value, rResponse.Headers.Value,
|
CheckMapForChanges(lResponse.Headers.Value, rResponse.Headers.Value,
|
||||||
&changes, v3.HeadersLabel, CompareHeadersV3)
|
&changes, v3.HeadersLabel, CompareHeadersV3)
|
||||||
|
|
||||||
rc.ContentChanges =
|
rc.ContentChanges =
|
||||||
CheckMapForChanges(lResponse.Content.Value, rResponse.Content.Value,
|
CheckMapForChanges(lResponse.Content.Value, rResponse.Content.Value,
|
||||||
&changes, v3.ContentLabel, CompareMediaTypes)
|
&changes, v3.ContentLabel, CompareMediaTypes)
|
||||||
|
|
||||||
rc.LinkChanges =
|
rc.LinkChanges =
|
||||||
CheckMapForChanges(lResponse.Links.Value, rResponse.Links.Value,
|
CheckMapForChanges(lResponse.Links.Value, rResponse.Links.Value,
|
||||||
&changes, v3.LinksLabel, CompareLinks)
|
&changes, v3.LinksLabel, CompareLinks)
|
||||||
|
|
||||||
rc.ExtensionChanges = CompareExtensions(lResponse.Extensions, rResponse.Extensions)
|
rc.ExtensionChanges = CompareExtensions(lResponse.Extensions, rResponse.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
rc.Changes = changes
|
rc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
if rc.TotalChanges() <= 0 {
|
if rc.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return rc
|
return rc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,121 +4,121 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResponsesChanges represents changes made between two Swagger or OpenAPI Responses objects.
|
// ResponsesChanges represents changes made between two Swagger or OpenAPI Responses objects.
|
||||||
type ResponsesChanges struct {
|
type ResponsesChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ResponseChanges map[string]*ResponseChanges `json:"response,omitempty" yaml:"response,omitempty"`
|
ResponseChanges map[string]*ResponseChanges `json:"response,omitempty" yaml:"response,omitempty"`
|
||||||
DefaultChanges *ResponseChanges `json:"default,omitempty" yaml:"default,omitempty"`
|
DefaultChanges *ResponseChanges `json:"default,omitempty" yaml:"default,omitempty"`
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns the total number of changes found between two Swagger or OpenAPI Responses objects
|
// TotalChanges returns the total number of changes found between two Swagger or OpenAPI Responses objects
|
||||||
func (r *ResponsesChanges) TotalChanges() int {
|
func (r *ResponsesChanges) TotalChanges() int {
|
||||||
c := r.PropertyChanges.TotalChanges()
|
c := r.PropertyChanges.TotalChanges()
|
||||||
for k := range r.ResponseChanges {
|
for k := range r.ResponseChanges {
|
||||||
c += r.ResponseChanges[k].TotalChanges()
|
c += r.ResponseChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
if r.DefaultChanges != nil {
|
if r.DefaultChanges != nil {
|
||||||
c += r.DefaultChanges.TotalChanges()
|
c += r.DefaultChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
if r.ExtensionChanges != nil {
|
if r.ExtensionChanges != nil {
|
||||||
c += r.ExtensionChanges.TotalChanges()
|
c += r.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the total number of changes found between two Swagger or OpenAPI
|
// TotalBreakingChanges returns the total number of changes found between two Swagger or OpenAPI
|
||||||
// Responses Objects
|
// Responses Objects
|
||||||
func (r *ResponsesChanges) TotalBreakingChanges() int {
|
func (r *ResponsesChanges) TotalBreakingChanges() int {
|
||||||
c := r.PropertyChanges.TotalBreakingChanges()
|
c := r.PropertyChanges.TotalBreakingChanges()
|
||||||
for k := range r.ResponseChanges {
|
for k := range r.ResponseChanges {
|
||||||
c += r.ResponseChanges[k].TotalBreakingChanges()
|
c += r.ResponseChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
if r.DefaultChanges != nil {
|
if r.DefaultChanges != nil {
|
||||||
c += r.DefaultChanges.TotalBreakingChanges()
|
c += r.DefaultChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareResponses compares a left and right Swagger or OpenAPI Responses object for any changes. If found
|
// CompareResponses compares a left and right Swagger or OpenAPI Responses object for any changes. If found
|
||||||
// returns a pointer to ResponsesChanges, or returns nil.
|
// returns a pointer to ResponsesChanges, or returns nil.
|
||||||
func CompareResponses(l, r any) *ResponsesChanges {
|
func CompareResponses(l, r any) *ResponsesChanges {
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
|
|
||||||
rc := new(ResponsesChanges)
|
rc := new(ResponsesChanges)
|
||||||
|
|
||||||
// swagger
|
// swagger
|
||||||
if reflect.TypeOf(&v2.Responses{}) == reflect.TypeOf(l) &&
|
if reflect.TypeOf(&v2.Responses{}) == reflect.TypeOf(l) &&
|
||||||
reflect.TypeOf(&v2.Responses{}) == reflect.TypeOf(r) {
|
reflect.TypeOf(&v2.Responses{}) == reflect.TypeOf(r) {
|
||||||
|
|
||||||
lResponses := l.(*v2.Responses)
|
lResponses := l.(*v2.Responses)
|
||||||
rResponses := r.(*v2.Responses)
|
rResponses := r.(*v2.Responses)
|
||||||
|
|
||||||
// perform hash check to avoid further processing
|
// perform hash check to avoid further processing
|
||||||
if low.AreEqual(lResponses, rResponses) {
|
if low.AreEqual(lResponses, rResponses) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() {
|
if !lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() {
|
||||||
rc.DefaultChanges = CompareResponse(lResponses.Default.Value, rResponses.Default.Value)
|
rc.DefaultChanges = CompareResponse(lResponses.Default.Value, rResponses.Default.Value)
|
||||||
}
|
}
|
||||||
if !lResponses.Default.IsEmpty() && rResponses.Default.IsEmpty() {
|
if !lResponses.Default.IsEmpty() && rResponses.Default.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.DefaultLabel,
|
CreateChange(&changes, ObjectRemoved, v3.DefaultLabel,
|
||||||
lResponses.Default.ValueNode, nil, true,
|
lResponses.Default.ValueNode, nil, true,
|
||||||
lResponses.Default.Value, nil)
|
lResponses.Default.Value, nil)
|
||||||
}
|
}
|
||||||
if lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() {
|
if lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectAdded, v3.DefaultLabel,
|
CreateChange(&changes, ObjectAdded, v3.DefaultLabel,
|
||||||
nil, rResponses.Default.ValueNode, false,
|
nil, rResponses.Default.ValueNode, false,
|
||||||
nil, lResponses.Default.Value)
|
nil, lResponses.Default.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
rc.ResponseChanges = CheckMapForChanges(lResponses.Codes, rResponses.Codes,
|
rc.ResponseChanges = CheckMapForChanges(lResponses.Codes, rResponses.Codes,
|
||||||
&changes, v3.CodesLabel, CompareResponseV2)
|
&changes, v3.CodesLabel, CompareResponseV2)
|
||||||
|
|
||||||
rc.ExtensionChanges = CompareExtensions(lResponses.Extensions, rResponses.Extensions)
|
rc.ExtensionChanges = CompareExtensions(lResponses.Extensions, rResponses.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// openapi
|
// openapi
|
||||||
if reflect.TypeOf(&v3.Responses{}) == reflect.TypeOf(l) &&
|
if reflect.TypeOf(&v3.Responses{}) == reflect.TypeOf(l) &&
|
||||||
reflect.TypeOf(&v3.Responses{}) == reflect.TypeOf(r) {
|
reflect.TypeOf(&v3.Responses{}) == reflect.TypeOf(r) {
|
||||||
|
|
||||||
lResponses := l.(*v3.Responses)
|
lResponses := l.(*v3.Responses)
|
||||||
rResponses := r.(*v3.Responses)
|
rResponses := r.(*v3.Responses)
|
||||||
|
|
||||||
//perform hash check to avoid further processing
|
//perform hash check to avoid further processing
|
||||||
if low.AreEqual(lResponses, rResponses) {
|
if low.AreEqual(lResponses, rResponses) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() {
|
if !lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() {
|
||||||
rc.DefaultChanges = CompareResponse(lResponses.Default.Value, rResponses.Default.Value)
|
rc.DefaultChanges = CompareResponse(lResponses.Default.Value, rResponses.Default.Value)
|
||||||
}
|
}
|
||||||
if !lResponses.Default.IsEmpty() && rResponses.Default.IsEmpty() {
|
if !lResponses.Default.IsEmpty() && rResponses.Default.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.DefaultLabel,
|
CreateChange(&changes, ObjectRemoved, v3.DefaultLabel,
|
||||||
lResponses.Default.ValueNode, nil, true,
|
lResponses.Default.ValueNode, nil, true,
|
||||||
lResponses.Default.Value, nil)
|
lResponses.Default.Value, nil)
|
||||||
}
|
}
|
||||||
if lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() {
|
if lResponses.Default.IsEmpty() && !rResponses.Default.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectAdded, v3.DefaultLabel,
|
CreateChange(&changes, ObjectAdded, v3.DefaultLabel,
|
||||||
nil, rResponses.Default.ValueNode, false,
|
nil, rResponses.Default.ValueNode, false,
|
||||||
nil, lResponses.Default.Value)
|
nil, lResponses.Default.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
rc.ResponseChanges = CheckMapForChanges(lResponses.Codes, rResponses.Codes,
|
rc.ResponseChanges = CheckMapForChanges(lResponses.Codes, rResponses.Codes,
|
||||||
&changes, v3.CodesLabel, CompareResponseV3)
|
&changes, v3.CodesLabel, CompareResponseV3)
|
||||||
|
|
||||||
rc.ExtensionChanges = CompareExtensions(lResponses.Extensions, rResponses.Extensions)
|
rc.ExtensionChanges = CompareExtensions(lResponses.Extensions, rResponses.Extensions)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rc.Changes = changes
|
rc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
return rc
|
return rc
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4,63 +4,63 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ScopesChanges represents changes between two Swagger Scopes Objects
|
// ScopesChanges represents changes between two Swagger Scopes Objects
|
||||||
type ScopesChanges struct {
|
type ScopesChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns the total changes found between two Swagger Scopes objects.
|
// TotalChanges returns the total changes found between two Swagger Scopes objects.
|
||||||
func (s *ScopesChanges) TotalChanges() int {
|
func (s *ScopesChanges) TotalChanges() int {
|
||||||
c := s.PropertyChanges.TotalChanges()
|
c := s.PropertyChanges.TotalChanges()
|
||||||
if s.ExtensionChanges != nil {
|
if s.ExtensionChanges != nil {
|
||||||
c += s.ExtensionChanges.TotalChanges()
|
c += s.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the total number of breaking changes between two Swagger Scopes objects.
|
// TotalBreakingChanges returns the total number of breaking changes between two Swagger Scopes objects.
|
||||||
func (s *ScopesChanges) TotalBreakingChanges() int {
|
func (s *ScopesChanges) TotalBreakingChanges() int {
|
||||||
return s.PropertyChanges.TotalBreakingChanges()
|
return s.PropertyChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareScopes compares a left and right Swagger Scopes objects for changes. If anything is found, returns
|
// CompareScopes compares a left and right Swagger Scopes objects for changes. If anything is found, returns
|
||||||
// a pointer to ScopesChanges, or returns nil if nothing is found.
|
// a pointer to ScopesChanges, or returns nil if nothing is found.
|
||||||
func CompareScopes(l, r *v2.Scopes) *ScopesChanges {
|
func CompareScopes(l, r *v2.Scopes) *ScopesChanges {
|
||||||
if low.AreEqual(l, r) {
|
if low.AreEqual(l, r) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
for v := range l.Values {
|
for v := range l.Values {
|
||||||
if r != nil && r.FindScope(v.Value) == nil {
|
if r != nil && r.FindScope(v.Value) == nil {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.Scopes,
|
CreateChange(&changes, ObjectRemoved, v3.Scopes,
|
||||||
l.Values[v].ValueNode, nil, true,
|
l.Values[v].ValueNode, nil, true,
|
||||||
v.Value, nil)
|
v.Value, nil)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if r != nil && r.FindScope(v.Value) != nil {
|
if r != nil && r.FindScope(v.Value) != nil {
|
||||||
if l.Values[v].Value != r.FindScope(v.Value).Value {
|
if l.Values[v].Value != r.FindScope(v.Value).Value {
|
||||||
CreateChange(&changes, Modified, v3.Scopes,
|
CreateChange(&changes, Modified, v3.Scopes,
|
||||||
l.Values[v].ValueNode, r.FindScope(v.Value).ValueNode, true,
|
l.Values[v].ValueNode, r.FindScope(v.Value).ValueNode, true,
|
||||||
l.Values[v].Value, r.FindScope(v.Value).Value)
|
l.Values[v].Value, r.FindScope(v.Value).Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for v := range r.Values {
|
for v := range r.Values {
|
||||||
if l != nil && l.FindScope(v.Value) == nil {
|
if l != nil && l.FindScope(v.Value) == nil {
|
||||||
CreateChange(&changes, ObjectAdded, v3.Scopes,
|
CreateChange(&changes, ObjectAdded, v3.Scopes,
|
||||||
nil, r.Values[v].ValueNode, false,
|
nil, r.Values[v].ValueNode, false,
|
||||||
nil, v.Value)
|
nil, v.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sc := new(ScopesChanges)
|
sc := new(ScopesChanges)
|
||||||
sc.Changes = changes
|
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
sc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
sc.ExtensionChanges = CompareExtensions(l.Extensions, r.Extensions)
|
||||||
return sc
|
return sc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,142 +4,142 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SecurityRequirementChanges represents changes found between two SecurityRequirement Objects.
|
// SecurityRequirementChanges represents changes found between two SecurityRequirement Objects.
|
||||||
type SecurityRequirementChanges struct {
|
type SecurityRequirementChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns the total number of changes between two SecurityRequirement Objects.
|
// TotalChanges returns the total number of changes between two SecurityRequirement Objects.
|
||||||
func (s *SecurityRequirementChanges) TotalChanges() int {
|
func (s *SecurityRequirementChanges) TotalChanges() int {
|
||||||
return s.PropertyChanges.TotalChanges()
|
return s.PropertyChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the total number of breaking changes between two SecurityRequirement Objects.
|
// TotalBreakingChanges returns the total number of breaking changes between two SecurityRequirement Objects.
|
||||||
func (s *SecurityRequirementChanges) TotalBreakingChanges() int {
|
func (s *SecurityRequirementChanges) TotalBreakingChanges() int {
|
||||||
return s.PropertyChanges.TotalBreakingChanges()
|
return s.PropertyChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareSecurityRequirement compares left and right SecurityRequirement objects for changes. If anything
|
// CompareSecurityRequirement compares left and right SecurityRequirement objects for changes. If anything
|
||||||
// is found, then a pointer to SecurityRequirementChanges is returned, otherwise nil.
|
// is found, then a pointer to SecurityRequirementChanges is returned, otherwise nil.
|
||||||
func CompareSecurityRequirement(l, r *base.SecurityRequirement) *SecurityRequirementChanges {
|
func CompareSecurityRequirement(l, r *base.SecurityRequirement) *SecurityRequirementChanges {
|
||||||
|
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
sc := new(SecurityRequirementChanges)
|
sc := new(SecurityRequirementChanges)
|
||||||
|
|
||||||
if low.AreEqual(l, r) {
|
if low.AreEqual(l, r) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
checkSecurityRequirement(l.Requirements.Value, r.Requirements.Value, &changes)
|
checkSecurityRequirement(l.Requirements.Value, r.Requirements.Value, &changes)
|
||||||
sc.Changes = changes
|
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
return sc
|
return sc
|
||||||
}
|
}
|
||||||
|
|
||||||
func removedSecurityRequirement(vn *yaml.Node, name string, changes *[]*Change) {
|
func removedSecurityRequirement(vn *yaml.Node, name string, changes *[]*Change) {
|
||||||
CreateChange(changes, ObjectRemoved, v3.SecurityLabel,
|
CreateChange(changes, ObjectRemoved, v3.SecurityLabel,
|
||||||
vn, nil, true, name, nil)
|
vn, nil, true, name, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func addedSecurityRequirement(vn *yaml.Node, name string, changes *[]*Change) {
|
func addedSecurityRequirement(vn *yaml.Node, name string, changes *[]*Change) {
|
||||||
CreateChange(changes, ObjectAdded, v3.SecurityLabel,
|
CreateChange(changes, ObjectAdded, v3.SecurityLabel,
|
||||||
nil, vn, false, nil, name)
|
nil, vn, false, nil, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// tricky to do this correctly, this is my solution.
|
// tricky to do this correctly, this is my solution.
|
||||||
func checkSecurityRequirement(lSec, rSec map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]],
|
func checkSecurityRequirement(lSec, rSec map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]],
|
||||||
changes *[]*Change) {
|
changes *[]*Change) {
|
||||||
|
|
||||||
lKeys := make([]string, len(lSec))
|
lKeys := make([]string, len(lSec))
|
||||||
rKeys := make([]string, len(rSec))
|
rKeys := make([]string, len(rSec))
|
||||||
lValues := make(map[string]low.ValueReference[[]low.ValueReference[string]])
|
lValues := make(map[string]low.ValueReference[[]low.ValueReference[string]])
|
||||||
rValues := make(map[string]low.ValueReference[[]low.ValueReference[string]])
|
rValues := make(map[string]low.ValueReference[[]low.ValueReference[string]])
|
||||||
var n, z int
|
var n, z int
|
||||||
for i := range lSec {
|
for i := range lSec {
|
||||||
lKeys[n] = i.Value
|
lKeys[n] = i.Value
|
||||||
lValues[i.Value] = lSec[i]
|
lValues[i.Value] = lSec[i]
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
for i := range rSec {
|
for i := range rSec {
|
||||||
rKeys[z] = i.Value
|
rKeys[z] = i.Value
|
||||||
rValues[i.Value] = rSec[i]
|
rValues[i.Value] = rSec[i]
|
||||||
z++
|
z++
|
||||||
}
|
}
|
||||||
|
|
||||||
for z = range lKeys {
|
for z = range lKeys {
|
||||||
if z < len(rKeys) {
|
if z < len(rKeys) {
|
||||||
if _, ok := rValues[lKeys[z]]; !ok {
|
if _, ok := rValues[lKeys[z]]; !ok {
|
||||||
removedSecurityRequirement(lValues[lKeys[z]].ValueNode, lKeys[z], changes)
|
removedSecurityRequirement(lValues[lKeys[z]].ValueNode, lKeys[z], changes)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
lValue := lValues[lKeys[z]].Value
|
lValue := lValues[lKeys[z]].Value
|
||||||
rValue := rValues[lKeys[z]].Value
|
rValue := rValues[lKeys[z]].Value
|
||||||
|
|
||||||
// check if actual values match up
|
// check if actual values match up
|
||||||
lRoleKeys := make([]string, len(lValue))
|
lRoleKeys := make([]string, len(lValue))
|
||||||
rRoleKeys := make([]string, len(rValue))
|
rRoleKeys := make([]string, len(rValue))
|
||||||
lRoleValues := make(map[string]low.ValueReference[string])
|
lRoleValues := make(map[string]low.ValueReference[string])
|
||||||
rRoleValues := make(map[string]low.ValueReference[string])
|
rRoleValues := make(map[string]low.ValueReference[string])
|
||||||
var t, k int
|
var t, k int
|
||||||
for i := range lValue {
|
for i := range lValue {
|
||||||
lRoleKeys[t] = lValue[i].Value
|
lRoleKeys[t] = lValue[i].Value
|
||||||
lRoleValues[lValue[i].Value] = lValue[i]
|
lRoleValues[lValue[i].Value] = lValue[i]
|
||||||
t++
|
t++
|
||||||
}
|
}
|
||||||
for i := range rValue {
|
for i := range rValue {
|
||||||
rRoleKeys[k] = rValue[i].Value
|
rRoleKeys[k] = rValue[i].Value
|
||||||
rRoleValues[rValue[i].Value] = rValue[i]
|
rRoleValues[rValue[i].Value] = rValue[i]
|
||||||
k++
|
k++
|
||||||
}
|
}
|
||||||
|
|
||||||
for t = range lRoleKeys {
|
for t = range lRoleKeys {
|
||||||
if t < len(rRoleKeys) {
|
if t < len(rRoleKeys) {
|
||||||
if _, ok := rRoleValues[lRoleKeys[t]]; !ok {
|
if _, ok := rRoleValues[lRoleKeys[t]]; !ok {
|
||||||
removedSecurityRequirement(lRoleValues[lRoleKeys[t]].ValueNode, lRoleKeys[t], changes)
|
removedSecurityRequirement(lRoleValues[lRoleKeys[t]].ValueNode, lRoleKeys[t], changes)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t >= len(rRoleKeys) {
|
if t >= len(rRoleKeys) {
|
||||||
if _, ok := rRoleValues[lRoleKeys[t]]; !ok {
|
if _, ok := rRoleValues[lRoleKeys[t]]; !ok {
|
||||||
removedSecurityRequirement(lRoleValues[lRoleKeys[t]].ValueNode, lRoleKeys[t], changes)
|
removedSecurityRequirement(lRoleValues[lRoleKeys[t]].ValueNode, lRoleKeys[t], changes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for t = range rRoleKeys {
|
for t = range rRoleKeys {
|
||||||
if t < len(lRoleKeys) {
|
if t < len(lRoleKeys) {
|
||||||
if _, ok := lRoleValues[rRoleKeys[t]]; !ok {
|
if _, ok := lRoleValues[rRoleKeys[t]]; !ok {
|
||||||
addedSecurityRequirement(rRoleValues[rRoleKeys[t]].ValueNode, rRoleKeys[t], changes)
|
addedSecurityRequirement(rRoleValues[rRoleKeys[t]].ValueNode, rRoleKeys[t], changes)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t >= len(lRoleKeys) {
|
if t >= len(lRoleKeys) {
|
||||||
addedSecurityRequirement(rRoleValues[rRoleKeys[t]].ValueNode, rRoleKeys[t], changes)
|
addedSecurityRequirement(rRoleValues[rRoleKeys[t]].ValueNode, rRoleKeys[t], changes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if z >= len(rKeys) {
|
if z >= len(rKeys) {
|
||||||
if _, ok := rValues[lKeys[z]]; !ok {
|
if _, ok := rValues[lKeys[z]]; !ok {
|
||||||
removedSecurityRequirement(lValues[lKeys[z]].ValueNode, lKeys[z], changes)
|
removedSecurityRequirement(lValues[lKeys[z]].ValueNode, lKeys[z], changes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for z = range rKeys {
|
for z = range rKeys {
|
||||||
if z < len(lKeys) {
|
if z < len(lKeys) {
|
||||||
if _, ok := lValues[rKeys[z]]; !ok {
|
if _, ok := lValues[rKeys[z]]; !ok {
|
||||||
addedSecurityRequirement(rValues[rKeys[z]].ValueNode, rKeys[z], changes)
|
addedSecurityRequirement(rValues[rKeys[z]].ValueNode, rKeys[z], changes)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if z >= len(lKeys) {
|
if z >= len(lKeys) {
|
||||||
if _, ok := lValues[rKeys[z]]; !ok {
|
if _, ok := lValues[rKeys[z]]; !ok {
|
||||||
addedSecurityRequirement(rValues[rKeys[z]].ValueNode, rKeys[z], changes)
|
addedSecurityRequirement(rValues[rKeys[z]].ValueNode, rKeys[z], changes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,162 +4,162 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
"github.com/pb33f/libopenapi/datamodel/low/v2"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SecuritySchemeChanges represents changes made between Swagger or OpenAPI SecurityScheme Objects.
|
// SecuritySchemeChanges represents changes made between Swagger or OpenAPI SecurityScheme Objects.
|
||||||
type SecuritySchemeChanges struct {
|
type SecuritySchemeChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
|
|
||||||
// OpenAPI Version
|
// OpenAPI Version
|
||||||
OAuthFlowChanges *OAuthFlowsChanges `json:"oAuthFlow,omitempty" yaml:"oAuthFlow,omitempty"`
|
OAuthFlowChanges *OAuthFlowsChanges `json:"oAuthFlow,omitempty" yaml:"oAuthFlow,omitempty"`
|
||||||
|
|
||||||
// Swagger Version
|
// Swagger Version
|
||||||
ScopesChanges *ScopesChanges `json:"scopes,omitempty" yaml:"scopes,omitempty"`
|
ScopesChanges *ScopesChanges `json:"scopes,omitempty" yaml:"scopes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges represents total changes found between two Swagger or OpenAPI SecurityScheme instances.
|
// TotalChanges represents total changes found between two Swagger or OpenAPI SecurityScheme instances.
|
||||||
func (ss *SecuritySchemeChanges) TotalChanges() int {
|
func (ss *SecuritySchemeChanges) TotalChanges() int {
|
||||||
c := ss.PropertyChanges.TotalChanges()
|
c := ss.PropertyChanges.TotalChanges()
|
||||||
if ss.OAuthFlowChanges != nil {
|
if ss.OAuthFlowChanges != nil {
|
||||||
c += ss.OAuthFlowChanges.TotalChanges()
|
c += ss.OAuthFlowChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
if ss.ScopesChanges != nil {
|
if ss.ScopesChanges != nil {
|
||||||
c += ss.ScopesChanges.TotalChanges()
|
c += ss.ScopesChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
if ss.ExtensionChanges != nil {
|
if ss.ExtensionChanges != nil {
|
||||||
c += ss.ExtensionChanges.TotalChanges()
|
c += ss.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns total number of breaking changes between two SecurityScheme Objects.
|
// TotalBreakingChanges returns total number of breaking changes between two SecurityScheme Objects.
|
||||||
func (ss *SecuritySchemeChanges) TotalBreakingChanges() int {
|
func (ss *SecuritySchemeChanges) TotalBreakingChanges() int {
|
||||||
c := ss.PropertyChanges.TotalBreakingChanges()
|
c := ss.PropertyChanges.TotalBreakingChanges()
|
||||||
if ss.OAuthFlowChanges != nil {
|
if ss.OAuthFlowChanges != nil {
|
||||||
c += ss.OAuthFlowChanges.TotalBreakingChanges()
|
c += ss.OAuthFlowChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
if ss.ScopesChanges != nil {
|
if ss.ScopesChanges != nil {
|
||||||
c += ss.ScopesChanges.TotalBreakingChanges()
|
c += ss.ScopesChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareSecuritySchemesV2 is a Swagger type safe proxy for CompareSecuritySchemes
|
// CompareSecuritySchemesV2 is a Swagger type safe proxy for CompareSecuritySchemes
|
||||||
func CompareSecuritySchemesV2(l, r *v2.SecurityScheme) *SecuritySchemeChanges {
|
func CompareSecuritySchemesV2(l, r *v2.SecurityScheme) *SecuritySchemeChanges {
|
||||||
return CompareSecuritySchemes(l, r)
|
return CompareSecuritySchemes(l, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareSecuritySchemesV3 is an OpenAPI type safe proxt for CompareSecuritySchemes
|
// CompareSecuritySchemesV3 is an OpenAPI type safe proxt for CompareSecuritySchemes
|
||||||
func CompareSecuritySchemesV3(l, r *v3.SecurityScheme) *SecuritySchemeChanges {
|
func CompareSecuritySchemesV3(l, r *v3.SecurityScheme) *SecuritySchemeChanges {
|
||||||
return CompareSecuritySchemes(l, r)
|
return CompareSecuritySchemes(l, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareSecuritySchemes compares left and right Swagger or OpenAPI Security Scheme objects for changes.
|
// CompareSecuritySchemes compares left and right Swagger or OpenAPI Security Scheme objects for changes.
|
||||||
// If anything is found, returns a pointer to *SecuritySchemeChanges or nil if nothing is found.
|
// If anything is found, returns a pointer to *SecuritySchemeChanges or nil if nothing is found.
|
||||||
func CompareSecuritySchemes(l, r any) *SecuritySchemeChanges {
|
func CompareSecuritySchemes(l, r any) *SecuritySchemeChanges {
|
||||||
|
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
|
|
||||||
sc := new(SecuritySchemeChanges)
|
sc := new(SecuritySchemeChanges)
|
||||||
if reflect.TypeOf(&v2.SecurityScheme{}) == reflect.TypeOf(l) &&
|
if reflect.TypeOf(&v2.SecurityScheme{}) == reflect.TypeOf(l) &&
|
||||||
reflect.TypeOf(&v2.SecurityScheme{}) == reflect.TypeOf(r) {
|
reflect.TypeOf(&v2.SecurityScheme{}) == reflect.TypeOf(r) {
|
||||||
|
|
||||||
lSS := l.(*v2.SecurityScheme)
|
lSS := l.(*v2.SecurityScheme)
|
||||||
rSS := r.(*v2.SecurityScheme)
|
rSS := r.(*v2.SecurityScheme)
|
||||||
|
|
||||||
if low.AreEqual(lSS, rSS) {
|
if low.AreEqual(lSS, rSS) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
addPropertyCheck(&props, lSS.Type.ValueNode, rSS.Type.ValueNode,
|
addPropertyCheck(&props, lSS.Type.ValueNode, rSS.Type.ValueNode,
|
||||||
lSS.Type.Value, rSS.Type.Value, &changes, v3.TypeLabel, true)
|
lSS.Type.Value, rSS.Type.Value, &changes, v3.TypeLabel, true)
|
||||||
|
|
||||||
addPropertyCheck(&props, lSS.Description.ValueNode, rSS.Description.ValueNode,
|
addPropertyCheck(&props, lSS.Description.ValueNode, rSS.Description.ValueNode,
|
||||||
lSS.Description.Value, rSS.Description.Value, &changes, v3.DescriptionLabel, false)
|
lSS.Description.Value, rSS.Description.Value, &changes, v3.DescriptionLabel, false)
|
||||||
|
|
||||||
addPropertyCheck(&props, lSS.Name.ValueNode, rSS.Name.ValueNode,
|
addPropertyCheck(&props, lSS.Name.ValueNode, rSS.Name.ValueNode,
|
||||||
lSS.Name.Value, rSS.Name.Value, &changes, v3.NameLabel, true)
|
lSS.Name.Value, rSS.Name.Value, &changes, v3.NameLabel, true)
|
||||||
|
|
||||||
addPropertyCheck(&props, lSS.In.ValueNode, rSS.In.ValueNode,
|
addPropertyCheck(&props, lSS.In.ValueNode, rSS.In.ValueNode,
|
||||||
lSS.In.Value, rSS.In.Value, &changes, v3.InLabel, true)
|
lSS.In.Value, rSS.In.Value, &changes, v3.InLabel, true)
|
||||||
|
|
||||||
addPropertyCheck(&props, lSS.Flow.ValueNode, rSS.Flow.ValueNode,
|
addPropertyCheck(&props, lSS.Flow.ValueNode, rSS.Flow.ValueNode,
|
||||||
lSS.Flow.Value, rSS.Flow.Value, &changes, v3.FlowLabel, true)
|
lSS.Flow.Value, rSS.Flow.Value, &changes, v3.FlowLabel, true)
|
||||||
|
|
||||||
addPropertyCheck(&props, lSS.AuthorizationUrl.ValueNode, rSS.AuthorizationUrl.ValueNode,
|
addPropertyCheck(&props, lSS.AuthorizationUrl.ValueNode, rSS.AuthorizationUrl.ValueNode,
|
||||||
lSS.AuthorizationUrl.Value, rSS.AuthorizationUrl.Value, &changes, v3.AuthorizationUrlLabel, true)
|
lSS.AuthorizationUrl.Value, rSS.AuthorizationUrl.Value, &changes, v3.AuthorizationUrlLabel, true)
|
||||||
|
|
||||||
addPropertyCheck(&props, lSS.TokenUrl.ValueNode, rSS.TokenUrl.ValueNode,
|
addPropertyCheck(&props, lSS.TokenUrl.ValueNode, rSS.TokenUrl.ValueNode,
|
||||||
lSS.TokenUrl.Value, rSS.TokenUrl.Value, &changes, v3.TokenUrlLabel, true)
|
lSS.TokenUrl.Value, rSS.TokenUrl.Value, &changes, v3.TokenUrlLabel, true)
|
||||||
|
|
||||||
if !lSS.Scopes.IsEmpty() && !rSS.Scopes.IsEmpty() {
|
if !lSS.Scopes.IsEmpty() && !rSS.Scopes.IsEmpty() {
|
||||||
if !low.AreEqual(lSS.Scopes.Value, rSS.Scopes.Value) {
|
if !low.AreEqual(lSS.Scopes.Value, rSS.Scopes.Value) {
|
||||||
sc.ScopesChanges = CompareScopes(lSS.Scopes.Value, rSS.Scopes.Value)
|
sc.ScopesChanges = CompareScopes(lSS.Scopes.Value, rSS.Scopes.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if lSS.Scopes.IsEmpty() && !rSS.Scopes.IsEmpty() {
|
if lSS.Scopes.IsEmpty() && !rSS.Scopes.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectAdded, v3.ScopesLabel,
|
CreateChange(&changes, ObjectAdded, v3.ScopesLabel,
|
||||||
nil, rSS.Scopes.ValueNode, false, nil, rSS.Scopes.Value)
|
nil, rSS.Scopes.ValueNode, false, nil, rSS.Scopes.Value)
|
||||||
}
|
}
|
||||||
if !lSS.Scopes.IsEmpty() && rSS.Scopes.IsEmpty() {
|
if !lSS.Scopes.IsEmpty() && rSS.Scopes.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.ScopesLabel,
|
CreateChange(&changes, ObjectRemoved, v3.ScopesLabel,
|
||||||
lSS.Scopes.ValueNode, nil, true, lSS.Scopes.Value, nil)
|
lSS.Scopes.ValueNode, nil, true, lSS.Scopes.Value, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
sc.ExtensionChanges = CompareExtensions(lSS.Extensions, rSS.Extensions)
|
sc.ExtensionChanges = CompareExtensions(lSS.Extensions, rSS.Extensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
if reflect.TypeOf(&v3.SecurityScheme{}) == reflect.TypeOf(l) &&
|
if reflect.TypeOf(&v3.SecurityScheme{}) == reflect.TypeOf(l) &&
|
||||||
reflect.TypeOf(&v3.SecurityScheme{}) == reflect.TypeOf(r) {
|
reflect.TypeOf(&v3.SecurityScheme{}) == reflect.TypeOf(r) {
|
||||||
|
|
||||||
lSS := l.(*v3.SecurityScheme)
|
lSS := l.(*v3.SecurityScheme)
|
||||||
rSS := r.(*v3.SecurityScheme)
|
rSS := r.(*v3.SecurityScheme)
|
||||||
|
|
||||||
if low.AreEqual(lSS, rSS) {
|
if low.AreEqual(lSS, rSS) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
addPropertyCheck(&props, lSS.Type.ValueNode, rSS.Type.ValueNode,
|
addPropertyCheck(&props, lSS.Type.ValueNode, rSS.Type.ValueNode,
|
||||||
lSS.Type.Value, rSS.Type.Value, &changes, v3.TypeLabel, true)
|
lSS.Type.Value, rSS.Type.Value, &changes, v3.TypeLabel, true)
|
||||||
|
|
||||||
addPropertyCheck(&props, lSS.Description.ValueNode, rSS.Description.ValueNode,
|
addPropertyCheck(&props, lSS.Description.ValueNode, rSS.Description.ValueNode,
|
||||||
lSS.Description.Value, rSS.Description.Value, &changes, v3.DescriptionLabel, false)
|
lSS.Description.Value, rSS.Description.Value, &changes, v3.DescriptionLabel, false)
|
||||||
|
|
||||||
addPropertyCheck(&props, lSS.Name.ValueNode, rSS.Name.ValueNode,
|
addPropertyCheck(&props, lSS.Name.ValueNode, rSS.Name.ValueNode,
|
||||||
lSS.Name.Value, rSS.Name.Value, &changes, v3.NameLabel, true)
|
lSS.Name.Value, rSS.Name.Value, &changes, v3.NameLabel, true)
|
||||||
|
|
||||||
addPropertyCheck(&props, lSS.In.ValueNode, rSS.In.ValueNode,
|
addPropertyCheck(&props, lSS.In.ValueNode, rSS.In.ValueNode,
|
||||||
lSS.In.Value, rSS.In.Value, &changes, v3.InLabel, true)
|
lSS.In.Value, rSS.In.Value, &changes, v3.InLabel, true)
|
||||||
|
|
||||||
addPropertyCheck(&props, lSS.Scheme.ValueNode, rSS.Scheme.ValueNode,
|
addPropertyCheck(&props, lSS.Scheme.ValueNode, rSS.Scheme.ValueNode,
|
||||||
lSS.Scheme.Value, rSS.Scheme.Value, &changes, v3.SchemeLabel, true)
|
lSS.Scheme.Value, rSS.Scheme.Value, &changes, v3.SchemeLabel, true)
|
||||||
|
|
||||||
addPropertyCheck(&props, lSS.BearerFormat.ValueNode, rSS.BearerFormat.ValueNode,
|
addPropertyCheck(&props, lSS.BearerFormat.ValueNode, rSS.BearerFormat.ValueNode,
|
||||||
lSS.BearerFormat.Value, rSS.BearerFormat.Value, &changes, v3.SchemeLabel, false)
|
lSS.BearerFormat.Value, rSS.BearerFormat.Value, &changes, v3.SchemeLabel, false)
|
||||||
|
|
||||||
addPropertyCheck(&props, lSS.OpenIdConnectUrl.ValueNode, rSS.OpenIdConnectUrl.ValueNode,
|
addPropertyCheck(&props, lSS.OpenIdConnectUrl.ValueNode, rSS.OpenIdConnectUrl.ValueNode,
|
||||||
lSS.OpenIdConnectUrl.Value, rSS.OpenIdConnectUrl.Value, &changes, v3.OpenIdConnectUrlLabel, false)
|
lSS.OpenIdConnectUrl.Value, rSS.OpenIdConnectUrl.Value, &changes, v3.OpenIdConnectUrlLabel, false)
|
||||||
|
|
||||||
if !lSS.Flows.IsEmpty() && !rSS.Flows.IsEmpty() {
|
if !lSS.Flows.IsEmpty() && !rSS.Flows.IsEmpty() {
|
||||||
if !low.AreEqual(lSS.Flows.Value, rSS.Flows.Value) {
|
if !low.AreEqual(lSS.Flows.Value, rSS.Flows.Value) {
|
||||||
sc.OAuthFlowChanges = CompareOAuthFlows(lSS.Flows.Value, rSS.Flows.Value)
|
sc.OAuthFlowChanges = CompareOAuthFlows(lSS.Flows.Value, rSS.Flows.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if lSS.Flows.IsEmpty() && !rSS.Flows.IsEmpty() {
|
if lSS.Flows.IsEmpty() && !rSS.Flows.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectAdded, v3.FlowsLabel,
|
CreateChange(&changes, ObjectAdded, v3.FlowsLabel,
|
||||||
nil, rSS.Flows.ValueNode, false, nil, rSS.Flows.Value)
|
nil, rSS.Flows.ValueNode, false, nil, rSS.Flows.Value)
|
||||||
}
|
}
|
||||||
if !lSS.Flows.IsEmpty() && rSS.Flows.IsEmpty() {
|
if !lSS.Flows.IsEmpty() && rSS.Flows.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.ScopesLabel,
|
CreateChange(&changes, ObjectRemoved, v3.ScopesLabel,
|
||||||
lSS.Flows.ValueNode, nil, true, lSS.Flows.Value, nil)
|
lSS.Flows.ValueNode, nil, true, lSS.Flows.Value, nil)
|
||||||
}
|
}
|
||||||
sc.ExtensionChanges = CompareExtensions(lSS.Extensions, rSS.Extensions)
|
sc.ExtensionChanges = CompareExtensions(lSS.Extensions, rSS.Extensions)
|
||||||
}
|
}
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
sc.Changes = changes
|
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
return sc
|
return sc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,69 +4,69 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ServerChanges represents changes found between two OpenAPI Server Objects
|
// ServerChanges represents changes found between two OpenAPI Server Objects
|
||||||
type ServerChanges struct {
|
type ServerChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ServerVariableChanges map[string]*ServerVariableChanges `json:"serverVariables,omitempty" yaml:"serverVariables,omitempty"`
|
ServerVariableChanges map[string]*ServerVariableChanges `json:"serverVariables,omitempty" yaml:"serverVariables,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns total changes found between two OpenAPI Server Objects
|
// TotalChanges returns total changes found between two OpenAPI Server Objects
|
||||||
func (s *ServerChanges) TotalChanges() int {
|
func (s *ServerChanges) TotalChanges() int {
|
||||||
c := s.PropertyChanges.TotalChanges()
|
c := s.PropertyChanges.TotalChanges()
|
||||||
for k := range s.ServerVariableChanges {
|
for k := range s.ServerVariableChanges {
|
||||||
c += s.ServerVariableChanges[k].TotalChanges()
|
c += s.ServerVariableChanges[k].TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the total number of breaking changes found between two OpenAPI Server objects.
|
// TotalBreakingChanges returns the total number of breaking changes found between two OpenAPI Server objects.
|
||||||
func (s *ServerChanges) TotalBreakingChanges() int {
|
func (s *ServerChanges) TotalBreakingChanges() int {
|
||||||
c := s.PropertyChanges.TotalBreakingChanges()
|
c := s.PropertyChanges.TotalBreakingChanges()
|
||||||
for k := range s.ServerVariableChanges {
|
for k := range s.ServerVariableChanges {
|
||||||
c += s.ServerVariableChanges[k].TotalBreakingChanges()
|
c += s.ServerVariableChanges[k].TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareServers compares two OpenAPI Server objects for any changes. If anything is found, returns a pointer
|
// CompareServers compares two OpenAPI Server objects for any changes. If anything is found, returns a pointer
|
||||||
// to a ServerChanges instance, or returns nil if nothing is found.
|
// to a ServerChanges instance, or returns nil if nothing is found.
|
||||||
func CompareServers(l, r *v3.Server) *ServerChanges {
|
func CompareServers(l, r *v3.Server) *ServerChanges {
|
||||||
if low.AreEqual(l, r) {
|
if low.AreEqual(l, r) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
// URL
|
// URL
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.URL.ValueNode,
|
LeftNode: l.URL.ValueNode,
|
||||||
RightNode: r.URL.ValueNode,
|
RightNode: r.URL.ValueNode,
|
||||||
Label: v3.URLLabel,
|
Label: v3.URLLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
// Description
|
// Description
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Description.ValueNode,
|
LeftNode: l.Description.ValueNode,
|
||||||
RightNode: r.Description.ValueNode,
|
RightNode: r.Description.ValueNode,
|
||||||
Label: v3.DescriptionLabel,
|
Label: v3.DescriptionLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
sc := new(ServerChanges)
|
sc := new(ServerChanges)
|
||||||
sc.Changes = changes
|
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
sc.ServerVariableChanges = CheckMapForChanges(l.Variables.Value, r.Variables.Value,
|
sc.ServerVariableChanges = CheckMapForChanges(l.Variables.Value, r.Variables.Value,
|
||||||
&changes, v3.VariablesLabel, CompareServerVariables)
|
&changes, v3.VariablesLabel, CompareServerVariables)
|
||||||
|
|
||||||
return sc
|
return sc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,74 +4,74 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ServerVariableChanges represents changes found between two OpenAPI ServerVariable Objects
|
// ServerVariableChanges represents changes found between two OpenAPI ServerVariable Objects
|
||||||
type ServerVariableChanges struct {
|
type ServerVariableChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareServerVariables compares a left and right OpenAPI ServerVariable object for changes.
|
// CompareServerVariables compares a left and right OpenAPI ServerVariable object for changes.
|
||||||
// If anything is found, returns a pointer to a ServerVariableChanges instance, otherwise returns nil.
|
// If anything is found, returns a pointer to a ServerVariableChanges instance, otherwise returns nil.
|
||||||
func CompareServerVariables(l, r *v3.ServerVariable) *ServerVariableChanges {
|
func CompareServerVariables(l, r *v3.ServerVariable) *ServerVariableChanges {
|
||||||
if low.AreEqual(l, r) {
|
if low.AreEqual(l, r) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
|
|
||||||
lValues := make(map[string]low.NodeReference[string])
|
lValues := make(map[string]low.NodeReference[string])
|
||||||
rValues := make(map[string]low.NodeReference[string])
|
rValues := make(map[string]low.NodeReference[string])
|
||||||
for i := range l.Enum {
|
for i := range l.Enum {
|
||||||
lValues[l.Enum[i].Value] = l.Enum[i]
|
lValues[l.Enum[i].Value] = l.Enum[i]
|
||||||
}
|
}
|
||||||
for i := range r.Enum {
|
for i := range r.Enum {
|
||||||
rValues[r.Enum[i].Value] = r.Enum[i]
|
rValues[r.Enum[i].Value] = r.Enum[i]
|
||||||
}
|
}
|
||||||
for k := range lValues {
|
for k := range lValues {
|
||||||
if _, ok := rValues[k]; !ok {
|
if _, ok := rValues[k]; !ok {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.EnumLabel,
|
CreateChange(&changes, ObjectRemoved, v3.EnumLabel,
|
||||||
lValues[k].ValueNode, nil, true,
|
lValues[k].ValueNode, nil, true,
|
||||||
lValues[k].Value, nil)
|
lValues[k].Value, nil)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for k := range rValues {
|
for k := range rValues {
|
||||||
if _, ok := lValues[k]; !ok {
|
if _, ok := lValues[k]; !ok {
|
||||||
CreateChange(&changes, ObjectAdded, v3.EnumLabel,
|
CreateChange(&changes, ObjectAdded, v3.EnumLabel,
|
||||||
lValues[k].ValueNode, rValues[k].ValueNode, false,
|
lValues[k].ValueNode, rValues[k].ValueNode, false,
|
||||||
lValues[k].Value, rValues[k].Value)
|
lValues[k].Value, rValues[k].Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// default
|
// default
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Default.ValueNode,
|
LeftNode: l.Default.ValueNode,
|
||||||
RightNode: r.Default.ValueNode,
|
RightNode: r.Default.ValueNode,
|
||||||
Label: v3.DefaultLabel,
|
Label: v3.DefaultLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// description
|
// description
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Description.ValueNode,
|
LeftNode: l.Description.ValueNode,
|
||||||
RightNode: r.Description.ValueNode,
|
RightNode: r.Description.ValueNode,
|
||||||
Label: v3.DescriptionLabel,
|
Label: v3.DescriptionLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// check everything.
|
// check everything.
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
sc := new(ServerVariableChanges)
|
sc := new(ServerVariableChanges)
|
||||||
sc.Changes = changes
|
sc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
return sc
|
return sc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,33 +4,33 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low"
|
"github.com/pb33f/libopenapi/datamodel/low"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
"github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TagChanges represents changes made to the Tags object of an OpenAPI document.
|
// TagChanges represents changes made to the Tags object of an OpenAPI document.
|
||||||
type TagChanges struct {
|
type TagChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ExternalDocs *ExternalDocChanges `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
ExternalDocs *ExternalDocChanges `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns a count of everything that changed within tags.
|
// TotalChanges returns a count of everything that changed within tags.
|
||||||
func (t *TagChanges) TotalChanges() int {
|
func (t *TagChanges) TotalChanges() int {
|
||||||
c := t.PropertyChanges.TotalChanges()
|
c := t.PropertyChanges.TotalChanges()
|
||||||
if t.ExternalDocs != nil {
|
if t.ExternalDocs != nil {
|
||||||
c += t.ExternalDocs.TotalChanges()
|
c += t.ExternalDocs.TotalChanges()
|
||||||
}
|
}
|
||||||
if t.ExtensionChanges != nil {
|
if t.ExtensionChanges != nil {
|
||||||
c += t.ExtensionChanges.TotalChanges()
|
c += t.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the number of breaking changes made by Tags
|
// TotalBreakingChanges returns the number of breaking changes made by Tags
|
||||||
func (t *TagChanges) TotalBreakingChanges() int {
|
func (t *TagChanges) TotalBreakingChanges() int {
|
||||||
return t.PropertyChanges.TotalBreakingChanges()
|
return t.PropertyChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareTags will compare a left (original) and a right (new) slice of ValueReference nodes for
|
// CompareTags will compare a left (original) and a right (new) slice of ValueReference nodes for
|
||||||
@@ -38,100 +38,100 @@ func (t *TagChanges) TotalBreakingChanges() int {
|
|||||||
// nil is returned instead.
|
// nil is returned instead.
|
||||||
func CompareTags(l, r []low.ValueReference[*base.Tag]) []*TagChanges {
|
func CompareTags(l, r []low.ValueReference[*base.Tag]) []*TagChanges {
|
||||||
|
|
||||||
var tagResults []*TagChanges
|
var tagResults []*TagChanges
|
||||||
|
|
||||||
// look at the original and then look through the new.
|
// look at the original and then look through the new.
|
||||||
seenLeft := make(map[string]*low.ValueReference[*base.Tag])
|
seenLeft := make(map[string]*low.ValueReference[*base.Tag])
|
||||||
seenRight := make(map[string]*low.ValueReference[*base.Tag])
|
seenRight := make(map[string]*low.ValueReference[*base.Tag])
|
||||||
for i := range l {
|
for i := range l {
|
||||||
h := l[i]
|
h := l[i]
|
||||||
seenLeft[l[i].Value.Name.Value] = &h
|
seenLeft[l[i].Value.Name.Value] = &h
|
||||||
}
|
}
|
||||||
for i := range r {
|
for i := range r {
|
||||||
h := r[i]
|
h := r[i]
|
||||||
seenRight[r[i].Value.Name.Value] = &h
|
seenRight[r[i].Value.Name.Value] = &h
|
||||||
}
|
}
|
||||||
|
|
||||||
//var changes []*Change
|
//var changes []*Change
|
||||||
|
|
||||||
// check for removals, modifications and moves
|
// check for removals, modifications and moves
|
||||||
for i := range seenLeft {
|
for i := range seenLeft {
|
||||||
tc := new(TagChanges)
|
tc := new(TagChanges)
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
|
|
||||||
CheckForObjectAdditionOrRemoval[*base.Tag](seenLeft, seenRight, i, &changes, false, true)
|
CheckForObjectAdditionOrRemoval[*base.Tag](seenLeft, seenRight, i, &changes, false, true)
|
||||||
|
|
||||||
// if the existing tag exists, let's check it.
|
// if the existing tag exists, let's check it.
|
||||||
if seenRight[i] != nil {
|
if seenRight[i] != nil {
|
||||||
|
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
// Name
|
// Name
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: seenLeft[i].Value.Name.ValueNode,
|
LeftNode: seenLeft[i].Value.Name.ValueNode,
|
||||||
RightNode: seenRight[i].Value.Name.ValueNode,
|
RightNode: seenRight[i].Value.Name.ValueNode,
|
||||||
Label: v3.NameLabel,
|
Label: v3.NameLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: seenLeft[i].Value,
|
Original: seenLeft[i].Value,
|
||||||
New: seenRight[i].Value,
|
New: seenRight[i].Value,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Description
|
// Description
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: seenLeft[i].Value.Description.ValueNode,
|
LeftNode: seenLeft[i].Value.Description.ValueNode,
|
||||||
RightNode: seenRight[i].Value.Description.ValueNode,
|
RightNode: seenRight[i].Value.Description.ValueNode,
|
||||||
Label: v3.DescriptionLabel,
|
Label: v3.DescriptionLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: false,
|
Breaking: false,
|
||||||
Original: seenLeft[i].Value,
|
Original: seenLeft[i].Value,
|
||||||
New: seenRight[i].Value,
|
New: seenRight[i].Value,
|
||||||
})
|
})
|
||||||
|
|
||||||
// check properties
|
// check properties
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
|
|
||||||
// compare external docs
|
// compare external docs
|
||||||
if !seenLeft[i].Value.ExternalDocs.IsEmpty() && !seenRight[i].Value.ExternalDocs.IsEmpty() {
|
if !seenLeft[i].Value.ExternalDocs.IsEmpty() && !seenRight[i].Value.ExternalDocs.IsEmpty() {
|
||||||
tc.ExternalDocs = CompareExternalDocs(seenLeft[i].Value.ExternalDocs.Value,
|
tc.ExternalDocs = CompareExternalDocs(seenLeft[i].Value.ExternalDocs.Value,
|
||||||
seenRight[i].Value.ExternalDocs.Value)
|
seenRight[i].Value.ExternalDocs.Value)
|
||||||
}
|
}
|
||||||
if seenLeft[i].Value.ExternalDocs.IsEmpty() && !seenRight[i].Value.ExternalDocs.IsEmpty() {
|
if seenLeft[i].Value.ExternalDocs.IsEmpty() && !seenRight[i].Value.ExternalDocs.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectAdded, v3.ExternalDocsLabel, nil, seenRight[i].GetValueNode(),
|
CreateChange(&changes, ObjectAdded, v3.ExternalDocsLabel, nil, seenRight[i].GetValueNode(),
|
||||||
false, nil, seenRight[i].Value.ExternalDocs.Value)
|
false, nil, seenRight[i].Value.ExternalDocs.Value)
|
||||||
}
|
}
|
||||||
if !seenLeft[i].Value.ExternalDocs.IsEmpty() && seenRight[i].Value.ExternalDocs.IsEmpty() {
|
if !seenLeft[i].Value.ExternalDocs.IsEmpty() && seenRight[i].Value.ExternalDocs.IsEmpty() {
|
||||||
CreateChange(&changes, ObjectRemoved, v3.ExternalDocsLabel, seenLeft[i].GetValueNode(), nil,
|
CreateChange(&changes, ObjectRemoved, v3.ExternalDocsLabel, seenLeft[i].GetValueNode(), nil,
|
||||||
false, seenLeft[i].Value.ExternalDocs.Value, nil)
|
false, seenLeft[i].Value.ExternalDocs.Value, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check extensions
|
// check extensions
|
||||||
tc.ExtensionChanges = CompareExtensions(seenLeft[i].Value.Extensions, seenRight[i].Value.Extensions)
|
tc.ExtensionChanges = CompareExtensions(seenLeft[i].Value.Extensions, seenRight[i].Value.Extensions)
|
||||||
tc.Changes = changes
|
tc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
if tc.TotalChanges() > 0 {
|
if tc.TotalChanges() > 0 {
|
||||||
tagResults = append(tagResults, tc)
|
tagResults = append(tagResults, tc)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(changes) > 0 {
|
if len(changes) > 0 {
|
||||||
tc.Changes = changes
|
tc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
tagResults = append(tagResults, tc)
|
tagResults = append(tagResults, tc)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
for i := range seenRight {
|
for i := range seenRight {
|
||||||
if seenLeft[i] == nil {
|
if seenLeft[i] == nil {
|
||||||
tc := new(TagChanges)
|
tc := new(TagChanges)
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
|
|
||||||
CreateChange(&changes, ObjectAdded, i, nil, seenRight[i].GetValueNode(),
|
CreateChange(&changes, ObjectAdded, i, nil, seenRight[i].GetValueNode(),
|
||||||
false, nil, seenRight[i].GetValue())
|
false, nil, seenRight[i].GetValue())
|
||||||
|
|
||||||
tc.Changes = changes
|
tc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
tagResults = append(tagResults, tc)
|
tagResults = append(tagResults, tc)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tagResults
|
return tagResults
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,101 +4,101 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pb33f/libopenapi/datamodel/low/base"
|
"github.com/pb33f/libopenapi/datamodel/low/base"
|
||||||
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
v3 "github.com/pb33f/libopenapi/datamodel/low/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// XMLChanges represents changes made to the XML object of an OpenAPI document.
|
// XMLChanges represents changes made to the XML object of an OpenAPI document.
|
||||||
type XMLChanges struct {
|
type XMLChanges struct {
|
||||||
PropertyChanges
|
*PropertyChanges
|
||||||
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
ExtensionChanges *ExtensionChanges `json:"extensions,omitempty" yaml:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalChanges returns a count of everything that was changed within an XML object.
|
// TotalChanges returns a count of everything that was changed within an XML object.
|
||||||
func (x *XMLChanges) TotalChanges() int {
|
func (x *XMLChanges) TotalChanges() int {
|
||||||
c := x.PropertyChanges.TotalChanges()
|
c := x.PropertyChanges.TotalChanges()
|
||||||
if x.ExtensionChanges != nil {
|
if x.ExtensionChanges != nil {
|
||||||
c += x.ExtensionChanges.TotalChanges()
|
c += x.ExtensionChanges.TotalChanges()
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalBreakingChanges returns the number of breaking changes made by the XML object.
|
// TotalBreakingChanges returns the number of breaking changes made by the XML object.
|
||||||
func (x *XMLChanges) TotalBreakingChanges() int {
|
func (x *XMLChanges) TotalBreakingChanges() int {
|
||||||
return x.PropertyChanges.TotalBreakingChanges()
|
return x.PropertyChanges.TotalBreakingChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareXML will compare a left (original) and a right (new) XML instance, and check for
|
// CompareXML will compare a left (original) and a right (new) XML instance, and check for
|
||||||
// any changes between them. If changes are found, the function returns a pointer to XMLChanges,
|
// any changes between them. If changes are found, the function returns a pointer to XMLChanges,
|
||||||
// otherwise, if nothing changed - it will return nil
|
// otherwise, if nothing changed - it will return nil
|
||||||
func CompareXML(l, r *base.XML) *XMLChanges {
|
func CompareXML(l, r *base.XML) *XMLChanges {
|
||||||
xc := new(XMLChanges)
|
xc := new(XMLChanges)
|
||||||
var changes []*Change
|
var changes []*Change
|
||||||
var props []*PropertyCheck
|
var props []*PropertyCheck
|
||||||
|
|
||||||
// Name (breaking change)
|
// Name (breaking change)
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Name.ValueNode,
|
LeftNode: l.Name.ValueNode,
|
||||||
RightNode: r.Name.ValueNode,
|
RightNode: r.Name.ValueNode,
|
||||||
Label: v3.NameLabel,
|
Label: v3.NameLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Namespace (breaking change)
|
// Namespace (breaking change)
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Namespace.ValueNode,
|
LeftNode: l.Namespace.ValueNode,
|
||||||
RightNode: r.Namespace.ValueNode,
|
RightNode: r.Namespace.ValueNode,
|
||||||
Label: v3.NamespaceLabel,
|
Label: v3.NamespaceLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Prefix (breaking change)
|
// Prefix (breaking change)
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Prefix.ValueNode,
|
LeftNode: l.Prefix.ValueNode,
|
||||||
RightNode: r.Prefix.ValueNode,
|
RightNode: r.Prefix.ValueNode,
|
||||||
Label: v3.PrefixLabel,
|
Label: v3.PrefixLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Attribute (breaking change)
|
// Attribute (breaking change)
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Attribute.ValueNode,
|
LeftNode: l.Attribute.ValueNode,
|
||||||
RightNode: r.Attribute.ValueNode,
|
RightNode: r.Attribute.ValueNode,
|
||||||
Label: v3.AttributeLabel,
|
Label: v3.AttributeLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Wrapped (breaking change)
|
// Wrapped (breaking change)
|
||||||
props = append(props, &PropertyCheck{
|
props = append(props, &PropertyCheck{
|
||||||
LeftNode: l.Wrapped.ValueNode,
|
LeftNode: l.Wrapped.ValueNode,
|
||||||
RightNode: r.Wrapped.ValueNode,
|
RightNode: r.Wrapped.ValueNode,
|
||||||
Label: v3.WrappedLabel,
|
Label: v3.WrappedLabel,
|
||||||
Changes: &changes,
|
Changes: &changes,
|
||||||
Breaking: true,
|
Breaking: true,
|
||||||
Original: l,
|
Original: l,
|
||||||
New: r,
|
New: r,
|
||||||
})
|
})
|
||||||
|
|
||||||
// check properties
|
// check properties
|
||||||
CheckProperties(props)
|
CheckProperties(props)
|
||||||
|
|
||||||
// check extensions
|
// check extensions
|
||||||
xc.ExtensionChanges = CheckExtensions(l, r)
|
xc.ExtensionChanges = CheckExtensions(l, r)
|
||||||
xc.Changes = changes
|
xc.PropertyChanges = NewPropertyChanges(changes)
|
||||||
if xc.TotalChanges() <= 0 {
|
if xc.TotalChanges() <= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return xc
|
return xc
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user