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