From 554857b9f7275cdeae6787f99ea8f601a4268809 Mon Sep 17 00:00:00 2001 From: andreaangiolillo Date: Mon, 24 Mar 2025 16:24:16 +0000 Subject: [PATCH 1/3] CLOUDP-297946: removes the `x-sunset=9999-12-31` from the openapi spec --- tools/cli/internal/openapi/filter/filter.go | 1 + .../cli/internal/openapi/filter/operations.go | 1 + tools/cli/internal/openapi/filter/sunset.go | 68 ++++ .../internal/openapi/filter/sunset_test.go | 336 ++++++++++++++++++ 4 files changed, 406 insertions(+) create mode 100644 tools/cli/internal/openapi/filter/sunset.go create mode 100644 tools/cli/internal/openapi/filter/sunset_test.go diff --git a/tools/cli/internal/openapi/filter/filter.go b/tools/cli/internal/openapi/filter/filter.go index 3a18988072..923acb7e96 100644 --- a/tools/cli/internal/openapi/filter/filter.go +++ b/tools/cli/internal/openapi/filter/filter.go @@ -77,6 +77,7 @@ func DefaultFilters(oas *openapi3.T, metadata *Metadata) []Filter { &HiddenEnvsFilter{oas: oas, metadata: metadata}, &TagsFilter{oas: oas}, &OperationsFilter{oas: oas}, + &SunsetFilter{oas: oas}, } } diff --git a/tools/cli/internal/openapi/filter/operations.go b/tools/cli/internal/openapi/filter/operations.go index 65b3760ba5..5d90152b0c 100644 --- a/tools/cli/internal/openapi/filter/operations.go +++ b/tools/cli/internal/openapi/filter/operations.go @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + package filter import ( diff --git a/tools/cli/internal/openapi/filter/sunset.go b/tools/cli/internal/openapi/filter/sunset.go new file mode 100644 index 0000000000..870a31a171 --- /dev/null +++ b/tools/cli/internal/openapi/filter/sunset.go @@ -0,0 +1,68 @@ +// Copyright 2025 MongoDB Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package filter + +import ( + "github.com/getkin/kin-openapi/openapi3" + "strings" +) + +const sunsetToBeDecided = "9999-12-31" + +// SunsetFilter removes the sunsetToBeDecided from the openapi specification +type SunsetFilter struct { + oas *openapi3.T +} + +func (f *SunsetFilter) ValidateMetadata() error { + return nil +} + +func (f *SunsetFilter) Apply() error { + if f.oas.Paths == nil { + return nil + } + + for _, pathItem := range f.oas.Paths.Map() { + for _, operation := range pathItem.Operations() { + if operation.Responses == nil { + continue + } + + applyOnOperation(operation) + } + } + return nil +} + +func applyOnOperation(op *openapi3.Operation) { + //newResponses := make(map[string]*openapi3.ResponseRef, 1) + for key, response := range op.Responses.Map() { + if !strings.HasPrefix(key, "20") { + continue + } + + for _, content := range response.Value.Content { + if v, ok := content.Extensions["x-sunset"]; ok { + if v != sunsetToBeDecided { + continue + } + + delete(content.Extensions, "x-sunset") + //newResponses[key] = response + } + } + } +} diff --git a/tools/cli/internal/openapi/filter/sunset_test.go b/tools/cli/internal/openapi/filter/sunset_test.go new file mode 100644 index 0000000000..7a7341a8e0 --- /dev/null +++ b/tools/cli/internal/openapi/filter/sunset_test.go @@ -0,0 +1,336 @@ +// Copyright 2025 MongoDB Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package filter + +import ( + "github.com/getkin/kin-openapi/openapi3" + "github.com/stretchr/testify/require" + "testing" +) + +func TestSunsetFilter_Apply(t *testing.T) { + testCases := []struct { + name string + initSpec *openapi3.T + wantedSpec *openapi3.T + }{ + { + name: "Remove x-sunset when value is 9999-12-31", + initSpec: &openapi3.T{ + Paths: openapi3.NewPaths(openapi3.WithPath("test", &openapi3.PathItem{ + Get: &openapi3.Operation{ + OperationID: "testOperationID", + Summary: "testSummary", + Responses: openapi3.NewResponses(openapi3.WithName("200", &openapi3.Response{ + Content: openapi3.Content{ + "application/vnd.atlas.2025-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2025-01-01", + }, + }, + "application/vnd.atlas.2024-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2024-01-01", + "x-sunset": "2024-12-31", + }, + }, + "application/vnd.atlas.2023-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2023-01-01", + "x-sunset": "9999-12-31", + }, + }, + }, + })), + }, + })), + }, + wantedSpec: &openapi3.T{ + Paths: openapi3.NewPaths(openapi3.WithPath("test", &openapi3.PathItem{ + Get: &openapi3.Operation{ + OperationID: "testOperationID", + Summary: "testSummary", + Responses: openapi3.NewResponses(openapi3.WithName("200", &openapi3.Response{ + Content: openapi3.Content{ + "application/vnd.atlas.2025-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2025-01-01", + }, + }, + "application/vnd.atlas.2024-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2024-01-01", + "x-sunset": "2024-12-31", + }, + }, + "application/vnd.atlas.2023-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2023-01-01", + }, + }, + }, + })), + }, + })), + }, + }, + { + name: "Remove x-sunset when value is 9999-12-31 for a 204", + initSpec: &openapi3.T{ + Paths: openapi3.NewPaths(openapi3.WithPath("test", &openapi3.PathItem{ + Get: &openapi3.Operation{ + OperationID: "testOperationID", + Summary: "testSummary", + Responses: openapi3.NewResponses(openapi3.WithName("204", &openapi3.Response{ + Content: openapi3.Content{ + "application/vnd.atlas.2025-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2025-01-01", + }, + }, + "application/vnd.atlas.2024-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2024-01-01", + "x-sunset": "2024-12-31", + }, + }, + "application/vnd.atlas.2023-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2023-01-01", + "x-sunset": "9999-12-31", + }, + }, + }, + })), + }, + })), + }, + wantedSpec: &openapi3.T{ + Paths: openapi3.NewPaths(openapi3.WithPath("test", &openapi3.PathItem{ + Get: &openapi3.Operation{ + OperationID: "testOperationID", + Summary: "testSummary", + Responses: openapi3.NewResponses(openapi3.WithName("204", &openapi3.Response{ + Content: openapi3.Content{ + "application/vnd.atlas.2025-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2025-01-01", + }, + }, + "application/vnd.atlas.2024-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2024-01-01", + "x-sunset": "2024-12-31", + }, + }, + "application/vnd.atlas.2023-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2023-01-01", + }, + }, + }, + })), + }, + })), + }, + }, + { + name: "Keep x-sunset when value is different", + initSpec: &openapi3.T{ + Paths: openapi3.NewPaths(openapi3.WithPath("test", &openapi3.PathItem{ + Get: &openapi3.Operation{ + OperationID: "testOperationID", + Summary: "testSummary", + Responses: openapi3.NewResponses(openapi3.WithName("200", &openapi3.Response{ + Content: openapi3.Content{ + "application/vnd.atlas.2025-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2025-01-01", + }, + }, + "application/vnd.atlas.2024-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2024-01-01", + "x-sunset": "2024-12-31", + }, + }, + }, + })), + }, + })), + }, + wantedSpec: &openapi3.T{ + Paths: openapi3.NewPaths(openapi3.WithPath("test", &openapi3.PathItem{ + Get: &openapi3.Operation{ + OperationID: "testOperationID", + Summary: "testSummary", + Responses: openapi3.NewResponses(openapi3.WithName("200", &openapi3.Response{ + Content: openapi3.Content{ + "application/vnd.atlas.2025-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2025-01-01", + }, + }, + "application/vnd.atlas.2024-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2024-01-01", + "x-sunset": "2024-12-31", + }, + }, + }, + })), + }, + })), + }, + }, + { + name: "Ignore non-2xx responses", + initSpec: &openapi3.T{ + Paths: openapi3.NewPaths(openapi3.WithPath("test", &openapi3.PathItem{ + Get: &openapi3.Operation{ + OperationID: "testOperationID", + Summary: "testSummary", + Responses: openapi3.NewResponses(openapi3.WithName("404", &openapi3.Response{ + Content: openapi3.Content{ + "application/vnd.atlas.2025-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2025-01-01", + }, + }, + "application/vnd.atlas.2024-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2024-01-01", + "x-sunset": "2024-12-31", + }, + }, + "application/vnd.atlas.2023-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2023-01-01", + "x-sunset": "9999-12-31", + }, + }, + }, + })), + }, + })), + }, + wantedSpec: &openapi3.T{ + Paths: openapi3.NewPaths(openapi3.WithPath("test", &openapi3.PathItem{ + Get: &openapi3.Operation{ + OperationID: "testOperationID", + Summary: "testSummary", + Responses: openapi3.NewResponses(openapi3.WithName("404", &openapi3.Response{ + Content: openapi3.Content{ + "application/vnd.atlas.2025-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2025-01-01", + }, + }, + "application/vnd.atlas.2024-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2024-01-01", + "x-sunset": "2024-12-31", + }, + }, + "application/vnd.atlas.2023-01-01+json": { + Schema: &openapi3.SchemaRef{ + Ref: "#/components/schemas/PaginatedAppUserView", + }, + Extensions: map[string]any{ + "x-gen-version": "2023-01-01", + "x-sunset": "9999-12-31", + }, + }, + }, + })), + }, + })), + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + f := &SunsetFilter{ + oas: tc.initSpec, + } + + require.NoError(t, f.Apply()) + require.EqualValues(t, f.oas, tc.wantedSpec) + }) + } +} From e4bf26cfc3711b67e92ae522f580dede0fd6f27f Mon Sep 17 00:00:00 2001 From: andreaangiolillo Date: Mon, 24 Mar 2025 16:37:37 +0000 Subject: [PATCH 2/3] lint --- tools/cli/internal/openapi/filter/sunset.go | 10 ++++------ tools/cli/internal/openapi/filter/sunset_test.go | 5 +++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/tools/cli/internal/openapi/filter/sunset.go b/tools/cli/internal/openapi/filter/sunset.go index 870a31a171..ae13930f3b 100644 --- a/tools/cli/internal/openapi/filter/sunset.go +++ b/tools/cli/internal/openapi/filter/sunset.go @@ -15,18 +15,19 @@ package filter import ( - "github.com/getkin/kin-openapi/openapi3" "strings" + + "github.com/getkin/kin-openapi/openapi3" ) const sunsetToBeDecided = "9999-12-31" -// SunsetFilter removes the sunsetToBeDecided from the openapi specification +// SunsetFilter removes the sunsetToBeDecided from the openapi specification. type SunsetFilter struct { oas *openapi3.T } -func (f *SunsetFilter) ValidateMetadata() error { +func (*SunsetFilter) ValidateMetadata() error { return nil } @@ -48,7 +49,6 @@ func (f *SunsetFilter) Apply() error { } func applyOnOperation(op *openapi3.Operation) { - //newResponses := make(map[string]*openapi3.ResponseRef, 1) for key, response := range op.Responses.Map() { if !strings.HasPrefix(key, "20") { continue @@ -59,9 +59,7 @@ func applyOnOperation(op *openapi3.Operation) { if v != sunsetToBeDecided { continue } - delete(content.Extensions, "x-sunset") - //newResponses[key] = response } } } diff --git a/tools/cli/internal/openapi/filter/sunset_test.go b/tools/cli/internal/openapi/filter/sunset_test.go index 7a7341a8e0..3ef1e67c23 100644 --- a/tools/cli/internal/openapi/filter/sunset_test.go +++ b/tools/cli/internal/openapi/filter/sunset_test.go @@ -14,9 +14,10 @@ package filter import ( + "testing" + "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/require" - "testing" ) func TestSunsetFilter_Apply(t *testing.T) { @@ -330,7 +331,7 @@ func TestSunsetFilter_Apply(t *testing.T) { } require.NoError(t, f.Apply()) - require.EqualValues(t, f.oas, tc.wantedSpec) + require.EqualValues(t, tc.wantedSpec, f.oas) }) } } From 9d1650a51b4af6a09d239a9c31950e2a0dc22442 Mon Sep 17 00:00:00 2001 From: andreaangiolillo Date: Mon, 24 Mar 2025 16:41:59 +0000 Subject: [PATCH 3/3] fix --- tools/cli/internal/openapi/filter/filter.go | 1 + tools/cli/internal/openapi/filter/filter_test.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/cli/internal/openapi/filter/filter.go b/tools/cli/internal/openapi/filter/filter.go index 923acb7e96..f6c238f3fc 100644 --- a/tools/cli/internal/openapi/filter/filter.go +++ b/tools/cli/internal/openapi/filter/filter.go @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + package filter import ( diff --git a/tools/cli/internal/openapi/filter/filter_test.go b/tools/cli/internal/openapi/filter/filter_test.go index 89b86d0029..ba437684eb 100644 --- a/tools/cli/internal/openapi/filter/filter_test.go +++ b/tools/cli/internal/openapi/filter/filter_test.go @@ -112,7 +112,7 @@ func TestDefaultFilters(t *testing.T) { metadata := &Metadata{} filters := DefaultFilters(doc, metadata) - assert.Len(t, filters, 7) + assert.Len(t, filters, 8) } func TestFiltersWithoutVersioning(t *testing.T) {