mirror of https://github.com/databricks/cli.git
Use interactive prompt to select resource to run if not specified (#762)
## Changes Display an interactive prompt with a list of resources to run if one isn't specified and the command is run interactively. ## Tests Manually confirmed: * The new prompt works * Shell completion still works * Specifying a key argument still works
This commit is contained in:
parent
0cb05d1ded
commit
a2775f836f
|
@ -95,6 +95,13 @@ type jobRunner struct {
|
||||||
job *resources.Job
|
job *resources.Job
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *jobRunner) Name() string {
|
||||||
|
if r.job == nil || r.job.JobSettings == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return r.job.JobSettings.Name
|
||||||
|
}
|
||||||
|
|
||||||
func isFailed(task jobs.RunTask) bool {
|
func isFailed(task jobs.RunTask) bool {
|
||||||
return task.State.LifeCycleState == jobs.RunLifeCycleStateInternalError ||
|
return task.State.LifeCycleState == jobs.RunLifeCycleStateInternalError ||
|
||||||
(task.State.LifeCycleState == jobs.RunLifeCycleStateTerminated &&
|
(task.State.LifeCycleState == jobs.RunLifeCycleStateTerminated &&
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/databricks/cli/bundle"
|
"github.com/databricks/cli/bundle"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RunnerLookup maps identifiers to a list of workloads that match that identifier.
|
// RunnerLookup maps identifiers to a list of workloads that match that identifier.
|
||||||
|
@ -32,18 +33,20 @@ func ResourceKeys(b *bundle.Bundle) (keyOnly RunnerLookup, keyWithType RunnerLoo
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourceCompletions returns a list of keys that unambiguously reference resources in the bundle.
|
// ResourceCompletionMap returns a map of resource keys to their respective names.
|
||||||
func ResourceCompletions(b *bundle.Bundle) []string {
|
func ResourceCompletionMap(b *bundle.Bundle) map[string]string {
|
||||||
seen := make(map[string]bool)
|
out := make(map[string]string)
|
||||||
comps := []string{}
|
|
||||||
keyOnly, keyWithType := ResourceKeys(b)
|
keyOnly, keyWithType := ResourceKeys(b)
|
||||||
|
|
||||||
|
// Keep track of resources we have seen by their fully qualified key.
|
||||||
|
seen := make(map[string]bool)
|
||||||
|
|
||||||
// First add resources that can be identified by key alone.
|
// First add resources that can be identified by key alone.
|
||||||
for k, v := range keyOnly {
|
for k, v := range keyOnly {
|
||||||
// Invariant: len(v) >= 1. See [ResourceKeys].
|
// Invariant: len(v) >= 1. See [ResourceKeys].
|
||||||
if len(v) == 1 {
|
if len(v) == 1 {
|
||||||
seen[v[0].Key()] = true
|
seen[v[0].Key()] = true
|
||||||
comps = append(comps, k)
|
out[k] = v[0].Name()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,8 +57,13 @@ func ResourceCompletions(b *bundle.Bundle) []string {
|
||||||
if ok {
|
if ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
comps = append(comps, k)
|
out[k] = v[0].Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
return comps
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceCompletions returns a list of keys that unambiguously reference resources in the bundle.
|
||||||
|
func ResourceCompletions(b *bundle.Bundle) []string {
|
||||||
|
return maps.Keys(ResourceCompletionMap(b))
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,6 +136,13 @@ type pipelineRunner struct {
|
||||||
pipeline *resources.Pipeline
|
pipeline *resources.Pipeline
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *pipelineRunner) Name() string {
|
||||||
|
if r.pipeline == nil || r.pipeline.PipelineSpec == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return r.pipeline.PipelineSpec.Name
|
||||||
|
}
|
||||||
|
|
||||||
func (r *pipelineRunner) Run(ctx context.Context, opts *Options) (output.RunOutput, error) {
|
func (r *pipelineRunner) Run(ctx context.Context, opts *Options) (output.RunOutput, error) {
|
||||||
var pipelineID = r.pipeline.ID
|
var pipelineID = r.pipeline.ID
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,9 @@ type Runner interface {
|
||||||
// This is used for showing the user hints w.r.t. disambiguation.
|
// This is used for showing the user hints w.r.t. disambiguation.
|
||||||
Key() string
|
Key() string
|
||||||
|
|
||||||
|
// Name returns the resource's name, if defined.
|
||||||
|
Name() string
|
||||||
|
|
||||||
// Run the underlying worklow.
|
// Run the underlying worklow.
|
||||||
Run(ctx context.Context, opts *Options) (output.RunOutput, error)
|
Run(ctx context.Context, opts *Options) (output.RunOutput, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/databricks/cli/bundle/phases"
|
"github.com/databricks/cli/bundle/phases"
|
||||||
"github.com/databricks/cli/bundle/run"
|
"github.com/databricks/cli/bundle/run"
|
||||||
"github.com/databricks/cli/cmd/root"
|
"github.com/databricks/cli/cmd/root"
|
||||||
|
"github.com/databricks/cli/libs/cmdio"
|
||||||
"github.com/databricks/cli/libs/flags"
|
"github.com/databricks/cli/libs/flags"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
@ -16,9 +17,9 @@ import (
|
||||||
func newRunCommand() *cobra.Command {
|
func newRunCommand() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "run [flags] KEY",
|
Use: "run [flags] KEY",
|
||||||
Short: "Run a workload (e.g. a job or a pipeline)",
|
Short: "Run a resource (e.g. a job or a pipeline)",
|
||||||
|
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.MaximumNArgs(1),
|
||||||
PreRunE: ConfigureBundleWithVariables,
|
PreRunE: ConfigureBundleWithVariables,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,9 +30,10 @@ func newRunCommand() *cobra.Command {
|
||||||
cmd.Flags().BoolVar(&noWait, "no-wait", false, "Don't wait for the run to complete.")
|
cmd.Flags().BoolVar(&noWait, "no-wait", false, "Don't wait for the run to complete.")
|
||||||
|
|
||||||
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
||||||
b := bundle.Get(cmd.Context())
|
ctx := cmd.Context()
|
||||||
|
b := bundle.Get(ctx)
|
||||||
|
|
||||||
err := bundle.Apply(cmd.Context(), b, bundle.Seq(
|
err := bundle.Apply(ctx, b, bundle.Seq(
|
||||||
phases.Initialize(),
|
phases.Initialize(),
|
||||||
terraform.Interpolate(),
|
terraform.Interpolate(),
|
||||||
terraform.Write(),
|
terraform.Write(),
|
||||||
|
@ -42,13 +44,31 @@ func newRunCommand() *cobra.Command {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If no arguments are specified, prompt the user to select something to run.
|
||||||
|
if len(args) == 0 && cmdio.IsInteractive(ctx) {
|
||||||
|
// Invert completions from KEY -> NAME, to NAME -> KEY.
|
||||||
|
inv := make(map[string]string)
|
||||||
|
for k, v := range run.ResourceCompletionMap(b) {
|
||||||
|
inv[v] = k
|
||||||
|
}
|
||||||
|
id, err := cmdio.Select(ctx, inv, "Resource to run")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
args = append(args, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) != 1 {
|
||||||
|
return fmt.Errorf("expected a KEY of the resource to run")
|
||||||
|
}
|
||||||
|
|
||||||
runner, err := run.Find(b, args[0])
|
runner, err := run.Find(b, args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
runOptions.NoWait = noWait
|
runOptions.NoWait = noWait
|
||||||
output, err := runner.Run(cmd.Context(), &runOptions)
|
output, err := runner.Run(ctx, &runOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue