Skip to content

Commit 5c5be9f

Browse files
authored
CLOUDP-297221: Support private preview version customization (#412)
1 parent 6b144e8 commit 5c5be9f

File tree

4 files changed

+176
-8
lines changed

4 files changed

+176
-8
lines changed

tools/cli/internal/apiversion/version.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ type APIVersion struct {
3131
}
3232

3333
const (
34-
dateFormat = "2006-01-02"
35-
StableStabilityLevel = "stable"
36-
PreviewStabilityLevel = "preview"
34+
dateFormat = "2006-01-02"
35+
StableStabilityLevel = "stable"
36+
PreviewStabilityLevel = "preview"
37+
PrivatePreviewStabilityLevel = "private-preview"
3738
)
3839

3940
var contentPattern = regexp.MustCompile(`application/vnd\.atlas\.((\d{4})-(\d{2})-(\d{2})|preview)\+(.+)`)
@@ -150,7 +151,8 @@ func (v *APIVersion) IsPreview() bool {
150151
}
151152

152153
func IsPreviewSabilityLevel(value string) bool {
153-
return strings.EqualFold(value, PreviewStabilityLevel)
154+
// we also need string match given private preview versions like "private-preview-<name>"
155+
return strings.EqualFold(value, PreviewStabilityLevel) || strings.Contains(value, PrivatePreviewStabilityLevel)
154156
}
155157

156158
func IsStableSabilityLevel(value string) bool {

tools/cli/internal/openapi/versions.go

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
package openapi
1616

1717
import (
18+
"errors"
19+
"fmt"
1820
"sort"
21+
"strings"
1922

2023
"github.com/getkin/kin-openapi/openapi3"
2124
"github.com/mongodb/openapi/tools/cli/internal/apiversion"
@@ -53,11 +56,22 @@ func extractVersions(oas *openapi3.T) ([]string, error) {
5356
if response.Value == nil || response.Value.Content == nil {
5457
continue
5558
}
56-
for contentType := range response.Value.Content {
59+
for contentType, contentTypeValue := range response.Value.Content {
5760
version, err := apiversion.Parse(contentType)
58-
if err == nil {
59-
versions[version] = struct{}{}
61+
if err != nil {
62+
continue
6063
}
64+
65+
if apiversion.IsPreviewSabilityLevel(version) {
66+
// parse if it is public or not
67+
version, err = getPreviewVersionName(contentTypeValue)
68+
if err != nil {
69+
fmt.Printf("failed to parse preview version name: %v\n", err)
70+
continue
71+
}
72+
}
73+
74+
versions[version] = struct{}{}
6175
}
6276
}
6377
}
@@ -66,6 +80,66 @@ func extractVersions(oas *openapi3.T) ([]string, error) {
6680
return mapKeysToSortedSlice(versions), nil
6781
}
6882

83+
func getPreviewVersionName(contentTypeValue *openapi3.MediaType) (name string, err error) {
84+
public, name, err := parsePreviewExtensionData(contentTypeValue)
85+
if err != nil {
86+
return "", err
87+
}
88+
89+
if public {
90+
return "preview", nil
91+
}
92+
93+
if !public && name != "" {
94+
return "private-preview-" + name, nil
95+
}
96+
97+
return "", errors.New("no preview extension found")
98+
}
99+
100+
func parsePreviewExtensionData(contentTypeValue *openapi3.MediaType) (public bool, name string, err error) {
101+
// Expected formats:
102+
//
103+
// "x-xgen-preview": {
104+
// "name": "api-registry-private-preview"
105+
// }
106+
//
107+
// "x-xgen-preview": {
108+
// "public": "true"
109+
// }
110+
111+
name = ""
112+
public = false
113+
114+
if contentTypeValue.Extensions == nil {
115+
return false, "", errors.New("no preview extension found")
116+
}
117+
118+
previewExtension, ok := contentTypeValue.Extensions["x-xgen-preview"]
119+
if !ok {
120+
return false, "", errors.New("no preview extension found")
121+
}
122+
123+
previewExtensionMap, ok := previewExtension.(map[string]any)
124+
if !ok {
125+
return false, "", errors.New("no preview extension found")
126+
}
127+
128+
// Reading if it's public or not
129+
publicV, ok := previewExtensionMap["public"].(string)
130+
if ok {
131+
public = strings.EqualFold(publicV, "true")
132+
}
133+
134+
// Reading the name
135+
nameV, ok := previewExtensionMap["name"].(string)
136+
if ok {
137+
name = nameV
138+
}
139+
140+
return public, name, nil
141+
}
142+
69143
// mapKeysToSortedSlice converts map keys to a sorted slice.
70144
func mapKeysToSortedSlice(m map[string]struct{}) []string {
71145
keys := make([]string, 0, len(m))

tools/cli/internal/openapi/versions_test.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,18 @@ func TestVersions(t *testing.T) {
2727
assert.Equal(t, []string{"2023-01-01", "2023-02-01"}, versions)
2828
}
2929

30+
func TestVersions_PrivatePreview(t *testing.T) {
31+
versions, err := ExtractVersionsWithEnv(NewVersionedResponses(t), "dev")
32+
require.NoError(t, err)
33+
assert.ElementsMatch(t, []string{"2023-01-01", "2023-02-01", "private-preview-info-resource", "preview"}, versions)
34+
}
35+
36+
func TestVersions_PublicPreview(t *testing.T) {
37+
versions, err := ExtractVersionsWithEnv(NewVersionedResponses(t), "qa")
38+
require.NoError(t, err)
39+
assert.Equal(t, []string{"2023-01-01", "2023-02-01", "preview"}, versions)
40+
}
41+
3042
func NewVersionedResponses(t *testing.T) *openapi3.T {
3143
t.Helper()
3244
inputPath := &openapi3.Paths{}
@@ -83,6 +95,83 @@ func NewVersionedResponses(t *testing.T) *openapi3.T {
8395
},
8496
})
8597

98+
extensionThree := map[string]any{
99+
"x-xgen-version": "preview",
100+
"x-xgen-preview": map[string]any{
101+
"name": "info-resource",
102+
},
103+
}
104+
105+
responseThree := &openapi3.ResponseRef{
106+
Value: &openapi3.Response{
107+
Extensions: nil,
108+
Content: map[string]*openapi3.MediaType{
109+
"application/vnd.atlas.preview+json": {
110+
Extensions: extensionThree,
111+
},
112+
},
113+
},
114+
}
115+
116+
hiddenEnvExtension := map[string]any{
117+
"x-xgen-hidden-env": map[string]any{
118+
"envs": "qa,prod",
119+
},
120+
}
121+
122+
responsesThree := &openapi3.Responses{}
123+
responsesThree.Set("200", responseThree)
124+
125+
inputPath.Set("pathBase3", &openapi3.PathItem{
126+
Extensions: hiddenEnvExtension,
127+
Ref: "",
128+
Summary: "pathBase3",
129+
Description: "pathBase3Description",
130+
Delete: &openapi3.Operation{
131+
Tags: []string{"tag1"},
132+
Responses: responsesThree,
133+
},
134+
})
135+
136+
extensionFour := map[string]any{
137+
"x-xgen-version": "preview",
138+
"x-xgen-preview": map[string]any{
139+
"public": "true",
140+
},
141+
}
142+
143+
responseFour := &openapi3.ResponseRef{
144+
Value: &openapi3.Response{
145+
Extensions: nil,
146+
Content: map[string]*openapi3.MediaType{
147+
"application/vnd.atlas.preview+json": {
148+
Extensions: extensionFour,
149+
},
150+
},
151+
},
152+
}
153+
154+
hiddenEnvExtensionTwo := map[string]any{
155+
"x-xgen-hidden-env": map[string]any{
156+
"envs": "prod",
157+
},
158+
}
159+
160+
responsesFour := &openapi3.Responses{}
161+
responsesFour.Set("200", responseFour)
162+
163+
inputPath.Set("pathBase4", &openapi3.PathItem{
164+
Extensions: hiddenEnvExtensionTwo,
165+
Ref: "",
166+
Summary: "pathBase4",
167+
Description: "pathBase4Description",
168+
Post: &openapi3.Operation{
169+
170+
Tags: []string{"tag1"},
171+
Responses: responsesFour,
172+
},
173+
})
174+
86175
oas := &openapi3.T{
87176
Paths: inputPath,
88177
}

tools/cli/test/data/base_spec_with_preview.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4038,7 +4038,10 @@
40384038
"$ref": "#/components/schemas/PaginatedAtlasGroupView"
40394039
},
40404040
"x-xgen-version": "preview",
4041-
"x-sunset": "2025-06-30"
4041+
"x-sunset": "2025-06-30",
4042+
"x-xgen-preview": {
4043+
"name": "new-feature"
4044+
}
40424045
}
40434046
}
40444047
},

0 commit comments

Comments
 (0)