Skip to content

Commit 9d003d2

Browse files
Expose stage/release status in schema (#5443)
## Changes Expose launch stage/release status in the bundle schema ## Why Non-GA fields should be annotated as such when viewing a bundle in IDEs. ## Tests Example vector search endpoint: Enum with one GA, one PuPr: <img width="444" height="208" alt="Screenshot 2026-06-12 at 09 32 00" src="https://github.com/user-attachments/assets/42fcacb3-fb9d-431a-8f2d-f8f254e610d1" /> PuPr field without any annotation: <img width="444" height="254" alt="Screenshot 2026-06-04 at 14 29 49" src="https://github.com/user-attachments/assets/4c8e1c9d-5030-4eb9-a4b8-9898c3515d33" /> --------- Co-authored-by: Pieter Noordhuis <pieter.noordhuis@databricks.com>
1 parent f6abcf9 commit 9d003d2

76 files changed

Lines changed: 3615 additions & 1048 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.vscode/settings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,11 @@
2222
"script": "shellscript",
2323
"script.prepare": "shellscript",
2424
"script.cleanup": "shellscript"
25+
},
26+
"yaml.schemas": {
27+
"./bundle/schema/jsonschema.json": [
28+
"databricks.yml",
29+
"databricks.yaml",
30+
]
2531
}
2632
}
Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package annotation
22

33
type Descriptor struct {
4-
Description string `json:"description,omitempty"`
5-
MarkdownDescription string `json:"markdown_description,omitempty"`
6-
Title string `json:"title,omitempty"`
7-
Default any `json:"default,omitempty"`
8-
Enum []any `json:"enum,omitempty"`
9-
MarkdownExamples string `json:"markdown_examples,omitempty"`
10-
DeprecationMessage string `json:"deprecation_message,omitempty"`
11-
Preview string `json:"x-databricks-preview,omitempty"`
12-
OutputOnly *bool `json:"x-databricks-field-behaviors_output_only,omitempty"`
4+
Description string `json:"description,omitempty"`
5+
MarkdownDescription string `json:"markdown_description,omitempty"`
6+
Title string `json:"title,omitempty"`
7+
Default any `json:"default,omitempty"`
8+
Enum []any `json:"enum,omitempty"`
9+
MarkdownExamples string `json:"markdown_examples,omitempty"`
10+
DeprecationMessage string `json:"deprecation_message,omitempty"`
11+
Preview string `json:"x-databricks-preview,omitempty"`
12+
LaunchStage string `json:"x-databricks-launch-stage,omitempty"`
13+
EnumLaunchStages map[string]string `json:"x-databricks-enum-launch-stages,omitempty"`
14+
EnumDescriptions map[string]string `json:"x-databricks-enum-descriptions,omitempty"`
15+
OutputOnly *bool `json:"x-databricks-field-behaviors_output_only,omitempty"`
1316
}
1417

1518
const Placeholder = "PLACEHOLDER"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package annotation
2+
3+
// PreviewTag returns the human-readable launch-stage prefix to prepend to a
4+
// field's or enum value's description. Others are skipped.
5+
func PreviewTag(launchStage string) string {
6+
switch launchStage {
7+
case "PRIVATE_PREVIEW":
8+
return "[Private Preview]"
9+
case "PUBLIC_BETA":
10+
return "[Beta]"
11+
case "PUBLIC_PREVIEW":
12+
return "[Public Preview]"
13+
}
14+
return ""
15+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package annotation_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/databricks/cli/bundle/internal/annotation"
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestPreviewTag(t *testing.T) {
11+
tests := []struct {
12+
launchStage string
13+
want string
14+
}{
15+
{"PUBLIC_PREVIEW", "[Public Preview]"},
16+
{"PUBLIC_BETA", "[Beta]"},
17+
{"PRIVATE_PREVIEW", "[Private Preview]"},
18+
{"GA", ""},
19+
{"", ""},
20+
{"SOMETHING_ELSE", ""},
21+
}
22+
for _, tc := range tests {
23+
assert.Equal(t, tc.want, annotation.PreviewTag(tc.launchStage))
24+
}
25+
}

bundle/internal/schema/annotations.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ func assignAnnotation(s *jsonschema.Schema, a annotation.Descriptor) {
134134
s.DeprecationMessage = a.DeprecationMessage
135135
}
136136

137+
// The raw launch stage is intentionally not emitted into the published
138+
// schema — nothing consumes it there. It surfaces only as the description
139+
// prefix below and the per-value enumDescriptions labels.
140+
// x-databricks-preview does stay: the parser derives it from launch_stage
141+
// (PRIVATE iff PRIVATE_PREVIEW), and pydabs reads it from jsonschema.json
142+
// to mark fields experimental, so this branch also covers hiding
143+
// private-preview fields.
137144
if a.Preview == "PRIVATE" {
138145
s.DoNotSuggest = true
139146
s.Preview = a.Preview
@@ -146,6 +153,54 @@ func assignAnnotation(s *jsonschema.Schema, a annotation.Descriptor) {
146153
s.MarkdownDescription = convertLinksToAbsoluteUrl(a.MarkdownDescription)
147154
s.Title = a.Title
148155
s.Enum = a.Enum
156+
s.EnumDescriptions = buildEnumDescriptions(a.Enum, a.EnumLaunchStages, a.EnumDescriptions)
157+
158+
// Surface launch stage in hover tooltips. Editors only render the standard
159+
// description field, so the tag is baked into the text.
160+
if tag := annotation.PreviewTag(a.LaunchStage); tag != "" {
161+
s.Description = prefixWithPreviewTag(s.Description, tag)
162+
}
163+
}
164+
165+
// buildEnumDescriptions produces the parallel enumDescriptions array VSCode
166+
// renders next to each enum value. Each entry combines the launch-stage tag
167+
// and the per-value description text. Returns nil when every entry would be
168+
// empty so the field is omitted from the schema. The enum slice is the same
169+
// one assigned to s.Enum, so the arrays stay index-aligned.
170+
func buildEnumDescriptions(enum []any, launchStages, descriptions map[string]string) []string {
171+
if len(enum) == 0 || (len(launchStages) == 0 && len(descriptions) == 0) {
172+
return nil
173+
}
174+
result := make([]string, len(enum))
175+
hasContent := false
176+
for i, v := range enum {
177+
key, ok := v.(string)
178+
if !ok {
179+
continue
180+
}
181+
result[i] = prefixWithPreviewTag(descriptions[key], annotation.PreviewTag(launchStages[key]))
182+
if result[i] != "" {
183+
hasContent = true
184+
}
185+
}
186+
if !hasContent {
187+
return nil
188+
}
189+
return result
190+
}
191+
192+
// prefixWithPreviewTag prepends the launch-stage tag to a description while
193+
// guarding against double-tagging — if the description already starts with
194+
// the tag, it is returned unchanged. An empty tag (GA) also takes the
195+
// HasPrefix path, returning the description as-is.
196+
func prefixWithPreviewTag(description, tag string) string {
197+
if description == "" {
198+
return tag
199+
}
200+
if strings.HasPrefix(description, tag) {
201+
return description
202+
}
203+
return tag + " " + description
149204
}
150205

151206
func saveYamlWithStyle(outputPath string, annotations annotation.File) error {

0 commit comments

Comments
 (0)