Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions bundle/internal/schema/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,9 @@ func assignAnnotation(s *jsonschema.Schema, a annotation.Descriptor) {

s.MarkdownDescription = convertLinksToAbsoluteUrl(a.MarkdownDescription)
s.Title = a.Title
s.Enum = a.Enum
s.EnumDescriptions = buildEnumDescriptions(a.Enum, a.EnumLaunchStages, a.EnumDescriptions)
enum := deduplicateEnumValues(a.Enum)
s.Enum = enum
s.EnumDescriptions = buildEnumDescriptions(enum, a.EnumLaunchStages, a.EnumDescriptions)

// Surface launch stage in hover tooltips. Editors only render the standard
// description field, so the tag is baked into the text.
Expand All @@ -185,6 +186,30 @@ func assignAnnotation(s *jsonschema.Schema, a annotation.Descriptor) {
}
}

func deduplicateEnumValues(enum []any) []any {
if len(enum) < 2 {
return enum
}

out := make([]any, 0, len(enum))
for _, value := range enum {
found := false
for _, existing := range out {
if reflect.DeepEqual(existing, value) {
found = true
break
}
}
if !found {
out = append(out, value)
}
}
if len(out) == len(enum) {
return enum
}
return out
}

// buildEnumDescriptions produces the parallel enumDescriptions array VSCode
// renders next to each enum value. Each entry combines the launch-stage tag
// and the per-value description text. Returns nil when every entry would be
Expand Down
13 changes: 13 additions & 0 deletions bundle/internal/schema/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,19 @@ func TestAssignAnnotationLaunchStage(t *testing.T) {
assert.Equal(t, "Type of endpoint.", s.Description)
assert.Equal(t, []string{"[Public Preview]", ""}, s.EnumDescriptions)
})

t.Run("deduplicates enum values before building enum descriptions", func(t *testing.T) {
s := &jsonschema.Schema{}
assignAnnotation(s, annotation.Descriptor{
Enum: []any{"AWS_SSE_S3", "AWS_SSE_KMS", "AWS_SSE_KMS", "AWS_SSE_S3"},
EnumDescriptions: map[string]string{
"AWS_SSE_KMS": "SSE-KMS encryption.",
"AWS_SSE_S3": "SSE-S3 encryption.",
},
})
assert.Equal(t, []any{"AWS_SSE_S3", "AWS_SSE_KMS"}, s.Enum)
assert.Equal(t, []string{"SSE-S3 encryption.", "SSE-KMS encryption."}, s.EnumDescriptions)
})
}

func TestPrefixWithPreviewTagNoDoubleTag(t *testing.T) {
Expand Down
44 changes: 44 additions & 0 deletions bundle/schema/embed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package schema_test

import (
"encoding/json"
"fmt"
"testing"

"github.com/databricks/cli/bundle/schema"
Expand Down Expand Up @@ -64,3 +65,46 @@ func TestJsonSchema(t *testing.T) {
assert.Contains(t, providers.OneOf[0].Enum, "gitHubEnterprise")
assert.Contains(t, providers.OneOf[0].Enum, "bitbucketServer")
}

func TestJsonSchemaEnumsAreUnique(t *testing.T) {
var s any
err := json.Unmarshal(schema.Bytes, &s)
require.NoError(t, err)

duplicateEnums := duplicateEnumPaths(s, "")
assert.Empty(t, duplicateEnums)
}

func duplicateEnumPaths(v any, path string) []string {
var duplicates []string
switch v := v.(type) {
case map[string]any:
if enum, ok := v["enum"].([]any); ok {
seen := map[string]struct{}{}
for _, item := range enum {
keyBytes, err := json.Marshal(item)
if err != nil {
panic(err)
}
key := string(keyBytes)
if _, ok := seen[key]; ok {
duplicates = append(duplicates, path)
break
}
seen[key] = struct{}{}
}
}
for key, value := range v {
childPath := key
if path != "" {
childPath = fmt.Sprintf("%s/%s", path, key)
}
duplicates = append(duplicates, duplicateEnumPaths(value, childPath)...)
}
case []any:
for i, value := range v {
duplicates = append(duplicates, duplicateEnumPaths(value, fmt.Sprintf("%s[%d]", path, i))...)
}
}
return duplicates
}
4 changes: 1 addition & 3 deletions bundle/schema/jsonschema.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.