From 5278af1d9f2f9fa6a9968d384f6184ad7d9aebd2 Mon Sep 17 00:00:00 2001 From: Lennart Kats Date: Mon, 11 Dec 2023 10:49:11 +0100 Subject: [PATCH 1/5] Improve support for multiple builtin templates --- cmd/bundle/init.go | 36 ++++++++++++++++++++++++++++++------ cmd/bundle/init_test.go | 8 -------- libs/cmdio/io.go | 26 ++++++++++++++------------ 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/cmd/bundle/init.go b/cmd/bundle/init.go index ac6f49de38..8aa8f6cc30 100644 --- a/cmd/bundle/init.go +++ b/cmd/bundle/init.go @@ -30,14 +30,18 @@ type nativeTemplate struct { var nativeTemplates = []nativeTemplate{ { name: "default-python", - description: "The default Python template", + description: "The default Python template for Notebooks / Delta Live Tables / Workflows", }, { name: "mlops-stacks", gitUrl: "https://github.com/databricks/mlops-stacks", - description: "The Databricks MLOps Stacks template (https://github.com/databricks/mlops-stacks)", + description: "The Databricks MLOps Stacks template (github.com/databricks/mlops-stacks)", aliases: []string{"mlops-stack"}, }, + { + name: "custom...", + description: "Bring your own template", + }, } func nativeTemplateDescriptions() string { @@ -48,14 +52,27 @@ func nativeTemplateDescriptions() string { return strings.Join(lines, "\n") } -func nativeTemplateOptions() []string { - names := make([]string, 0, len(nativeTemplates)) +func nativeTemplateOptions() []cmdio.Tuple { + names := make([]cmdio.Tuple, 0, len(nativeTemplates)) for _, template := range nativeTemplates { - names = append(names, template.name) + tuple := cmdio.Tuple{ + Name: template.name, + Id: template.description, + } + names = append(names, tuple) } return names } +func getNativeTemplateByDescription(description string) string { + for _, template := range nativeTemplates { + if template.description == description { + return template.name + } + } + return "" +} + func getUrlForNativeTemplate(name string) string { for _, template := range nativeTemplates { if template.name == name { @@ -134,10 +151,17 @@ See https://docs.databricks.com/en/dev-tools/bundles/templates.html for more inf if !cmdio.IsOutTTY(ctx) || !cmdio.IsInTTY(ctx) { return errors.New("please specify a template") } - templatePath, err = cmdio.AskSelect(ctx, "Template to use", nativeTemplateOptions()) + description, err := cmdio.SelectOrdered(ctx, nativeTemplateOptions(), "Template to use") if err != nil { return err } + templatePath = getNativeTemplateByDescription(description) + } + + if templatePath == "custom..." { + cmdio.LogString(ctx, "Please specify a path or Git repository to use a custom template.") + cmdio.LogString(ctx, "See https://docs.databricks.com/en/dev-tools/bundles/templates.html to learn more about custom templates.") + return nil } // Expand templatePath to a git URL if it's an alias for a known native template diff --git a/cmd/bundle/init_test.go b/cmd/bundle/init_test.go index db4446bb1c..f49a37a8cf 100644 --- a/cmd/bundle/init_test.go +++ b/cmd/bundle/init_test.go @@ -26,14 +26,6 @@ func TestBundleInitRepoName(t *testing.T) { assert.Equal(t, "www.github.com", repoName("https://www.github.com")) } -func TestNativeTemplateOptions(t *testing.T) { - assert.Equal(t, []string{"default-python", "mlops-stacks"}, nativeTemplateOptions()) -} - -func TestNativeTemplateDescriptions(t *testing.T) { - assert.Equal(t, "- default-python: The default Python template\n- mlops-stacks: The Databricks MLOps Stacks template (https://github.com/databricks/mlops-stacks)", nativeTemplateDescriptions()) -} - func TestGetUrlForNativeTemplate(t *testing.T) { assert.Equal(t, "https://github.com/databricks/mlops-stacks", getUrlForNativeTemplate("mlops-stacks")) assert.Equal(t, "https://github.com/databricks/mlops-stacks", getUrlForNativeTemplate("mlops-stack")) diff --git a/libs/cmdio/io.go b/libs/cmdio/io.go index cf405a7a49..2fb141c261 100644 --- a/libs/cmdio/io.go +++ b/libs/cmdio/io.go @@ -130,19 +130,13 @@ func RenderReader(ctx context.Context, r io.Reader) error { } } -type tuple struct{ Name, Id string } +type Tuple struct{ Name, Id string } -func (c *cmdIO) Select(names map[string]string, label string) (id string, err error) { +func (c *cmdIO) Select(items []Tuple, label string) (id string, err error) { if !c.interactive { return "", fmt.Errorf("expected to have %s", label) } - var items []tuple - for k, v := range names { - items = append(items, tuple{k, v}) - } - slices.SortFunc(items, func(a, b tuple) int { - return strings.Compare(a.Name, b.Name) - }) + idx, _, err := (&promptui.Select{ Label: label, Items: items, @@ -167,11 +161,19 @@ func (c *cmdIO) Select(names map[string]string, label string) (id string, err er func Select[V any](ctx context.Context, names map[string]V, label string) (id string, err error) { c := fromContext(ctx) - stringNames := map[string]string{} + var items []Tuple for k, v := range names { - stringNames[k] = fmt.Sprint(v) + items = append(items, Tuple{k, fmt.Sprint(v)}) } - return c.Select(stringNames, label) + slices.SortFunc(items, func(a, b Tuple) int { + return strings.Compare(a.Name, b.Name) + }) + return c.Select(items, label) +} + +func SelectOrdered(ctx context.Context, items []Tuple, label string) (id string, err error) { + c := fromContext(ctx) + return c.Select(items, label) } func (c *cmdIO) Secret(label string) (value string, err error) { From 354c642319b38abf207fc4a8a59d9a03e0edf2de Mon Sep 17 00:00:00 2001 From: Lennart Kats Date: Wed, 20 Dec 2023 12:18:57 +0100 Subject: [PATCH 2/5] Use a const --- cmd/bundle/init.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/bundle/init.go b/cmd/bundle/init.go index 8aa8f6cc30..5602c82906 100644 --- a/cmd/bundle/init.go +++ b/cmd/bundle/init.go @@ -27,6 +27,8 @@ type nativeTemplate struct { aliases []string } +const customTemplate = "custom..." + var nativeTemplates = []nativeTemplate{ { name: "default-python", @@ -39,7 +41,7 @@ var nativeTemplates = []nativeTemplate{ aliases: []string{"mlops-stack"}, }, { - name: "custom...", + name: customTemplate, description: "Bring your own template", }, } @@ -158,7 +160,7 @@ See https://docs.databricks.com/en/dev-tools/bundles/templates.html for more inf templatePath = getNativeTemplateByDescription(description) } - if templatePath == "custom..." { + if templatePath == customTemplate { cmdio.LogString(ctx, "Please specify a path or Git repository to use a custom template.") cmdio.LogString(ctx, "See https://docs.databricks.com/en/dev-tools/bundles/templates.html to learn more about custom templates.") return nil From d58811fed59f748fcaef77886f56ea23e8ecce70 Mon Sep 17 00:00:00 2001 From: Lennart Kats Date: Sat, 23 Dec 2023 17:38:00 +0100 Subject: [PATCH 3/5] Process feedback --- cmd/bundle/init.go | 6 +++++- cmd/bundle/init_test.go | 16 ++++++++++++++++ libs/cmdio/io.go | 4 ++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/cmd/bundle/init.go b/cmd/bundle/init.go index bc4cebef1e..d1f95028dc 100644 --- a/cmd/bundle/init.go +++ b/cmd/bundle/init.go @@ -46,14 +46,18 @@ var nativeTemplates = []nativeTemplate{ }, } +// Return template descriptions for command-line help func nativeTemplateDescriptions() string { var lines []string for _, template := range nativeTemplates { - lines = append(lines, fmt.Sprintf("- %s: %s", template.name, template.description)) + if template.name != customTemplate { + lines = append(lines, fmt.Sprintf("- %s: %s", template.name, template.description)) + } } return strings.Join(lines, "\n") } +// Return template options for an interactive prompt func nativeTemplateOptions() []cmdio.Tuple { names := make([]cmdio.Tuple, 0, len(nativeTemplates)) for _, template := range nativeTemplates { diff --git a/cmd/bundle/init_test.go b/cmd/bundle/init_test.go index f49a37a8cf..01343f870e 100644 --- a/cmd/bundle/init_test.go +++ b/cmd/bundle/init_test.go @@ -3,6 +3,7 @@ package bundle import ( "testing" + "github.com/databricks/cli/libs/cmdio" "github.com/stretchr/testify/assert" ) @@ -26,6 +27,21 @@ func TestBundleInitRepoName(t *testing.T) { assert.Equal(t, "www.github.com", repoName("https://www.github.com")) } +func TestNativeTemplateOptions(t *testing.T) { + expected := []cmdio.Tuple{ + {Name: "default-python", Id: "The default Python template for Notebooks / Delta Live Tables / Workflows"}, + {Name: "mlops-stacks", Id: "The Databricks MLOps Stacks template (github.com/databricks/mlops-stacks)"}, + {Name: "custom...", Id: "Bring your own template"}, + } + assert.Equal(t, expected, nativeTemplateOptions()) +} + +func TestNativeTemplateDescriptions(t *testing.T) { + expected := `- default-python: The default Python template for Notebooks / Delta Live Tables / Workflows +- mlops-stacks: The Databricks MLOps Stacks template (github.com/databricks/mlops-stacks)` + assert.Equal(t, expected, nativeTemplateDescriptions()) +} + func TestGetUrlForNativeTemplate(t *testing.T) { assert.Equal(t, "https://github.com/databricks/mlops-stacks", getUrlForNativeTemplate("mlops-stacks")) assert.Equal(t, "https://github.com/databricks/mlops-stacks", getUrlForNativeTemplate("mlops-stack")) diff --git a/libs/cmdio/io.go b/libs/cmdio/io.go index 1e1345bdae..9d95611a4e 100644 --- a/libs/cmdio/io.go +++ b/libs/cmdio/io.go @@ -184,6 +184,8 @@ func (c *cmdIO) Select(items []Tuple, label string) (id string, err error) { return } +// Show a selection prompt where the user can pick one of the name/id items. +// The items are sorted alphabetically by name. func Select[V any](ctx context.Context, names map[string]V, label string) (id string, err error) { c := fromContext(ctx) var items []Tuple @@ -196,6 +198,8 @@ func Select[V any](ctx context.Context, names map[string]V, label string) (id st return c.Select(items, label) } +// Show a selection prompt where the user can pick one of the name/id items. +// The items can appear in a custom order and are not alphabetically sorted. func SelectOrdered(ctx context.Context, items []Tuple, label string) (id string, err error) { c := fromContext(ctx) return c.Select(items, label) From d01eaf426c0b194c8d5859b62f8ff6d59a6e0b54 Mon Sep 17 00:00:00 2001 From: Lennart Kats Date: Sat, 23 Dec 2023 17:39:50 +0100 Subject: [PATCH 4/5] Clarify name --- cmd/bundle/init.go | 4 ++-- cmd/bundle/init_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/bundle/init.go b/cmd/bundle/init.go index d1f95028dc..db8250d071 100644 --- a/cmd/bundle/init.go +++ b/cmd/bundle/init.go @@ -47,7 +47,7 @@ var nativeTemplates = []nativeTemplate{ } // Return template descriptions for command-line help -func nativeTemplateDescriptions() string { +func nativeTemplateHelpDescriptions() string { var lines []string for _, template := range nativeTemplates { if template.name != customTemplate { @@ -122,7 +122,7 @@ TEMPLATE_PATH optionally specifies which template to use. It can be one of the f - a local file system path with a template directory - a Git repository URL, e.g. https://github.com/my/repository -See https://docs.databricks.com/en/dev-tools/bundles/templates.html for more information on templates.`, nativeTemplateDescriptions()), +See https://docs.databricks.com/en/dev-tools/bundles/templates.html for more information on templates.`, nativeTemplateHelpDescriptions()), } var configFile string diff --git a/cmd/bundle/init_test.go b/cmd/bundle/init_test.go index 01343f870e..aa89915968 100644 --- a/cmd/bundle/init_test.go +++ b/cmd/bundle/init_test.go @@ -36,10 +36,10 @@ func TestNativeTemplateOptions(t *testing.T) { assert.Equal(t, expected, nativeTemplateOptions()) } -func TestNativeTemplateDescriptions(t *testing.T) { +func TestNativeTemplateHelpDescriptions(t *testing.T) { expected := `- default-python: The default Python template for Notebooks / Delta Live Tables / Workflows - mlops-stacks: The Databricks MLOps Stacks template (github.com/databricks/mlops-stacks)` - assert.Equal(t, expected, nativeTemplateDescriptions()) + assert.Equal(t, expected, nativeTemplateHelpDescriptions()) } func TestGetUrlForNativeTemplate(t *testing.T) { From 885efa6385702070ab06837d1413e1e91b8eec34 Mon Sep 17 00:00:00 2001 From: "Lennart Kats (databricks)" Date: Wed, 27 Dec 2023 12:58:35 +0100 Subject: [PATCH 5/5] Update libs/cmdio/io.go Co-authored-by: shreyas-goenka <88374338+shreyas-goenka@users.noreply.github.com> --- libs/cmdio/io.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/cmdio/io.go b/libs/cmdio/io.go index 9d95611a4e..d20991a7c2 100644 --- a/libs/cmdio/io.go +++ b/libs/cmdio/io.go @@ -199,7 +199,7 @@ func Select[V any](ctx context.Context, names map[string]V, label string) (id st } // Show a selection prompt where the user can pick one of the name/id items. -// The items can appear in a custom order and are not alphabetically sorted. +// The items appear in the order specified in the "items" argument. func SelectOrdered(ctx context.Context, items []Tuple, label string) (id string, err error) { c := fromContext(ctx) return c.Select(items, label)