From 2b56755d3f005ac0ed8c83a0de19a4a0a8ce9bb4 Mon Sep 17 00:00:00 2001 From: Reuven Harrison Date: Fri, 23 Aug 2024 12:21:54 +0200 Subject: [PATCH 01/12] proof of concept --- checker/api_change.go | 16 +++++++++++++++ formatters/changes.go | 46 +++++++++++++++++++++++-------------------- go.mod | 6 ++++++ go.sum | 13 ++++++------ internal/diff.go | 1 + 5 files changed, 54 insertions(+), 28 deletions(-) diff --git a/checker/api_change.go b/checker/api_change.go index fe4e9e50..efe9dfeb 100644 --- a/checker/api_change.go +++ b/checker/api_change.go @@ -31,6 +31,9 @@ type ApiChange struct { } func NewApiChange(id string, config *Config, args []any, comment string, operationsSources *diff.OperationsSourcesMap, operation *openapi3.Operation, method, path string) ApiChange { + + line, col := getOrigin(operation) + return ApiChange{ Id: id, Level: config.getLogLevel(id), @@ -43,9 +46,22 @@ func NewApiChange(id string, config *Config, args []any, comment string, operati CommonChange: CommonChange{ Attributes: getAttributes(config, operation), }, + SourceLine: line, + SourceColumn: col, } } +func getOrigin(operation *openapi3.Operation) (int, int) { + if operation == nil || operation.Origin == nil { + return 0, 0 + } + + line := operation.Origin.Key.Line + col := operation.Origin.Key.Column + + return line, col +} + func getAttributes(config *Config, operation *openapi3.Operation) map[string]any { result := map[string]any{} for _, tag := range config.Attributes { diff --git a/formatters/changes.go b/formatters/changes.go index 0230646a..158cf8c4 100644 --- a/formatters/changes.go +++ b/formatters/changes.go @@ -5,17 +5,19 @@ import ( ) type Change struct { - Id string `json:"id,omitempty" yaml:"id,omitempty"` - Text string `json:"text,omitempty" yaml:"text,omitempty"` - Comment string `json:"comment,omitempty" yaml:"comment,omitempty"` - Level checker.Level `json:"level" yaml:"level"` - Operation string `json:"operation,omitempty" yaml:"operation,omitempty"` - OperationId string `json:"operationId,omitempty" yaml:"operationId,omitempty"` - Path string `json:"path,omitempty" yaml:"path,omitempty"` - Source string `json:"source,omitempty" yaml:"source,omitempty"` - Section string `json:"section,omitempty" yaml:"section,omitempty"` - IsBreaking bool `json:"-" yaml:"-"` - Attributes map[string]any `json:"attributes,omitempty" yaml:"attributes,omitempty"` + Id string `json:"id,omitempty" yaml:"id,omitempty"` + Text string `json:"text,omitempty" yaml:"text,omitempty"` + Comment string `json:"comment,omitempty" yaml:"comment,omitempty"` + Level checker.Level `json:"level" yaml:"level"` + Operation string `json:"operation,omitempty" yaml:"operation,omitempty"` + OperationId string `json:"operationId,omitempty" yaml:"operationId,omitempty"` + Path string `json:"path,omitempty" yaml:"path,omitempty"` + Source string `json:"source,omitempty" yaml:"source,omitempty"` + Section string `json:"section,omitempty" yaml:"section,omitempty"` + IsBreaking bool `json:"-" yaml:"-"` + Attributes map[string]any `json:"attributes,omitempty" yaml:"attributes,omitempty"` + SourceLine int `json:"sourceLine,omitempty" yaml:"sourceLine,omitempty"` + SourceColumm int `json:"sourceColumn,omitempty" yaml:"sourceColumn,omitempty"` } type Changes []Change @@ -24,16 +26,18 @@ func NewChanges(originalChanges checker.Changes, l checker.Localizer) Changes { changes := make(Changes, len(originalChanges)) for i, change := range originalChanges { changes[i] = Change{ - Section: change.GetSection(), - Id: change.GetId(), - Text: change.GetUncolorizedText(l), - Comment: change.GetComment(l), - Level: change.GetLevel(), - Operation: change.GetOperation(), - OperationId: change.GetOperationId(), - Path: change.GetPath(), - Source: change.GetSource(), - Attributes: change.GetAttributes(), + Section: change.GetSection(), + Id: change.GetId(), + Text: change.GetUncolorizedText(l), + Comment: change.GetComment(l), + Level: change.GetLevel(), + Operation: change.GetOperation(), + OperationId: change.GetOperationId(), + Path: change.GetPath(), + Source: change.GetSource(), + Attributes: change.GetAttributes(), + SourceLine: change.GetSourceLine(), + SourceColumm: change.GetSourceColumn(), } } return changes diff --git a/go.mod b/go.mod index 1b65afe6..acdd0e3e 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,12 @@ module github.com/tufin/oasdiff go 1.22.5 +replace gopkg.in/yaml.v3 => github.com/oasdiff/yaml3 v0.0.0-20240819204501-233901bce7fe + +replace github.com/invopop/yaml => github.com/oasdiff/yaml v0.0.0-20240822113848-2830227c9671 + +replace github.com/getkin/kin-openapi => github.com/oasdiff/kin-openapi v0.0.0-20240822114340-77f909bcefa1 + require ( cloud.google.com/go v0.115.0 github.com/TwiN/go-color v1.4.1 diff --git a/go.sum b/go.sum index 3ea92b53..7df205fe 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,6 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= -github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= @@ -29,8 +27,6 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso= -github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -45,8 +41,14 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/oasdiff/kin-openapi v0.0.0-20240822114340-77f909bcefa1 h1:ljShh904MDrvao/PtQTzfaAnonDA3tYupY9R5NuuL8w= +github.com/oasdiff/kin-openapi v0.0.0-20240822114340-77f909bcefa1/go.mod h1:dttoAiKGJ89CXBRPozVnlbkS6QI2CA1bL2uziw1uQmE= github.com/oasdiff/telemetry v0.1.2 h1:hkmA5YTISVF2/zWa23y29WdPws1Q53pyLOFYMHXoZ1U= github.com/oasdiff/telemetry v0.1.2/go.mod h1:Y0DaW/CasxZ+vzR54btj430XsL6DGF+rMbJkRld6u3M= +github.com/oasdiff/yaml v0.0.0-20240822113848-2830227c9671 h1:qM2AH1Js3b+0wWCE5SrfSwa/rIXtqMyQZyXx3YaIb5Q= +github.com/oasdiff/yaml v0.0.0-20240822113848-2830227c9671/go.mod h1:/hkd7qQO7Qp3G9ytouXHWapZeeq18qNBkyNAHDpqR1U= +github.com/oasdiff/yaml3 v0.0.0-20240819204501-233901bce7fe h1:sHb5QDQFoFYvM+Ebq0Bo2JC27+U8oHM8Mm50oBwBtnQ= +github.com/oasdiff/yaml3 v0.0.0-20240819204501-233901bce7fe/go.mod h1:lqlOfJRrYpgeWHQj+ky2tf7UJ3PzgHTHRQEpc90nbp0= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= @@ -118,6 +120,3 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/diff.go b/internal/diff.go index 2474c16d..5ae54c2b 100644 --- a/internal/diff.go +++ b/internal/diff.go @@ -72,6 +72,7 @@ func calcDiff(flags *Flags) (*diffResult, *ReturnError) { loader := openapi3.NewLoader() loader.IsExternalRefsAllowed = true + loader.IncludeOrigin = true if flags.getComposed() { return composedDiff(loader, flags) From 70585968a71723d5833412f913b0da2c8dd8a694 Mon Sep 17 00:00:00 2001 From: Reuven Harrison Date: Sat, 21 Sep 2024 11:18:45 +0300 Subject: [PATCH 02/12] update deps --- diff/discriminator_diff.go | 3 ++- diff/oauth_flow.go | 2 +- diff/scopes.go | 16 ++++++++++++++++ go.mod | 6 +++--- go.sum | 12 ++++++------ 5 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 diff/scopes.go diff --git a/diff/discriminator_diff.go b/diff/discriminator_diff.go index c0d24b29..acbb466f 100644 --- a/diff/discriminator_diff.go +++ b/diff/discriminator_diff.go @@ -2,6 +2,7 @@ package diff import ( "github.com/getkin/kin-openapi/openapi3" + "github.com/tufin/oasdiff/utils" ) // DiscriminatorDiff describes the changes between a pair of discriminator objects: https://swagger.io/specification/#discriminator-object @@ -60,7 +61,7 @@ func getDiscriminatorDiffInternal(config *Config, state *state, discriminator1, return nil, err } result.PropertyNameDiff = getValueDiff(discriminator1.PropertyName, discriminator2.PropertyName) - result.MappingDiff = getStringMapDiff(discriminator1.Mapping, discriminator2.Mapping) + result.MappingDiff = getStringMapDiff(utils.StringMap(discriminator1.Mapping), utils.StringMap(discriminator2.Mapping)) return result, nil } diff --git a/diff/oauth_flow.go b/diff/oauth_flow.go index 4befb6a7..a6ee119f 100644 --- a/diff/oauth_flow.go +++ b/diff/oauth_flow.go @@ -60,7 +60,7 @@ func getOAuthFlowDiffInternal(config *Config, state *state, flow1, flow2 *openap result.AuthorizationURLDiff = getValueDiff(flow1.AuthorizationURL, flow2.AuthorizationURL) result.TokenURLDiff = getValueDiff(flow1.TokenURL, flow2.TokenURL) result.RefreshURLDiff = getValueDiff(flow1.RefreshURL, flow2.RefreshURL) - result.ScopesDiff = getStringMapDiff(flow1.Scopes, flow2.Scopes) + result.ScopesDiff = getScopesDiff(flow1.Scopes, flow2.Scopes) return &result, nil } diff --git a/diff/scopes.go b/diff/scopes.go new file mode 100644 index 00000000..6ceab60f --- /dev/null +++ b/diff/scopes.go @@ -0,0 +1,16 @@ +package diff + +import ( + "github.com/getkin/kin-openapi/openapi3" + "github.com/tufin/oasdiff/utils" +) + +func getScopesDiff(scopes1, scopes2 openapi3.StringMap) *StringMapDiff { + diff := getStringMapDiff(utils.StringMap(scopes1), utils.StringMap(scopes2)) + + if diff.Empty() { + return nil + } + + return diff +} diff --git a/go.mod b/go.mod index acdd0e3e..cbec1ab3 100644 --- a/go.mod +++ b/go.mod @@ -2,11 +2,11 @@ module github.com/tufin/oasdiff go 1.22.5 -replace gopkg.in/yaml.v3 => github.com/oasdiff/yaml3 v0.0.0-20240819204501-233901bce7fe +replace gopkg.in/yaml.v3 => github.com/oasdiff/yaml3 v0.0.0-20240920135353-c185dc6ea7c6 -replace github.com/invopop/yaml => github.com/oasdiff/yaml v0.0.0-20240822113848-2830227c9671 +replace github.com/invopop/yaml => github.com/oasdiff/yaml v0.0.0-20240920191703-3e5a9fb5bdf3 -replace github.com/getkin/kin-openapi => github.com/oasdiff/kin-openapi v0.0.0-20240822114340-77f909bcefa1 +replace github.com/getkin/kin-openapi => github.com/oasdiff/kin-openapi v0.0.0-20240921075217-8a00ba059558 require ( cloud.google.com/go v0.115.0 diff --git a/go.sum b/go.sum index 7df205fe..3fb115b7 100644 --- a/go.sum +++ b/go.sum @@ -41,14 +41,14 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/oasdiff/kin-openapi v0.0.0-20240822114340-77f909bcefa1 h1:ljShh904MDrvao/PtQTzfaAnonDA3tYupY9R5NuuL8w= -github.com/oasdiff/kin-openapi v0.0.0-20240822114340-77f909bcefa1/go.mod h1:dttoAiKGJ89CXBRPozVnlbkS6QI2CA1bL2uziw1uQmE= +github.com/oasdiff/kin-openapi v0.0.0-20240921075217-8a00ba059558 h1:aIfXRW0EbLKQsUA9RdAcIDvShF6I4DqQO3viCFEpnzw= +github.com/oasdiff/kin-openapi v0.0.0-20240921075217-8a00ba059558/go.mod h1:5MaNKmkfVAFfhyQtzgwYLynYAHgFA0KSykwF6+NoGMc= github.com/oasdiff/telemetry v0.1.2 h1:hkmA5YTISVF2/zWa23y29WdPws1Q53pyLOFYMHXoZ1U= github.com/oasdiff/telemetry v0.1.2/go.mod h1:Y0DaW/CasxZ+vzR54btj430XsL6DGF+rMbJkRld6u3M= -github.com/oasdiff/yaml v0.0.0-20240822113848-2830227c9671 h1:qM2AH1Js3b+0wWCE5SrfSwa/rIXtqMyQZyXx3YaIb5Q= -github.com/oasdiff/yaml v0.0.0-20240822113848-2830227c9671/go.mod h1:/hkd7qQO7Qp3G9ytouXHWapZeeq18qNBkyNAHDpqR1U= -github.com/oasdiff/yaml3 v0.0.0-20240819204501-233901bce7fe h1:sHb5QDQFoFYvM+Ebq0Bo2JC27+U8oHM8Mm50oBwBtnQ= -github.com/oasdiff/yaml3 v0.0.0-20240819204501-233901bce7fe/go.mod h1:lqlOfJRrYpgeWHQj+ky2tf7UJ3PzgHTHRQEpc90nbp0= +github.com/oasdiff/yaml v0.0.0-20240920191703-3e5a9fb5bdf3 h1:nqCxALSUgWobWkFGIrhLRzR/bpImQdGj+3JS4/scTJo= +github.com/oasdiff/yaml v0.0.0-20240920191703-3e5a9fb5bdf3/go.mod h1:AOyUNV9ElKz7EEZeBm/48U54UtjtgCMT9fFbZEsClQc= +github.com/oasdiff/yaml3 v0.0.0-20240920135353-c185dc6ea7c6 h1:+ZsuDTdapTJxfMQk7SOJiNMg0v36pui01L7FEO615r8= +github.com/oasdiff/yaml3 v0.0.0-20240920135353-c185dc6ea7c6/go.mod h1:lqlOfJRrYpgeWHQj+ky2tf7UJ3PzgHTHRQEpc90nbp0= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= From e7f5761c367b59c5aa0a4ee5d201d91676a9e5f1 Mon Sep 17 00:00:00 2001 From: Reuven Harrison Date: Wed, 25 Sep 2024 10:28:18 +0300 Subject: [PATCH 03/12] add origin to ApiChange --- checker/api_change.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/checker/api_change.go b/checker/api_change.go index efe9dfeb..0c183542 100644 --- a/checker/api_change.go +++ b/checker/api_change.go @@ -22,6 +22,7 @@ type ApiChange struct { OperationId string Path string Source *load.Source + Origin *openapi3.Origin SourceFile string SourceLine int @@ -51,6 +52,11 @@ func NewApiChange(id string, config *Config, args []any, comment string, operati } } +func (c ApiChange) WithOrigin(origin *openapi3.Origin) ApiChange { + c.Origin = origin + return c +} + func getOrigin(operation *openapi3.Operation) (int, int) { if operation == nil || operation.Origin == nil { return 0, 0 From 2f2c175d3b0e12eb13d9ba0a2855462811b90cbd Mon Sep 17 00:00:00 2001 From: Reuven Harrison Date: Sun, 24 Nov 2024 14:48:39 +0200 Subject: [PATCH 04/12] use kin-openapi --- go.mod | 4 +--- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index cbec1ab3..2b5e0681 100644 --- a/go.mod +++ b/go.mod @@ -6,12 +6,10 @@ replace gopkg.in/yaml.v3 => github.com/oasdiff/yaml3 v0.0.0-20240920135353-c185d replace github.com/invopop/yaml => github.com/oasdiff/yaml v0.0.0-20240920191703-3e5a9fb5bdf3 -replace github.com/getkin/kin-openapi => github.com/oasdiff/kin-openapi v0.0.0-20240921075217-8a00ba059558 - require ( cloud.google.com/go v0.115.0 github.com/TwiN/go-color v1.4.1 - github.com/getkin/kin-openapi v0.127.0 + github.com/getkin/kin-openapi v0.128.1-0.20241113210624-e230c133e5ca github.com/oasdiff/telemetry v0.1.2 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 diff --git a/go.sum b/go.sum index 3fb115b7..2876534c 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/getkin/kin-openapi v0.128.1-0.20241113210624-e230c133e5ca h1:14qX2UfAWKqPdofcSlsK9pPX3UbAlFHYPbRpoYRd0io= +github.com/getkin/kin-openapi v0.128.1-0.20241113210624-e230c133e5ca/go.mod h1:5MaNKmkfVAFfhyQtzgwYLynYAHgFA0KSykwF6+NoGMc= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= @@ -41,8 +43,6 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/oasdiff/kin-openapi v0.0.0-20240921075217-8a00ba059558 h1:aIfXRW0EbLKQsUA9RdAcIDvShF6I4DqQO3viCFEpnzw= -github.com/oasdiff/kin-openapi v0.0.0-20240921075217-8a00ba059558/go.mod h1:5MaNKmkfVAFfhyQtzgwYLynYAHgFA0KSykwF6+NoGMc= github.com/oasdiff/telemetry v0.1.2 h1:hkmA5YTISVF2/zWa23y29WdPws1Q53pyLOFYMHXoZ1U= github.com/oasdiff/telemetry v0.1.2/go.mod h1:Y0DaW/CasxZ+vzR54btj430XsL6DGF+rMbJkRld6u3M= github.com/oasdiff/yaml v0.0.0-20240920191703-3e5a9fb5bdf3 h1:nqCxALSUgWobWkFGIrhLRzR/bpImQdGj+3JS4/scTJo= From baa48939c16316e41daadb49d9ff5ce58d4e28c9 Mon Sep 17 00:00:00 2001 From: Reuven Harrison Date: Sun, 24 Nov 2024 14:50:26 +0200 Subject: [PATCH 05/12] indexes are 1-based --- formatters/format_githubactions.go | 8 ++++---- formatters/format_githubactions_test.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/formatters/format_githubactions.go b/formatters/format_githubactions.go index 34737ec9..ecfb5ec3 100644 --- a/formatters/format_githubactions.go +++ b/formatters/format_githubactions.go @@ -50,16 +50,16 @@ func (f GitHubActionsFormatter) RenderChangelog(changes checker.Changes, opts Re params = append(params, "file="+change.GetSourceFile()) } if change.GetSourceColumn() != 0 { - params = append(params, "col="+strconv.Itoa(change.GetSourceColumn()+1)) + params = append(params, "col="+strconv.Itoa(change.GetSourceColumn())) } if change.GetSourceColumnEnd() != 0 { - params = append(params, "endColumn="+strconv.Itoa(change.GetSourceColumnEnd()+1)) + params = append(params, "endColumn="+strconv.Itoa(change.GetSourceColumnEnd())) } if change.GetSourceLine() != 0 { - params = append(params, "line="+strconv.Itoa(change.GetSourceLine()+1)) + params = append(params, "line="+strconv.Itoa(change.GetSourceLine())) } if change.GetSourceLineEnd() != 0 { - params = append(params, "endLine="+strconv.Itoa(change.GetSourceLineEnd()+1)) + params = append(params, "endLine="+strconv.Itoa(change.GetSourceLineEnd())) } buf.WriteString(fmt.Sprintf("::%s %s::%s\n", githubActionsSeverity[change.GetLevel()], strings.Join(params, ","), getMessage(change, f.Localizer))) diff --git a/formatters/format_githubactions_test.go b/formatters/format_githubactions_test.go index ca931274..f9477c35 100644 --- a/formatters/format_githubactions_test.go +++ b/formatters/format_githubactions_test.go @@ -127,7 +127,7 @@ func TestGitHubActionsFormatter_RenderChangelog_FileLocation(t *testing.T) { // check output output, err := gitHubFormatter.RenderChangelog(testChanges, formatters.NewRenderOpts(), nil) assert.NoError(t, err) - expectedOutput := "::error title=change_id,file=openapi.json,col=6,endColumn=11,line=21,endLine=26::in API GET /api/test This is a breaking change.\n" + expectedOutput := "::error title=change_id,file=openapi.json,col=5,endColumn=10,line=20,endLine=25::in API GET /api/test This is a breaking change.\n" assert.Equal(t, expectedOutput, string(output)) } From 8195d3b9d3aa4242b07a786c6017b241f61fba8b Mon Sep 17 00:00:00 2001 From: Reuven Harrison Date: Sun, 24 Nov 2024 14:53:45 +0200 Subject: [PATCH 06/12] getOriginLine, getOriginCol --- checker/api_change.go | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/checker/api_change.go b/checker/api_change.go index 0c183542..aa7ece14 100644 --- a/checker/api_change.go +++ b/checker/api_change.go @@ -33,8 +33,6 @@ type ApiChange struct { func NewApiChange(id string, config *Config, args []any, comment string, operationsSources *diff.OperationsSourcesMap, operation *openapi3.Operation, method, path string) ApiChange { - line, col := getOrigin(operation) - return ApiChange{ Id: id, Level: config.getLogLevel(id), @@ -47,8 +45,8 @@ func NewApiChange(id string, config *Config, args []any, comment string, operati CommonChange: CommonChange{ Attributes: getAttributes(config, operation), }, - SourceLine: line, - SourceColumn: col, + SourceLine: getOriginLine(operation), + SourceColumn: getOriginCol(operation), } } @@ -57,15 +55,20 @@ func (c ApiChange) WithOrigin(origin *openapi3.Origin) ApiChange { return c } -func getOrigin(operation *openapi3.Operation) (int, int) { +func getOriginLine(operation *openapi3.Operation) int { if operation == nil || operation.Origin == nil { - return 0, 0 + return 0 } - line := operation.Origin.Key.Line - col := operation.Origin.Key.Column + return operation.Origin.Key.Line +} + +func getOriginCol(operation *openapi3.Operation) int { + if operation == nil || operation.Origin == nil { + return 0 + } - return line, col + return operation.Origin.Key.Column } func getAttributes(config *Config, operation *openapi3.Operation) map[string]any { From 9dc7298bea438ca63c69be649b3c1c751a9321ac Mon Sep 17 00:00:00 2001 From: Reuven Harrison Date: Sun, 24 Nov 2024 20:19:43 +0200 Subject: [PATCH 07/12] coverage --- checker/api_change_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/checker/api_change_test.go b/checker/api_change_test.go index 4d35ead6..23a667a7 100644 --- a/checker/api_change_test.go +++ b/checker/api_change_test.go @@ -3,6 +3,7 @@ package checker_test import ( "testing" + "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/require" "github.com/tufin/oasdiff/checker" "github.com/tufin/oasdiff/load" @@ -83,3 +84,9 @@ func TestApiChange_SourceUrl(t *testing.T) { require.Equal(t, "", apiChangeSourceFile.GetSourceFile()) } + +func TestApiChange_WithOrigin(t *testing.T) { + apiChangeSourceFile := apiChange + origin := openapi3.Origin{} + require.True(t, &origin == apiChangeSourceFile.WithOrigin(&origin).Origin) +} From 0e5acd7f7001598ea5f3fc855c0653dcaa156fca Mon Sep 17 00:00:00 2001 From: Reuven Harrison Date: Sun, 24 Nov 2024 20:38:39 +0200 Subject: [PATCH 08/12] enable docker on branch --- .github/workflows/docker.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index ca87603e..2d099083 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -3,6 +3,7 @@ on: push: branches: - 'main' + - 'origin' tags: - 'v*' jobs: @@ -50,7 +51,7 @@ jobs: platforms: linux/amd64,linux/arm64 context: ./ file: ./Dockerfile - tags: tufin/oasdiff:${{ github.ref_name }}, tufin/oasdiff:stable, tufin/oasdiff:latest + tags: tufin/oasdiff:${{ github.ref_name }} labels: ${{ steps.meta.outputs.labels }} if: github.ref != 'refs/heads/main' && github.event_name != 'pull_request' From ac2f9e20fa716ca4aa0ea145de56a345cf163515 Mon Sep 17 00:00:00 2001 From: Reuven Harrison Date: Mon, 25 Nov 2024 18:37:19 +0200 Subject: [PATCH 09/12] test WithLocation --- checker/api_change.go | 14 ++++- checker/api_change_test.go | 10 +++- checker/check_added_required_request_body.go | 2 +- checker/check_api_deprecation_test.go | 6 ++ ...eck_request_body_required_value_updated.go | 2 +- ...equest_body_required_value_updated_test.go | 20 +++---- ...request_body_became_required_revision.yaml | 60 +++++++++++++++++++ 7 files changed, 96 insertions(+), 18 deletions(-) create mode 100644 data/checker/request_body_became_required_revision.yaml diff --git a/checker/api_change.go b/checker/api_change.go index aa7ece14..70233ce5 100644 --- a/checker/api_change.go +++ b/checker/api_change.go @@ -22,7 +22,6 @@ type ApiChange struct { OperationId string Path string Source *load.Source - Origin *openapi3.Origin SourceFile string SourceLine int @@ -50,8 +49,17 @@ func NewApiChange(id string, config *Config, args []any, comment string, operati } } -func (c ApiChange) WithOrigin(origin *openapi3.Origin) ApiChange { - c.Origin = origin +func (c ApiChange) WithLocation(origin *openapi3.Origin, field string) ApiChange { + if origin == nil { + return c + } + location, ok := origin.Fields[field] + if !ok { + return c + } + + c.SourceLine = location.Line + c.SourceColumn = location.Column return c } diff --git a/checker/api_change_test.go b/checker/api_change_test.go index 23a667a7..5a4380c6 100644 --- a/checker/api_change_test.go +++ b/checker/api_change_test.go @@ -86,7 +86,11 @@ func TestApiChange_SourceUrl(t *testing.T) { } func TestApiChange_WithOrigin(t *testing.T) { - apiChangeSourceFile := apiChange - origin := openapi3.Origin{} - require.True(t, &origin == apiChangeSourceFile.WithOrigin(&origin).Origin) + apiChangeSourceFile := apiChange.WithLocation(&openapi3.Origin{ + Fields: map[string]openapi3.Location{"field": { + Line: 1, + Column: 2, + }}}, "field") + require.Equal(t, 1, apiChangeSourceFile.SourceLine) + require.Equal(t, 2, apiChangeSourceFile.SourceColumn) } diff --git a/checker/check_added_required_request_body.go b/checker/check_added_required_request_body.go index 14e23aa9..a681e607 100644 --- a/checker/check_added_required_request_body.go +++ b/checker/check_added_required_request_body.go @@ -38,7 +38,7 @@ func AddedRequestBodyCheck(diffReport *diff.Diff, operationsSources *diff.Operat operationItem.Revision, operation, path, - )) + ).WithLocation(operationItem.Revision.RequestBody.Value.Origin, "required")) } } } diff --git a/checker/check_api_deprecation_test.go b/checker/check_api_deprecation_test.go index 5acf8dbd..79d122f5 100644 --- a/checker/check_api_deprecation_test.go +++ b/checker/check_api_deprecation_test.go @@ -18,6 +18,12 @@ func open(file string) (*load.SpecInfo, error) { return load.NewSpecInfo(openapi3.NewLoader(), load.NewSource(file)) } +func openWithLocation(file string) (*load.SpecInfo, error) { + loader := openapi3.NewLoader() + loader.IncludeOrigin = true + return load.NewSpecInfo(loader, load.NewSource(file)) +} + func getDeprecationFile(file string) string { return fmt.Sprintf("../data/deprecation/%s", file) } diff --git a/checker/check_request_body_required_value_updated.go b/checker/check_request_body_required_value_updated.go index 7f1b037b..22c1f2e2 100644 --- a/checker/check_request_body_required_value_updated.go +++ b/checker/check_request_body_required_value_updated.go @@ -41,7 +41,7 @@ func RequestBodyRequiredUpdatedCheck(diffReport *diff.Diff, operationsSources *d operationItem.Revision, operation, path, - )) + ).WithLocation(operationItem.Revision.RequestBody.Value.Origin, "required")) } } return result diff --git a/checker/check_request_body_required_value_updated_test.go b/checker/check_request_body_required_value_updated_test.go index 67950e66..2f5d8805 100644 --- a/checker/check_request_body_required_value_updated_test.go +++ b/checker/check_request_body_required_value_updated_test.go @@ -11,24 +11,24 @@ import ( // CL: changing request's body to required is breaking func TestRequestBodyBecameRequired(t *testing.T) { - s1, err := open("../data/checker/request_body_became_required_base.yaml") + s1, err := openWithLocation("../data/checker/request_body_became_required_base.yaml") require.NoError(t, err) - s2, err := open("../data/checker/request_body_became_required_base.yaml") + s2, err := openWithLocation("../data/checker/request_body_became_required_revision.yaml") require.NoError(t, err) - s2.Spec.Paths.Value("/api/v1.0/groups").Post.RequestBody.Value.Required = true - d, osm, err := diff.GetWithOperationsSourcesMap(diff.NewConfig(), s1, s2) require.NoError(t, err) errs := checker.CheckBackwardCompatibility(singleCheckConfig(checker.RequestBodyRequiredUpdatedCheck), d, osm) require.Len(t, errs, 1) require.Equal(t, checker.ApiChange{ - Id: checker.RequestBodyBecameRequiredId, - Level: checker.ERR, - Operation: "POST", - Path: "/api/v1.0/groups", - Source: load.NewSource("../data/checker/request_body_became_required_base.yaml"), - OperationId: "createOneGroup", + Id: checker.RequestBodyBecameRequiredId, + Level: checker.ERR, + Operation: "POST", + Path: "/api/v1.0/groups", + Source: load.NewSource("../data/checker/request_body_became_required_revision.yaml"), + OperationId: "createOneGroup", + SourceLine: 19, + SourceColumn: 9, }, errs[0]) } diff --git a/data/checker/request_body_became_required_revision.yaml b/data/checker/request_body_became_required_revision.yaml new file mode 100644 index 00000000..5835dd48 --- /dev/null +++ b/data/checker/request_body_became_required_revision.yaml @@ -0,0 +1,60 @@ +openapi: 3.0.1 +info: + title: Tufin + version: "2.0" +servers: +- url: https://localhost:9080 +paths: + /api/v1.0/groups: + post: + tags: + - Group + operationId: createOneGroup + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/GroupView' + description: Creates one project. + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/GroupView' + description: OK + "409": + content: + application/json: + schema: + $ref: '#/components/schemas/GroupView' + description: Conflict + summary: Create One Project +components: + parameters: + groupId: + in: path + name: groupId + required: true + schema: + type: string + schemas: + GroupView: + type: object + properties: + data: + type: object + properties: + created: + type: string + format: date-time + readOnly: true + pattern: "^[a-z]+$" + id: + type: string + readOnly: true + name: + type: string + required: + - name \ No newline at end of file From 9643eed12d27d96d9cabc757899fbff56e0561b9 Mon Sep 17 00:00:00 2001 From: Reuven Harrison Date: Mon, 25 Nov 2024 18:40:50 +0200 Subject: [PATCH 10/12] fix docs --- docs/BREAKING-CHANGES-EXAMPLES.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/BREAKING-CHANGES-EXAMPLES.md b/docs/BREAKING-CHANGES-EXAMPLES.md index 8862f666..bf0be386 100644 --- a/docs/BREAKING-CHANGES-EXAMPLES.md +++ b/docs/BREAKING-CHANGES-EXAMPLES.md @@ -56,10 +56,10 @@ These examples are automatically generated from unit tests. [deleting an operation before sunset date is breaking](../checker/check_api_removed_test.go?plain=1#L11) [deleting an operation is breaking](../checker/check_breaking_test.go?plain=1#L45) [deleting sunset header for a deprecated endpoint is breaking](../checker/check_api_sunset_changed_test.go?plain=1#L11) -[deprecating an operation with a deprecation policy and an invalid stability level is breaking](../checker/check_api_deprecation_test.go?plain=1#L67) -[deprecating an operation with a deprecation policy and an invalid sunset date is breaking](../checker/check_api_deprecation_test.go?plain=1#L48) -[deprecating an operation with a deprecation policy and sunset date before required deprecation period is breaking](../checker/check_api_deprecation_test.go?plain=1#L214) -[deprecating an operation with a deprecation policy but without specifying sunset date is breaking](../checker/check_api_deprecation_test.go?plain=1#L103) +[deprecating an operation with a deprecation policy and an invalid stability level is breaking](../checker/check_api_deprecation_test.go?plain=1#L73) +[deprecating an operation with a deprecation policy and an invalid sunset date is breaking](../checker/check_api_deprecation_test.go?plain=1#L54) +[deprecating an operation with a deprecation policy and sunset date before required deprecation period is breaking](../checker/check_api_deprecation_test.go?plain=1#L220) +[deprecating an operation with a deprecation policy but without specifying sunset date is breaking](../checker/check_api_deprecation_test.go?plain=1#L109) [inclreasing request body min items is breaking](../checker/check_request_property_min_items_increased_test.go?plain=1#L12) [increasing max length in response is breaking](../checker/check_breaking_min_max_test.go?plain=1#L93) [increasing min items in request is breaking](../checker/check_breaking_min_max_test.go?plain=1#L236) @@ -129,21 +129,21 @@ These examples are automatically generated from unit tests. [changing response's body schema type from number to integer is not breaking](../checker/check_breaking_response_type_changed_test.go?plain=1#L52) [changing response's body schema type from number/none to integer/int32 is not breaking](../checker/check_breaking_response_type_changed_test.go?plain=1#L90) [changing servers is not breaking](../checker/check_not_breaking_test.go?plain=1#L252) -[deleting a path after sunset date of all contained operations is not breaking](../checker/check_api_deprecation_test.go?plain=1#L255) +[deleting a path after sunset date of all contained operations is not breaking](../checker/check_api_deprecation_test.go?plain=1#L261) [deleting a pattern from a schema is not breaking](../checker/check_breaking_test.go?plain=1#L459) [deleting a required write-only property in response body is not breaking](../checker/check_breaking_property_test.go?plain=1#L495) [deleting a tag is not breaking](../checker/check_not_breaking_test.go?plain=1#L71) -[deleting an operation after sunset date is not breaking](../checker/check_api_deprecation_test.go?plain=1#L33) +[deleting an operation after sunset date is not breaking](../checker/check_api_deprecation_test.go?plain=1#L39) [deleting an operation without sunset date is not breaking](../checker/check_api_removed_test.go?plain=1#L29) [deleting other extension (not sunset) header for a deprecated endpoint is not breaking](../checker/check_api_sunset_changed_test.go?plain=1#L84) [deprecating a header is not breaking](../checker/check_not_breaking_test.go?plain=1#L226) [deprecating a parameter is not breaking](../checker/check_not_breaking_test.go?plain=1#L213) [deprecating a schema is not breaking](../checker/check_not_breaking_test.go?plain=1#L239) -[deprecating an operation with a default deprecation policy but without specifying sunset date is not breaking](../checker/check_api_deprecation_test.go?plain=1#L121) -[deprecating an operation with a deprecation policy and sunset date after required deprecation period is not breaking](../checker/check_api_deprecation_test.go?plain=1#L234) -[deprecating an operation without a deprecation policy and without specifying sunset date is not breaking for alpha level](../checker/check_api_deprecation_test.go?plain=1#L137) -[deprecating an operation without a deprecation policy and without specifying sunset date is not breaking for draft level](../checker/check_api_deprecation_test.go?plain=1#L171) -[deprecating an operation without a deprecation policy but without specifying sunset date is not breaking](../checker/check_api_deprecation_test.go?plain=1#L87) +[deprecating an operation with a default deprecation policy but without specifying sunset date is not breaking](../checker/check_api_deprecation_test.go?plain=1#L127) +[deprecating an operation with a deprecation policy and sunset date after required deprecation period is not breaking](../checker/check_api_deprecation_test.go?plain=1#L240) +[deprecating an operation without a deprecation policy and without specifying sunset date is not breaking for alpha level](../checker/check_api_deprecation_test.go?plain=1#L143) +[deprecating an operation without a deprecation policy and without specifying sunset date is not breaking for draft level](../checker/check_api_deprecation_test.go?plain=1#L177) +[deprecating an operation without a deprecation policy but without specifying sunset date is not breaking](../checker/check_api_deprecation_test.go?plain=1#L93) [descreasing request body min items is not breaking](../checker/check_request_property_min_items_increased_test.go?plain=1#L35) [increasing max length in request is not breaking](../checker/check_breaking_min_max_test.go?plain=1#L76) [increasing min items in response is not breaking](../checker/check_breaking_min_max_test.go?plain=1#L250) @@ -162,8 +162,8 @@ These examples are automatically generated from unit tests. [reducing min length in request is not breaking](../checker/check_breaking_min_max_test.go?plain=1#L48) [removing an existing response with error status is not breaking](../checker/check_breaking_test.go?plain=1#L406) [removing an existing response with unparseable status is not breaking](../checker/check_breaking_test.go?plain=1#L390) -[removing the path without a deprecation policy and without specifying sunset date is not breaking for alpha level](../checker/check_api_deprecation_test.go?plain=1#L152) -[removing the path without a deprecation policy and without specifying sunset date is not breaking for draft level](../checker/check_api_deprecation_test.go?plain=1#L188) +[removing the path without a deprecation policy and without specifying sunset date is not breaking for alpha level](../checker/check_api_deprecation_test.go?plain=1#L158) +[removing the path without a deprecation policy and without specifying sunset date is not breaking for draft level](../checker/check_api_deprecation_test.go?plain=1#L194) [renaming a path parameter is not breaking](../checker/check_breaking_test.go?plain=1#L136) ## Examples of info-level changes for changelog @@ -306,8 +306,8 @@ These examples are automatically generated from unit tests. [making request property required, while also giving it a default value](../checker/check_request_property_required_updated_test.go?plain=1#L58) [new header, query and cookie request params](../checker/check_new_request_non_path_parameter_test.go?plain=1#L11) [new paths or path operations](../checker/check_api_added_test.go?plain=1#L11) -[path operations that became deprecated](../checker/check_api_deprecation_test.go?plain=1#L270) -[path operations that were re-activated](../checker/check_api_deprecation_test.go?plain=1#L293) +[path operations that became deprecated](../checker/check_api_deprecation_test.go?plain=1#L276) +[path operations that were re-activated](../checker/check_api_deprecation_test.go?plain=1#L299) [removing 'allOf' subschema from the request body or request body property](../checker/check_request_property_all_of_updated_test.go?plain=1#L46) [removing 'allOf' subschema from the response body or response body property](../checker/check_response_property_all_of_updated_test.go?plain=1#L46) [removing 'anyOf' schema from the request body or request body property](../checker/check_request_property_any_of_updated_test.go?plain=1#L46) From f22314d554ae428889c72961c6ec692cb6eb4066 Mon Sep 17 00:00:00 2001 From: Reuven Harrison Date: Mon, 25 Nov 2024 21:52:06 +0200 Subject: [PATCH 11/12] add unit tests --- checker/api_change_test.go | 2 +- ...equest_body_required_value_updated_test.go | 41 ++++++++++--- .../request_body_became_optional_deleted.yaml | 59 ++++++++++++++++++ ...request_body_became_optional_revision.yaml | 60 +++++++++++++++++++ docs/BREAKING-CHANGES-EXAMPLES.md | 1 + 5 files changed, 153 insertions(+), 10 deletions(-) create mode 100644 data/checker/request_body_became_optional_deleted.yaml create mode 100644 data/checker/request_body_became_optional_revision.yaml diff --git a/checker/api_change_test.go b/checker/api_change_test.go index 5a4380c6..49078a05 100644 --- a/checker/api_change_test.go +++ b/checker/api_change_test.go @@ -85,7 +85,7 @@ func TestApiChange_SourceUrl(t *testing.T) { require.Equal(t, "", apiChangeSourceFile.GetSourceFile()) } -func TestApiChange_WithOrigin(t *testing.T) { +func TestApiChange_WithLocation(t *testing.T) { apiChangeSourceFile := apiChange.WithLocation(&openapi3.Origin{ Fields: map[string]openapi3.Location{"field": { Line: 1, diff --git a/checker/check_request_body_required_value_updated_test.go b/checker/check_request_body_required_value_updated_test.go index 2f5d8805..a09b1ed8 100644 --- a/checker/check_request_body_required_value_updated_test.go +++ b/checker/check_request_body_required_value_updated_test.go @@ -34,23 +34,46 @@ func TestRequestBodyBecameRequired(t *testing.T) { // CL: changing request's body to optional func TestRequestBodyBecameOptional(t *testing.T) { - s1, err := open("../data/checker/request_body_became_optional_base.yaml") + s1, err := openWithLocation("../data/checker/request_body_became_optional_base.yaml") require.NoError(t, err) - s2, err := open("../data/checker/request_body_became_optional_base.yaml") + s2, err := openWithLocation("../data/checker/request_body_became_optional_revision.yaml") require.NoError(t, err) - s2.Spec.Paths.Value("/api/v1.0/groups").Post.RequestBody.Value.Required = false + d, osm, err := diff.GetWithOperationsSourcesMap(diff.NewConfig(), s1, s2) + require.NoError(t, err) + errs := checker.CheckBackwardCompatibilityUntilLevel(singleCheckConfig(checker.RequestBodyRequiredUpdatedCheck), d, osm, checker.INFO) + require.Len(t, errs, 1) + require.Equal(t, checker.ApiChange{ + Id: checker.RequestBodyBecameOptionalId, + Level: checker.INFO, + Operation: "POST", + Path: "/api/v1.0/groups", + Source: load.NewSource("../data/checker/request_body_became_optional_revision.yaml"), + OperationId: "createOneGroup", + SourceLine: 19, + SourceColumn: 9, + }, errs[0]) +} + +// CL: changing request's body to optional by deletion +func TestRequestBodyBecameOptionalDeleted(t *testing.T) { + s1, err := openWithLocation("../data/checker/request_body_became_optional_base.yaml") + require.NoError(t, err) + s2, err := openWithLocation("../data/checker/request_body_became_optional_deleted.yaml") + require.NoError(t, err) d, osm, err := diff.GetWithOperationsSourcesMap(diff.NewConfig(), s1, s2) require.NoError(t, err) errs := checker.CheckBackwardCompatibilityUntilLevel(singleCheckConfig(checker.RequestBodyRequiredUpdatedCheck), d, osm, checker.INFO) require.Len(t, errs, 1) require.Equal(t, checker.ApiChange{ - Id: checker.RequestBodyBecameOptionalId, - Level: checker.INFO, - Operation: "POST", - Path: "/api/v1.0/groups", - Source: load.NewSource("../data/checker/request_body_became_optional_base.yaml"), - OperationId: "createOneGroup", + Id: checker.RequestBodyBecameOptionalId, + Level: checker.INFO, + Operation: "POST", + Path: "/api/v1.0/groups", + Source: load.NewSource("../data/checker/request_body_became_optional_deleted.yaml"), + OperationId: "createOneGroup", + SourceLine: 9, + SourceColumn: 5, }, errs[0]) } diff --git a/data/checker/request_body_became_optional_deleted.yaml b/data/checker/request_body_became_optional_deleted.yaml new file mode 100644 index 00000000..42044a0b --- /dev/null +++ b/data/checker/request_body_became_optional_deleted.yaml @@ -0,0 +1,59 @@ +openapi: 3.0.1 +info: + title: Tufin + version: "2.0" +servers: +- url: https://localhost:9080 +paths: + /api/v1.0/groups: + post: + tags: + - Group + operationId: createOneGroup + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/GroupView' + description: Creates one project. + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/GroupView' + description: OK + "409": + content: + application/json: + schema: + $ref: '#/components/schemas/GroupView' + description: Conflict + summary: Create One Project +components: + parameters: + groupId: + in: path + name: groupId + required: true + schema: + type: string + schemas: + GroupView: + type: object + properties: + data: + type: object + properties: + created: + type: string + format: date-time + readOnly: true + pattern: "^[a-z]+$" + id: + type: string + readOnly: true + name: + type: string + required: + - name \ No newline at end of file diff --git a/data/checker/request_body_became_optional_revision.yaml b/data/checker/request_body_became_optional_revision.yaml new file mode 100644 index 00000000..5dddd5ed --- /dev/null +++ b/data/checker/request_body_became_optional_revision.yaml @@ -0,0 +1,60 @@ +openapi: 3.0.1 +info: + title: Tufin + version: "2.0" +servers: +- url: https://localhost:9080 +paths: + /api/v1.0/groups: + post: + tags: + - Group + operationId: createOneGroup + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/GroupView' + description: Creates one project. + required: false + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/GroupView' + description: OK + "409": + content: + application/json: + schema: + $ref: '#/components/schemas/GroupView' + description: Conflict + summary: Create One Project +components: + parameters: + groupId: + in: path + name: groupId + required: true + schema: + type: string + schemas: + GroupView: + type: object + properties: + data: + type: object + properties: + created: + type: string + format: date-time + readOnly: true + pattern: "^[a-z]+$" + id: + type: string + readOnly: true + name: + type: string + required: + - name \ No newline at end of file diff --git a/docs/BREAKING-CHANGES-EXAMPLES.md b/docs/BREAKING-CHANGES-EXAMPLES.md index bf0be386..5afe33f2 100644 --- a/docs/BREAKING-CHANGES-EXAMPLES.md +++ b/docs/BREAKING-CHANGES-EXAMPLES.md @@ -251,6 +251,7 @@ These examples are automatically generated from unit tests. [changing request property type](../checker/check_request_property_type_changed_test.go?plain=1#L64) [changing request query parameter format](../checker/check_request_parameters_type_changed_test.go?plain=1#L110) [changing request query parameter type](../checker/check_request_parameters_type_changed_test.go?plain=1#L38) +[changing request's body to optional by deletion](../checker/check_request_body_required_value_updated_test.go?plain=1#L58) [changing request's body to optional](../checker/check_request_body_required_value_updated_test.go?plain=1#L35) [changing request's body to required is breaking](../checker/check_request_body_required_value_updated_test.go?plain=1#L12) [changing required request property to not read-only](../checker/check_request_property_write_only_read_only_test.go?plain=1#L187) From 77143b8577418a49bd6ca17506ea3d341534019b Mon Sep 17 00:00:00 2001 From: Reuven Harrison Date: Sat, 14 Dec 2024 18:17:51 +0200 Subject: [PATCH 12/12] use latest kin-openapi --- go.mod | 9 +++------ go.sum | 15 +++++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 2b5e0681..5bc14c08 100644 --- a/go.mod +++ b/go.mod @@ -2,14 +2,10 @@ module github.com/tufin/oasdiff go 1.22.5 -replace gopkg.in/yaml.v3 => github.com/oasdiff/yaml3 v0.0.0-20240920135353-c185dc6ea7c6 - -replace github.com/invopop/yaml => github.com/oasdiff/yaml v0.0.0-20240920191703-3e5a9fb5bdf3 - require ( cloud.google.com/go v0.115.0 github.com/TwiN/go-color v1.4.1 - github.com/getkin/kin-openapi v0.128.1-0.20241113210624-e230c133e5ca + github.com/getkin/kin-openapi v0.128.1-0.20241211220347-325cecc5e4e1 github.com/oasdiff/telemetry v0.1.2 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 @@ -27,6 +23,8 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/oasdiff/yaml v0.0.0-20241210131133-6b86fb107d80 // indirect + github.com/oasdiff/yaml3 v0.0.0-20241210130736-a94c01f36349 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -49,7 +47,6 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect - github.com/invopop/yaml v0.3.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect diff --git a/go.sum b/go.sum index 2876534c..c7008498 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/getkin/kin-openapi v0.128.1-0.20241113210624-e230c133e5ca h1:14qX2UfAWKqPdofcSlsK9pPX3UbAlFHYPbRpoYRd0io= -github.com/getkin/kin-openapi v0.128.1-0.20241113210624-e230c133e5ca/go.mod h1:5MaNKmkfVAFfhyQtzgwYLynYAHgFA0KSykwF6+NoGMc= +github.com/getkin/kin-openapi v0.128.1-0.20241211220347-325cecc5e4e1 h1:jIUT6NT0F50dhHXlFWsGfdJI/5OnnzO6HZHSiSh5DfM= +github.com/getkin/kin-openapi v0.128.1-0.20241211220347-325cecc5e4e1/go.mod h1:gmWI+b/J45xqpyK5wJmRRZse5wefA5H0RDMK46kLUtI= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= @@ -45,10 +45,10 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/oasdiff/telemetry v0.1.2 h1:hkmA5YTISVF2/zWa23y29WdPws1Q53pyLOFYMHXoZ1U= github.com/oasdiff/telemetry v0.1.2/go.mod h1:Y0DaW/CasxZ+vzR54btj430XsL6DGF+rMbJkRld6u3M= -github.com/oasdiff/yaml v0.0.0-20240920191703-3e5a9fb5bdf3 h1:nqCxALSUgWobWkFGIrhLRzR/bpImQdGj+3JS4/scTJo= -github.com/oasdiff/yaml v0.0.0-20240920191703-3e5a9fb5bdf3/go.mod h1:AOyUNV9ElKz7EEZeBm/48U54UtjtgCMT9fFbZEsClQc= -github.com/oasdiff/yaml3 v0.0.0-20240920135353-c185dc6ea7c6 h1:+ZsuDTdapTJxfMQk7SOJiNMg0v36pui01L7FEO615r8= -github.com/oasdiff/yaml3 v0.0.0-20240920135353-c185dc6ea7c6/go.mod h1:lqlOfJRrYpgeWHQj+ky2tf7UJ3PzgHTHRQEpc90nbp0= +github.com/oasdiff/yaml v0.0.0-20241210131133-6b86fb107d80 h1:nZspmSkneBbtxU9TopEAE0CY+SBJLxO8LPUlw2vG4pU= +github.com/oasdiff/yaml v0.0.0-20241210131133-6b86fb107d80/go.mod h1:7tFDb+Y51LcDpn26GccuUgQXUk6t0CXZsivKjyimYX8= +github.com/oasdiff/yaml3 v0.0.0-20241210130736-a94c01f36349 h1:t05Ww3DxZutOqbMN+7OIuqDwXbhl32HiZGpLy26BAPc= +github.com/oasdiff/yaml3 v0.0.0-20241210130736-a94c01f36349/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= @@ -120,3 +120,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=