Skip to content

Commit

Permalink
case-insensitive header comparison (#488)
Browse files Browse the repository at this point in the history
  • Loading branch information
Reuven Harrison authored Feb 6, 2024
1 parent 957bdc6 commit f7552e1
Show file tree
Hide file tree
Showing 13 changed files with 135 additions and 4 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ docker run --rm -t tufin/oasdiff changelog https://raw.githubusercontent.com/Tuf
- [Multiple versions of the same endpoint](MATCHING-ENDPOINTS.md)
- [Merge allOf schemas](ALLOF.md)
- [Merge common parameters](COMMON-PARAMS.md)
- [Case-insensitive header comparison](#case-insensitive-header-comparison)
- [Path prefix modification](#path-prefix-modification)
- [Path parameter renaming](#path-parameter-renaming)
- [Excluding certain kinds of changes](#excluding-specific-kinds-of-changes)
Expand Down Expand Up @@ -241,6 +242,13 @@ Sometimes developers decide to change names of path parameters, for example, in
Oasdiff supports path parameter renaming by default.
[Learn more](MATCHING-ENDPOINTS.md) about how oasdiff supports path parameter renaming.
## Case-Insensitive Header Comparison
Header names comparison is normally case-sensitive.
To make this comparison case-insensitive, add the `--case-insensitive-headers` flag:
```
oasdiff diff data/header-case/base.yaml data/header-case/revision.yaml --case-insensitive-headers
```
## Excluding Specific Kinds of Changes
You can use the `--exclude-elements` flag to exclude certain kinds of changes:
- Use `--exclude-elements examples` to exclude [Examples](https://swagger.io/specification/#example-object)
Expand Down
18 changes: 18 additions & 0 deletions data/header-case/base.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
openapi: 3.0.1
info:
title: Test API
version: v1
paths:
/test:
parameters:
- in: header
name: X-Case
required: true
schema:
type: string
get:
tags:
- Test
responses:
"200":
description: Success
18 changes: 18 additions & 0 deletions data/header-case/revision.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
openapi: 3.0.1
info:
title: Test API
version: v1
paths:
/test:
parameters:
- in: header
name: x-case
required: true
schema:
type: string
get:
tags:
- Test
responses:
"200":
description: Success
4 changes: 4 additions & 0 deletions flatten/headers/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/*
Package headers replaces all header names to lowercase
*/
package headers
41 changes: 41 additions & 0 deletions flatten/headers/params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package headers

import (
"strings"

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

// Lowercase replaces header names to lowercase
func Lowercase(spec *openapi3.T) {
lowerHeaderNames(spec)
}

func lowerHeaderNames(spec *openapi3.T) {
for _, path := range spec.Paths.Map() {

for _, paramRef := range path.Parameters {
lowerHeaderName(paramRef.Value)
}

for _, op := range path.Operations() {
for _, paramRef := range op.Parameters {
lowerHeaderName(paramRef.Value)
}

for _, responseRef := range op.Responses.Map() {
for _, headerRef := range responseRef.Value.Headers {
lowerHeaderName(&headerRef.Value.Parameter)
}
}
}
}
}

func lowerHeaderName(param *openapi3.Parameter) {
if param.In != openapi3.ParameterInHeader {
return
}

param.Name = strings.ToLower(param.Name)
}
9 changes: 9 additions & 0 deletions internal/changelog_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type ChangelogFlags struct {
failOn string
flattenAllOf bool
flattenParams bool
insensitiveHeaders bool
lang string
errIgnoreFile string
warnIgnoreFile string
Expand Down Expand Up @@ -64,6 +65,10 @@ func (flags *ChangelogFlags) getFlattenParams() bool {
return flags.flattenParams
}

func (flags *ChangelogFlags) getInsensitiveHeaders() bool {
return flags.insensitiveHeaders
}

func (flags *ChangelogFlags) getCircularReferenceCounter() int {
return flags.circularReferenceCounter
}
Expand Down Expand Up @@ -172,6 +177,10 @@ func (flags *ChangelogFlags) refFlattenParams() *bool {
return &flags.flattenParams
}

func (flags *ChangelogFlags) refInsensitiveHeaders() *bool {
return &flags.insensitiveHeaders
}

func (flags *ChangelogFlags) refLang() *string {
return &flags.lang
}
Expand Down
1 change: 1 addition & 0 deletions internal/cmd_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func addCommonDiffFlags(cmd *cobra.Command, flags Flags) {
cmd.PersistentFlags().BoolVarP(flags.refIncludePathParams(), "include-path-params", "", false, "include path parameter names in endpoint matching")
cmd.PersistentFlags().BoolVarP(flags.refFlattenAllOf(), "flatten-allof", "", false, "merge subschemas under allOf before diff")
cmd.PersistentFlags().BoolVarP(flags.refFlattenParams(), "flatten-params", "", false, "merge common parameters at path level with operation parameters")
cmd.PersistentFlags().BoolVarP(flags.refInsensitiveHeaders(), "case-insensitive-headers", "", false, "case-insensitive header name comparison")
addDeprecatedFlattenFlag(cmd, flags)
}

Expand Down
4 changes: 4 additions & 0 deletions internal/delta_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,7 @@ func (flags *DeltaFlags) refFlattenAllOf() *bool {
func (flags *DeltaFlags) refFlattenParams() *bool {
return &flags.flattenParams
}

func (flags *DeltaFlags) refInsensitiveHeaders() *bool {
return &flags.insensitiveHeaders
}
10 changes: 6 additions & 4 deletions internal/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,14 @@ func normalDiff(loader load.Loader, flags Flags) (*diffResult, *ReturnError) {

flattenAllOf := load.GetOption(load.WithFlattenAllOf(), flags.getFlattenAllOf())
flattenParams := load.GetOption(load.WithFlattenParams(), flags.getFlattenParams())
lowerHeaderNames := load.GetOption(load.WithLowercaseHeaders(), flags.getInsensitiveHeaders())

s1, err := load.NewSpecInfo(loader, flags.getBase(), flattenAllOf, flattenParams)
s1, err := load.NewSpecInfo(loader, flags.getBase(), flattenAllOf, flattenParams, lowerHeaderNames)
if err != nil {
return nil, getErrFailedToLoadSpec("base", flags.getBase(), err)
}

s2, err := load.NewSpecInfo(loader, flags.getRevision(), flattenAllOf, flattenParams)
s2, err := load.NewSpecInfo(loader, flags.getRevision(), flattenAllOf, flattenParams, lowerHeaderNames)
if err != nil {
return nil, getErrFailedToLoadSpec("revision", flags.getRevision(), err)
}
Expand All @@ -127,13 +128,14 @@ func composedDiff(loader load.Loader, flags Flags) (*diffResult, *ReturnError) {

flattenAllOf := load.GetOption(load.WithFlattenAllOf(), flags.getFlattenAllOf())
flattenParams := load.GetOption(load.WithFlattenParams(), flags.getFlattenParams())
lowerHeaderNames := load.GetOption(load.WithLowercaseHeaders(), flags.getInsensitiveHeaders())

s1, err := load.NewSpecInfoFromGlob(loader, flags.getBase().Path, flattenAllOf, flattenParams)
s1, err := load.NewSpecInfoFromGlob(loader, flags.getBase().Path, flattenAllOf, flattenParams, lowerHeaderNames)
if err != nil {
return nil, getErrFailedToLoadSpecs("base", flags.getBase().Path, err)
}

s2, err := load.NewSpecInfoFromGlob(loader, flags.getRevision().Path, flattenAllOf, flattenParams)
s2, err := load.NewSpecInfoFromGlob(loader, flags.getRevision().Path, flattenAllOf, flattenParams, lowerHeaderNames)
if err != nil {
return nil, getErrFailedToLoadSpecs("revision", flags.getRevision().Path, err)
}
Expand Down
9 changes: 9 additions & 0 deletions internal/diff_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type DiffFlags struct {
failOnDiff bool
flattenAllOf bool
flattenParams bool
insensitiveHeaders bool
circularReferenceCounter int
includePathParams bool
excludeElements []string
Expand Down Expand Up @@ -57,6 +58,10 @@ func (flags *DiffFlags) getFlattenParams() bool {
return flags.flattenParams
}

func (flags *DiffFlags) getInsensitiveHeaders() bool {
return flags.insensitiveHeaders
}

func (flags *DiffFlags) getCircularReferenceCounter() int {
return flags.circularReferenceCounter
}
Expand Down Expand Up @@ -165,6 +170,10 @@ func (flags *DiffFlags) refFlattenParams() *bool {
return &flags.flattenParams
}

func (flags *DiffFlags) refInsensitiveHeaders() *bool {
return &flags.insensitiveHeaders
}

func (flags *DiffFlags) refLang() *string {
return nil
}
Expand Down
2 changes: 2 additions & 0 deletions internal/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type Flags interface {
getRevision() *load.Source
getFlattenAllOf() bool
getFlattenParams() bool
getInsensitiveHeaders() bool
getCircularReferenceCounter() int
getIncludeChecks() []string
getDeprecationDaysBeta() int
Expand Down Expand Up @@ -43,6 +44,7 @@ type Flags interface {
refIncludePathParams() *bool
refFlattenAllOf() *bool
refFlattenParams() *bool
refInsensitiveHeaders() *bool
refLang() *string
refErrIgnoreFile() *string
refWarnIgnoreFile() *string
Expand Down
4 changes: 4 additions & 0 deletions internal/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,10 @@ func Test_BreakingChangesFlattenCommonParams(t *testing.T) {
require.Zero(t, internal.Run(cmdToArgs("oasdiff breaking ../data/common-params/params_in_path.yaml ../data/common-params/params_in_op.yaml --flatten-params --fail-on ERR"), io.Discard, io.Discard))
}

func Test_BreakingChangesCaseInsensitiveHeaders(t *testing.T) {
require.Zero(t, internal.Run(cmdToArgs("oasdiff breaking ../data/header-case/base.yaml ../data/header-case/revision.yaml --case-insensitive-headers --fail-on ERR"), io.Discard, io.Discard))
}

func Test_FlattenCmdOK(t *testing.T) {
require.Zero(t, internal.Run(cmdToArgs("oasdiff flatten ../data/allof/simple.yaml"), io.Discard, io.Discard))
}
Expand Down
11 changes: 11 additions & 0 deletions load/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package load
import (
"github.com/tufin/oasdiff/flatten/allof"
"github.com/tufin/oasdiff/flatten/commonparams"
"github.com/tufin/oasdiff/flatten/headers"
)

// option functions can be used to preprocess specs after loading them
Expand Down Expand Up @@ -46,3 +47,13 @@ func WithFlattenParams() Option {
return specInfos, nil
}
}

// WithLowercaseHeaders returns SpecInfos with header names converted to lowercase
func WithLowercaseHeaders() Option {
return func(loader Loader, specInfos []*SpecInfo) ([]*SpecInfo, error) {
for _, specInfo := range specInfos {
headers.Lowercase(specInfo.Spec)
}
return specInfos, nil
}
}

0 comments on commit f7552e1

Please sign in to comment.