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 any `json:"default,omitempty"`
|
||||
|
||||
// Extension embeds our custom JSON schema extensions.
|
||||
Extension
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
if _, ok := c.values[name]; ok {
|
||||
continue
|
||||
|
|
Loading…
Reference in New Issue