Skip to content

Commit efc176a

Browse files
pipelines: stop command (#3275)
## Changes pipelines stop, new command allows for cancelling resources Requires specifying KEY of resource to stop or autocompletes if there is only one pipeline in the project and stops that pipeline. No arguments. ## Tests Tests in follow-up: #3276 --------- Co-authored-by: Jeffery Cheng <[email protected]>
1 parent 83a2dad commit efc176a

File tree

5 files changed

+145
-15
lines changed

5 files changed

+145
-15
lines changed

acceptance/pipelines/install-pipelines-cli/output.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Available Commands:
1919
init Initialize a new pipelines project
2020
open Open a pipeline in the browser
2121
run Run a pipeline
22+
stop Stop a pipeline
2223
version Retrieve information about the current version of the Pipelines CLI
2324

2425
Flags:
@@ -62,6 +63,7 @@ Available Commands:
6263
init Initialize a new pipelines project
6364
open Open a pipeline in the browser
6465
run Run a pipeline
66+
stop Stop a pipeline
6567
version Retrieve information about the current version of the Pipelines CLI
6668

6769
Flags:

cmd/pipelines/open.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,18 @@ func promptOpenArgument(ctx context.Context, b *bundle.Bundle) (string, error) {
4444
// When no arguments are specified, auto-selects a pipeline if there's exactly one,
4545
// otherwise prompts the user to select a pipeline to open.
4646
func resolveOpenArgument(ctx context.Context, b *bundle.Bundle, args []string) (string, error) {
47-
if len(args) == 0 {
48-
if key := autoSelectSinglePipeline(b); key != "" {
49-
return key, nil
50-
}
51-
52-
if cmdio.IsPromptSupported(ctx) {
53-
return promptOpenArgument(ctx, b)
54-
}
47+
if len(args) == 1 {
48+
return args[0], nil
5549
}
5650

57-
if len(args) < 1 {
58-
return "", errors.New("expected a KEY of the pipeline to open")
51+
if key := autoSelectSinglePipeline(b); key != "" {
52+
return key, nil
5953
}
6054

61-
return args[0], nil
55+
if cmdio.IsPromptSupported(ctx) {
56+
return promptOpenArgument(ctx, b)
57+
}
58+
return "", errors.New("expected a KEY of the pipeline to open")
6259
}
6360

6461
func openCommand() *cobra.Command {

cmd/pipelines/pipelines.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ func New(ctx context.Context) *cobra.Command {
1717
cli.AddCommand(dryRunCommand())
1818
cli.AddCommand(authCommand())
1919
cli.AddCommand(destroyCommand())
20+
cli.AddCommand(stopCommand())
2021
cli.AddCommand(versionCommand())
2122
return cli
2223
}

cmd/pipelines/stop.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package pipelines
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
8+
"github.com/databricks/cli/bundle"
9+
"github.com/databricks/cli/bundle/deploy/terraform"
10+
"github.com/databricks/cli/bundle/phases"
11+
"github.com/databricks/cli/bundle/resources"
12+
"github.com/databricks/cli/bundle/run"
13+
"github.com/databricks/cli/bundle/statemgmt"
14+
"github.com/databricks/cli/cmd/bundle/utils"
15+
"github.com/databricks/cli/cmd/root"
16+
"github.com/databricks/cli/libs/cmdio"
17+
"github.com/databricks/cli/libs/logdiag"
18+
"github.com/spf13/cobra"
19+
"golang.org/x/exp/maps"
20+
)
21+
22+
// resolveStopArgument resolves the pipeline key to stop
23+
// If there is only one pipeline in the project, KEY is optional and the pipeline will be auto-selected.
24+
// Otherwise, the user will be prompted to select a pipeline.
25+
func resolveStopArgument(ctx context.Context, b *bundle.Bundle, args []string) (string, error) {
26+
if len(args) == 1 {
27+
return args[0], nil
28+
}
29+
30+
if key := autoSelectSinglePipeline(b); key != "" {
31+
return key, nil
32+
}
33+
34+
if cmdio.IsPromptSupported(ctx) {
35+
return promptRunnablePipeline(ctx, b)
36+
}
37+
38+
return "", errors.New("expected a KEY of the pipeline to stop")
39+
}
40+
41+
func stopCommand() *cobra.Command {
42+
cmd := &cobra.Command{
43+
Use: "stop [KEY]",
44+
Short: "Stop a pipeline",
45+
Long: `Stop the pipeline if it's running, identified by KEY.
46+
KEY is the unique name of the pipeline to stop, as defined in its YAML file.
47+
If there is only one pipeline in the project, KEY is optional and the pipeline will be auto-selected.`,
48+
Args: root.MaximumNArgs(1),
49+
}
50+
51+
cmd.RunE = func(cmd *cobra.Command, args []string) error {
52+
ctx := logdiag.InitContext(cmd.Context())
53+
cmd.SetContext(ctx)
54+
55+
b := utils.ConfigureBundleWithVariables(cmd)
56+
if b == nil || logdiag.HasError(ctx) {
57+
return root.ErrAlreadyPrinted
58+
}
59+
60+
phases.Initialize(ctx, b)
61+
if logdiag.HasError(ctx) {
62+
return root.ErrAlreadyPrinted
63+
}
64+
65+
key, err := resolveStopArgument(ctx, b, args)
66+
if err != nil {
67+
return err
68+
}
69+
70+
if !b.DirectDeployment {
71+
bundle.ApplySeqContext(ctx, b,
72+
terraform.Interpolate(),
73+
terraform.Write(),
74+
)
75+
if logdiag.HasError(ctx) {
76+
return root.ErrAlreadyPrinted
77+
}
78+
}
79+
80+
bundle.ApplySeqContext(ctx, b,
81+
statemgmt.StatePull(),
82+
statemgmt.Load(statemgmt.ErrorOnEmptyState),
83+
)
84+
if logdiag.HasError(ctx) {
85+
return root.ErrAlreadyPrinted
86+
}
87+
88+
runner, err := keyToRunner(b, key)
89+
if err != nil {
90+
return err
91+
}
92+
93+
cmdio.LogString(ctx, fmt.Sprintf("Stopping %s...", key))
94+
err = runner.Cancel(ctx)
95+
if err != nil {
96+
return err
97+
}
98+
99+
cmdio.LogString(ctx, key+" has been stopped.")
100+
return nil
101+
}
102+
103+
// TODO: This autocomplete functionality was copied from cmd/bundle/run.go and is not working properly.
104+
cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
105+
b := root.MustConfigureBundle(cmd)
106+
if logdiag.HasError(cmd.Context()) {
107+
return nil, cobra.ShellCompDirectiveError
108+
}
109+
110+
// No completion in the context of a bundle.
111+
// Source and destination paths are taken from bundle configuration.
112+
if b == nil {
113+
return nil, cobra.ShellCompDirectiveNoFileComp
114+
}
115+
116+
if len(args) == 0 {
117+
completions := resources.Completions(b, run.IsRunnable)
118+
return maps.Keys(completions), cobra.ShellCompDirectiveNoFileComp
119+
} else {
120+
// If we know the resource to stop, we can complete additional positional arguments.
121+
runner, err := keyToRunner(b, args[0])
122+
if err != nil {
123+
return nil, cobra.ShellCompDirectiveError
124+
}
125+
return runner.CompleteArgs(args[1:], toComplete)
126+
}
127+
}
128+
129+
return cmd
130+
}

cmd/pipelines/utils.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@ import (
1313
)
1414

1515
// Copied from cmd/bundle/run.go
16-
// promptRunArgument prompts the user to select a resource to run.
17-
func promptRunArgument(ctx context.Context, b *bundle.Bundle) (string, error) {
16+
// promptRunnablePipeline prompts the user to select a runnable pipeline.
17+
func promptRunnablePipeline(ctx context.Context, b *bundle.Bundle) (string, error) {
1818
// Compute map of "Human readable name of resource" -> "resource key".
1919
inv := make(map[string]string)
2020
for k, ref := range resources.Completions(b, run.IsRunnable) {
2121
title := fmt.Sprintf("%s: %s", ref.Description.SingularTitle, ref.Resource.GetName())
2222
inv[title] = k
2323
}
2424

25-
key, err := cmdio.Select(ctx, inv, "Pipeline to run")
25+
key, err := cmdio.Select(ctx, inv, "Select a pipeline")
2626
if err != nil {
2727
return "", err
2828
}
@@ -56,7 +56,7 @@ func resolveRunArgument(ctx context.Context, b *bundle.Bundle, args []string) (s
5656
}
5757

5858
if cmdio.IsPromptSupported(ctx) {
59-
key, err := promptRunArgument(ctx, b)
59+
key, err := promptRunnablePipeline(ctx, b)
6060
if err != nil {
6161
return "", nil, err
6262
}

0 commit comments

Comments
 (0)