diff --git a/tools/cli/internal/openapi/oasdiff.go b/tools/cli/internal/openapi/oasdiff.go new file mode 100644 index 000000000..be42623f7 --- /dev/null +++ b/tools/cli/internal/openapi/oasdiff.go @@ -0,0 +1,74 @@ +package openapi + +import ( + "fmt" + "mongodb/openapi/tools/cli/internal/openapi/errors" + "os" + + "github.com/tufin/oasdiff/diff" + "github.com/tufin/oasdiff/load" +) + +type OasDiff struct { + base *load.SpecInfo + external *load.SpecInfo + config *diff.Config + specDiff *diff.Diff + parser Parser +} + +func NewOasDiff(base *load.SpecInfo) *OasDiff { + return &OasDiff{ + base: base, + parser: NewOpenAPI3(), + } +} + +func (o *OasDiff) MergeOpenAPISpecs(paths []string) (*load.SpecInfo, error) { + for _, p := range paths { + spec, err := o.parser.CreateOpenAPISpecFromPath(p) + if err != nil { + return nil, err + } + + o.config = &diff.Config{ + IncludePathParams: true, + } + + specDiff, err := diff.Get(o.config, o.base.Spec, spec.Spec) + if err != nil { + _, _ = fmt.Fprintf(os.Stderr, "error in calculating the diff of the specs: %s", err) + return nil, err + } + + o.specDiff = specDiff + o.external = spec + err = o.mergeSpecIntoBase() + if err != nil { + return nil, err + } + } + + return o.base, nil +} + +func (o OasDiff) mergeSpecIntoBase() error { + return o.mergePaths() +} + +func (o OasDiff) mergePaths() error { + pathsToMerge := o.external.Spec.Paths + basePaths := o.base.Spec.Paths + for k, v := range pathsToMerge { + if _, ok := basePaths[k]; !ok { + basePaths[k] = v + } else { + return errors.PathConflictError{ + Entry: k, + } + } + } + + o.base.Spec.Paths = basePaths + return nil +} diff --git a/tools/cli/internal/openapi/openapi3.go b/tools/cli/internal/openapi/openapi3.go new file mode 100644 index 000000000..840dbfc5c --- /dev/null +++ b/tools/cli/internal/openapi/openapi3.go @@ -0,0 +1,31 @@ +package openapi + +import ( + "github.com/getkin/kin-openapi/openapi3" + "github.com/tufin/oasdiff/load" +) + +type OpenAPI3 struct { + IsExternalRefsAllowed bool + CircularReferenceCounter int +} + +func NewOpenAPI3() *OpenAPI3 { + return &OpenAPI3{ + IsExternalRefsAllowed: true, + CircularReferenceCounter: 10, + } +} + +func (o *OpenAPI3) CreateOpenAPISpecFromPath(path string) (*load.SpecInfo, error) { + loader := openapi3.NewLoader() + loader.IsExternalRefsAllowed = true + openapi3.CircularReferenceCounter = 10 + + spec, err := load.LoadSpecInfo(loader, load.NewSource(path)) + if err != nil { + return nil, err + } + + return spec, nil +}