diff --git a/cmd/vervet/main.go b/cmd/vervet/main.go index 16c5e950..d0a78745 100644 --- a/cmd/vervet/main.go +++ b/cmd/vervet/main.go @@ -4,7 +4,7 @@ import ( "log" "os" - "github.com/snyk/vervet/v7/internal/cmd" + "github.com/snyk/vervet/v8/internal/cmd" ) func main() { diff --git a/cmd/vu-api/main.go b/cmd/vu-api/main.go index 53537b74..0777a526 100644 --- a/cmd/vu-api/main.go +++ b/cmd/vu-api/main.go @@ -15,12 +15,12 @@ import ( "github.com/rs/zerolog/log" "golang.org/x/sync/errgroup" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/internal/handler" - "github.com/snyk/vervet/v7/internal/storage" - "github.com/snyk/vervet/v7/internal/storage/disk" - "github.com/snyk/vervet/v7/internal/storage/gcs" - "github.com/snyk/vervet/v7/internal/storage/s3" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/internal/handler" + "github.com/snyk/vervet/v8/internal/storage" + "github.com/snyk/vervet/v8/internal/storage/disk" + "github.com/snyk/vervet/v8/internal/storage/gcs" + "github.com/snyk/vervet/v8/internal/storage/s3" ) func main() { diff --git a/cmd/vu-scraper/main.go b/cmd/vu-scraper/main.go index ec746282..77520ce2 100644 --- a/cmd/vu-scraper/main.go +++ b/cmd/vu-scraper/main.go @@ -11,12 +11,12 @@ import ( "github.com/rs/zerolog" "github.com/rs/zerolog/log" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/internal/scraper" - "github.com/snyk/vervet/v7/internal/storage" - "github.com/snyk/vervet/v7/internal/storage/disk" - "github.com/snyk/vervet/v7/internal/storage/gcs" - "github.com/snyk/vervet/v7/internal/storage/s3" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/internal/scraper" + "github.com/snyk/vervet/v8/internal/storage" + "github.com/snyk/vervet/v8/internal/storage/disk" + "github.com/snyk/vervet/v8/internal/storage/gcs" + "github.com/snyk/vervet/v8/internal/storage/s3" ) func main() { diff --git a/collator.go b/collator.go index 162f7976..300bf49e 100644 --- a/collator.go +++ b/collator.go @@ -268,10 +268,10 @@ func tagsEqual(x, y interface{}) bool { func (c *Collator) mergePaths(rv *ResourceVersion) error { if rv.T.Paths != nil && c.result.Paths == nil { - c.result.Paths = make(openapi3.Paths) + c.result.Paths = openapi3.NewPaths() } var errs error - for k, v := range rv.T.Paths { + for k, v := range rv.T.Paths.Map() { for opName, opValue := range v.Operations() { route := routeForPath(k, opName) if _, ok := c.seenRoutes[route]; ok { @@ -285,13 +285,13 @@ func (c *Collator) mergePaths(rv *ResourceVersion) error { } } else { c.seenRoutes[route] = struct{}{} - if c.result.Paths[k] == nil { + if c.result.Paths.Value(k) == nil { // Path doesn't exist in output - c.result.Paths[k] = v + c.result.Paths.Set(k, v) } else { // There is another operation on this path, merge the // current operation into that one - c.result.Paths[k].SetOperation(opName, opValue) + c.result.Paths.Value(k).SetOperation(opName, opValue) } c.pathSources[k] = rv.path } diff --git a/collator_test.go b/collator_test.go index 3e09de30..260a9fc2 100644 --- a/collator_test.go +++ b/collator_test.go @@ -5,22 +5,19 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/testdata" ) func TestRefRemover(t *testing.T) { c := qt.New(t) doc, err := vervet.NewDocumentFile(testdata.Path("resources/projects/2021-08-20/spec.yaml")) c.Assert(err, qt.IsNil) - resp400 := doc.Paths["/orgs/{org_id}/projects/{project_id}"].Delete.Responses["400"] + resp400 := doc.Paths.Value("/orgs/{org_id}/projects/{project_id}").Delete.Responses.Status(400) errDoc := resp400.Value.Content["application/vnd.api+json"].Schema c.Assert(err, qt.IsNil) c.Assert("{\"$ref\":\"../errors.yaml#/ErrorDocument\"}", qt.JSONEquals, errDoc) - in := vervet.NewRefRemover(errDoc) - err = in.RemoveRef() - c.Assert(err, qt.IsNil) - c.Assert(err, qt.IsNil) + vervet.RemoveRefs(errDoc) //nolint:lll // acked c.Assert("{\"additionalProperties\":false,\"example\":{\"errors\":[{\"detail\":\"Permission denied for this "+ "resource\",\"status\":\"403\"}],\"jsonapi\":{\"version\":\"1.0\"}},\"properties\":{\"errors\":{\"example\":"+ @@ -62,8 +59,8 @@ func TestCollator(t *testing.T) { result := collator.Result() c.Assert( - result.Paths["/orgs/{orgId}/projects"]. - Get.Responses["200"]. + result.Paths.Value("/orgs/{orgId}/projects"). + Get.Responses.Status(200). Value. Content["application/vnd.api+json"]. Schema.Value.Properties["jsonapi"].Ref, @@ -71,9 +68,9 @@ func TestCollator(t *testing.T) { "#/components/schemas/JsonApi", ) schemaRef := result. - Paths["/examples/hello-world/{id}"]. + Paths.Value("/examples/hello-world/{id}"). Get. - Responses["200"]. + Responses.Status(200). Value. Content["application/vnd.api+json"]. Schema. @@ -86,9 +83,9 @@ func TestCollator(t *testing.T) { ":\"object\"}\n", qt.JSONEquals, schemaRef.Value) c.Assert(result.Components.Schemas["JsonApi"], qt.IsNotNil) - projectParameterRef := result.Paths["/orgs/{orgId}/projects"].Get.Parameters[0] + projectParameterRef := result.Paths.Value("/orgs/{orgId}/projects").Get.Parameters[0] c.Assert(projectParameterRef.Ref, qt.Equals, "#/components/parameters/Version") - exampleParameterRef := result.Paths["/examples/hello-world/{id}"].Get.Parameters[0] + exampleParameterRef := result.Paths.Value("/examples/hello-world/{id}").Get.Parameters[0] c.Assert(exampleParameterRef.Ref, qt.Equals, "") //nolint:lll // acked c.Assert("{\"description\":\"The requested version of the endpoint to process the request\",\"example\""+ @@ -96,13 +93,13 @@ func TestCollator(t *testing.T) { "\"Requested API version\",\"pattern\":\"^(wip|work-in-progress|experimental|beta|((([0-9]{4})-([0-1][0-9]))"+ "-((3[01])|(0[1-9])|([12][0-9]))(~(wip|work-in-progress|experimental|beta))?))$\",\"type\":\"string\"}}\n", qt.JSONEquals, exampleParameterRef.Value) - projectConflictRef := result.Paths["/orgs/{orgId}/projects"].Get.Parameters[6] - exampleConflictRef := result.Paths["/examples/hello-world/{id}"].Get.Parameters[3] + projectConflictRef := result.Paths.Value("/orgs/{orgId}/projects").Get.Parameters[6] + exampleConflictRef := result.Paths.Value("/examples/hello-world/{id}").Get.Parameters[3] c.Assert(projectConflictRef.Ref, qt.Not(qt.Equals), exampleConflictRef.Ref) - projectResp400Ref := result.Paths["/orgs/{orgId}/projects"].Get.Responses["400"] + projectResp400Ref := result.Paths.Value("/orgs/{orgId}/projects").Get.Responses.Status(400) c.Assert(projectResp400Ref.Ref, qt.Equals, "#/components/responses/400") - exampleResp400Ref := result.Paths["/examples/hello-world/{id}"].Get.Responses["400"] + exampleResp400Ref := result.Paths.Value("/examples/hello-world/{id}").Get.Responses.Status(400) c.Assert(exampleResp400Ref.Ref, qt.Equals, "") c.Assert("{\"content\":{\"application/vnd.api+json\":{\"schema\":{\"additionalProperties\":false,\"example\":{"+ "\"errors\":[{\"detail\":\"Permission denied for this resource\",\"status\":\"403\"}],\"jsonapi\":{\"version\":"+ @@ -168,11 +165,11 @@ func TestCollateUseFirstRoute(t *testing.T) { result := collator.Result() // First path chosen, route matching rules ignore path variable - c.Assert(result.Paths["/examples/hello-world/{id1}"], qt.Not(qt.IsNil)) - c.Assert(result.Paths["/examples/hello-world/{id2}"], qt.IsNil) + c.Assert(result.Paths.Value("/examples/hello-world/{id1}"), qt.Not(qt.IsNil)) + c.Assert(result.Paths.Value("/examples/hello-world/{id2}"), qt.IsNil) // First chosen path has description expected - c.Assert(result.Paths["/examples/hello-world/{id1}"].Get.Description, qt.Contains, " - from example 1") + c.Assert(result.Paths.Value("/examples/hello-world/{id1}").Get.Description, qt.Contains, " - from example 1") } func TestCollatePathConflict(t *testing.T) { @@ -215,7 +212,7 @@ func TestCollateMergingResources(t *testing.T) { c.Assert(err, qt.IsNil) result := collator.Result() - c.Assert(result.Paths["/orgs/{org_id}/projects/{project_id}"].Delete.Responses["204"], qt.IsNotNil) + c.Assert(result.Paths.Value("/orgs/{org_id}/projects/{project_id}").Delete.Responses.Status(204), qt.IsNotNil) } func TestCollateOperationsOnSamePath(t *testing.T) { @@ -238,10 +235,10 @@ func TestCollateOperationsOnSamePath(t *testing.T) { result := collator.Result() - c.Assert(result.Paths["/examples/hello-world"].Get, qt.Not(qt.IsNil)) - c.Assert(result.Paths["/examples/hello-world"].Get.Description, qt.Contains, " - from example 1") - c.Assert(result.Paths["/examples/hello-world"].Post, qt.Not(qt.IsNil)) - c.Assert(result.Paths["/examples/hello-world"].Post.Description, qt.Contains, " - from example 1") - c.Assert(result.Paths["/examples/hello-world"].Put, qt.Not(qt.IsNil)) - c.Assert(result.Paths["/examples/hello-world"].Put.Description, qt.Contains, " - from example 2") + c.Assert(result.Paths.Value("/examples/hello-world").Get, qt.Not(qt.IsNil)) + c.Assert(result.Paths.Value("/examples/hello-world").Get.Description, qt.Contains, " - from example 1") + c.Assert(result.Paths.Value("/examples/hello-world").Post, qt.Not(qt.IsNil)) + c.Assert(result.Paths.Value("/examples/hello-world").Post.Description, qt.Contains, " - from example 1") + c.Assert(result.Paths.Value("/examples/hello-world").Put, qt.Not(qt.IsNil)) + c.Assert(result.Paths.Value("/examples/hello-world").Put.Description, qt.Contains, " - from example 2") } diff --git a/config/config_test.go b/config/config_test.go index 609ce845..e692c7fe 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -6,7 +6,7 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7/config" + "github.com/snyk/vervet/v8/config" ) func TestLoad(t *testing.T) { diff --git a/config/underground.go b/config/underground.go index d4393bea..16fcf02f 100644 --- a/config/underground.go +++ b/config/underground.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/viper" - "github.com/snyk/vervet/v7" + "github.com/snyk/vervet/v8" ) // StorageType describes backend implementations supported by Vervet Underground. diff --git a/config/underground_test.go b/config/underground_test.go index 08123951..f3d6330a 100644 --- a/config/underground_test.go +++ b/config/underground_test.go @@ -6,8 +6,8 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/config" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/config" ) func createTestFile(c *qt.C, data []byte) *os.File { diff --git a/document.go b/document.go index 266b0082..c5e0d9c8 100644 --- a/document.go +++ b/document.go @@ -70,21 +70,21 @@ func NewDocumentFile(specFile string) (_ *Document, returnErr error) { } var t openapi3.T + contents, err := os.ReadFile(specFile) if err != nil { return nil, err } + err = yaml.Unmarshal(contents, &t) if err != nil { return nil, err } - err = newRefAliasResolver(&t).resolve() - if err != nil { - return nil, err - } + newRefAliasResolver(&t).resolve() l := openapi3.NewLoader() l.IsExternalRefsAllowed = true + err = l.ResolveRefsIn(&t, specURL) if err != nil { return nil, fmt.Errorf("failed to load %q: %w", specBase, err) diff --git a/document_test.go b/document_test.go index 4c346854..fbf63319 100644 --- a/document_test.go +++ b/document_test.go @@ -6,16 +6,16 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/testdata" ) func TestNewDocumentFile(t *testing.T) { c := qt.New(t) doc, err := vervet.NewDocumentFile(testdata.Path("resources/_examples/hello-world/2021-06-01/spec.yaml")) c.Assert(err, qt.IsNil) - c.Assert(doc.Paths, qt.HasLen, 1) - c.Assert(doc.Paths["/examples/hello-world/{id}"], qt.Not(qt.IsNil)) + c.Assert(doc.Paths.Len(), qt.Equals, 1) + c.Assert(doc.Paths.Value("/examples/hello-world/{id}"), qt.Not(qt.IsNil)) c.Assert(doc.Components.Schemas["HelloWorld"], qt.Not(qt.IsNil)) c.Assert(doc.Validate(context.TODO()), qt.IsNil) } diff --git a/generate/generate.go b/generate/generate.go index fa82fa5f..32802efe 100644 --- a/generate/generate.go +++ b/generate/generate.go @@ -8,8 +8,8 @@ import ( "strings" "text/template" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/internal/generator" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/internal/generator" ) // GeneratorParams contains the metadata needed to execute code generators. diff --git a/generate/generate_test.go b/generate/generate_test.go index ec6a23cb..cb7d9158 100644 --- a/generate/generate_test.go +++ b/generate/generate_test.go @@ -8,8 +8,8 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7/generate" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8/generate" + "github.com/snyk/vervet/v8/testdata" ) func TestGenerateFS(t *testing.T) { diff --git a/go.mod b/go.mod index 88406758..e69ad7b6 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/snyk/vervet/v7 +module github.com/snyk/vervet/v8 go 1.22 @@ -14,11 +14,11 @@ require ( github.com/dop251/goja v0.0.0-20231024180952-594410467bc6 github.com/elgohr/go-localstack v1.0.36 github.com/frankban/quicktest v1.14.6 - github.com/getkin/kin-openapi v0.120.0 + github.com/getkin/kin-openapi v0.127.0 github.com/ghodss/yaml v1.0.0 github.com/go-chi/chi/v5 v5.0.10 github.com/google/go-cmp v0.6.0 - github.com/google/uuid v1.4.0 + github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.0 github.com/manifoldco/promptui v0.9.0 github.com/mitchellh/reflectwalk v1.0.2 @@ -34,8 +34,8 @@ require ( github.com/urfave/cli/v2 v2.25.7 github.com/vmware-labs/yaml-jsonpath v0.3.2 go.uber.org/multierr v1.11.0 - golang.org/x/exp v0.0.0-20231006140011-7918f672742d - golang.org/x/sync v0.4.0 + golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa + golang.org/x/sync v0.8.0 google.golang.org/api v0.149.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -80,8 +80,8 @@ require ( github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect - github.com/go-openapi/jsonpointer v0.20.0 // indirect - github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -91,7 +91,7 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/invopop/yaml v0.2.0 // indirect + github.com/invopop/yaml v0.3.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/klauspost/compress v1.17.1 // indirect @@ -121,7 +121,7 @@ require ( github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/rivo/uniseg v0.4.4 // indirect - github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.3.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -138,13 +138,13 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.22.0 // indirect - golang.org/x/mod v0.13.0 // indirect - golang.org/x/net v0.24.0 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/mod v0.20.0 // indirect + golang.org/x/net v0.28.0 // indirect golang.org/x/oauth2 v0.13.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.14.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect + golang.org/x/tools v0.24.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect diff --git a/go.sum b/go.sum index f5b719f6..fa895389 100644 --- a/go.sum +++ b/go.sum @@ -190,8 +190,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/getkin/kin-openapi v0.120.0 h1:MqJcNJFrMDFNc07iwE8iFC5eT2k/NPUFDIpNeiZv8Jg= -github.com/getkin/kin-openapi v0.120.0/go.mod h1:PCWw/lfBrJY4HcdqE3jj+QFkaFK8ABoqo7PvqVhXXqw= +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/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= @@ -201,10 +201,10 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= -github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +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= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= @@ -287,8 +287,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -306,8 +306,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= -github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY= -github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= +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/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -423,8 +423,8 @@ github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= @@ -477,8 +477,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -524,8 +525,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -536,8 +537,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= +golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -562,8 +563,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -602,8 +603,8 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -626,8 +627,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -690,8 +691,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -703,8 +704,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -761,8 +762,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -893,7 +894,6 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/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= gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY= diff --git a/include_headers.go b/include_headers.go index 0e6029ef..b760f13b 100644 --- a/include_headers.go +++ b/include_headers.go @@ -32,7 +32,8 @@ type includeHeaders struct { } func (w *includeHeaders) apply() error { - for _, pathItem := range w.doc.Paths { + for _, path := range w.doc.Paths.InMatchingOrder() { + pathItem := w.doc.Paths.Value(path) if err := w.applyOperation(pathItem.Connect); err != nil { return err } @@ -65,7 +66,7 @@ func (w *includeHeaders) applyOperation(op *openapi3.Operation) error { if op == nil { return nil // nothing to do } - for _, respRef := range op.Responses { + for _, respRef := range op.Responses.Map() { resp := respRef.Value headersContents, ok := resp.Extensions[ExtSnykIncludeHeaders].(map[string]interface{}) if !ok { diff --git a/include_headers_test.go b/include_headers_test.go index 77888258..84408520 100644 --- a/include_headers_test.go +++ b/include_headers_test.go @@ -6,8 +6,8 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/testdata" ) func TestCommonResponseHeaders(t *testing.T) { @@ -19,9 +19,9 @@ func TestCommonResponseHeaders(t *testing.T) { c.Assert(err, qt.IsNil) // Headers are not included - pathItem := doc.Paths["/examples/hello-world"] + pathItem := doc.Paths.Value("/examples/hello-world") c.Assert(pathItem, qt.Not(qt.IsNil)) - resp := pathItem.Post.Responses["201"].Value + resp := pathItem.Post.Responses.Status(201).Value c.Assert(resp, qt.Not(qt.IsNil)) // There's a Location header defined outside of the common includes c.Assert(resp.Headers, qt.HasLen, 1) @@ -30,14 +30,14 @@ func TestCommonResponseHeaders(t *testing.T) { c.Assert(err, qt.IsNil) // Included header refs are resolved - pathItem = doc.Paths["/examples/hello-world"] + pathItem = doc.Paths.Value("/examples/hello-world") c.Assert(pathItem, qt.Not(qt.IsNil)) - resp = pathItem.Post.Responses["201"].Value + resp = pathItem.Post.Responses.Status(201).Value c.Assert(resp, qt.Not(qt.IsNil)) // Now add 3 more common included headers c.Assert(resp.Headers, qt.HasLen, 4) for _, name := range []string{"snyk-version-requested", "snyk-version-served", "snyk-request-id"} { // All of these headers are string type - c.Assert(resp.Headers[name].Value.Schema.Value.Type, qt.Equals, "string") + c.Assert(resp.Headers[name].Value.Schema.Value.Type.Is("string"), qt.IsTrue) } } diff --git a/inliner.go b/inliner.go index ce606d5c..1b329472 100644 --- a/inliner.go +++ b/inliner.go @@ -1,10 +1,9 @@ package vervet import ( - "reflect" - "github.com/getkin/kin-openapi/openapi3" - "github.com/mitchellh/reflectwalk" + + "github.com/snyk/vervet/v8/internal/openapiwalker" ) // Inliner inlines the component. @@ -12,6 +11,60 @@ type Inliner struct { refs map[string]struct{} } +func (in *Inliner) ProcessCallbackRef(ref *openapi3.CallbackRef) { + if in.matched(ref.Ref) { + RemoveRefs(ref) + } +} + +func (in *Inliner) ProcessExampleRef(ref *openapi3.ExampleRef) { + if in.matched(ref.Ref) { + RemoveRefs(ref) + } +} + +func (in *Inliner) ProcessHeaderRef(ref *openapi3.HeaderRef) { + if in.matched(ref.Ref) { + RemoveRefs(ref) + } +} + +func (in *Inliner) ProcessLinkRef(ref *openapi3.LinkRef) { + if in.matched(ref.Ref) { + RemoveRefs(ref) + } +} + +func (in *Inliner) ProcessParameterRef(ref *openapi3.ParameterRef) { + if in.matched(ref.Ref) { + RemoveRefs(ref) + } +} + +func (in *Inliner) ProcessRequestBodyRef(ref *openapi3.RequestBodyRef) { + if in.matched(ref.Ref) { + RemoveRefs(ref) + } +} + +func (in *Inliner) ProcessResponseRef(ref *openapi3.ResponseRef) { + if in.matched(ref.Ref) { + RemoveRefs(ref) + } +} + +func (in *Inliner) ProcessSchemaRef(ref *openapi3.SchemaRef) { + if in.matched(ref.Ref) { + RemoveRefs(ref) + } +} + +func (in *Inliner) ProcessSecuritySchemeRef(ref *openapi3.SecuritySchemeRef) { + if in.matched(ref.Ref) { + RemoveRefs(ref) + } +} + // NewInliner returns a new Inliner instance. func NewInliner() *Inliner { return &Inliner{refs: map[string]struct{}{}} @@ -25,162 +78,62 @@ func (in *Inliner) AddRef(ref string) { // Inline inlines all the JSON References previously indicated with AddRef in // the given OpenAPI document. func (in *Inliner) Inline(doc *openapi3.T) error { - return reflectwalk.Walk(doc, in) -} - -// Struct implements reflectwalk.StructWalker. -func (in *Inliner) Struct(v reflect.Value) error { - if !v.CanInterface() { + if len(in.refs) == 0 { return nil } - switch val := v.Interface().(type) { - case openapi3.SchemaRef: - if _, ok := in.refs[val.Ref]; ok { - valPointer := v.Addr().Interface().(*openapi3.SchemaRef) - refRemover := NewRefRemover(valPointer) - err := refRemover.RemoveRef() - if err != nil { - return err - } - } - case openapi3.ParameterRef: - if _, ok := in.refs[val.Ref]; ok { - valPointer := v.Addr().Interface().(*openapi3.ParameterRef) - refRemover := NewRefRemover(valPointer) - err := refRemover.RemoveRef() - if err != nil { - return err - } - } - case openapi3.HeaderRef: - if _, ok := in.refs[val.Ref]; ok { - valPointer := v.Addr().Interface().(*openapi3.HeaderRef) - refRemover := NewRefRemover(valPointer) - err := refRemover.RemoveRef() - if err != nil { - return err - } - } - case openapi3.RequestBodyRef: - if _, ok := in.refs[val.Ref]; ok { - valPointer := v.Addr().Interface().(*openapi3.RequestBodyRef) - refRemover := NewRefRemover(valPointer) - err := refRemover.RemoveRef() - if err != nil { - return err - } - } - case openapi3.ResponseRef: - if _, ok := in.refs[val.Ref]; ok { - valPointer := v.Addr().Interface().(*openapi3.ResponseRef) - refRemover := NewRefRemover(valPointer) - err := refRemover.RemoveRef() - if err != nil { - return err - } - } - case openapi3.SecuritySchemeRef: - if _, ok := in.refs[val.Ref]; ok { - valPointer := v.Addr().Interface().(*openapi3.SecuritySchemeRef) - refRemover := NewRefRemover(valPointer) - err := refRemover.RemoveRef() - if err != nil { - return err - } - } - case openapi3.ExampleRef: - if _, ok := in.refs[val.Ref]; ok { - valPointer := v.Addr().Interface().(*openapi3.ExampleRef) - refRemover := NewRefRemover(valPointer) - err := refRemover.RemoveRef() - if err != nil { - return err - } - } - case openapi3.LinkRef: - if _, ok := in.refs[val.Ref]; ok { - valPointer := v.Addr().Interface().(*openapi3.LinkRef) - refRemover := NewRefRemover(valPointer) - err := refRemover.RemoveRef() - if err != nil { - return err - } - } - case openapi3.CallbackRef: - if _, ok := in.refs[val.Ref]; ok { - valPointer := v.Addr().Interface().(*openapi3.CallbackRef) - refRemover := NewRefRemover(valPointer) - err := refRemover.RemoveRef() - if err != nil { - return err - } - } - } - return nil -} + openapiwalker.ProcessRefs(doc, in) -// StructField implements reflectwalk.StructWalker. -func (in *Inliner) StructField(field reflect.StructField, v reflect.Value) error { return nil } -// RefRemover removes the ref from the component. -type RefRemover struct { - target interface{} -} - -// NewRefRemover returns a new RefRemover instance. -func NewRefRemover(target interface{}) *RefRemover { - return &RefRemover{target: target} +func (in *Inliner) matched(ref string) bool { + _, match := in.refs[ref] + return match } -// RemoveRef removes all $ref locations from an OpenAPI document object +// RemoveRefs removes all $ref locations from an OpenAPI document object // fragment. If the reference has already been resolved, this has the effect of // "inlining" the formerly referenced object when serializing the OpenAPI // document. -func (rr *RefRemover) RemoveRef() error { - return reflectwalk.Walk(rr.target, rr) +func RemoveRefs(target interface{}) { + openapiwalker.ProcessRefs(target, clearRefs{}) } -// Struct implements reflectwalk.StructWalker. -func (rr *RefRemover) Struct(v reflect.Value) error { - if !v.CanInterface() { - return nil - } - switch v.Interface().(type) { - case openapi3.SchemaRef: - valPointer := v.Addr().Interface().(*openapi3.SchemaRef) - valPointer.Ref = "" - case openapi3.ParameterRef: - valPointer := v.Addr().Interface().(*openapi3.ParameterRef) - valPointer.Ref = "" - case openapi3.HeaderRef: - valPointer := v.Addr().Interface().(*openapi3.HeaderRef) - valPointer.Ref = "" - case openapi3.RequestBodyRef: - valPointer := v.Addr().Interface().(*openapi3.RequestBodyRef) - valPointer.Ref = "" - case openapi3.ResponseRef: - valPointer := v.Addr().Interface().(*openapi3.ResponseRef) - valPointer.Ref = "" - case openapi3.SecuritySchemeRef: - valPointer := v.Addr().Interface().(*openapi3.SecuritySchemeRef) - valPointer.Ref = "" - case openapi3.ExampleRef: - valPointer := v.Addr().Interface().(*openapi3.ExampleRef) - valPointer.Ref = "" - case openapi3.LinkRef: - valPointer := v.Addr().Interface().(*openapi3.LinkRef) - valPointer.Ref = "" - case openapi3.CallbackRef: - valPointer := v.Addr().Interface().(*openapi3.CallbackRef) - valPointer.Ref = "" - } +type clearRefs struct { +} - return nil +func (c clearRefs) ProcessCallbackRef(ref *openapi3.CallbackRef) { + ref.Ref = "" } -// StructField implements reflectwalk.StructWalker. -func (rr *RefRemover) StructField(field reflect.StructField, v reflect.Value) error { - return nil +func (c clearRefs) ProcessExampleRef(ref *openapi3.ExampleRef) { + ref.Ref = "" +} + +func (c clearRefs) ProcessHeaderRef(ref *openapi3.HeaderRef) { + ref.Ref = "" +} + +func (c clearRefs) ProcessLinkRef(ref *openapi3.LinkRef) { + ref.Ref = "" +} + +func (c clearRefs) ProcessParameterRef(ref *openapi3.ParameterRef) { + ref.Ref = "" +} + +func (c clearRefs) ProcessRequestBodyRef(ref *openapi3.RequestBodyRef) { + ref.Ref = "" +} + +func (c clearRefs) ProcessResponseRef(ref *openapi3.ResponseRef) { + ref.Ref = "" +} + +func (c clearRefs) ProcessSchemaRef(ref *openapi3.SchemaRef) { + ref.Ref = "" +} + +func (c clearRefs) ProcessSecuritySchemeRef(ref *openapi3.SecuritySchemeRef) { + ref.Ref = "" } diff --git a/internal/backstage/backstage.go b/internal/backstage/backstage.go index 996b3916..8075f9e4 100644 --- a/internal/backstage/backstage.go +++ b/internal/backstage/backstage.go @@ -16,7 +16,7 @@ import ( "github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath" "gopkg.in/yaml.v3" - "github.com/snyk/vervet/v7" + "github.com/snyk/vervet/v8" ) const ( diff --git a/internal/backstage/backstage_test.go b/internal/backstage/backstage_test.go index 857779f4..52f0e3d0 100644 --- a/internal/backstage/backstage_test.go +++ b/internal/backstage/backstage_test.go @@ -7,7 +7,7 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8/testdata" ) func TestBackstageName(t *testing.T) { diff --git a/internal/cmd/backstage.go b/internal/cmd/backstage.go index e82ce1e4..4069e405 100644 --- a/internal/cmd/backstage.go +++ b/internal/cmd/backstage.go @@ -11,8 +11,8 @@ import ( "github.com/urfave/cli/v2" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/internal/backstage" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/internal/backstage" ) // BackstageCommand is the `vervet backstage` subcommand. diff --git a/internal/cmd/compiler.go b/internal/cmd/compiler.go index c228dc7f..ece748fc 100644 --- a/internal/cmd/compiler.go +++ b/internal/cmd/compiler.go @@ -6,10 +6,10 @@ import ( "github.com/urfave/cli/v2" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/internal/compiler" - "github.com/snyk/vervet/v7/internal/simplebuild" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/internal/compiler" + "github.com/snyk/vervet/v8/internal/simplebuild" ) var defaultPivotDate = vervet.MustParseVersion("2024-09-01") diff --git a/internal/cmd/compiler_test.go b/internal/cmd/compiler_test.go index 7ddd6c37..729f96da 100644 --- a/internal/cmd/compiler_test.go +++ b/internal/cmd/compiler_test.go @@ -8,9 +8,9 @@ import ( qt "github.com/frankban/quicktest" "github.com/getkin/kin-openapi/openapi3" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/internal/cmd" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/internal/cmd" + "github.com/snyk/vervet/v8/testdata" ) var specFile = "/spec.yaml" @@ -42,7 +42,7 @@ func TestBuild(t *testing.T) { c.Assert(err, qt.IsNil) c.Assert(doc.Validate(context.TODO()), qt.IsNil) for _, path := range test.paths { - c.Assert(doc.Paths[path], qt.Not(qt.IsNil)) + c.Assert(doc.Paths.Value(path), qt.Not(qt.IsNil)) } }) } diff --git a/internal/cmd/filter.go b/internal/cmd/filter.go index 9dd0b420..357ae19c 100644 --- a/internal/cmd/filter.go +++ b/internal/cmd/filter.go @@ -6,7 +6,7 @@ import ( "github.com/getkin/kin-openapi/openapi3" "github.com/urfave/cli/v2" - "github.com/snyk/vervet/v7" + "github.com/snyk/vervet/v8" ) // FilterCommand is the `vervet filter` subcommand. @@ -43,14 +43,14 @@ func Filter(ctx *cli.Context) error { if excludePaths := ctx.StringSlice("exclude-paths"); len(excludePaths) > 0 { for _, excludePath := range excludePaths { - delete(doc.Paths, excludePath) + doc.Paths.Delete(excludePath) } } if includePaths := ctx.StringSlice("include-paths"); len(includePaths) > 0 { - newPaths := openapi3.Paths{} + newPaths := openapi3.NewPaths() for _, includePath := range includePaths { - if pathInfo, ok := doc.Paths[includePath]; ok { - newPaths[includePath] = pathInfo + if pathInfo := doc.Paths.Value(includePath); pathInfo != nil { + newPaths.Set(includePath, pathInfo) } } doc.Paths = newPaths diff --git a/internal/cmd/filter_test.go b/internal/cmd/filter_test.go index 6f46996a..2c84d445 100644 --- a/internal/cmd/filter_test.go +++ b/internal/cmd/filter_test.go @@ -6,9 +6,9 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/internal/cmd" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/internal/cmd" + "github.com/snyk/vervet/v8/testdata" ) func TestFilterInclude(t *testing.T) { @@ -40,11 +40,11 @@ func TestFilterInclude(t *testing.T) { c.Assert(err, qt.IsNil) // Included paths and their referenced components are present - c.Assert(doc.Paths["/examples/hello-world/{id}"], qt.Not(qt.IsNil)) + c.Assert(doc.Paths.Value("/examples/hello-world/{id}"), qt.Not(qt.IsNil)) c.Assert(doc.Components.Schemas["HelloWorld"], qt.Not(qt.IsNil)) // Not-included paths are not present - c.Assert(doc.Paths["/openapi"], qt.IsNil) + c.Assert(doc.Paths.Value("/openapi"), qt.IsNil) } func XestFilterExclude(t *testing.T) { @@ -78,11 +78,11 @@ func XestFilterExclude(t *testing.T) { c.Assert(err, qt.IsNil) // Excluded paths and components only these reference, are not present - c.Assert(doc.Paths["/examples/hello-world/{id}"], qt.IsNil) + c.Assert(doc.Paths.Value("/examples/hello-world/{id}"), qt.IsNil) c.Assert(doc.Components.Schemas["HelloWorld"], qt.IsNil) // Not-excluded paths and referenced components are present - c.Assert(doc.Paths["/openapi"], qt.Not(qt.IsNil)) - c.Assert(doc.Paths["/openapi/{version}"], qt.Not(qt.IsNil)) + c.Assert(doc.Paths.Value("/openapi"), qt.Not(qt.IsNil)) + c.Assert(doc.Paths.Value("/openapi/{version}"), qt.Not(qt.IsNil)) c.Assert(doc.Components.Headers["VersionRequestedResponseHeader"], qt.Not(qt.IsNil)) } diff --git a/internal/cmd/generate.go b/internal/cmd/generate.go index 94f92d73..1d4d914c 100644 --- a/internal/cmd/generate.go +++ b/internal/cmd/generate.go @@ -5,7 +5,7 @@ import ( "github.com/urfave/cli/v2" - "github.com/snyk/vervet/v7/generate" + "github.com/snyk/vervet/v8/generate" ) // GenerateCommand is the `vervet generate` subcommand. diff --git a/internal/cmd/localize.go b/internal/cmd/localize.go index 5a0f2527..6ce9932c 100644 --- a/internal/cmd/localize.go +++ b/internal/cmd/localize.go @@ -5,7 +5,7 @@ import ( "github.com/urfave/cli/v2" - "github.com/snyk/vervet/v7" + "github.com/snyk/vervet/v8" ) // LocalizeCommand is the `vervet localize` subcommand. diff --git a/internal/cmd/resolve.go b/internal/cmd/resolve.go index f5f5ae2a..2fe1d3d1 100644 --- a/internal/cmd/resolve.go +++ b/internal/cmd/resolve.go @@ -5,7 +5,7 @@ import ( "github.com/urfave/cli/v2" - "github.com/snyk/vervet/v7" + "github.com/snyk/vervet/v8" ) // ResolveCommand is the `vervet resolve` subcommand. diff --git a/internal/cmd/resource.go b/internal/cmd/resource.go index fe0cd570..f6853280 100644 --- a/internal/cmd/resource.go +++ b/internal/cmd/resource.go @@ -9,9 +9,9 @@ import ( "github.com/olekukonko/tablewriter" "github.com/urfave/cli/v2" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/internal/compiler" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/internal/compiler" ) // ResourceCommand is the `vervet resource` subcommand. @@ -82,13 +82,11 @@ func ResourceShow(ctx *cli.Context) error { if rcArg := ctx.Args().Get(1); rcArg != "" && rcArg != rc.Name { continue } - var pathNames []string - for k := range rc.Paths { - pathNames = append(pathNames, k) - } + + pathNames := rc.Paths.InMatchingOrder() sort.Strings(pathNames) for _, pathName := range pathNames { - pathSpec := rc.Paths[pathName] + pathSpec := rc.Paths.Value(pathName) if pathSpec.Get != nil { table.Append([]string{apiName, rc.Name, version.String(), pathName, "GET", pathSpec.Get.OperationID}) } diff --git a/internal/cmd/resource_test.go b/internal/cmd/resource_test.go index 798e0b30..cc1e677e 100644 --- a/internal/cmd/resource_test.go +++ b/internal/cmd/resource_test.go @@ -7,8 +7,8 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7/internal/cmd" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8/internal/cmd" + "github.com/snyk/vervet/v8/testdata" ) func cd(c *qt.C, path string) { diff --git a/internal/cmd/scaffold.go b/internal/cmd/scaffold.go index eb3f67f9..eae47a2a 100644 --- a/internal/cmd/scaffold.go +++ b/internal/cmd/scaffold.go @@ -7,7 +7,7 @@ import ( "github.com/urfave/cli/v2" - "github.com/snyk/vervet/v7/internal/scaffold" + "github.com/snyk/vervet/v8/internal/scaffold" ) // Scaffold is the `vervet scaffold` subcommand. diff --git a/internal/cmd/scaffold_test.go b/internal/cmd/scaffold_test.go index cd7b7e96..879c9585 100644 --- a/internal/cmd/scaffold_test.go +++ b/internal/cmd/scaffold_test.go @@ -8,8 +8,8 @@ import ( qt "github.com/frankban/quicktest" "github.com/urfave/cli/v2" - "github.com/snyk/vervet/v7/internal/cmd" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8/internal/cmd" + "github.com/snyk/vervet/v8/testdata" ) var vervetConfigFile = "./.vervet.yaml" diff --git a/internal/compiler/compiler.go b/internal/compiler/compiler.go index 8e4faba0..be4bbeb3 100644 --- a/internal/compiler/compiler.go +++ b/internal/compiler/compiler.go @@ -13,9 +13,9 @@ import ( "github.com/ghodss/yaml" "go.uber.org/multierr" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/internal/files" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/internal/files" ) // A Compiler checks and builds versioned API resource inputs into aggregated diff --git a/internal/compiler/compiler_test.go b/internal/compiler/compiler_test.go index e82eff2b..4deb16cd 100644 --- a/internal/compiler/compiler_test.go +++ b/internal/compiler/compiler_test.go @@ -11,9 +11,9 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/testdata" ) func setup(c *qt.C) { @@ -96,7 +96,7 @@ func TestCompilerSmoke(t *testing.T) { c.Assert(restApi.resources, qt.HasLen, 1) c.Assert(restApi.resources[0].sourceFiles, qt.Contains, "testdata/resources/projects/2021-06-04/spec.yaml") c.Assert(restApi.overlayIncludes, qt.HasLen, 1) - c.Assert(restApi.overlayIncludes[0].Paths, qt.HasLen, 2) + c.Assert(restApi.overlayIncludes[0].Paths.Len(), qt.Equals, 2) c.Assert( restApi.overlayInlines[0].Servers[0].URL, qt.Contains, diff --git a/internal/files/files.go b/internal/files/files.go index 0f25af5a..ef6d504b 100644 --- a/internal/files/files.go +++ b/internal/files/files.go @@ -7,8 +7,8 @@ import ( "github.com/bmatcuk/doublestar/v4" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/config" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/config" ) // FileSource defines a source of spec files to lint. This abstraction allows diff --git a/internal/generator/functions.go b/internal/generator/functions.go index 625af205..a7f69bea 100644 --- a/internal/generator/functions.go +++ b/internal/generator/functions.go @@ -58,7 +58,7 @@ var ( }, "isAssociativeArray": func(s *openapi3.Schema) bool { return s != nil && - s.Type == "object" && + s.Type.Is("object") && len(s.Properties) == 0 && s.AdditionalProperties.Has != nil && *s.AdditionalProperties.Has diff --git a/internal/generator/generator.go b/internal/generator/generator.go index 8cbd545f..bd4ca288 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -13,8 +13,8 @@ import ( "github.com/ghodss/yaml" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/config" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/config" ) // Generator generates files for new resources from data models and templates. diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go index eb19b733..637a1cf8 100644 --- a/internal/generator/generator_test.go +++ b/internal/generator/generator_test.go @@ -9,8 +9,8 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/testdata" ) func setup(c *qt.C) { @@ -260,11 +260,11 @@ function tsType(oasType) { [key: string]: object; } -{{- else if eq .Type "object" }}{ +{{- else if .Type.Is "object" }}{ {{- include "interfaceProperties" . | indent 2 }} } -{{- else if eq .Type "array" }}Array<{{ template "resolveSchemaRef" .Items }}> +{{- else if .Type.Is "array" }}Array<{{ template "resolveSchemaRef" .Items }}> {{- else }}{{ .Type | tsType }} @@ -282,7 +282,7 @@ function tsType(oasType) { {{- if isAssociativeArray .Schema.Value }} export interface {{ .Name }} {{ template "schemaTypeDef" .Schema.Value }}; -{{- else if eq .Schema.Value.Type "object" }} +{{- else if .Schema.Value.Type.Is "object" }} export interface {{ .Name }} {{ template "schemaTypeDef" .Schema.Value }}; {{- else }} diff --git a/internal/generator/resources.go b/internal/generator/resources.go index 0de2eeab..3fc2ff5c 100644 --- a/internal/generator/resources.go +++ b/internal/generator/resources.go @@ -5,9 +5,9 @@ import ( "github.com/getkin/kin-openapi/openapi3" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/internal/compiler" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/internal/compiler" ) // ResourceKey uniquely identifies an API resource. @@ -43,7 +43,8 @@ func MapResourceOperations(resourceVersions *vervet.ResourceVersions) (Operation if err != nil { return nil, err } - for path, pathItem := range r.Document.Paths { + for _, path := range r.Document.Paths.InMatchingOrder() { + pathItem := r.Document.Paths.Value(path) ops := MapPathOperations(pathItem) for method, op := range ops { opVersion := OperationVersion{ diff --git a/internal/handler/handler.go b/internal/handler/handler.go index bb97b8d3..5e81a226 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -16,10 +16,10 @@ import ( prommiddleware "github.com/slok/go-http-metrics/middleware" prommiddlewarestd "github.com/slok/go-http-metrics/middleware/std" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/internal/storage" - "github.com/snyk/vervet/v7/versionware" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/internal/storage" + "github.com/snyk/vervet/v8/versionware" ) // Handler handles Vervet Underground HTTP requests. diff --git a/internal/handler/handler_test.go b/internal/handler/handler_test.go index 58bba9ed..0170023a 100644 --- a/internal/handler/handler_test.go +++ b/internal/handler/handler_test.go @@ -9,9 +9,9 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/internal/handler" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/internal/handler" ) func TestHealth(t *testing.T) { diff --git a/internal/openapiwalker/walker.go b/internal/openapiwalker/walker.go new file mode 100644 index 00000000..a1a25787 --- /dev/null +++ b/internal/openapiwalker/walker.go @@ -0,0 +1,293 @@ +package openapiwalker + +import ( + "fmt" + + "github.com/getkin/kin-openapi/openapi3" +) + +type RefProcessor interface { + ProcessCallbackRef(ref *openapi3.CallbackRef) + ProcessExampleRef(ref *openapi3.ExampleRef) + ProcessHeaderRef(ref *openapi3.HeaderRef) + ProcessLinkRef(ref *openapi3.LinkRef) + ProcessParameterRef(ref *openapi3.ParameterRef) + ProcessRequestBodyRef(ref *openapi3.RequestBodyRef) + ProcessResponseRef(ref *openapi3.ResponseRef) + ProcessSchemaRef(ref *openapi3.SchemaRef) + ProcessSecuritySchemeRef(ref *openapi3.SecuritySchemeRef) +} + +// ProcessRefs visits all the documents and calls the RefProcessor for each ref encountered. +// +//nolint:gocyclo // needs to check each type in the kinopneapi lib +func ProcessRefs(data any, p RefProcessor) { + switch v := data.(type) { + case nil: + return + + case *openapi3.T: + if v != nil { + ProcessRefs(*v, p) + } + case *openapi3.Components: + if v != nil { + ProcessRefs(*v, p) + } + case *openapi3.MediaType: + if v != nil { + ProcessRefs(*v, p) + } + case *openapi3.Response: + if v != nil { + ProcessRefs(*v, p) + } + + case *openapi3.Parameter: + if v != nil { + ProcessRefs(*v, p) + } + case *openapi3.RequestBody: + if v != nil { + ProcessRefs(*v, p) + } + case openapi3.RequestBody: + ProcessRefs(v.Content, p) + + case openapi3.T: + ProcessRefs(v.Components, p) + ProcessRefs(v.Info, p) + ProcessRefs(v.Paths, p) + ProcessRefs(v.Security, p) + ProcessRefs(v.Servers, p) + ProcessRefs(v.Tags, p) + ProcessRefs(v.ExternalDocs, p) + case openapi3.Components: + ProcessRefs(v.Schemas, p) + ProcessRefs(v.Parameters, p) + ProcessRefs(v.Headers, p) + ProcessRefs(v.RequestBodies, p) + ProcessRefs(v.Responses, p) + ProcessRefs(v.SecuritySchemes, p) + ProcessRefs(v.Examples, p) + ProcessRefs(v.Links, p) + ProcessRefs(v.Callbacks, p) + + case openapi3.ResponseBodies: + for _, ref := range v { + ProcessRefs(ref, p) + } + + case openapi3.RequestBodies: + for _, ref := range v { + ProcessRefs(ref, p) + } + + case openapi3.SecurityRequirements: + for _, requirement := range v { + ProcessRefs(requirement, p) + } + + case openapi3.Response: + ProcessRefs(v.Headers, p) + ProcessRefs(v.Content, p) + ProcessRefs(v.Links, p) + + case openapi3.Links: + for _, link := range v { + ProcessRefs(link, p) + } + case openapi3.Content: + for _, mediaType := range v { + ProcessRefs(mediaType, p) + } + case openapi3.ParametersMap: + for _, ref := range v { + ProcessRefs(ref, p) + } + case openapi3.Schemas: + for _, schema := range v { + ProcessRefs(schema, p) + } + case openapi3.SchemaRefs: + for _, schema := range v { + ProcessRefs(schema, p) + } + case openapi3.Headers: + for _, header := range v { + ProcessRefs(header, p) + } + + case openapi3.MediaType: + ProcessRefs(v.Schema, p) + ProcessRefs(v.Examples, p) + + case openapi3.Parameter: + ProcessRefs(v.Schema, p) + ProcessRefs(v.Content, p) + ProcessRefs(v.Examples, p) + + case openapi3.Examples: + for _, example := range v { + ProcessRefs(example, p) + } + case *openapi3.Schema: + if v != nil { + ProcessRefs(*v, p) + } + case openapi3.SecuritySchemes: + for _, ref := range v { + ProcessRefs(ref, p) + } + case openapi3.Callbacks: + for _, ref := range v { + ProcessRefs(ref, p) + } + case *openapi3.Paths: + if v != nil { + ProcessRefs(*v, p) + } + case openapi3.Paths: + for _, path := range v.Map() { + ProcessRefs(path, p) + } + + case openapi3.Schema: + ProcessRefs(v.Properties, p) + ProcessRefs(v.Items, p) + ProcessRefs(v.AllOf, p) + ProcessRefs(v.AnyOf, p) + ProcessRefs(v.OneOf, p) + ProcessRefs(v.Not, p) + + case *openapi3.PathItem: + if v != nil { + ProcessRefs(*v, p) + } + case openapi3.PathItem: + ProcessRefs(v.Connect, p) + ProcessRefs(v.Delete, p) + ProcessRefs(v.Get, p) + ProcessRefs(v.Head, p) + ProcessRefs(v.Options, p) + ProcessRefs(v.Patch, p) + ProcessRefs(v.Post, p) + ProcessRefs(v.Put, p) + ProcessRefs(v.Trace, p) + ProcessRefs(v.Servers, p) + ProcessRefs(v.Parameters, p) + case *openapi3.Operation: + if v != nil { + ProcessRefs(*v, p) + } + case openapi3.Operation: + ProcessRefs(v.Parameters, p) + ProcessRefs(v.RequestBody, p) + ProcessRefs(v.Responses, p) + ProcessRefs(v.Callbacks, p) + ProcessRefs(v.Security, p) + ProcessRefs(v.Servers, p) + ProcessRefs(v.ExternalDocs, p) + case *openapi3.Responses: + if v != nil { + ProcessRefs(*v, p) + } + case openapi3.Responses: + for _, ref := range v.Map() { + ProcessRefs(ref, p) + } + case openapi3.Parameters: + for _, parameter := range v { + ProcessRefs(parameter, p) + } + case *openapi3.Callback: + if v != nil { + ProcessRefs(*v, p) + } + case openapi3.Callback: + for _, pathItem := range v.Map() { + ProcessRefs(pathItem, p) + } + case *openapi3.Example: + if v != nil { + ProcessRefs(*v, p) + } + case *openapi3.Header: + if v != nil { + ProcessRefs(*v, p) + } + case openapi3.Header: + ProcessRefs(v.Parameter, p) + + case *openapi3.CallbackRef: + if v != nil { + p.ProcessCallbackRef(v) + ProcessRefs(v.Value, p) + } + + case *openapi3.ExampleRef: + if v != nil { + p.ProcessExampleRef(v) + ProcessRefs(v.Value, p) + } + + case *openapi3.HeaderRef: + if v != nil { + p.ProcessHeaderRef(v) + ProcessRefs(v.Value, p) + } + case *openapi3.LinkRef: + if v != nil { + p.ProcessLinkRef(v) + ProcessRefs(v.Value, p) + } + case *openapi3.ParameterRef: + if v != nil { + p.ProcessParameterRef(v) + ProcessRefs(v.Value, p) + } + case *openapi3.RequestBodyRef: + if v != nil { + p.ProcessRequestBodyRef(v) + ProcessRefs(v.Value, p) + } + case *openapi3.ResponseRef: + if v != nil { + p.ProcessResponseRef(v) + ProcessRefs(v.Value, p) + } + + case *openapi3.SchemaRef: + if v != nil { + p.ProcessSchemaRef(v) + ProcessRefs(v.Value, p) + } + case *openapi3.SecuritySchemeRef: + if v != nil { + p.ProcessSecuritySchemeRef(v) + ProcessRefs(v.Value, p) + } + // no interesting nested fields + case *openapi3.Info: + case openapi3.Info: + case *openapi3.SecurityRequirements: + case *openapi3.SecurityRequirement: + case openapi3.SecurityRequirement: + case *openapi3.Servers: + case openapi3.Servers: + case openapi3.Server: + case *openapi3.ExternalDocs: + case openapi3.ExternalDocs: + case openapi3.Tags: + case openapi3.Tag: + case *openapi3.SecurityScheme: + case openapi3.SecurityScheme: + case openapi3.Example: + + default: + // intentional panic, have covered all the types in kin-openapi v0.127.0 + // might fail in the future if new types are added/types changed, should + // be caught in tests + panic(fmt.Sprintf("unhandled type %#v", v)) + } +} diff --git a/internal/scaffold/scaffold.go b/internal/scaffold/scaffold.go index 312e756a..d37ac158 100644 --- a/internal/scaffold/scaffold.go +++ b/internal/scaffold/scaffold.go @@ -8,7 +8,7 @@ import ( "github.com/ghodss/yaml" - "github.com/snyk/vervet/v7/internal/files" + "github.com/snyk/vervet/v8/internal/files" ) // ErrAlreadyInitialized is used when scaffolding is being run on a project that is already setup. diff --git a/internal/scaffold/scaffold_test.go b/internal/scaffold/scaffold_test.go index 4e0d1889..128eae92 100644 --- a/internal/scaffold/scaffold_test.go +++ b/internal/scaffold/scaffold_test.go @@ -7,8 +7,8 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7/internal/scaffold" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8/internal/scaffold" + "github.com/snyk/vervet/v8/testdata" ) func TestScaffold(t *testing.T) { diff --git a/internal/scraper/gcs_scraper_test.go b/internal/scraper/gcs_scraper_test.go index 8c63a905..81d9364c 100644 --- a/internal/scraper/gcs_scraper_test.go +++ b/internal/scraper/gcs_scraper_test.go @@ -9,10 +9,10 @@ import ( qt "github.com/frankban/quicktest" "github.com/getkin/kin-openapi/openapi3" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/internal/scraper" - "github.com/snyk/vervet/v7/internal/storage/gcs" - gcstesting "github.com/snyk/vervet/v7/internal/storage/gcs/testing" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/internal/scraper" + "github.com/snyk/vervet/v8/internal/storage/gcs" + gcstesting "github.com/snyk/vervet/v8/internal/storage/gcs/testing" ) func TestGCSScraper(t *testing.T) { @@ -76,7 +76,7 @@ func TestGCSScraper(t *testing.T) { spec, err := l.LoadFromData(specData) c.Assert(err, qt.IsNil) c.Assert(spec, qt.IsNotNil) - c.Assert(len(spec.Paths), qt.Equals, collatedPaths[version.String()]) + c.Assert(spec.Paths.Len(), qt.Equals, collatedPaths[version.String()]) } } @@ -140,6 +140,6 @@ func TestGCSScraperCollation(t *testing.T) { spec, err := l.LoadFromData(specData) c.Assert(err, qt.IsNil) c.Assert(spec, qt.IsNotNil) - c.Assert(len(spec.Paths), qt.Equals, collatedPaths[version.String()]) + c.Assert(spec.Paths.Len(), qt.Equals, collatedPaths[version.String()]) } } diff --git a/internal/scraper/metrics_test.go b/internal/scraper/metrics_test.go index e373c0b6..9d4ff988 100644 --- a/internal/scraper/metrics_test.go +++ b/internal/scraper/metrics_test.go @@ -8,8 +8,8 @@ import ( qt "github.com/frankban/quicktest" "github.com/prometheus/client_golang/prometheus" - "github.com/snyk/vervet/v7/internal/scraper" - "github.com/snyk/vervet/v7/internal/testutil" + "github.com/snyk/vervet/v8/internal/scraper" + "github.com/snyk/vervet/v8/internal/testutil" ) type mockRoundTripper struct { diff --git a/internal/scraper/s3_scraper_test.go b/internal/scraper/s3_scraper_test.go index 32c82ace..b57205ab 100644 --- a/internal/scraper/s3_scraper_test.go +++ b/internal/scraper/s3_scraper_test.go @@ -9,10 +9,10 @@ import ( qt "github.com/frankban/quicktest" "github.com/getkin/kin-openapi/openapi3" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/internal/scraper" - "github.com/snyk/vervet/v7/internal/storage/s3" - s3testing "github.com/snyk/vervet/v7/internal/storage/s3/testing" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/internal/scraper" + "github.com/snyk/vervet/v8/internal/storage/s3" + s3testing "github.com/snyk/vervet/v8/internal/storage/s3/testing" ) func TestS3Scraper(t *testing.T) { @@ -72,7 +72,7 @@ func TestS3Scraper(t *testing.T) { spec, err := l.LoadFromData(specData) c.Assert(err, qt.IsNil) c.Assert(spec, qt.IsNotNil) - c.Assert(len(spec.Paths), qt.Equals, collatedPaths[version.String()]) + c.Assert(spec.Paths.Len(), qt.Equals, collatedPaths[version.String()]) } } @@ -132,6 +132,6 @@ func TestS3ScraperCollation(t *testing.T) { spec, err := l.LoadFromData(specData) c.Assert(err, qt.IsNil) c.Assert(spec, qt.IsNotNil) - c.Assert(len(spec.Paths), qt.Equals, collatedPaths[version.String()]) + c.Assert(spec.Paths.Len(), qt.Equals, collatedPaths[version.String()]) } } diff --git a/internal/scraper/scraper.go b/internal/scraper/scraper.go index a1e85375..89f83408 100644 --- a/internal/scraper/scraper.go +++ b/internal/scraper/scraper.go @@ -16,8 +16,8 @@ import ( "github.com/rs/zerolog/log" "go.uber.org/multierr" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/internal/storage" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/internal/storage" ) // Scraper gets OpenAPI specs from a collection of services and updates storage diff --git a/internal/scraper/scraper_test.go b/internal/scraper/scraper_test.go index c326218b..af406916 100644 --- a/internal/scraper/scraper_test.go +++ b/internal/scraper/scraper_test.go @@ -14,9 +14,9 @@ import ( "github.com/gorilla/mux" "github.com/rs/zerolog/log" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/internal/scraper" - "github.com/snyk/vervet/v7/internal/storage/disk" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/internal/scraper" + "github.com/snyk/vervet/v8/internal/storage/disk" ) var ( @@ -141,7 +141,7 @@ func TestScraper(t *testing.T) { spec, err := l.LoadFromData(specData) c.Assert(err, qt.IsNil) c.Assert(spec, qt.IsNotNil) - c.Assert(len(spec.Paths), qt.Equals, collatedPaths[version.String()]) + c.Assert(spec.Paths.Len(), qt.Equals, collatedPaths[version.String()]) } } diff --git a/internal/simplebuild/build.go b/internal/simplebuild/build.go index f058b497..9b80bf2c 100644 --- a/internal/simplebuild/build.go +++ b/internal/simplebuild/build.go @@ -9,9 +9,9 @@ import ( "github.com/getkin/kin-openapi/openapi3" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/internal/files" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/internal/files" ) // Build compiles the versioned resources in a project configuration based on @@ -151,13 +151,14 @@ func LoadPaths(ctx context.Context, api *config.API) (Operations, error) { return nil, fmt.Errorf("invalid version %q", versionStr) } - doc.InternalizeRefs(ctx, nil) + doc.InternalizeRefs(ctx, vervet.ResolveRefsWithoutSourceName) err = doc.ResolveRefs() if err != nil { return nil, fmt.Errorf("failed to localize refs: %w", err) } - for pathName, pathDef := range doc.T.Paths { + for _, pathName := range doc.T.Paths.InMatchingOrder() { + pathDef := doc.T.Paths.Value(pathName) for opName, opDef := range pathDef.Operations() { k := OpKey{ Path: pathName, diff --git a/internal/simplebuild/build_test.go b/internal/simplebuild/build_test.go index 6f68031f..c8fc328d 100644 --- a/internal/simplebuild/build_test.go +++ b/internal/simplebuild/build_test.go @@ -8,8 +8,8 @@ import ( qt "github.com/frankban/quicktest" "github.com/getkin/kin-openapi/openapi3" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/internal/simplebuild" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/internal/simplebuild" ) func TestGetLatest(t *testing.T) { @@ -107,7 +107,7 @@ func TestBuild(t *testing.T) { output, err := ops.Build(vervet.MustParseVersion("2024-01-01")) c.Assert(err, qt.IsNil) c.Assert(output[0].VersionDate, qt.Equals, time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)) - c.Assert(output[0].Doc.Paths["/foo"].Get, qt.IsNotNil) + c.Assert(output[0].Doc.Paths.Value("/foo").Get, qt.IsNotNil) }) c.Run("merges operations from the same version", func(c *qt.C) { @@ -146,9 +146,9 @@ func TestBuild(t *testing.T) { output, err := ops.Build(vervet.MustParseVersion("2024-01-01")) c.Assert(err, qt.IsNil) c.Assert(output[0].VersionDate, qt.Equals, version.Date) - c.Assert(output[0].Doc.Paths["/foo"].Get, qt.Equals, getFoo) - c.Assert(output[0].Doc.Paths["/foo"].Post, qt.Equals, postFoo) - c.Assert(output[0].Doc.Paths["/bar"].Get, qt.Equals, getBar) + c.Assert(output[0].Doc.Paths.Value("/foo").Get, qt.Equals, getFoo) + c.Assert(output[0].Doc.Paths.Value("/foo").Post, qt.Equals, postFoo) + c.Assert(output[0].Doc.Paths.Value("/bar").Get, qt.Equals, getBar) }) c.Run("generates an output per unique version", func(c *qt.C) { @@ -238,19 +238,19 @@ func TestBuild(t *testing.T) { slices.SortFunc(output, compareDocs) c.Assert(output[0].VersionDate, qt.Equals, versionA.Date) - c.Assert(output[0].Doc.Paths["/foo"].Get, qt.Equals, getFoo) - c.Assert(output[0].Doc.Paths["/foo"].Post, qt.IsNil) - c.Assert(output[0].Doc.Paths["/bar"], qt.IsNil) + c.Assert(output[0].Doc.Paths.Value("/foo").Get, qt.Equals, getFoo) + c.Assert(output[0].Doc.Paths.Value("/foo").Post, qt.IsNil) + c.Assert(output[0].Doc.Paths.Value("/bar"), qt.IsNil) c.Assert(output[1].VersionDate, qt.Equals, versionB.Date) - c.Assert(output[1].Doc.Paths["/foo"].Get, qt.Equals, getFoo) - c.Assert(output[1].Doc.Paths["/foo"].Post, qt.Equals, postFoo) - c.Assert(output[1].Doc.Paths["/bar"], qt.IsNil) + c.Assert(output[1].Doc.Paths.Value("/foo").Get, qt.Equals, getFoo) + c.Assert(output[1].Doc.Paths.Value("/foo").Post, qt.Equals, postFoo) + c.Assert(output[1].Doc.Paths.Value("/bar"), qt.IsNil) c.Assert(output[2].VersionDate, qt.Equals, versionC.Date) - c.Assert(output[2].Doc.Paths["/foo"].Get, qt.Equals, getFoo) - c.Assert(output[2].Doc.Paths["/foo"].Post, qt.Equals, postFoo) - c.Assert(output[2].Doc.Paths["/bar"].Get, qt.Equals, getBar) + c.Assert(output[2].Doc.Paths.Value("/foo").Get, qt.Equals, getFoo) + c.Assert(output[2].Doc.Paths.Value("/foo").Post, qt.Equals, postFoo) + c.Assert(output[2].Doc.Paths.Value("/bar").Get, qt.Equals, getBar) }) c.Run("resolves operations to latest version with respect to output", func(c *qt.C) { @@ -289,16 +289,16 @@ func TestBuild(t *testing.T) { slices.SortFunc(output, compareDocs) c.Assert(output[0].VersionDate, qt.Equals, versionA.Date) - c.Assert(output[0].Doc.Paths["/foo"].Get, qt.Equals, getFooOld) - c.Assert(output[0].Doc.Paths["/bar"], qt.IsNil) + c.Assert(output[0].Doc.Paths.Value("/foo").Get, qt.Equals, getFooOld) + c.Assert(output[0].Doc.Paths.Value("/bar"), qt.IsNil) c.Assert(output[1].VersionDate, qt.Equals, versionB.Date) - c.Assert(output[1].Doc.Paths["/foo"].Get, qt.Equals, getFooOld) - c.Assert(output[1].Doc.Paths["/bar"].Get, qt.Equals, getBar) + c.Assert(output[1].Doc.Paths.Value("/foo").Get, qt.Equals, getFooOld) + c.Assert(output[1].Doc.Paths.Value("/bar").Get, qt.Equals, getBar) c.Assert(output[2].VersionDate, qt.Equals, versionC.Date) - c.Assert(output[2].Doc.Paths["/foo"].Get, qt.Equals, getFooNew) - c.Assert(output[2].Doc.Paths["/bar"].Get, qt.Equals, getBar) + c.Assert(output[2].Doc.Paths.Value("/foo").Get, qt.Equals, getFooNew) + c.Assert(output[2].Doc.Paths.Value("/bar").Get, qt.Equals, getBar) }) c.Run("does not generate versions before pivot date", func(c *qt.C) { @@ -339,12 +339,12 @@ func TestBuild(t *testing.T) { c.Assert(len(output), qt.Equals, 2) c.Assert(output[0].VersionDate, qt.Equals, versionB.Date) - c.Assert(output[0].Doc.Paths["/foo"].Get, qt.Equals, getFooOld) - c.Assert(output[0].Doc.Paths["/bar"].Get, qt.Equals, getBar) + c.Assert(output[0].Doc.Paths.Value("/foo").Get, qt.Equals, getFooOld) + c.Assert(output[0].Doc.Paths.Value("/bar").Get, qt.Equals, getBar) c.Assert(output[1].VersionDate, qt.Equals, versionC.Date) - c.Assert(output[1].Doc.Paths["/foo"].Get, qt.Equals, getFooNew) - c.Assert(output[1].Doc.Paths["/bar"].Get, qt.Equals, getBar) + c.Assert(output[1].Doc.Paths.Value("/foo").Get, qt.Equals, getFooNew) + c.Assert(output[1].Doc.Paths.Value("/bar").Get, qt.Equals, getBar) }) c.Run("lower stabilities are merged into higher", func(c *qt.C) { @@ -388,18 +388,18 @@ func TestBuild(t *testing.T) { slices.SortFunc(output, compareDocs) c.Assert(output[0].VersionDate, qt.Equals, versionBetaA.Date) - c.Assert(output[0].Doc.Paths["/foo"], qt.IsNil) - c.Assert(output[0].Doc.Paths["/bar"].Get, qt.Equals, getBar) + c.Assert(output[0].Doc.Paths.Value("/foo"), qt.IsNil) + c.Assert(output[0].Doc.Paths.Value("/bar").Get, qt.Equals, getBar) c.Assert(output[1].VersionDate, qt.Equals, versionGA.Date) - c.Assert(output[1].Doc.Paths["/foo"].Get, qt.Equals, getFoo) - c.Assert(output[1].Doc.Paths["/foo"].Post, qt.IsNil) - c.Assert(output[0].Doc.Paths["/bar"].Get, qt.Equals, getBar) + c.Assert(output[1].Doc.Paths.Value("/foo").Get, qt.Equals, getFoo) + c.Assert(output[1].Doc.Paths.Value("/foo").Post, qt.IsNil) + c.Assert(output[0].Doc.Paths.Value("/bar").Get, qt.Equals, getBar) c.Assert(output[2].VersionDate, qt.Equals, versionBetaB.Date) - c.Assert(output[2].Doc.Paths["/foo"].Get, qt.Equals, getFoo) - c.Assert(output[2].Doc.Paths["/foo"].Post, qt.Equals, postFoo) - c.Assert(output[2].Doc.Paths["/bar"].Get, qt.Equals, getBar) + c.Assert(output[2].Doc.Paths.Value("/foo").Get, qt.Equals, getFoo) + c.Assert(output[2].Doc.Paths.Value("/foo").Post, qt.Equals, postFoo) + c.Assert(output[2].Doc.Paths.Value("/bar").Get, qt.Equals, getBar) }) } diff --git a/internal/simplebuild/output.go b/internal/simplebuild/output.go index 00bb2e8e..7b5cd7af 100644 --- a/internal/simplebuild/output.go +++ b/internal/simplebuild/output.go @@ -11,10 +11,10 @@ import ( "github.com/ghodss/yaml" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/config" - "github.com/snyk/vervet/v7/internal/compiler" - "github.com/snyk/vervet/v7/internal/files" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/config" + "github.com/snyk/vervet/v8/internal/compiler" + "github.com/snyk/vervet/v8/internal/files" ) // Some services have a need to write specs to multiple destinations. This diff --git a/internal/simplebuild/output_test.go b/internal/simplebuild/output_test.go index 9afef9b8..45dfd08b 100644 --- a/internal/simplebuild/output_test.go +++ b/internal/simplebuild/output_test.go @@ -9,8 +9,8 @@ import ( qt "github.com/frankban/quicktest" "github.com/getkin/kin-openapi/openapi3" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/config" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/config" ) func TestDocSet_WriteOutputs(t *testing.T) { diff --git a/internal/simplebuild/overlays.go b/internal/simplebuild/overlays.go index 23d6d51d..b3e504de 100644 --- a/internal/simplebuild/overlays.go +++ b/internal/simplebuild/overlays.go @@ -7,8 +7,8 @@ import ( "github.com/getkin/kin-openapi/openapi3" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/config" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/config" ) func (docs DocSet) ApplyOverlays(ctx context.Context, cfgs []*config.Overlay) error { diff --git a/internal/simplebuild/refs_test.go b/internal/simplebuild/refs_test.go index 2ebade08..bd41d69e 100644 --- a/internal/simplebuild/refs_test.go +++ b/internal/simplebuild/refs_test.go @@ -6,7 +6,7 @@ import ( qt "github.com/frankban/quicktest" "github.com/getkin/kin-openapi/openapi3" - "github.com/snyk/vervet/v7/internal/simplebuild" + "github.com/snyk/vervet/v8/internal/simplebuild" ) func TestResolveRefs(t *testing.T) { @@ -21,9 +21,7 @@ func TestResolveRefs(t *testing.T) { }}, } doc := openapi3.T{ - Paths: openapi3.Paths{ - "/foo": &path, - }, + Paths: openapi3.NewPaths(openapi3.WithPath("/foo", &path)), } rr := simplebuild.NewRefResolver(&doc) @@ -48,10 +46,7 @@ func TestResolveRefs(t *testing.T) { }}, } doc := openapi3.T{ - Paths: openapi3.Paths{ - "/foo": &pathA, - "/bar": &pathB, - }, + Paths: openapi3.NewPaths(openapi3.WithPath("/foo", &pathA), openapi3.WithPath("/bar", &pathB)), } rr := simplebuild.NewRefResolver(&doc) @@ -77,10 +72,8 @@ func TestResolveRefs(t *testing.T) { }}, } doc := openapi3.T{ - Paths: openapi3.Paths{ - "/foo": &pathA, - "/bar": &pathB, - }, + + Paths: openapi3.NewPaths(openapi3.WithPath("/foo", &pathA), openapi3.WithPath("/bar", &pathB)), } rr := simplebuild.NewRefResolver(&doc) @@ -108,9 +101,7 @@ func TestResolveRefs(t *testing.T) { }}, } doc := openapi3.T{ - Paths: openapi3.Paths{ - "/foo": &path, - }, + Paths: openapi3.NewPaths(openapi3.WithPath("/foo", &path)), } rr := simplebuild.NewRefResolver(&doc) @@ -130,9 +121,7 @@ func TestResolveRefs(t *testing.T) { } doc := openapi3.T{ Components: &openapi3.Components{}, - Paths: openapi3.Paths{ - "/foo": &path, - }, + Paths: openapi3.NewPaths(openapi3.WithPath("/foo", &path)), } rr := simplebuild.NewRefResolver(&doc) diff --git a/internal/storage/collator.go b/internal/storage/collator.go index 5df1fbae..824ff8d7 100644 --- a/internal/storage/collator.go +++ b/internal/storage/collator.go @@ -8,7 +8,7 @@ import ( "github.com/getkin/kin-openapi/openapi3" "github.com/rs/zerolog/log" - "github.com/snyk/vervet/v7" + "github.com/snyk/vervet/v8" ) // Collator is an aggregate of service specs and uniqueVersions scraped by VU. It @@ -164,13 +164,13 @@ func mergeRevisions(revisions ContentRevisions) (*openapi3.T, error) { // first instances of these paths and remove them from subsequent specs // to prevent failing the collate on conflicting paths. if haveOpenAPI { - delete(src.Paths, "/openapi") - } else if _, ok := src.Paths["/openapi"]; ok { + src.Paths.Delete("/openapi") + } else if pathItem := src.Paths.Value("/openapi"); pathItem != nil { haveOpenAPI = true } if haveOpenAPIVersion { - delete(src.Paths, "/openapi/{version}") - } else if _, ok := src.Paths["/openapi/{version}"]; ok { + src.Paths.Delete("/openapi/{version}") + } else if pathItem := src.Paths.Value("/openapi/{version}"); pathItem != nil { haveOpenAPIVersion = true } diff --git a/internal/storage/collator_test.go b/internal/storage/collator_test.go index 9d31ddf3..c501c68f 100644 --- a/internal/storage/collator_test.go +++ b/internal/storage/collator_test.go @@ -7,9 +7,9 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/internal/storage" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/internal/storage" + "github.com/snyk/vervet/v8/testdata" ) const serviceASpec = ` @@ -150,8 +150,9 @@ func TestCollator_Collate(t *testing.T) { c.Assert(specs[v20220401_ga].Paths.Find("/example"), qt.IsNotNil) // No filtering, so extensions are all present - c.Assert(specs[v20220401_ga].Paths["/example"].Post.Extensions["x-other-internal"], qt.Not(qt.IsNil)) - c.Assert(specs[v20220401_ga].Paths["/example"].Post.Responses["204"].Value.Extensions["x-internal"], qt.Not(qt.IsNil)) + c.Assert(specs[v20220401_ga].Paths.Value("/example").Post.Extensions["x-other-internal"], qt.Not(qt.IsNil)) + c.Assert(specs[v20220401_ga].Paths.Value("/example").Post. + Responses.Status(204).Value.Extensions["x-internal"], qt.Not(qt.IsNil)) } func TestCollator_Collate_MigratingEndpoints(t *testing.T) { @@ -183,11 +184,11 @@ func TestCollator_Collate_MigratingEndpoints(t *testing.T) { c.Assert(specs[v20220201_exp].Paths.Find("/test"), qt.IsNotNil) c.Assert(specs[v20230314_exp].Paths.Find("/test"), qt.IsNotNil) - c.Assert(specs[v20220201_exp].Paths["/test"].Get.Responses["204"], qt.IsNotNil) - c.Assert(specs[v20220201_exp].Paths["/test"].Get.Responses["200"], qt.IsNil) + c.Assert(specs[v20220201_exp].Paths.Value("/test").Get.Responses.Status(204), qt.IsNotNil) + c.Assert(specs[v20220201_exp].Paths.Value("/test").Get.Responses.Status(200), qt.IsNil) - c.Assert(specs[v20230314_exp].Paths["/test"].Get.Responses["200"], qt.IsNotNil) - c.Assert(specs[v20230314_exp].Paths["/test"].Get.Responses["204"], qt.IsNil) + c.Assert(specs[v20230314_exp].Paths.Value("/test").Get.Responses.Status(200), qt.IsNotNil) + c.Assert(specs[v20230314_exp].Paths.Value("/test").Get.Responses.Status(204), qt.IsNil) } func TestCollator_Collate_ExcludePatterns(t *testing.T) { @@ -218,8 +219,9 @@ func TestCollator_Collate_ExcludePatterns(t *testing.T) { specs, err := collator.Collate() c.Assert(err, qt.IsNil) - c.Assert(specs[v20220401_ga].Paths["/example"].Post.Extensions["x-other-internal"], qt.IsNil) - c.Assert(specs[v20220401_ga].Paths["/example"].Post.Responses["204"].Value.Extensions["x-internal"], qt.IsNil) + c.Assert(specs[v20220401_ga].Paths.Value("/example").Post.Extensions["x-other-internal"], qt.IsNil) + c.Assert(specs[v20220401_ga].Paths.Value("/example").Post. + Responses.Status(204).Value.Extensions["x-internal"], qt.IsNil) } func TestCollator_Collate_Conflict(t *testing.T) { @@ -252,7 +254,7 @@ func TestCollator_Collate_Conflict(t *testing.T) { specs, err := collator.Collate() c.Assert(err, qt.IsNil) // First path wins - c.Assert(specs[vervet.MustParseVersion("2021-06-15")].Paths["/examples/hello-world"].Post.Description, + c.Assert(specs[vervet.MustParseVersion("2021-06-15")].Paths.Value("/examples/hello-world").Post.Description, qt.Equals, "Create a single result from the hello-world example - from example 1") } diff --git a/internal/storage/disk/disk.go b/internal/storage/disk/disk.go index 911c6fb6..f1419ec9 100644 --- a/internal/storage/disk/disk.go +++ b/internal/storage/disk/disk.go @@ -17,8 +17,8 @@ import ( "github.com/getkin/kin-openapi/openapi3" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/internal/storage" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/internal/storage" ) type Storage struct { diff --git a/internal/storage/disk/disk_test.go b/internal/storage/disk/disk_test.go index 8c9d2e7b..2198953a 100644 --- a/internal/storage/disk/disk_test.go +++ b/internal/storage/disk/disk_test.go @@ -8,7 +8,7 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7/internal/storage" + "github.com/snyk/vervet/v8/internal/storage" ) var t0 = time.Date(2021, time.December, 3, 20, 49, 51, 0, time.UTC) diff --git a/internal/storage/gcs/client.go b/internal/storage/gcs/client.go index 1cb9ec65..640ea4e5 100644 --- a/internal/storage/gcs/client.go +++ b/internal/storage/gcs/client.go @@ -16,8 +16,8 @@ import ( "google.golang.org/api/iterator" "google.golang.org/api/option" - "github.com/snyk/vervet/v7" - vustorage "github.com/snyk/vervet/v7/internal/storage" + "github.com/snyk/vervet/v8" + vustorage "github.com/snyk/vervet/v8/internal/storage" ) // StaticKeyCredentials structure google.Credentials for diff --git a/internal/storage/gcs/client_test.go b/internal/storage/gcs/client_test.go index 50a84140..ed6d2aff 100644 --- a/internal/storage/gcs/client_test.go +++ b/internal/storage/gcs/client_test.go @@ -7,9 +7,9 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7/internal/storage" - "github.com/snyk/vervet/v7/internal/storage/gcs" - gcstesting "github.com/snyk/vervet/v7/internal/storage/gcs/testing" + "github.com/snyk/vervet/v8/internal/storage" + "github.com/snyk/vervet/v8/internal/storage/gcs" + gcstesting "github.com/snyk/vervet/v8/internal/storage/gcs/testing" ) var specFile = "spec.txt" diff --git a/internal/storage/gcs/testing/testing.go b/internal/storage/gcs/testing/testing.go index 3c816a23..1baced9d 100644 --- a/internal/storage/gcs/testing/testing.go +++ b/internal/storage/gcs/testing/testing.go @@ -16,7 +16,7 @@ import ( "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/wait" - "github.com/snyk/vervet/v7/internal/storage/gcs" + "github.com/snyk/vervet/v8/internal/storage/gcs" ) const ( diff --git a/internal/storage/revision.go b/internal/storage/revision.go index be6f7078..14ef5a31 100644 --- a/internal/storage/revision.go +++ b/internal/storage/revision.go @@ -5,7 +5,7 @@ import ( "sort" "time" - "github.com/snyk/vervet/v7" + "github.com/snyk/vervet/v8" ) // ContentRevision is the exact contents and metadata of a service's version at scraping timestamp. diff --git a/internal/storage/revision_test.go b/internal/storage/revision_test.go index a36eb764..45248e06 100644 --- a/internal/storage/revision_test.go +++ b/internal/storage/revision_test.go @@ -6,8 +6,8 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/internal/storage" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/internal/storage" ) func TestServiceRevisions_ResolveLatestRevision(t *testing.T) { diff --git a/internal/storage/s3/client.go b/internal/storage/s3/client.go index 201fa502..d9cb13c4 100644 --- a/internal/storage/s3/client.go +++ b/internal/storage/s3/client.go @@ -22,8 +22,8 @@ import ( "github.com/rs/zerolog/log" "go.uber.org/multierr" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/internal/storage" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/internal/storage" ) // StaticKeyCredentials defines credential structure used in config.LoadDefaultConfig. diff --git a/internal/storage/s3/client_test.go b/internal/storage/s3/client_test.go index bb0d4877..5904def5 100644 --- a/internal/storage/s3/client_test.go +++ b/internal/storage/s3/client_test.go @@ -7,9 +7,9 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7/internal/storage" - "github.com/snyk/vervet/v7/internal/storage/s3" - s3testing "github.com/snyk/vervet/v7/internal/storage/s3/testing" + "github.com/snyk/vervet/v8/internal/storage" + "github.com/snyk/vervet/v8/internal/storage/s3" + s3testing "github.com/snyk/vervet/v8/internal/storage/s3/testing" ) func TestPutObject(t *testing.T) { diff --git a/internal/storage/s3/testing/testing.go b/internal/storage/s3/testing/testing.go index 68470f0b..25bb9cbe 100644 --- a/internal/storage/s3/testing/testing.go +++ b/internal/storage/s3/testing/testing.go @@ -6,7 +6,7 @@ import ( "github.com/elgohr/go-localstack" qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7/internal/storage/s3" + "github.com/snyk/vervet/v8/internal/storage/s3" ) const ( diff --git a/internal/storage/storage.go b/internal/storage/storage.go index 692368a0..ac2a7cef 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -9,7 +9,7 @@ import ( "github.com/getkin/kin-openapi/openapi3" "github.com/rs/zerolog/log" - "github.com/snyk/vervet/v7" + "github.com/snyk/vervet/v8" ) // ReadOnlyStorage defines functionality needed to fetch spec versions. diff --git a/merge.go b/merge.go index 1c3e238e..536e504d 100644 --- a/merge.go +++ b/merge.go @@ -177,11 +177,12 @@ func mergeInfo(dst, src *openapi3.T, replace bool) { func mergePaths(dst, src *openapi3.T, replace bool) { if src.Paths != nil && dst.Paths == nil { - dst.Paths = make(openapi3.Paths, len(src.Paths)) + dst.Paths = openapi3.NewPathsWithCapacity(src.Paths.Len()) } - for k, v := range src.Paths { - if _, ok := dst.Paths[k]; !ok || replace { - dst.Paths[k] = v + for _, key := range src.Paths.InMatchingOrder() { + v := src.Paths.Value(key) + if pathItem := dst.Paths.Value(key); pathItem == nil || replace { + dst.Paths.Set(key, v) } } } diff --git a/merge_test.go b/merge_test.go index 3f6d7730..77fbc14b 100644 --- a/merge_test.go +++ b/merge_test.go @@ -7,8 +7,8 @@ import ( "github.com/getkin/kin-openapi/openapi3" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/testdata" ) var openapiCmp = qt.CmpEquals(cmpopts.IgnoreUnexported( @@ -159,15 +159,12 @@ tags: err := vervet.Merge(dst, src, false) c.Assert(err, qt.IsNil) c.Assert(dst.Tags, qt.DeepEquals, openapi3.Tags{{ - Extensions: map[string]interface{}{}, Name: "bar", Description: "bar resource (src)", }, { - Extensions: map[string]interface{}{}, Name: "baz", Description: "baz resource (dst)", }, { - Extensions: map[string]interface{}{}, Name: "foo", Description: "foo resource (dst)", }}) @@ -178,15 +175,12 @@ tags: err := vervet.Merge(dst, src, true) c.Assert(err, qt.IsNil) c.Assert(dst.Tags, qt.DeepEquals, openapi3.Tags{{ - Extensions: map[string]interface{}{}, Name: "bar", Description: "bar resource (src)", }, { - Extensions: map[string]interface{}{}, Name: "baz", Description: "baz resource (dst)", }, { - Extensions: map[string]interface{}{}, Name: "foo", Description: "foo resource (src)", }}) @@ -239,9 +233,8 @@ x-extension: err := vervet.Merge(dst, src, false) c.Assert(err, qt.IsNil) c.Assert(dst.Info, qt.DeepEquals, &openapi3.Info{ - Extensions: map[string]interface{}{}, - Title: "Dst", - Version: "dst", + Title: "Dst", + Version: "dst", }) c.Assert(dst.Security, qt.DeepEquals, openapi3.SecurityRequirements{{ "Foo": []string{"up", "down"}, @@ -249,11 +242,9 @@ x-extension: "Baz": []string{"strange", "crunchy"}, }}) c.Assert(dst.Servers, qt.DeepEquals, openapi3.Servers{{ - Extensions: map[string]interface{}{}, URL: "https://example.com/foo", Description: "Foo (dst)", }, { - Extensions: map[string]interface{}{}, URL: "https://example.com/baz", Description: "Baz (dst)", }}) @@ -270,9 +261,8 @@ x-extension: err := vervet.Merge(dst, src, true) c.Assert(err, qt.IsNil) c.Assert(dst.Info, qt.DeepEquals, &openapi3.Info{ - Extensions: map[string]interface{}{}, - Title: "Src", - Version: "src", + Title: "Src", + Version: "src", }) c.Assert(dst.Security, qt.DeepEquals, openapi3.SecurityRequirements{{ "Foo": []string{}, @@ -280,11 +270,9 @@ x-extension: "Bar": []string{"read", "write"}, }}) c.Assert(dst.Servers, qt.DeepEquals, openapi3.Servers{{ - Extensions: map[string]interface{}{}, URL: "https://example.com/foo", Description: "Foo (src)", }, { - Extensions: map[string]interface{}{}, URL: "https://example.com/bar", Description: "Bar (src)", }}) @@ -318,7 +306,7 @@ paths: dst := &openapi3.T{} err := vervet.Merge(dst, src, false) c.Assert(err, qt.IsNil) - c.Assert(dst.Paths, qt.HasLen, 1) + c.Assert(dst.Paths.Len(), qt.Equals, 1) } func mustLoadFile(c *qt.C, path string) *openapi3.T { diff --git a/ref_alias_resolver.go b/ref_alias_resolver.go index ef9b8885..ff7b27b2 100644 --- a/ref_alias_resolver.go +++ b/ref_alias_resolver.go @@ -1,20 +1,54 @@ package vervet import ( - "reflect" "strings" "github.com/getkin/kin-openapi/openapi3" - "github.com/mitchellh/reflectwalk" + + "github.com/snyk/vervet/v8/internal/openapiwalker" ) // refAliasResolver rewrites references in an OpenAPI document object to local // references, so that the spec is self-contained. type refAliasResolver struct { - doc *openapi3.T - refAliases map[string]string - curRefType reflect.Value - curRefField reflect.Value + doc *openapi3.T + refAliases map[string]string +} + +func (l *refAliasResolver) ProcessCallbackRef(ref *openapi3.CallbackRef) { + ref.Ref = l.resolveRefAlias(ref.Ref) +} + +func (l *refAliasResolver) ProcessExampleRef(ref *openapi3.ExampleRef) { + ref.Ref = l.resolveRefAlias(ref.Ref) +} + +func (l *refAliasResolver) ProcessHeaderRef(ref *openapi3.HeaderRef) { + ref.Ref = l.resolveRefAlias(ref.Ref) +} + +func (l *refAliasResolver) ProcessLinkRef(ref *openapi3.LinkRef) { + ref.Ref = l.resolveRefAlias(ref.Ref) +} + +func (l *refAliasResolver) ProcessParameterRef(ref *openapi3.ParameterRef) { + ref.Ref = l.resolveRefAlias(ref.Ref) +} + +func (l *refAliasResolver) ProcessRequestBodyRef(ref *openapi3.RequestBodyRef) { + ref.Ref = l.resolveRefAlias(ref.Ref) +} + +func (l *refAliasResolver) ProcessResponseRef(ref *openapi3.ResponseRef) { + ref.Ref = l.resolveRefAlias(ref.Ref) +} + +func (l *refAliasResolver) ProcessSchemaRef(ref *openapi3.SchemaRef) { + ref.Ref = l.resolveRefAlias(ref.Ref) +} + +func (l *refAliasResolver) ProcessSecuritySchemeRef(ref *openapi3.SecuritySchemeRef) { + ref.Ref = l.resolveRefAlias(ref.Ref) } // newRefAliasResolver returns a new refAliasResolver. @@ -52,26 +86,6 @@ func (l *refAliasResolver) resolveRefAlias(ref string) string { } // resolve rewrites all references in the OpenAPI document to local references. -func (l *refAliasResolver) resolve() error { - return reflectwalk.Walk(l.doc, l) -} - -// Struct implements reflectwalk.StructWalker. -func (l *refAliasResolver) Struct(v reflect.Value) error { - l.curRefType, l.curRefField = v, v.FieldByName("Ref") - return nil -} - -// StructField implements reflectwalk.StructWalker. -func (l *refAliasResolver) StructField(sf reflect.StructField, v reflect.Value) error { - if !l.curRefField.IsValid() { - return nil - } - ref := l.curRefField.String() - if ref == "" { - return nil - } - ref = l.resolveRefAlias(ref) - l.curRefField.Set(reflect.ValueOf(ref)) - return nil +func (l *refAliasResolver) resolve() { + openapiwalker.ProcessRefs(l.doc, l) } diff --git a/ref_alias_resolver_test.go b/ref_alias_resolver_test.go index c4f63620..c34bb4fb 100644 --- a/ref_alias_resolver_test.go +++ b/ref_alias_resolver_test.go @@ -9,8 +9,8 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/testdata" ) func TestLocalize(t *testing.T) { diff --git a/ref_index.go b/ref_index.go index c66e8d13..67c12075 100644 --- a/ref_index.go +++ b/ref_index.go @@ -1,10 +1,7 @@ package vervet import ( - "reflect" - "github.com/getkin/kin-openapi/openapi3" - "github.com/mitchellh/reflectwalk" ) // RefIndex indexes the distinct references used in an OpenAPI document. @@ -15,14 +12,51 @@ type RefIndex struct { // NewRefIndex returns a new reference index on an OpenAPI document. func NewRefIndex(doc *openapi3.T) (*RefIndex, error) { ix := &RefIndex{refs: map[string]struct{}{}} - if err := ix.index(doc); err != nil { - return nil, err - } + ix.index(doc) return ix, nil } -func (ix *RefIndex) index(doc *openapi3.T) error { - return reflectwalk.Walk(doc, ix) +func (ix *RefIndex) index(doc *openapi3.T) { + for _, schemaRef := range doc.Components.Schemas { + ix.refs[extractRef(schemaRef)] = struct{}{} + } + for _, parameterRef := range doc.Components.Parameters { + ix.refs[extractRef(parameterRef)] = struct{}{} + } + for _, headerRef := range doc.Components.Headers { + ix.refs[extractRef(headerRef)] = struct{}{} + } + for _, requestBodyRef := range doc.Components.RequestBodies { + ix.refs[extractRef(requestBodyRef)] = struct{}{} + } + for _, responseRef := range doc.Components.Responses { + ix.refs[extractRef(responseRef)] = struct{}{} + for _, content := range responseRef.Value.Content { + ix.refs[extractRef(content.Schema)] = struct{}{} + for _, propertyRef := range content.Schema.Value.Properties { + ix.refs[extractRef(propertyRef)] = struct{}{} + } + } + } + for _, securitySchemesRef := range doc.Components.SecuritySchemes { + ix.refs[extractRef(securitySchemesRef)] = struct{}{} + } + for _, exampleRef := range doc.Components.Examples { + ix.refs[extractRef(exampleRef)] = struct{}{} + } + for _, linkRef := range doc.Components.Links { + ix.refs[extractRef(linkRef)] = struct{}{} + } + for _, callbackRef := range doc.Components.Callbacks { + ix.refs[extractRef(callbackRef)] = struct{}{} + } +} + +func extractRef(componentRef openapi3.ComponentRef) string { + if componentRef == nil || componentRef.RefPath() == nil { + return "" + } + return "#" + componentRef.RefPath().Fragment } // HasRef returns whether the indexed document contains the given ref. @@ -30,37 +64,3 @@ func (ix *RefIndex) HasRef(ref string) bool { _, ok := ix.refs[ref] return ok } - -// Struct implements reflectwalk.StructWalker. -func (ix *RefIndex) Struct(v reflect.Value) error { - if !v.CanInterface() { - return nil - } - - switch val := v.Addr().Interface().(type) { - case *openapi3.SchemaRef: - ix.refs[val.Ref] = struct{}{} - case *openapi3.ParameterRef: - ix.refs[val.Ref] = struct{}{} - case *openapi3.HeaderRef: - ix.refs[val.Ref] = struct{}{} - case *openapi3.RequestBodyRef: - ix.refs[val.Ref] = struct{}{} - case *openapi3.ResponseRef: - ix.refs[val.Ref] = struct{}{} - case *openapi3.SecuritySchemeRef: - ix.refs[val.Ref] = struct{}{} - case *openapi3.ExampleRef: - ix.refs[val.Ref] = struct{}{} - case *openapi3.LinkRef: - ix.refs[val.Ref] = struct{}{} - case *openapi3.CallbackRef: - ix.refs[val.Ref] = struct{}{} - } - return nil -} - -// StructField implements reflectwalk.StructWalker. -func (*RefIndex) StructField(field reflect.StructField, v reflect.Value) error { - return nil -} diff --git a/ref_index_test.go b/ref_index_test.go index c9e6c0b2..2fb37a65 100644 --- a/ref_index_test.go +++ b/ref_index_test.go @@ -5,8 +5,8 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/testdata" ) func TestRefIndexSource(t *testing.T) { diff --git a/remove_elements.go b/remove_elements.go index 15f7f370..91685680 100644 --- a/remove_elements.go +++ b/remove_elements.go @@ -1,11 +1,9 @@ package vervet import ( - "reflect" "regexp" "github.com/getkin/kin-openapi/openapi3" - "github.com/mitchellh/reflectwalk" ) // ExcludePatterns defines patterns matching elements to be removed from an @@ -49,13 +47,13 @@ func RemoveElements(doc *openapi3.T, excludes ExcludePatterns) error { } // Remove excluded paths excludedPaths := map[string]struct{}{} - for path := range doc.Paths { + for _, path := range doc.Paths.InMatchingOrder() { if ex.isExcludedPath(path) { excludedPaths[path] = struct{}{} } } for path := range excludedPaths { - delete(doc.Paths, path) + doc.Paths.Delete(path) } // Remove excluded elements if err := ex.apply(); err != nil { @@ -65,45 +63,31 @@ func RemoveElements(doc *openapi3.T, excludes ExcludePatterns) error { } func (ex *excluder) apply() error { - return reflectwalk.Walk(ex.doc, ex) -} - -// Struct implements reflectwalk.StructWalker. -func (ex *excluder) Struct(v reflect.Value) error { - if !v.CanInterface() { - return nil - } - - switch v.Interface().(type) { - case openapi3.Operation: - ex.applyOperation(v.Addr().Interface().(*openapi3.Operation)) - } - - return nil -} - -// StructField implements reflectwalk.StructWalker. -func (ex *excluder) StructField(field reflect.StructField, v reflect.Value) error { - if field.Name != "Extensions" || !v.CanInterface() { - return nil - } - - switch v.Interface().(type) { - case map[string]interface{}: - ex.applyExtensions(v.Addr().Interface().(*map[string]interface{})) + for _, pathItem := range ex.doc.Paths.Map() { + ex.applyExtensions(pathItem.Extensions) + for _, operation := range pathItem.Operations() { + ex.applyOperation(operation) + ex.applyExtensions(operation.Extensions) + if operation.Responses != nil { + ex.applyExtensions(operation.Responses.Extensions) + } + for _, responseRef := range operation.Responses.Map() { + ex.applyExtensions(responseRef.Extensions) + if responseRef.Value != nil { + ex.applyExtensions(responseRef.Value.Extensions) + } + } + } } - return nil } -func (ex *excluder) applyExtensions(extensions *map[string]interface{}) { - exts := make(map[string]interface{}, len(*extensions)) - for k, v := range *extensions { - if !ex.isExcludedExtension(k) { - exts[k] = v +func (ex *excluder) applyExtensions(extensions map[string]interface{}) { + for k := range extensions { + if ex.isExcludedExtension(k) { + delete(extensions, k) } } - *extensions = exts } func (ex *excluder) applyOperation(op *openapi3.Operation) { @@ -115,7 +99,7 @@ func (ex *excluder) applyOperation(op *openapi3.Operation) { } op.Parameters = params - for _, resp := range op.Responses { + for _, resp := range op.Responses.Map() { if resp.Value == nil { continue } diff --git a/remove_elements_test.go b/remove_elements_test.go index 43dbed7d..db6a8a4a 100644 --- a/remove_elements_test.go +++ b/remove_elements_test.go @@ -5,8 +5,8 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/testdata" ) func TestRemoveElementsExact(t *testing.T) { @@ -16,24 +16,24 @@ func TestRemoveElementsExact(t *testing.T) { // Establish that the OpenAPI document has these expected features - c.Assert(doc.Paths["/examples/hello-world"], qt.Not(qt.IsNil)) - c.Assert(doc.Paths["/examples/hello-world/{id}"], qt.Not(qt.IsNil)) + c.Assert(doc.Paths.Value("/examples/hello-world"), qt.Not(qt.IsNil)) + c.Assert(doc.Paths.Value("/examples/hello-world/{id}"), qt.Not(qt.IsNil)) c.Assert( - doc.Paths["/orgs/{orgId}/projects"].Get.Responses["200"].Value.Headers["snyk-request-id"], + doc.Paths.Value("/orgs/{orgId}/projects").Get.Responses.Status(200).Value.Headers["snyk-request-id"], qt.Not(qt.IsNil), ) c.Assert( - doc.Paths["/orgs/{orgId}/projects"].Get.Responses["200"].Value.Headers["snyk-version-served"], + doc.Paths.Value("/orgs/{orgId}/projects").Get.Responses.Status(200).Value.Headers["snyk-version-served"], qt.Not(qt.IsNil), ) - c.Assert(doc.Paths["/orgs/{org_id}/projects/{project_id}"].Delete.Parameters, qt.HasLen, 4) + c.Assert(doc.Paths.Value("/orgs/{org_id}/projects/{project_id}").Delete.Parameters, qt.HasLen, 4) c.Assert( - doc.Paths["/orgs/{org_id}/projects/{project_id}"].Delete.Parameters[3].Value.Name, + doc.Paths.Value("/orgs/{org_id}/projects/{project_id}").Delete.Parameters[3].Value.Name, qt.Equals, "x-private-matter", ) - c.Assert(doc.Paths["/orgs/{orgId}/projects"].Extensions["x-snyk-api-resource"], qt.Not(qt.IsNil)) + c.Assert(doc.Paths.Value("/orgs/{orgId}/projects").Extensions["x-snyk-api-resource"], qt.Not(qt.IsNil)) c.Assert(doc.Extensions["x-snyk-api-lifecycle"], qt.Not(qt.IsNil)) // Remove some of them @@ -47,20 +47,21 @@ func TestRemoveElementsExact(t *testing.T) { // Assert their removal - c.Assert(doc.Paths["/examples/hello-world"], qt.IsNil) - c.Assert(doc.Paths["/examples/hello-world/{id}"], qt.IsNil) + c.Assert(doc.Paths.Value("/examples/hello-world"), qt.IsNil) + c.Assert(doc.Paths.Value("/examples/hello-world/{id}"), qt.IsNil) c.Assert( - doc.Paths["/orgs/{orgId}/projects"].Get.Responses["200"].Value.Headers["snyk-request-id"], + doc.Paths.Value("/orgs/{orgId}/projects").Get.Responses.Status(200).Value.Headers["snyk-request-id"], qt.IsNil, ) // now removed c.Assert( - doc.Paths["/orgs/{orgId}/projects"].Get.Responses["200"].Value.Headers["snyk-version-served"], + doc.Paths.Value("/orgs/{orgId}/projects").Get.Responses.Status(200).Value.Headers["snyk-version-served"], qt.Not(qt.IsNil), ) // still there - c.Assert(doc.Paths["/orgs/{org_id}/projects/{project_id}"].Delete.Parameters, qt.HasLen, 3) // x-private-matter removed + c.Assert(doc.Paths.Value("/orgs/{org_id}/projects/{project_id}"). + Delete.Parameters, qt.HasLen, 3) // x-private-matter removed - c.Assert(doc.Paths["/orgs/{orgId}/projects"].Extensions["x-snyk-api-resource"], qt.IsNil) // now removed - c.Assert(doc.Extensions["x-snyk-api-lifecycle"], qt.Not(qt.IsNil)) // still there + c.Assert(doc.Paths.Value("/orgs/{orgId}/projects").Extensions["x-snyk-api-resource"], qt.IsNil) // now removed + c.Assert(doc.Extensions["x-snyk-api-lifecycle"], qt.Not(qt.IsNil)) // still there } func TestRemoveElementsRegex(t *testing.T) { @@ -71,25 +72,25 @@ func TestRemoveElementsRegex(t *testing.T) { // Establish that the OpenAPI document has these expected features c.Assert( - doc.Paths["/orgs/{orgId}/projects"].Get.Responses["200"].Value.Headers["snyk-request-id"], + doc.Paths.Value("/orgs/{orgId}/projects").Get.Responses.Status(200).Value.Headers["snyk-request-id"], qt.Not(qt.IsNil), ) c.Assert( - doc.Paths["/orgs/{orgId}/projects"].Get.Responses["200"].Value.Headers["snyk-version-served"], + doc.Paths.Value("/orgs/{orgId}/projects").Get.Responses.Status(200).Value.Headers["snyk-version-served"], qt.Not(qt.IsNil), ) c.Assert( - doc.Paths["/orgs/{org_id}/projects/{project_id}"].Delete.Parameters, + doc.Paths.Value("/orgs/{org_id}/projects/{project_id}").Delete.Parameters, qt.HasLen, 4, ) c.Assert( - doc.Paths["/orgs/{org_id}/projects/{project_id}"].Delete.Parameters[3].Value.Name, + doc.Paths.Value("/orgs/{org_id}/projects/{project_id}").Delete.Parameters[3].Value.Name, qt.Equals, "x-private-matter", ) - c.Assert(doc.Paths["/orgs/{orgId}/projects"].Extensions["x-snyk-api-resource"], qt.Not(qt.IsNil)) + c.Assert(doc.Paths.Value("/orgs/{orgId}/projects").Extensions["x-snyk-api-resource"], qt.Not(qt.IsNil)) c.Assert(doc.Extensions["x-snyk-api-lifecycle"], qt.Not(qt.IsNil)) // Remove some of them @@ -103,19 +104,19 @@ func TestRemoveElementsRegex(t *testing.T) { // Assert their removal c.Assert( - doc.Paths["/orgs/{orgId}/projects"].Get.Responses["200"].Value.Headers["snyk-request-id"], + doc.Paths.Value("/orgs/{orgId}/projects").Get.Responses.Status(200).Value.Headers["snyk-request-id"], qt.Not(qt.IsNil), ) // still there c.Assert( - doc.Paths["/orgs/{orgId}/projects"].Get.Responses["200"].Value.Headers["snyk-version-served"], + doc.Paths.Value("/orgs/{orgId}/projects").Get.Responses.Status(200).Value.Headers["snyk-version-served"], qt.IsNil, ) // now removed c.Assert( - doc.Paths["/orgs/{org_id}/projects/{project_id}"].Delete.Parameters, + doc.Paths.Value("/orgs/{org_id}/projects/{project_id}").Delete.Parameters, qt.HasLen, 3, ) // x-private-matter removed - c.Assert(doc.Paths["/orgs/{orgId}/projects"].Extensions["x-snyk-api-resource"], qt.IsNil) // now removed - c.Assert(doc.Extensions["x-snyk-api-lifecycle"], qt.Not(qt.IsNil)) // still there + c.Assert(doc.Paths.Value("/orgs/{orgId}/projects").Extensions["x-snyk-api-resource"], qt.IsNil) // now removed + c.Assert(doc.Extensions["x-snyk-api-lifecycle"], qt.Not(qt.IsNil)) // still there } diff --git a/resource.go b/resource.go index 25bf5ac2..82ee7e01 100644 --- a/resource.go +++ b/resource.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "path/filepath" + "strings" "time" "github.com/bmatcuk/doublestar/v4" @@ -84,7 +85,7 @@ func (rv *ResourceVersion) Validate(ctx context.Context) error { return err } // Resource path checks. There should be at least one path per resource. - if len(rv.Paths) < 1 { + if rv.Paths.Len() < 1 { return fmt.Errorf("spec contains no paths") } return nil @@ -228,10 +229,14 @@ func LoadResourceVersionsFileset(specYamls []string) (*ResourceVersions, error) return nil, err } // Map release versions per operation - for path, pathItem := range rc.Paths { + for _, path := range rc.Paths.InMatchingOrder() { + pathItem := rc.Paths.Value(path) for _, opName := range operationNames { op := getOperationByName(pathItem, opName) if op != nil { + if op.Extensions == nil { + op.Extensions = make(map[string]any) + } op.Extensions[ExtSnykApiVersion] = rc.Version.String() opKey := operationKey{path, opName} opReleases[opKey] = append(opReleases[opKey], rc.Version) @@ -248,7 +253,8 @@ func LoadResourceVersionsFileset(specYamls []string) (*ResourceVersions, error) // Annotate each path in each resource version with the other change // versions affecting the path. This supports navigation across versions. for _, rc := range resourceVersions.versions { - for path, pathItem := range rc.Paths { + for _, path := range rc.Paths.InMatchingOrder() { + pathItem := rc.Paths.Value(path) for _, opName := range operationNames { op := getOperationByName(pathItem, opName) if op == nil { @@ -313,7 +319,7 @@ func loadResource(specPath string, versionStr string) (*ResourceVersion, error) return nil, fmt.Errorf("invalid version %q", versionStr) } - if len(doc.Paths) == 0 { + if doc.Paths.Len() == 0 { return nil, nil //nolint:nilnil //acked } @@ -331,14 +337,37 @@ func loadResource(specPath string, versionStr string) (*ResourceVersion, error) } ep := &ResourceVersion{Name: name, Document: doc, Version: version} - for path := range doc.T.Paths { - doc.T.Paths[path].Extensions[ExtSnykApiResource] = name + for _, path := range doc.T.Paths.InMatchingOrder() { + if doc.T.Paths.Value(path).Extensions == nil { + doc.T.Paths.Value(path).Extensions = make(map[string]any) + } + doc.T.Paths.Value(path).Extensions[ExtSnykApiResource] = name } return ep, nil } // Localize rewrites all references in an OpenAPI document to local references. func Localize(ctx context.Context, doc *Document) error { - doc.InternalizeRefs(ctx, nil) + doc.InternalizeRefs(ctx, ResolveRefsWithoutSourceName) return doc.ResolveRefs() } + +// ResolveRefsWithoutSourceName resolves references without the source url/file name in ref +// background: this was the way kin-openapi used to resolve references, but it was changed +// in the recent versions(v0.127.0) to include the filename in the ref name. Although this +// method prevents conflicts, it causes existing specs to break. +func ResolveRefsWithoutSourceName(t *openapi3.T, componentRef openapi3.ComponentRef) string { + ref := componentRef.RefString() + if ref == "" { + return "" + } + split := strings.SplitN(ref, "#", 2) + if len(split) == 2 { + return filepath.Base(split[1]) + } + ref = split[0] + for ext := filepath.Ext(ref); len(ext) > 0; ext = filepath.Ext(ref) { + ref = strings.TrimSuffix(ref, ext) + } + return filepath.Base(ref) +} diff --git a/resource_test.go b/resource_test.go index d2f784c3..2d2d9688 100644 --- a/resource_test.go +++ b/resource_test.go @@ -2,13 +2,14 @@ package vervet_test import ( "context" + "net/url" "testing" "time" qt "github.com/frankban/quicktest" - . "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/testdata" + . "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/testdata" ) func TestResource(t *testing.T) { @@ -142,3 +143,63 @@ func TestResourceVersionsAtSunset(t *testing.T) { } } } + +func TestResolveRefsWithoutSourceName(t *testing.T) { + tests := []struct { + name string + ref string + want string + }{ + { + name: "empty ref", + ref: "", + want: "", + }, + { + name: "ref with source and fragment", + ref: "#/components/schemas/Pet", + want: "Pet", + }, + { + name: "ref without source", + ref: "components/schemas/Pet", + want: "Pet", + }, + { + name: "ref with extension", + ref: "models/Pet.yaml", + want: "Pet", + }, + { + name: "ref with multiple extensions", + ref: "models/Pet.json.gz", + want: "Pet", + }, + { + name: "ref with complex path", + ref: "path/to/models/Pet.yaml", + want: "Pet", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := ResolveRefsWithoutSourceName(nil, mockComponentRef(tt.ref)); got != tt.want { + t.Errorf("ResolveRefsWithoutSourceName() = %v, want %v", got, tt.want) + } + }) + } +} + +type mockComponentRef string + +func (m mockComponentRef) RefString() string { + return string(m) +} + +func (m mockComponentRef) RefPath() *url.URL { + return nil +} + +func (m mockComponentRef) CollectionName() string { + return "" +} diff --git a/resource_versions.go b/resource_versions.go index ac17d898..3712ea44 100644 --- a/resource_versions.go +++ b/resource_versions.go @@ -20,7 +20,7 @@ func (s resourceVersionsSlice) validate() error { } else if err != nil { return fmt.Errorf("validation failed: %w", err) } - for path := range ep.Paths { + for _, path := range ep.Paths.InMatchingOrder() { if conflict, ok := resourcePaths[path]; ok { return fmt.Errorf("conflict: %q %q", conflict, ep.sourcePrefix) } @@ -65,7 +65,7 @@ func (s resourceVersionsSlice) at(v Version) (*openapi3.T, error) { return nil, ErrNoMatchingVersion } if result.Extensions == nil { - result.Extensions = map[string]interface{}{} + result.Extensions = map[string]any{} } result.Extensions[ExtSnykApiLifecycle] = v.LifecycleAt(time.Time{}).String() return result, nil diff --git a/spec.go b/spec.go index e118de26..7240fbb3 100644 --- a/spec.go +++ b/spec.go @@ -115,7 +115,8 @@ func (sv *SpecVersions) resolveOperations() error { // Operations declared in this spec become active for the next version // at this stability. nextActiveOps := operationVersionMap{} - for path, pathItem := range doc.Paths { + for _, path := range doc.Paths.InMatchingOrder() { + pathItem := doc.Paths.Value(path) for _, opName := range operationNames { op := getOperationByName(pathItem, opName) if op != nil { @@ -129,7 +130,7 @@ func (sv *SpecVersions) resolveOperations() error { // Operations currently active for this versions's stability get // carried forward and remain active. for opKey, opValue := range currentActiveOps { - currentPathItem := doc.Paths[opKey.path] + currentPathItem := doc.Paths.Value(opKey.path) // skip promoting sunset operations into current document lc, ok := opValue.operation.Extensions[ExtSnykApiLifecycle].(string) @@ -145,7 +146,7 @@ func (sv *SpecVersions) resolveOperations() error { Servers: opValue.pathItem.Servers, Parameters: opValue.pathItem.Parameters, } - doc.Paths[opKey.path] = currentPathItem + doc.Paths.Set(opKey.path, currentPathItem) } currentOp := getOperationByName(currentPathItem, opKey.operation) if currentOp == nil { diff --git a/spec_test.go b/spec_test.go index ce0c3844..3816e96d 100644 --- a/spec_test.go +++ b/spec_test.go @@ -6,8 +6,8 @@ import ( qt "github.com/frankban/quicktest" "github.com/getkin/kin-openapi/openapi3" - . "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/testdata" + . "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/testdata" ) func TestSpecs(t *testing.T) { @@ -135,7 +135,7 @@ func TestSpecs(t *testing.T) { c.Assert(err, qt.IsNil) c.Assert(version, qt.Equals, t.match) for _, expected := range t.hasVersions { - pathItem := spec.Paths[expected.path] + pathItem := spec.Paths.Value(expected.path) if !expected.shouldExist { c.Assert(pathItem, qt.IsNil) diff --git a/testdata/.vervet/resource/version/index.ts.tmpl b/testdata/.vervet/resource/version/index.ts.tmpl index 78ed4977..01063cf4 100644 --- a/testdata/.vervet/resource/version/index.ts.tmpl +++ b/testdata/.vervet/resource/version/index.ts.tmpl @@ -1,4 +1,4 @@ -{{ range $path, $pathItem := .ResourceVersion.Document.Paths -}} +{{ range $path, $pathItem := .ResourceVersion.Document.Paths.Map -}} {{ range $method, $operation := $pathItem|pathOperations -}} export {{ "{" }} {{ $operation.OperationID }} {{ "}" }} from './{{ $operation.OperationID }}'; {{ end }} diff --git a/testdata/generators.yaml b/testdata/generators.yaml index 105385f6..4a66281a 100644 --- a/testdata/generators.yaml +++ b/testdata/generators.yaml @@ -6,7 +6,7 @@ version-controller: scope: version files: |- {{- $path := .Path -}} - {{- range $_, $pathItem := .ResourceVersion.Document.Paths -}} + {{- range $_, $pathItem := .ResourceVersion.Document.Paths.Map -}} {{- range $method, $operation := $pathItem|pathOperations -}} {{- $operationId := $operation.OperationID -}} {{- $ctx := map "Context" . "OperationId" $operationId }} diff --git a/util_test.go b/util_test.go index 827875b4..678cb669 100644 --- a/util_test.go +++ b/util_test.go @@ -6,8 +6,8 @@ import ( qt "github.com/frankban/quicktest" "github.com/ghodss/yaml" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/testdata" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/testdata" ) func TestToSpecYAML(t *testing.T) { diff --git a/version_test.go b/version_test.go index c9cb9fba..4a91b0f6 100644 --- a/version_test.go +++ b/version_test.go @@ -7,7 +7,7 @@ import ( qt "github.com/frankban/quicktest" - . "github.com/snyk/vervet/v7" + . "github.com/snyk/vervet/v8" ) func TestParseVersion(t *testing.T) { diff --git a/versionware/handler.go b/versionware/handler.go index f19c5a62..10d2799c 100644 --- a/versionware/handler.go +++ b/versionware/handler.go @@ -6,7 +6,7 @@ import ( "fmt" "net/http" - "github.com/snyk/vervet/v7" + "github.com/snyk/vervet/v8" ) const ( diff --git a/versionware/handler_test.go b/versionware/handler_test.go index b5c65c91..b6a44eea 100644 --- a/versionware/handler_test.go +++ b/versionware/handler_test.go @@ -9,8 +9,8 @@ import ( qt "github.com/frankban/quicktest" - "github.com/snyk/vervet/v7" - "github.com/snyk/vervet/v7/versionware" + "github.com/snyk/vervet/v8" + "github.com/snyk/vervet/v8/versionware" ) func ExampleHandler() { diff --git a/versionware/validator.go b/versionware/validator.go index fb4f6b6d..fe5da860 100644 --- a/versionware/validator.go +++ b/versionware/validator.go @@ -1,6 +1,7 @@ package versionware import ( + "context" "errors" "fmt" "net/http" @@ -11,7 +12,7 @@ import ( "github.com/getkin/kin-openapi/openapi3filter" "github.com/getkin/kin-openapi/routers/gorillamux" - "github.com/snyk/vervet/v7" + "github.com/snyk/vervet/v8" ) // Validator provides versioned OpenAPI validation middleware for HTTP requests @@ -43,16 +44,17 @@ type ValidatorConfig struct { var defaultValidatorConfig = ValidatorConfig{ VersionError: DefaultVersionError, Options: []openapi3filter.ValidatorOption{ - openapi3filter.OnErr(func(w http.ResponseWriter, status int, code openapi3filter.ErrCode, _ error) { - statusText := http.StatusText(http.StatusInternalServerError) - switch code { - case openapi3filter.ErrCodeCannotFindRoute: - statusText = "Not Found" - case openapi3filter.ErrCodeRequestInvalid: - statusText = "Bad Request" - } - http.Error(w, statusText, status) - }), + openapi3filter.OnErr( + func(ctx context.Context, w http.ResponseWriter, status int, code openapi3filter.ErrCode, _ error) { + statusText := http.StatusText(http.StatusInternalServerError) + switch code { + case openapi3filter.ErrCodeCannotFindRoute: + statusText = "Not Found" + case openapi3filter.ErrCodeRequestInvalid: + statusText = "Bad Request" + } + http.Error(w, statusText, status) + }), }, } diff --git a/versionware/validator_test.go b/versionware/validator_test.go index 4d8ce4b3..753dd76b 100644 --- a/versionware/validator_test.go +++ b/versionware/validator_test.go @@ -15,7 +15,7 @@ import ( "github.com/getkin/kin-openapi/openapi3" "github.com/getkin/kin-openapi/openapi3filter" - "github.com/snyk/vervet/v7/versionware" + "github.com/snyk/vervet/v8/versionware" ) const (