2022-12-15 14:12:47 +00:00
|
|
|
package bundle
|
|
|
|
|
|
|
|
import (
|
2024-10-24 13:24:30 +00:00
|
|
|
"context"
|
2023-03-21 15:25:18 +00:00
|
|
|
"encoding/json"
|
2025-01-07 10:49:23 +00:00
|
|
|
"errors"
|
2023-03-21 15:25:18 +00:00
|
|
|
"fmt"
|
|
|
|
|
2023-05-16 16:35:39 +00:00
|
|
|
"github.com/databricks/cli/bundle"
|
|
|
|
"github.com/databricks/cli/bundle/deploy/terraform"
|
|
|
|
"github.com/databricks/cli/bundle/phases"
|
2024-10-24 13:24:30 +00:00
|
|
|
"github.com/databricks/cli/bundle/resources"
|
2023-05-16 16:35:39 +00:00
|
|
|
"github.com/databricks/cli/bundle/run"
|
2024-10-22 14:59:17 +00:00
|
|
|
"github.com/databricks/cli/bundle/run/output"
|
2024-02-14 18:04:45 +00:00
|
|
|
"github.com/databricks/cli/cmd/bundle/utils"
|
2023-05-16 16:35:39 +00:00
|
|
|
"github.com/databricks/cli/cmd/root"
|
2023-09-11 18:03:12 +00:00
|
|
|
"github.com/databricks/cli/libs/cmdio"
|
2023-05-16 16:35:39 +00:00
|
|
|
"github.com/databricks/cli/libs/flags"
|
2022-12-15 14:12:47 +00:00
|
|
|
"github.com/spf13/cobra"
|
2024-10-24 13:24:30 +00:00
|
|
|
"golang.org/x/exp/maps"
|
2022-12-15 14:12:47 +00:00
|
|
|
)
|
|
|
|
|
2024-10-24 13:24:30 +00:00
|
|
|
func promptRunArgument(ctx context.Context, b *bundle.Bundle) (string, error) {
|
|
|
|
// Compute map of "Human readable name of resource" -> "resource key".
|
|
|
|
inv := make(map[string]string)
|
|
|
|
for k, ref := range resources.Completions(b, run.IsRunnable) {
|
|
|
|
title := fmt.Sprintf("%s: %s", ref.Description.SingularTitle, ref.Resource.GetName())
|
|
|
|
inv[title] = k
|
|
|
|
}
|
|
|
|
|
|
|
|
key, err := cmdio.Select(ctx, inv, "Resource to run")
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return key, nil
|
|
|
|
}
|
|
|
|
|
2024-11-05 09:30:11 +00:00
|
|
|
// resolveRunArgument resolves the resource key to run.
|
|
|
|
// It returns the remaining arguments to pass to the runner, if applicable.
|
|
|
|
func resolveRunArgument(ctx context.Context, b *bundle.Bundle, args []string) (string, []string, error) {
|
2024-10-24 13:24:30 +00:00
|
|
|
// If no arguments are specified, prompt the user to select something to run.
|
|
|
|
if len(args) == 0 && cmdio.IsPromptSupported(ctx) {
|
2024-11-05 09:30:11 +00:00
|
|
|
key, err := promptRunArgument(ctx, b)
|
|
|
|
if err != nil {
|
|
|
|
return "", nil, err
|
|
|
|
}
|
|
|
|
return key, args, nil
|
2024-10-24 13:24:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(args) < 1 {
|
2025-01-07 10:49:23 +00:00
|
|
|
return "", nil, errors.New("expected a KEY of the resource to run")
|
2024-10-24 13:24:30 +00:00
|
|
|
}
|
|
|
|
|
2024-11-05 09:30:11 +00:00
|
|
|
return args[0], args[1:], nil
|
2024-10-24 13:24:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func keyToRunner(b *bundle.Bundle, arg string) (run.Runner, error) {
|
|
|
|
// Locate the resource to run.
|
|
|
|
ref, err := resources.Lookup(b, arg, run.IsRunnable)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert the resource to a runnable resource.
|
|
|
|
runner, err := run.ToRunner(b, ref)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return runner, nil
|
|
|
|
}
|
|
|
|
|
2023-07-27 10:03:08 +00:00
|
|
|
func newRunCommand() *cobra.Command {
|
|
|
|
cmd := &cobra.Command{
|
2024-03-28 10:32:34 +00:00
|
|
|
Use: "run [flags] KEY",
|
2024-04-22 11:50:13 +00:00
|
|
|
Short: "Run a job or pipeline update",
|
|
|
|
Long: `Run the job or pipeline identified by KEY.
|
|
|
|
|
|
|
|
The KEY is the unique identifier of the resource to run. In addition to
|
|
|
|
customizing the run using any of the available flags, you can also specify
|
|
|
|
keyword or positional arguments as shown in these examples:
|
|
|
|
|
|
|
|
databricks bundle run my_job -- --key1 value1 --key2 value2
|
|
|
|
|
|
|
|
Or:
|
|
|
|
|
|
|
|
databricks bundle run my_job -- value1 value2 value3
|
|
|
|
|
|
|
|
If the specified job uses job parameters or the job has a notebook task with
|
|
|
|
parameters, the first example applies and flag names are mapped to the
|
|
|
|
parameter names.
|
|
|
|
|
|
|
|
If the specified job does not use job parameters and the job has a Python file
|
|
|
|
task or a Python wheel task, the second example applies.
|
|
|
|
`,
|
2023-07-27 10:03:08 +00:00
|
|
|
}
|
2022-12-15 14:12:47 +00:00
|
|
|
|
2023-07-27 10:03:08 +00:00
|
|
|
var runOptions run.Options
|
2024-02-06 14:51:02 +00:00
|
|
|
runOptions.Define(cmd)
|
2023-07-27 10:03:08 +00:00
|
|
|
|
|
|
|
var noWait bool
|
2024-02-09 14:33:14 +00:00
|
|
|
var restart bool
|
2023-07-27 10:03:08 +00:00
|
|
|
cmd.Flags().BoolVar(&noWait, "no-wait", false, "Don't wait for the run to complete.")
|
2024-02-09 14:33:14 +00:00
|
|
|
cmd.Flags().BoolVar(&restart, "restart", false, "Restart the run if it is already running.")
|
2023-07-27 10:03:08 +00:00
|
|
|
|
|
|
|
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
2023-09-11 18:03:12 +00:00
|
|
|
ctx := cmd.Context()
|
2024-03-28 10:32:34 +00:00
|
|
|
b, diags := utils.ConfigureBundleWithVariables(cmd)
|
|
|
|
if err := diags.Error(); err != nil {
|
|
|
|
return diags.Error()
|
|
|
|
}
|
2023-07-12 06:51:54 +00:00
|
|
|
|
Remove bundle.{Seq,If,Defer,newPhase,logString}, switch to regular functions (#2390)
## Changes
- Instead of constructing chains of mutators and then executing them,
execute them directly.
- Remove functionality related to chain-building: Seq, If, Defer,
newPhase, logString.
- Phases become functions that apply the changes directly rather than
construct mutator chains that will be called later.
- Add a helper ApplySeq to call multiple mutators, use it where
Apply+Seq were used before.
This is intended to be a refactoring without functional changes, but
there are a few behaviour changes:
- Since defer() is used to call unlock instead of bundle.Defer()
unlocking will now happen even in case of panics.
- In --debug, the phase names are are still logged once before start of
the phase but each entry no longer has 'seq' or phase name in it.
- The message "Deployment complete!" was printed even if
terraform.Apply() mutator had an error. It no longer does that.
## Motivation
The use of the chains was necessary when mutators were returning a list
of other mutators instead of calling them directly. But that has since
been removed, so now the chain machinery have no purpose anymore.
Use of direct functions simplifies the logic and makes bugs more
apparent and easy to fix.
Other improvements that this unlocks:
- Simpler stacktraces/debugging (breakpoints).
- Use of functions with narrowly scoped API: instead of mutators that
receive full bundle config, we can use focused functions that only deal
with sections they care about prepareGitSettings(currentGitSection) ->
updatedGitSection. This makes the data flow more apparent.
- Parallel computations across mutators (within phase): launch
goroutines fetching data from APIs at the beggining, process them once
they are ready.
## Tests
Existing tests.
2025-02-27 11:41:58 +00:00
|
|
|
diags = phases.Initialize(ctx, b)
|
2024-03-25 14:18:47 +00:00
|
|
|
if err := diags.Error(); err != nil {
|
2022-12-15 14:12:47 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-11-05 09:30:11 +00:00
|
|
|
key, args, err := resolveRunArgument(ctx, b, args)
|
2024-10-24 13:24:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2023-09-11 18:03:12 +00:00
|
|
|
}
|
|
|
|
|
Remove bundle.{Seq,If,Defer,newPhase,logString}, switch to regular functions (#2390)
## Changes
- Instead of constructing chains of mutators and then executing them,
execute them directly.
- Remove functionality related to chain-building: Seq, If, Defer,
newPhase, logString.
- Phases become functions that apply the changes directly rather than
construct mutator chains that will be called later.
- Add a helper ApplySeq to call multiple mutators, use it where
Apply+Seq were used before.
This is intended to be a refactoring without functional changes, but
there are a few behaviour changes:
- Since defer() is used to call unlock instead of bundle.Defer()
unlocking will now happen even in case of panics.
- In --debug, the phase names are are still logged once before start of
the phase but each entry no longer has 'seq' or phase name in it.
- The message "Deployment complete!" was printed even if
terraform.Apply() mutator had an error. It no longer does that.
## Motivation
The use of the chains was necessary when mutators were returning a list
of other mutators instead of calling them directly. But that has since
been removed, so now the chain machinery have no purpose anymore.
Use of direct functions simplifies the logic and makes bugs more
apparent and easy to fix.
Other improvements that this unlocks:
- Simpler stacktraces/debugging (breakpoints).
- Use of functions with narrowly scoped API: instead of mutators that
receive full bundle config, we can use focused functions that only deal
with sections they care about prepareGitSettings(currentGitSection) ->
updatedGitSection. This makes the data flow more apparent.
- Parallel computations across mutators (within phase): launch
goroutines fetching data from APIs at the beggining, process them once
they are ready.
## Tests
Existing tests.
2025-02-27 11:41:58 +00:00
|
|
|
diags = bundle.ApplySeq(ctx, b,
|
2024-09-21 06:36:47 +00:00
|
|
|
terraform.Interpolate(),
|
|
|
|
terraform.Write(),
|
|
|
|
terraform.StatePull(),
|
|
|
|
terraform.Load(terraform.ErrorOnEmptyState),
|
Remove bundle.{Seq,If,Defer,newPhase,logString}, switch to regular functions (#2390)
## Changes
- Instead of constructing chains of mutators and then executing them,
execute them directly.
- Remove functionality related to chain-building: Seq, If, Defer,
newPhase, logString.
- Phases become functions that apply the changes directly rather than
construct mutator chains that will be called later.
- Add a helper ApplySeq to call multiple mutators, use it where
Apply+Seq were used before.
This is intended to be a refactoring without functional changes, but
there are a few behaviour changes:
- Since defer() is used to call unlock instead of bundle.Defer()
unlocking will now happen even in case of panics.
- In --debug, the phase names are are still logged once before start of
the phase but each entry no longer has 'seq' or phase name in it.
- The message "Deployment complete!" was printed even if
terraform.Apply() mutator had an error. It no longer does that.
## Motivation
The use of the chains was necessary when mutators were returning a list
of other mutators instead of calling them directly. But that has since
been removed, so now the chain machinery have no purpose anymore.
Use of direct functions simplifies the logic and makes bugs more
apparent and easy to fix.
Other improvements that this unlocks:
- Simpler stacktraces/debugging (breakpoints).
- Use of functions with narrowly scoped API: instead of mutators that
receive full bundle config, we can use focused functions that only deal
with sections they care about prepareGitSettings(currentGitSection) ->
updatedGitSection. This makes the data flow more apparent.
- Parallel computations across mutators (within phase): launch
goroutines fetching data from APIs at the beggining, process them once
they are ready.
## Tests
Existing tests.
2025-02-27 11:41:58 +00:00
|
|
|
)
|
2024-09-21 06:36:47 +00:00
|
|
|
if err := diags.Error(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-11-05 09:30:11 +00:00
|
|
|
runner, err := keyToRunner(b, key)
|
2022-12-15 14:12:47 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-04-22 11:50:13 +00:00
|
|
|
// Parse additional positional arguments.
|
2024-11-05 09:30:11 +00:00
|
|
|
err = runner.ParseArgs(args, &runOptions)
|
2024-04-22 11:50:13 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-07-12 06:51:54 +00:00
|
|
|
runOptions.NoWait = noWait
|
2024-10-22 14:59:17 +00:00
|
|
|
var output output.RunOutput
|
2024-02-09 14:33:14 +00:00
|
|
|
if restart {
|
2024-10-22 14:59:17 +00:00
|
|
|
output, err = runner.Restart(ctx, &runOptions)
|
|
|
|
} else {
|
|
|
|
output, err = runner.Run(ctx, &runOptions)
|
2024-02-09 14:33:14 +00:00
|
|
|
}
|
2022-12-22 15:19:38 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2022-12-15 14:12:47 +00:00
|
|
|
}
|
2024-10-22 14:59:17 +00:00
|
|
|
|
2023-03-21 15:25:18 +00:00
|
|
|
if output != nil {
|
2023-07-26 11:17:09 +00:00
|
|
|
switch root.OutputType(cmd) {
|
2023-03-21 15:25:18 +00:00
|
|
|
case flags.OutputText:
|
|
|
|
resultString, err := output.String()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = cmd.OutOrStdout().Write([]byte(resultString))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2024-12-11 12:26:00 +00:00
|
|
|
}
|
2023-03-21 15:25:18 +00:00
|
|
|
case flags.OutputJSON:
|
|
|
|
b, err := json.MarshalIndent(output, "", " ")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = cmd.OutOrStdout().Write(b)
|
2024-03-28 10:32:34 +00:00
|
|
|
if err != nil {
|
2023-03-21 15:25:18 +00:00
|
|
|
return err
|
2024-12-11 12:26:00 +00:00
|
|
|
}
|
2025-02-10 13:00:49 +00:00
|
|
|
_, _ = cmd.OutOrStdout().Write([]byte{'\n'})
|
2023-03-21 15:25:18 +00:00
|
|
|
default:
|
2023-07-26 11:17:09 +00:00
|
|
|
return fmt.Errorf("unknown output type %s", root.OutputType(cmd))
|
2023-03-21 15:25:18 +00:00
|
|
|
}
|
|
|
|
}
|
2022-12-15 14:12:47 +00:00
|
|
|
return nil
|
2023-07-27 10:03:08 +00:00
|
|
|
}
|
2023-02-20 20:55:06 +00:00
|
|
|
|
2023-07-27 10:03:08 +00:00
|
|
|
cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
2024-03-28 10:32:34 +00:00
|
|
|
b, diags := root.MustConfigureBundle(cmd)
|
|
|
|
if err := diags.Error(); err != nil {
|
2023-02-20 20:55:06 +00:00
|
|
|
cobra.CompErrorln(err.Error())
|
|
|
|
return nil, cobra.ShellCompDirectiveError
|
|
|
|
}
|
|
|
|
|
|
|
|
// No completion in the context of a bundle.
|
|
|
|
// Source and destination paths are taken from bundle configuration.
|
|
|
|
if b == nil {
|
|
|
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
|
|
|
}
|
|
|
|
|
2024-04-22 11:50:13 +00:00
|
|
|
if len(args) == 0 {
|
2024-10-24 13:24:30 +00:00
|
|
|
completions := resources.Completions(b, run.IsRunnable)
|
|
|
|
return maps.Keys(completions), cobra.ShellCompDirectiveNoFileComp
|
2024-04-22 11:50:13 +00:00
|
|
|
} else {
|
|
|
|
// If we know the resource to run, we can complete additional positional arguments.
|
2024-10-24 13:24:30 +00:00
|
|
|
runner, err := keyToRunner(b, args[0])
|
2024-04-22 11:50:13 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, cobra.ShellCompDirectiveError
|
|
|
|
}
|
|
|
|
return runner.CompleteArgs(args[1:], toComplete)
|
|
|
|
}
|
2023-07-27 10:03:08 +00:00
|
|
|
}
|
2022-12-15 14:12:47 +00:00
|
|
|
|
2023-07-27 10:03:08 +00:00
|
|
|
return cmd
|
2022-12-15 14:12:47 +00:00
|
|
|
}
|