Skip to content

Commit

Permalink
new exclude-elements flag (#209)
Browse files Browse the repository at this point in the history
  • Loading branch information
Reuven Harrison authored Mar 28, 2023
1 parent 7a7d639 commit 12803e0
Show file tree
Hide file tree
Showing 56 changed files with 424 additions and 289 deletions.
46 changes: 27 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,31 +59,33 @@ Usage of oasdiff:
-deprecation-days int
minimal number of days required between deprecating a resource and removing it without being considered 'breaking'
-err-ignore string
the configuration file for ignoring errors with -check-breaking
the configuration file for ignoring errors with '-check-breaking'
-exclude-description
ignore changes to descriptions
ignore changes to descriptions (deprecated, use '-exclude-elements description' instead)
-exclude-elements value
comma-seperated list of elements to exclude from diff
-exclude-endpoints
exclude endpoints from output
exclude endpoints from output (deprecated, use '-exclude-elements endpoints' instead)
-exclude-examples
ignore changes to examples
ignore changes to examples (deprecated, use '-exclude-elements examples' instead)
-fail-on-diff
exit with return code 1 when any ERR-level breaking changes are found, used together with -check-breaking
exit with return code 1 when any ERR-level breaking changes are found, used together with '-check-breaking'
-fail-on-warns
exit with return code 1 when any WARN-level breaking changes are found, used together with -check-breaking and -fail-on-diff
exit with return code 1 when any WARN-level breaking changes are found, used together with '-check-breaking' and '-fail-on-diff'
-filter string
if provided, diff will include only paths that match this regular expression
-filter-extension string
if provided, diff will exclude paths and operations with an OpenAPI Extension matching this regular expression
-format string
output format: yaml, json, text or html (default "yaml")
-include-checks value
comma-seperated list of optional backwards compatibility checks
comma-seperated list of optional breaking-changes checks
-lang string
language for localized breaking changes checks errors (default "en")
-max-circular-dep int
maximum allowed number of circular dependencies between objects in OpenAPI specs (default 5)
-prefix string
deprecated. use -prefix-revision instead
deprecated. use '-prefix-revision' instead
-prefix-base string
if provided, paths in original (base) spec will be prefixed with the given prefix before comparison
-prefix-revision string
Expand All @@ -99,7 +101,7 @@ Usage of oasdiff:
-version
show version and quit
-warn-ignore string
the configuration file for ignoring warnings with -check-breaking
the configuration file for ignoring warnings with '-check-breaking'
```
All arguments can be passed with one or two leading minus signs.
For example, ```-breaking-only``` and ```--breaking-only``` are equivalent.
Expand Down Expand Up @@ -174,9 +176,9 @@ Notes:
1. [OpenAPI Extensions](https://swagger.io/docs/specification/openapi-extensions/) can be defined both at the [path](https://swagger.io/docs/specification/paths-and-operations/) level and at the [operation](https://swagger.io/docs/specification/paths-and-operations/) level. Both are matched and excluded with this flag.
2. If a path or operation has a matching extension only in one of the specs, but not in the other, it will appear as Added or Deleted.

### Ignore changes to descriptions and examples
### Ignore changes to description and examples
```bash
oasdiff -exclude-description -exclude-examples -format text -base data/openapi-test1.yaml -revision data/openapi-test3.yaml
oasdiff -exclude-elements description,examples -format text -base data/openapi-test1.yaml -revision data/openapi-test3.yaml
```

### Display change summary
Expand Down Expand Up @@ -224,7 +226,7 @@ Service source code: https://github.com/oasdiff/oasdiff-service
The default output format, YAML, provides a full view of all diff details.
Note that no output in the YAML format signifies that the diff is empty, or, in other words, there are no changes.
Other formats: text, markdown, and HTML, are designed to be more user-friendly by providing only the most important parts of the diff, in a simplified format.
The JSON format works only with `-exclude-endpoints` and is intended as a workaround for YAML complex mapping keys which aren't supported by some libraries (see comment at end of next section for more details).
The JSON format works only with `-exclude-elements endpoints` and is intended as a workaround for YAML complex mapping keys which aren't supported by some libraries (see comment at end of next section for more details).
If you wish to include additional details in non-YAML formats, please open an issue.

## Paths vs. Endpoints
Expand Down Expand Up @@ -261,7 +263,7 @@ Some YAML libraries don't support complex mapping keys:
- python PyYAML: see https://github.com/Tufin/oasdiff/issues/94#issuecomment-1087468450
- golang gopkg.in/yaml.v3 fails to unmarshal the oasdiff output. This package offers a solution: https://github.com/tliron/yamlkeys
In such cases, consider using the `-exclude-endpoints` flag and `format json` as a workaround.
In such cases, consider using `-exclude-elements endpoints` and `-format json` as a workaround.

## Breaking Changes
Breaking changes are changes that could break a client that is relying on the OpenAPI specification.
Expand Down Expand Up @@ -422,6 +424,18 @@ oasdiff -base original.yaml -revision new.yaml -strip-prefix-base /api/v1 -strip
```
Note that stripping precedes prepending.
## Excluding Specific Kinds of Changes
You can use the `-exclude-elements` flag to exclude certain kinds of changes:
- Use `-exclude-elements changes` to exclude [Examples](https://swagger.io/specification/#example-object)
- Use `-exclude-elements description` to exclude description fields
- Use `-exclude-elements title` to exclude title fields
- Use `-exclude-elements summary` to exclude summary fields
- Use `-exclude-elements endpoints` to exclude the [endpoints diff](#paths-vs-endpoints)
You can ignore multiple elements with a comma-seperated list of excluded elements as in [this example](#ignore-changes-to-description-and-examples).
Note that [Extensions](https://swagger.io/specification/#specification-extensions) are always excluded from the diff.
## Notes for Go Developers
### Embedding oasdiff into your program
```go
Expand All @@ -438,12 +452,6 @@ diff.Get(&diff.Config{}, spec1, spec2)
oasdiff expects [OpenAPI References](https://swagger.io/docs/specification/using-ref/) to be resolved.
References are normally resolved automatically when you load the spec. In other cases you can resolve refs using [Loader.ResolveRefsIn](https://pkg.go.dev/github.com/getkin/kin-openapi/openapi3#Loader.ResolveRefsIn).

### Excluding Changes to Examples etc.
Use [configuration](diff/config.go) to exclude certain types of changes:
- [Examples](https://swagger.io/specification/#example-object)
- Descriptions
- [Extensions](https://swagger.io/specification/#specification-extensions) are excluded by default

## Requests for enhancements
1. OpenAPI 3.1 support: see https://github.com/Tufin/oasdiff/issues/52

Expand Down
3 changes: 2 additions & 1 deletion checker/default_checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ func ValidateIncludeChecks(includeChecks utils.StringList) utils.StringList {
result = append(result, s)
}
}
return result

return result.Sort()
}

func includedChecks(includeChecks utils.StringList) []BackwardCompatibilityCheck {
Expand Down
9 changes: 5 additions & 4 deletions diff/callbacks_diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import (
"fmt"

"github.com/getkin/kin-openapi/openapi3"
"github.com/tufin/oasdiff/utils"
)

// CallbacksDiff describes the changes between a pair of callback objects: https://swagger.io/specification/#callback-object
type CallbacksDiff struct {
Added StringList `json:"added,omitempty" yaml:"added,omitempty"`
Deleted StringList `json:"deleted,omitempty" yaml:"deleted,omitempty"`
Added utils.StringList `json:"added,omitempty" yaml:"added,omitempty"`
Deleted utils.StringList `json:"deleted,omitempty" yaml:"deleted,omitempty"`
Modified ModifiedCallbacks `json:"modified,omitempty" yaml:"modified,omitempty"`
}

Expand Down Expand Up @@ -40,8 +41,8 @@ type ModifiedCallbacks map[string]*PathsDiff

func newCallbacksDiff() *CallbacksDiff {
return &CallbacksDiff{
Added: StringList{},
Deleted: StringList{},
Added: utils.StringList{},
Deleted: utils.StringList{},
Modified: ModifiedCallbacks{},
}
}
Expand Down
4 changes: 3 additions & 1 deletion diff/components_diff.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package diff

import "github.com/getkin/kin-openapi/openapi3"
import (
"github.com/getkin/kin-openapi/openapi3"
)

// ComponentsDiff describes the changes between a pair of component objects: https://swagger.io/specification/#components-object
type ComponentsDiff struct {
Expand Down
73 changes: 64 additions & 9 deletions diff/config.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package diff

import (
"github.com/tufin/oasdiff/utils"
)

// Config includes various settings to control the diff
type Config struct {
ExcludeExamples bool
ExcludeDescription bool
IncludeExtensions StringSet
IncludeExtensions utils.StringSet
PathFilter string
FilterExtension string
PathPrefixBase string
Expand All @@ -13,16 +15,69 @@ type Config struct {
PathStripPrefixRevision string
BreakingOnly bool
DeprecationDays int
ExcludeEndpoints bool
ExcludeElements utils.StringSet
}

const (
excludeExamplesOption = "examples"
excludeDescriptionOption = "description"
excludeEndpointsOption = "endpoints"
excludeTitleOption = "title"
excludeSummaryOption = "summary"
)

var excludeDiffOptions = utils.StringSet{
excludeExamplesOption: {},
excludeDescriptionOption: {},
excludeEndpointsOption: {},
excludeTitleOption: {},
excludeSummaryOption: {},
}

// NewConfig returns a default configuration
func NewConfig() *Config {
return &Config{
ExcludeExamples: false,
ExcludeDescription: false,
IncludeExtensions: StringSet{},
BreakingOnly: false,
ExcludeEndpoints: false,
IncludeExtensions: utils.StringSet{},
BreakingOnly: false,
ExcludeElements: utils.StringSet{},
}
}

func (config *Config) SetExcludeElements(excludeElements utils.StringSet, excludeExamples, excludeDescription, excludeEndpoints bool) {
config.ExcludeElements = excludeElements

// backwards compatibility for deprecated flags
if excludeExamples {
config.ExcludeElements.Add(excludeExamplesOption)
}
if excludeDescription {
config.ExcludeElements.Add(excludeDescriptionOption)
}
if excludeEndpoints {
config.ExcludeElements.Add(excludeEndpointsOption)
}
}

func (config *Config) IsExcludeExamples() bool {
return config.ExcludeElements.Contains(excludeExamplesOption)
}

func (config *Config) IsExcludeDescription() bool {
return config.ExcludeElements.Contains(excludeDescriptionOption)
}

func (config *Config) IsExcludeEndpoints() bool {
return config.ExcludeElements.Contains(excludeEndpointsOption)
}

func (config *Config) IsExcludeTitle() bool {
return config.ExcludeElements.Contains(excludeTitleOption)
}

func (config *Config) IsExcludeSummary() bool {
return config.ExcludeElements.Contains(excludeSummaryOption)
}

func ValidateExcludeElements(input utils.StringList) utils.StringList {
return input.ToStringSet().Minus(excludeDiffOptions).ToStringList().Sort()
}
4 changes: 3 additions & 1 deletion diff/contact.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package diff

import "github.com/getkin/kin-openapi/openapi3"
import (
"github.com/getkin/kin-openapi/openapi3"
)

// ContactDiff describes the changes between a pair of contact objects: https://swagger.io/specification/#contact-object
type ContactDiff struct {
Expand Down
9 changes: 5 additions & 4 deletions diff/content_diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ package diff

import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/tufin/oasdiff/utils"
)

// ContentDiff describes the changes between content properties each containing media type objects: https://swagger.io/specification/#media-type-object
type ContentDiff struct {
MediaTypeAdded StringList `json:"mediaTypeAdded,omitempty" yaml:"mediaTypeAdded,omitempty"`
MediaTypeDeleted StringList `json:"mediaTypeDeleted,omitempty" yaml:"mediaTypeDeleted,omitempty"`
MediaTypeAdded utils.StringList `json:"mediaTypeAdded,omitempty" yaml:"mediaTypeAdded,omitempty"`
MediaTypeDeleted utils.StringList `json:"mediaTypeDeleted,omitempty" yaml:"mediaTypeDeleted,omitempty"`
MediaTypeModified ModifiedMediaTypes `json:"mediaTypeModified,omitempty" yaml:"mediaTypeModified,omitempty"`
}

Expand All @@ -16,8 +17,8 @@ type ModifiedMediaTypes map[string]*MediaTypeDiff

func newContentDiff() *ContentDiff {
return &ContentDiff{
MediaTypeAdded: StringList{},
MediaTypeDeleted: StringList{},
MediaTypeAdded: utils.StringList{},
MediaTypeDeleted: utils.StringList{},
MediaTypeModified: ModifiedMediaTypes{},
}
}
Expand Down
19 changes: 10 additions & 9 deletions diff/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/stretchr/testify/require"
"github.com/tufin/oasdiff/diff"
"github.com/tufin/oasdiff/utils"
)

const (
Expand Down Expand Up @@ -83,16 +84,16 @@ func TestDiff_ModifiedOperation(t *testing.T) {
require.NoError(t, err)

require.Equal(t, &diff.OperationsDiff{
Added: diff.StringList{"GET"},
Deleted: diff.StringList{"POST"},
Added: utils.StringList{"GET"},
Deleted: utils.StringList{"POST"},
Modified: diff.ModifiedOperations{},
},
d.PathsDiff.Modified["/api/test"].OperationsDiff)
}

func TestAddedExtension(t *testing.T) {
config := diff.Config{
IncludeExtensions: diff.StringSet{"x-extension-test": struct{}{}},
IncludeExtensions: utils.StringSet{"x-extension-test": struct{}{}},
}

require.Contains(t,
Expand All @@ -102,7 +103,7 @@ func TestAddedExtension(t *testing.T) {

func TestDeletedExtension(t *testing.T) {
config := diff.Config{
IncludeExtensions: diff.StringSet{"x-extension-test": struct{}{}},
IncludeExtensions: utils.StringSet{"x-extension-test": struct{}{}},
}

require.Contains(t,
Expand All @@ -112,7 +113,7 @@ func TestDeletedExtension(t *testing.T) {

func TestModifiedExtension(t *testing.T) {
config := diff.Config{
IncludeExtensions: diff.StringSet{"x-extension-test2": struct{}{}},
IncludeExtensions: utils.StringSet{"x-extension-test2": struct{}{}},
}

require.NotNil(t,
Expand Down Expand Up @@ -231,13 +232,13 @@ func TestSchemaDiff_ContentDiff(t *testing.T) {

func TestSchemaDiff_MediaTypeAdded(t *testing.T) {
require.Equal(t,
diff.StringList([]string{"application/json"}),
utils.StringList([]string{"application/json"}),
d(t, diff.NewConfig(), 5, 1).PathsDiff.Modified[securityScorePath].OperationsDiff.Modified["GET"].ParametersDiff.Modified[openapi3.ParameterInHeader]["user"].ContentDiff.MediaTypeAdded)
}

func TestSchemaDiff_MediaTypeDeleted(t *testing.T) {
require.Equal(t,
diff.StringList([]string{"application/json"}),
utils.StringList([]string{"application/json"}),
d(t, diff.NewConfig(), 1, 5).PathsDiff.Modified[securityScorePath].OperationsDiff.Modified["GET"].ParametersDiff.Modified[openapi3.ParameterInHeader]["user"].ContentDiff.MediaTypeDeleted)
}

Expand Down Expand Up @@ -309,7 +310,7 @@ func TestResponseDeleted(t *testing.T) {

func TestResponseDescriptionModified(t *testing.T) {
config := diff.Config{
IncludeExtensions: diff.StringSet{"x-extension-test": struct{}{}},
IncludeExtensions: utils.StringSet{"x-extension-test": struct{}{}},
}

require.Equal(t,
Expand Down Expand Up @@ -343,7 +344,7 @@ func TestServerDeleted(t *testing.T) {

func TestServerModified(t *testing.T) {
config := diff.Config{
IncludeExtensions: diff.StringSet{"x-extension-test": struct{}{}},
IncludeExtensions: utils.StringSet{"x-extension-test": struct{}{}},
}

require.Contains(t,
Expand Down
Loading

0 comments on commit 12803e0

Please sign in to comment.