From 554857b9f7275cdeae6787f99ea8f601a4268809 Mon Sep 17 00:00:00 2001 From: andreaangiolillo Date: Mon, 24 Mar 2025 16:24:16 +0000 Subject: [PATCH 1/6] 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/6] 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/6] 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) { From 54c68b7284cacb5f3658f116f49c53050d92e3b8 Mon Sep 17 00:00:00 2001 From: andreaangiolillo Date: Tue, 25 Mar 2025 13:21:09 +0000 Subject: [PATCH 4/6] CLOUDP-308422: addressing follow up comments --- tools/cli/internal/openapi/filter/sunset.go | 11 ++++++----- tools/cli/internal/openapi/filter/sunset_test.go | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/cli/internal/openapi/filter/sunset.go b/tools/cli/internal/openapi/filter/sunset.go index ae13930f3b..8a5a2aa2f6 100644 --- a/tools/cli/internal/openapi/filter/sunset.go +++ b/tools/cli/internal/openapi/filter/sunset.go @@ -15,6 +15,7 @@ package filter import ( + "maps" "strings" "github.com/getkin/kin-openapi/openapi3" @@ -55,12 +56,12 @@ func applyOnOperation(op *openapi3.Operation) { } for _, content := range response.Value.Content { - if v, ok := content.Extensions["x-sunset"]; ok { - if v != sunsetToBeDecided { - continue - } - delete(content.Extensions, "x-sunset") + if content.Extensions == nil { + continue } + maps.DeleteFunc(content.Extensions, func(key string, v any) bool { + return v == sunsetToBeDecided + }) } } } diff --git a/tools/cli/internal/openapi/filter/sunset_test.go b/tools/cli/internal/openapi/filter/sunset_test.go index 3ef1e67c23..049c7c7ec0 100644 --- a/tools/cli/internal/openapi/filter/sunset_test.go +++ b/tools/cli/internal/openapi/filter/sunset_test.go @@ -326,6 +326,7 @@ func TestSunsetFilter_Apply(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + t.Parallel() f := &SunsetFilter{ oas: tc.initSpec, } From f8cf2473ff16f0ee49856dd70db4f2a3bc1ef889 Mon Sep 17 00:00:00 2001 From: andreaangiolillo Date: Tue, 25 Mar 2025 13:22:49 +0000 Subject: [PATCH 5/6] CLOUDP-308422: addressing follow up comments --- tools/cli/internal/openapi/filter/sunset.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/cli/internal/openapi/filter/sunset.go b/tools/cli/internal/openapi/filter/sunset.go index 8a5a2aa2f6..4b0c0eb68d 100644 --- a/tools/cli/internal/openapi/filter/sunset.go +++ b/tools/cli/internal/openapi/filter/sunset.go @@ -56,9 +56,6 @@ func applyOnOperation(op *openapi3.Operation) { } for _, content := range response.Value.Content { - if content.Extensions == nil { - continue - } maps.DeleteFunc(content.Extensions, func(key string, v any) bool { return v == sunsetToBeDecided }) From fc352f59d75c55f8268796b66a309eac445e3196 Mon Sep 17 00:00:00 2001 From: andreaangiolillo Date: Tue, 25 Mar 2025 13:27:32 +0000 Subject: [PATCH 6/6] Update sunset.go --- tools/cli/internal/openapi/filter/sunset.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cli/internal/openapi/filter/sunset.go b/tools/cli/internal/openapi/filter/sunset.go index 4b0c0eb68d..2f11c8f854 100644 --- a/tools/cli/internal/openapi/filter/sunset.go +++ b/tools/cli/internal/openapi/filter/sunset.go @@ -56,7 +56,7 @@ func applyOnOperation(op *openapi3.Operation) { } for _, content := range response.Value.Content { - maps.DeleteFunc(content.Extensions, func(key string, v any) bool { + maps.DeleteFunc(content.Extensions, func(_ string, v any) bool { return v == sunsetToBeDecided }) }