Skip to content

Commit 808d876

Browse files
authored
chore: decouple extension filters from versioning extension filters (#480)
1 parent 72eca91 commit 808d876

File tree

7 files changed

+324
-231
lines changed

7 files changed

+324
-231
lines changed

tools/cli/internal/openapi/filter/README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ The Atlas Admin API OpenAPI specifications are used not only to document REST en
88
- Filtering per version, so that only the endpoints that are available in that version are shown.
99
## What filters are available?
1010
### List of filters
11-
[ExtensionFilter is a filter that deletes the x-xgen-ipa-exception extensions, updates the x-sunset and x-xgen-version](../internal/openapi/filter/extension.go?plain=1#L24)
11+
[ExtensionFilter is a filter that removes the x-xgen-IPA-exception extension from the OpenAPI spec.](../internal/openapi/filter/extension.go?plain=1#L21)
1212
[HiddenEnvsFilter is a filter that removes paths, operations,](../internal/openapi/filter/hidden_envs.go?plain=1#L28)
13-
[InfoFilter is a filter that modifies the Info object in the OpenAPI spec.](../internal/openapi/filter/info.go?plain=1#L23)
1413
[OperationsFilter is a filter that removes the x-xgen-owner-team extension from operations](../internal/openapi/filter/operations.go?plain=1#L20)
15-
[TagsFilter removes tags that are not used in the operations.](../internal/openapi/filter/tags.go?plain=1#L22)
16-
[VersioningFilter is a filter that modifies the OpenAPI spec by removing operations and responses](../internal/openapi/filter/versioning.go?plain=1#L24)
14+
[VersioningExtensionFilter is a filter that updates the x-sunset and x-xgen-version extensions to a date string](../internal/openapi/filter/versioning_extension.go?plain=1#L25)
15+
[VersioningFilter is a filter that modifies the OpenAPI spec by removing operations and responses](../internal/openapi/filter/versioning.go?plain=1#L25)

tools/cli/internal/openapi/filter/extension.go

Lines changed: 1 addition & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,16 @@
1515
package filter
1616

1717
import (
18-
"log"
19-
"time"
20-
2118
"github.com/getkin/kin-openapi/openapi3"
22-
"github.com/mongodb/openapi/tools/cli/internal/apiversion"
2319
)
2420

25-
// Filter: ExtensionFilter is a filter that updates the x-sunset and x-xgen-version extensions to a date string
26-
// and deletes the x-sunset extension if the latest matched version is deprecated by hidden versions
27-
// for the target environment.
21+
// Filter: ExtensionFilter is a filter that removes the x-xgen-IPA-exception extension from the OpenAPI spec.
2822
type ExtensionFilter struct {
2923
oas *openapi3.T
3024
metadata *Metadata
3125
}
3226

3327
const (
34-
sunsetExtension = "x-sunset"
35-
xGenExtension = "x-xgen-version"
3628
ipaExceptionExtension = "x-xgen-IPA-exception"
3729
format = "2006-01-02T15:04:05Z07:00"
3830
)
@@ -42,15 +34,13 @@ func (f *ExtensionFilter) Apply() error {
4234
if pathItem == nil {
4335
continue
4436
}
45-
updateExtensionToDateString(pathItem.Extensions)
4637
deleteIpaExceptionExtension(pathItem.Extensions)
4738

4839
for _, operation := range pathItem.Operations() {
4940
if operation == nil {
5041
continue
5142
}
5243

53-
updateExtensionToDateString(operation.Extensions)
5444
deleteIpaExceptionExtension(operation.Extensions)
5545

5646
if operation.Parameters != nil {
@@ -59,37 +49,28 @@ func (f *ExtensionFilter) Apply() error {
5949

6050
updateExtensionsForRequestBody(operation.RequestBody)
6151

62-
latestVersionMatch := apiversion.FindLatestContentVersionMatched(operation, f.metadata.targetVersion)
63-
6452
for _, response := range operation.Responses.Map() {
6553
if response == nil {
6654
continue
6755
}
6856

69-
updateExtensionToDateString(response.Extensions)
7057
deleteIpaExceptionExtension(response.Extensions)
7158

7259
if response.Value == nil {
7360
continue
7461
}
7562

76-
updateExtensionToDateString(response.Value.Extensions)
7763
deleteIpaExceptionExtension(response.Value.Extensions)
7864

7965
if response.Value.Content == nil {
8066
continue
8167
}
82-
83-
f.deleteSunsetIfDeprecatedByHiddenVersions(latestVersionMatch, response.Value.Content)
84-
updateToDateString(response.Value.Content)
8568
}
8669

8770
request := operation.RequestBody
8871
if request == nil || request.Value == nil || request.Value.Content == nil {
8972
continue
9073
}
91-
updateToDateString(request.Value.Content)
92-
f.deleteSunsetIfDeprecatedByHiddenVersions(latestVersionMatch, request.Value.Content)
9374
}
9475
}
9576
if f.oas.Tags != nil {
@@ -196,76 +177,3 @@ func deleteIpaExceptionExtension(extensions map[string]any) {
196177

197178
delete(extensions, ipaExceptionExtension)
198179
}
199-
200-
func updateExtensionToDateString(extensions map[string]any) {
201-
if extensions == nil {
202-
return
203-
}
204-
205-
for k, v := range extensions {
206-
if k != sunsetExtension && k != xGenExtension {
207-
continue
208-
}
209-
date, err := time.Parse(format, v.(string))
210-
if err != nil {
211-
continue
212-
}
213-
extensions[k] = date.Format("2006-01-02")
214-
}
215-
}
216-
217-
func updateToDateString(content openapi3.Content) {
218-
for _, mediaType := range content {
219-
if mediaType.Extensions == nil {
220-
continue
221-
}
222-
223-
updateExtensionToDateString(mediaType.Extensions)
224-
}
225-
}
226-
227-
// deleteSunsetIfDeprecatedByHiddenVersions deletes the sunset extension if the latest matched version is deprecated by hidden versions.
228-
func (f *ExtensionFilter) deleteSunsetIfDeprecatedByHiddenVersions(latestMatchedVersion *apiversion.APIVersion, content openapi3.Content) {
229-
versions, versionToContentType := getVersionsInContentType(content)
230-
231-
deprecatedByHiddenVersions := make([]*apiversion.APIVersion, 0)
232-
deprecatedByVersions := make([]*apiversion.APIVersion, 0)
233-
234-
for _, v := range versions {
235-
if v.GreaterThan(latestMatchedVersion) {
236-
if value, ok := versionToContentType[v.String()]; ok {
237-
if isContentTypeHiddenForEnv(value, f.metadata.targetEnv) {
238-
deprecatedByHiddenVersions = append(deprecatedByHiddenVersions, v)
239-
continue
240-
}
241-
deprecatedByVersions = append(deprecatedByVersions, v)
242-
}
243-
}
244-
}
245-
246-
// If the exact requested version is marked for sunset for a list of hidden versions
247-
if value, ok := versionToContentType[latestMatchedVersion.String()]; ok {
248-
if len(deprecatedByHiddenVersions) > 0 && len(deprecatedByVersions) == 0 && value.Extensions != nil {
249-
delete(value.Extensions, sunsetExtension)
250-
}
251-
}
252-
}
253-
254-
func getVersionsInContentType(content map[string]*openapi3.MediaType) (
255-
versions []*apiversion.APIVersion, contentsInVersion map[string]*openapi3.MediaType) {
256-
contentsInVersion = make(map[string]*openapi3.MediaType)
257-
versionsInContentType := make(map[string]*apiversion.APIVersion)
258-
259-
for contentType, contentValue := range content {
260-
v, err := apiversion.New(apiversion.WithFullContent(contentType, contentValue))
261-
if err != nil {
262-
log.Printf("Ignoring invalid content type: %s", contentType)
263-
continue
264-
}
265-
versions = append(versions, v)
266-
versionsInContentType[v.String()] = v
267-
contentsInVersion[v.String()] = content[contentType]
268-
}
269-
270-
return versions, contentsInVersion
271-
}

tools/cli/internal/openapi/filter/extension_test.go

Lines changed: 0 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -24,59 +24,6 @@ import (
2424
"github.com/stretchr/testify/require"
2525
)
2626

27-
func TestXSunsetFilter_removeSunset(t *testing.T) {
28-
tests := []struct {
29-
name string
30-
oas *openapi3.T
31-
version string
32-
sunsetDate string
33-
}{
34-
{
35-
name: "sunset 2023-01-01",
36-
oas: getOasSunset(),
37-
version: "2023-01-01",
38-
sunsetDate: "2024-05-30",
39-
},
40-
{
41-
name: "sunset 2024-05-30",
42-
oas: getOasSunset(),
43-
version: "2024-05-30",
44-
sunsetDate: "",
45-
},
46-
}
47-
for _, tt := range tests {
48-
t.Run(tt.name, func(t *testing.T) {
49-
version, err := apiversion.New(apiversion.WithVersion(tt.version))
50-
require.NoError(t, err)
51-
oas := tt.oas
52-
53-
filter := &ExtensionFilter{
54-
oas: oas,
55-
metadata: &Metadata{targetVersion: version, targetEnv: "dev"},
56-
}
57-
58-
contentKey := fmt.Sprintf("application/vnd.atlas.%s+json", tt.version)
59-
require.NoError(t, filter.Apply())
60-
assert.NotNil(t, oas.Paths.Find("/path").Get)
61-
assert.NotEmpty(t, oas.Paths.Find("/path").Get.Responses)
62-
assert.NotNil(t, oas.Paths.Find("/path").Get.Responses.Map()["200"])
63-
64-
versionExtension := oas.Paths.Find("/path").Get.Responses.Map()["200"].Value.Content.Get(contentKey).Extensions[xGenExtension]
65-
assert.Equal(t, tt.version, versionExtension)
66-
67-
if tt.sunsetDate == "" {
68-
assert.Empty(t, oas.Paths.Find("/path").Get.Responses.Map()["200"].Value.Content.Get(contentKey).Extensions[sunsetExtension])
69-
return
70-
}
71-
72-
assert.NotNil(t, oas.Paths.Find("/path").Get.Responses.Map()["200"].Value.Content.Get(contentKey))
73-
contentExtensions := oas.Paths.Find("/path").Get.Responses.Map()["200"].Value.Content.Get(contentKey).Extensions
74-
assert.Contains(t, contentExtensions, sunsetExtension)
75-
assert.Equal(t, tt.sunsetDate, contentExtensions[sunsetExtension])
76-
})
77-
}
78-
}
79-
8027
func TestExtensionFilter_removeIpaException(t *testing.T) {
8128
oas := getOasIpaExceptions()
8229
version, err := apiversion.New(apiversion.WithVersion("2023-01-01"))
@@ -196,74 +143,6 @@ func TestExtensionFilter_removeIpaException(t *testing.T) {
196143
}
197144
}
198145

199-
func getOasSunset() *openapi3.T {
200-
oas := &openapi3.T{}
201-
oas.Paths = &openapi3.Paths{}
202-
203-
operation := &openapi3.Operation{
204-
Responses: &openapi3.Responses{},
205-
}
206-
207-
operation.Responses.Set("200", &openapi3.ResponseRef{
208-
Value: &openapi3.Response{
209-
Content: map[string]*openapi3.MediaType{
210-
"application/vnd.atlas.2023-01-01+json": {
211-
Schema: &openapi3.SchemaRef{
212-
Value: &openapi3.Schema{
213-
Description: "description",
214-
},
215-
},
216-
Extensions: map[string]any{
217-
"x-sunset": "2024-05-30T00:00:00Z",
218-
xGenExtension: "2023-01-01T00:00:00Z",
219-
},
220-
},
221-
"application/vnd.atlas.2024-02-30+json": {
222-
Schema: &openapi3.SchemaRef{
223-
Value: &openapi3.Schema{
224-
Description: "description",
225-
},
226-
},
227-
Extensions: map[string]any{
228-
"x-sunset": "2024-04-10",
229-
xGenExtension: "2024-02-30T00:00:00Z",
230-
},
231-
},
232-
"application/vnd.atlas.2025-01-01+json": {
233-
Schema: &openapi3.SchemaRef{
234-
Value: &openapi3.Schema{
235-
Description: "description",
236-
},
237-
Extensions: map[string]any{
238-
"x-sunset": "2025-01-01T00:00:00Z",
239-
xGenExtension: "2025-01-01",
240-
},
241-
},
242-
Extensions: map[string]any{
243-
hiddenEnvsExtension: map[string]any{
244-
"envs": "dev,qa,prod,stage",
245-
},
246-
},
247-
},
248-
"application/vnd.atlas.2024-05-30+json": {
249-
Schema: &openapi3.SchemaRef{
250-
Value: &openapi3.Schema{
251-
Description: "description",
252-
},
253-
},
254-
Extensions: map[string]any{
255-
"x-sunset": "2025-01-01T00:00:00Z",
256-
xGenExtension: "2024-05-30",
257-
},
258-
},
259-
},
260-
},
261-
})
262-
263-
oas.Paths.Set("/path", &openapi3.PathItem{Get: operation})
264-
return oas
265-
}
266-
267146
func getOasIpaExceptions() *openapi3.T {
268147
extension := map[string]any{
269148
ipaExceptionExtension: map[string]string{"IPA-104-resource-has-GET": "reason"},

tools/cli/internal/openapi/filter/filter.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ func validateMetadata(metadata *Metadata) error {
5050
func DefaultFilters(oas *openapi3.T, metadata *Metadata) []Filter {
5151
return []Filter{
5252
&ExtensionFilter{oas: oas, metadata: metadata},
53+
&VersioningExtensionFilter{oas: oas, metadata: metadata},
5354
&VersioningFilter{oas: oas, metadata: metadata},
5455
&InfoFilter{oas: oas, metadata: metadata},
5556
&HiddenEnvsFilter{oas: oas, metadata: metadata},

tools/cli/internal/openapi/filter/hidden_envs.go

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -165,19 +165,6 @@ func (f *HiddenEnvsFilter) isResponseHiddenForEnv(response *openapi3.ResponseRef
165165
return false
166166
}
167167

168-
func isContentTypeHiddenForEnv(contentType *openapi3.MediaType, targetEnv string) bool {
169-
if contentType == nil {
170-
return false
171-
}
172-
173-
if extension, ok := contentType.Extensions[hiddenEnvsExtension]; ok {
174-
log.Printf("Found x-hidden-envs: K: %q, V: %q", hiddenEnvsExtension, extension)
175-
return isHiddenExtensionEqualToTargetEnv(extension, targetEnv)
176-
}
177-
178-
return false
179-
}
180-
181168
func (f *HiddenEnvsFilter) isRequestBodyHiddenForEnv(requestBody *openapi3.RequestBodyRef) bool {
182169
if requestBody == nil {
183170
return false
@@ -208,3 +195,17 @@ func isHiddenExtensionEqualToTargetEnv(extension any, target string) bool {
208195
}
209196
return false
210197
}
198+
199+
// isContentTypeHiddenForEnv returns true if the content type is hidden for the target environment.
200+
func isContentTypeHiddenForEnv(contentType *openapi3.MediaType, targetEnv string) bool {
201+
if contentType == nil {
202+
return false
203+
}
204+
205+
if extension, ok := contentType.Extensions[hiddenEnvsExtension]; ok {
206+
log.Printf("Found x-hidden-envs: K: %q, V: %q", hiddenEnvsExtension, extension)
207+
return isHiddenExtensionEqualToTargetEnv(extension, targetEnv)
208+
}
209+
210+
return false
211+
}

0 commit comments

Comments
 (0)