mirror of https://github.com/databricks/cli.git
Add support for ordering of input prompts (#662)
## Changes JSON schema properties are a map and thus unordered. This PR introduces a JSON schema extension field called `order` to allow template authors to define the order in which template variables should be resolved/prompted. ## Tests Unit tests. --------- Co-authored-by: Pieter Noordhuis <pieter.noordhuis@databricks.com>
This commit is contained in:
parent
2f2386ef5a
commit
bbbeabf98c
|
@ -0,0 +1,14 @@
|
||||||
|
package jsonschema
|
||||||
|
|
||||||
|
// Extension defines our custom JSON schema extensions.
|
||||||
|
//
|
||||||
|
// JSON schema supports custom extensions through vocabularies:
|
||||||
|
// https://json-schema.org/understanding-json-schema/reference/schema.html#vocabularies.
|
||||||
|
// We don't (yet?) define a meta-schema for the extensions below.
|
||||||
|
// It's not a big issue because the reach/scope of these extensions is limited.
|
||||||
|
type Extension struct {
|
||||||
|
// Order defines the order of a field with respect to other fields.
|
||||||
|
// If not defined, the field is ordered alphabetically after all fields
|
||||||
|
// that do have an order defined.
|
||||||
|
Order *int `json:"order,omitempty"`
|
||||||
|
}
|
|
@ -40,6 +40,9 @@ type Schema struct {
|
||||||
|
|
||||||
// Default value for the property / object
|
// Default value for the property / object
|
||||||
Default any `json:"default,omitempty"`
|
Default any `json:"default,omitempty"`
|
||||||
|
|
||||||
|
// Extension embeds our custom JSON schema extensions.
|
||||||
|
Extension
|
||||||
}
|
}
|
||||||
|
|
||||||
type Type string
|
type Type string
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
package jsonschema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Property defines a single property of a struct schema.
|
||||||
|
// This type is not used in the schema itself but rather to
|
||||||
|
// return the pair of a property name and its schema.
|
||||||
|
type Property struct {
|
||||||
|
Name string
|
||||||
|
Schema *Schema
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrderedProperties returns the properties of the schema ordered according
|
||||||
|
// to the value of their `order` extension. If this extension is not set, the
|
||||||
|
// properties are ordered alphabetically.
|
||||||
|
func (s *Schema) OrderedProperties() []Property {
|
||||||
|
order := make(map[string]*int)
|
||||||
|
out := make([]Property, 0, len(s.Properties))
|
||||||
|
for key, property := range s.Properties {
|
||||||
|
order[key] = property.Order
|
||||||
|
out = append(out, Property{
|
||||||
|
Name: key,
|
||||||
|
Schema: property,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort the properties by order and then by name.
|
||||||
|
slices.SortFunc(out, func(a, b Property) int {
|
||||||
|
oa := order[a.Name]
|
||||||
|
ob := order[b.Name]
|
||||||
|
cmp := 0
|
||||||
|
switch {
|
||||||
|
case oa != nil && ob != nil:
|
||||||
|
// Compare the order values if both are set.
|
||||||
|
cmp = *oa - *ob
|
||||||
|
case oa == nil && ob != nil:
|
||||||
|
// If only one is set, the one that is set comes first.
|
||||||
|
cmp = 1
|
||||||
|
case oa != nil && ob == nil:
|
||||||
|
// If only one is set, the one that is set comes first.
|
||||||
|
cmp = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a non-zero comparison, return it.
|
||||||
|
if cmp != 0 {
|
||||||
|
return cmp
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the order is the same, compare by name.
|
||||||
|
return strings.Compare(a.Name, b.Name)
|
||||||
|
})
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package jsonschema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestOrderedProperties(t *testing.T) {
|
||||||
|
newInt := func(i int) *int {
|
||||||
|
return &i
|
||||||
|
}
|
||||||
|
|
||||||
|
s := Schema{
|
||||||
|
Properties: map[string]*Schema{
|
||||||
|
"bbb": {
|
||||||
|
Type: StringType,
|
||||||
|
},
|
||||||
|
"ccc": {
|
||||||
|
Type: StringType,
|
||||||
|
},
|
||||||
|
"ddd": {
|
||||||
|
Type: StringType,
|
||||||
|
},
|
||||||
|
"zzz1": {
|
||||||
|
Type: StringType,
|
||||||
|
Extension: Extension{
|
||||||
|
Order: newInt(-1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"zzz2": {
|
||||||
|
Type: StringType,
|
||||||
|
Extension: Extension{
|
||||||
|
Order: newInt(-2),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"aaa1": {
|
||||||
|
Type: StringType,
|
||||||
|
Extension: Extension{
|
||||||
|
Order: newInt(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"aaa2": {
|
||||||
|
Type: StringType,
|
||||||
|
Extension: Extension{
|
||||||
|
Order: newInt(2),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that the properties are ordered by order and then by name.
|
||||||
|
properties := s.OrderedProperties()
|
||||||
|
names := make([]string, len(properties))
|
||||||
|
for i, property := range properties {
|
||||||
|
names[i] = property.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, []string{"zzz2", "zzz1", "aaa1", "aaa2", "bbb", "ccc", "ddd"}, names)
|
||||||
|
}
|
|
@ -117,7 +117,10 @@ func (c *config) assignDefaultValues() error {
|
||||||
|
|
||||||
// Prompts user for values for properties that do not have a value set yet
|
// Prompts user for values for properties that do not have a value set yet
|
||||||
func (c *config) promptForValues() error {
|
func (c *config) promptForValues() error {
|
||||||
for name, property := range c.schema.Properties {
|
for _, p := range c.schema.OrderedProperties() {
|
||||||
|
name := p.Name
|
||||||
|
property := p.Schema
|
||||||
|
|
||||||
// Config already has a value assigned
|
// Config already has a value assigned
|
||||||
if _, ok := c.values[name]; ok {
|
if _, ok := c.values[name]; ok {
|
||||||
continue
|
continue
|
||||||
|
|
Loading…
Reference in New Issue