mirror of https://github.com/databricks/cli.git
Return early in bundle destroy if no deployment exists (#1581)
## Changes This PR: 1. Moves the if mutator to the bundle package, to live with all-time greats such as `bundle.Seq` and `bundle.Defer`. Also adds unit tests. 2. `bundle destroy` now returns early if `root_path` does not exist. We do this by leveraging a `bundle.If` condition. ## Tests Unit tests and manually. Here's an example of what it'll look like once the bundle is destroyed. ``` ➜ bundle-playground git:(master) ✗ cli bundle destroy No active deployment found to destroy! ``` I would have added some e2e coverage for this as well, but the `cobraTestRunner.Run()` method does not seem to return stdout/stderr logs correctly. We can probably punt looking into it.
This commit is contained in:
parent
8b468b423f
commit
5bc5c3c26a
|
@ -1,36 +0,0 @@
|
||||||
package mutator
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/databricks/cli/bundle"
|
|
||||||
"github.com/databricks/cli/libs/diag"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ifMutator struct {
|
|
||||||
condition func(*bundle.Bundle) bool
|
|
||||||
onTrueMutator bundle.Mutator
|
|
||||||
onFalseMutator bundle.Mutator
|
|
||||||
}
|
|
||||||
|
|
||||||
func If(
|
|
||||||
condition func(*bundle.Bundle) bool,
|
|
||||||
onTrueMutator bundle.Mutator,
|
|
||||||
onFalseMutator bundle.Mutator,
|
|
||||||
) bundle.Mutator {
|
|
||||||
return &ifMutator{
|
|
||||||
condition, onTrueMutator, onFalseMutator,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *ifMutator) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics {
|
|
||||||
if m.condition(b) {
|
|
||||||
return bundle.Apply(ctx, b, m.onTrueMutator)
|
|
||||||
} else {
|
|
||||||
return bundle.Apply(ctx, b, m.onFalseMutator)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *ifMutator) Name() string {
|
|
||||||
return "If"
|
|
||||||
}
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package bundle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/databricks/cli/libs/diag"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ifMutator struct {
|
||||||
|
condition func(context.Context, *Bundle) (bool, error)
|
||||||
|
onTrueMutator Mutator
|
||||||
|
onFalseMutator Mutator
|
||||||
|
}
|
||||||
|
|
||||||
|
func If(
|
||||||
|
condition func(context.Context, *Bundle) (bool, error),
|
||||||
|
onTrueMutator Mutator,
|
||||||
|
onFalseMutator Mutator,
|
||||||
|
) Mutator {
|
||||||
|
return &ifMutator{
|
||||||
|
condition, onTrueMutator, onFalseMutator,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ifMutator) Apply(ctx context.Context, b *Bundle) diag.Diagnostics {
|
||||||
|
v, err := m.condition(ctx, b)
|
||||||
|
if err != nil {
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v {
|
||||||
|
return Apply(ctx, b, m.onTrueMutator)
|
||||||
|
} else {
|
||||||
|
return Apply(ctx, b, m.onFalseMutator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ifMutator) Name() string {
|
||||||
|
return "If"
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package bundle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIfMutatorTrue(t *testing.T) {
|
||||||
|
m1 := &testMutator{}
|
||||||
|
m2 := &testMutator{}
|
||||||
|
ifMutator := If(func(context.Context, *Bundle) (bool, error) {
|
||||||
|
return true, nil
|
||||||
|
}, m1, m2)
|
||||||
|
|
||||||
|
b := &Bundle{}
|
||||||
|
diags := Apply(context.Background(), b, ifMutator)
|
||||||
|
assert.NoError(t, diags.Error())
|
||||||
|
|
||||||
|
assert.Equal(t, 1, m1.applyCalled)
|
||||||
|
assert.Equal(t, 0, m2.applyCalled)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIfMutatorFalse(t *testing.T) {
|
||||||
|
m1 := &testMutator{}
|
||||||
|
m2 := &testMutator{}
|
||||||
|
ifMutator := If(func(context.Context, *Bundle) (bool, error) {
|
||||||
|
return false, nil
|
||||||
|
}, m1, m2)
|
||||||
|
|
||||||
|
b := &Bundle{}
|
||||||
|
diags := Apply(context.Background(), b, ifMutator)
|
||||||
|
assert.NoError(t, diags.Error())
|
||||||
|
|
||||||
|
assert.Equal(t, 0, m1.applyCalled)
|
||||||
|
assert.Equal(t, 1, m2.applyCalled)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIfMutatorError(t *testing.T) {
|
||||||
|
m1 := &testMutator{}
|
||||||
|
m2 := &testMutator{}
|
||||||
|
ifMutator := If(func(context.Context, *Bundle) (bool, error) {
|
||||||
|
return true, assert.AnError
|
||||||
|
}, m1, m2)
|
||||||
|
|
||||||
|
b := &Bundle{}
|
||||||
|
diags := Apply(context.Background(), b, ifMutator)
|
||||||
|
assert.Error(t, diags.Error())
|
||||||
|
|
||||||
|
assert.Equal(t, 0, m1.applyCalled)
|
||||||
|
assert.Equal(t, 0, m2.applyCalled)
|
||||||
|
}
|
|
@ -1,15 +1,33 @@
|
||||||
package phases
|
package phases
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"github.com/databricks/cli/bundle"
|
"github.com/databricks/cli/bundle"
|
||||||
"github.com/databricks/cli/bundle/deploy/files"
|
"github.com/databricks/cli/bundle/deploy/files"
|
||||||
"github.com/databricks/cli/bundle/deploy/lock"
|
"github.com/databricks/cli/bundle/deploy/lock"
|
||||||
"github.com/databricks/cli/bundle/deploy/terraform"
|
"github.com/databricks/cli/bundle/deploy/terraform"
|
||||||
|
"github.com/databricks/cli/libs/log"
|
||||||
|
"github.com/databricks/databricks-sdk-go/apierr"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func assertRootPathExists(ctx context.Context, b *bundle.Bundle) (bool, error) {
|
||||||
|
w := b.WorkspaceClient()
|
||||||
|
_, err := w.Workspace.GetStatusByPath(ctx, b.Config.Workspace.RootPath)
|
||||||
|
|
||||||
|
var aerr *apierr.APIError
|
||||||
|
if errors.As(err, &aerr) && aerr.StatusCode == http.StatusNotFound {
|
||||||
|
log.Infof(ctx, "Root path does not exist: %s", b.Config.Workspace.RootPath)
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
|
||||||
// The destroy phase deletes artifacts and resources.
|
// The destroy phase deletes artifacts and resources.
|
||||||
func Destroy() bundle.Mutator {
|
func Destroy() bundle.Mutator {
|
||||||
|
|
||||||
destroyMutator := bundle.Seq(
|
destroyMutator := bundle.Seq(
|
||||||
lock.Acquire(),
|
lock.Acquire(),
|
||||||
bundle.Defer(
|
bundle.Defer(
|
||||||
|
@ -29,6 +47,13 @@ func Destroy() bundle.Mutator {
|
||||||
|
|
||||||
return newPhase(
|
return newPhase(
|
||||||
"destroy",
|
"destroy",
|
||||||
[]bundle.Mutator{destroyMutator},
|
[]bundle.Mutator{
|
||||||
|
// Only run deploy mutator if root path exists.
|
||||||
|
bundle.If(
|
||||||
|
assertRootPathExists,
|
||||||
|
destroyMutator,
|
||||||
|
bundle.LogString("No active deployment found to destroy!"),
|
||||||
|
),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package python
|
package python
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -63,9 +64,10 @@ dbutils.notebook.exit(s)
|
||||||
// which installs uploaded wheels using %pip and then calling corresponding
|
// which installs uploaded wheels using %pip and then calling corresponding
|
||||||
// entry point.
|
// entry point.
|
||||||
func TransformWheelTask() bundle.Mutator {
|
func TransformWheelTask() bundle.Mutator {
|
||||||
return mutator.If(
|
return bundle.If(
|
||||||
func(b *bundle.Bundle) bool {
|
func(_ context.Context, b *bundle.Bundle) (bool, error) {
|
||||||
return b.Config.Experimental != nil && b.Config.Experimental.PythonWheelWrapper
|
res := b.Config.Experimental != nil && b.Config.Experimental.PythonWheelWrapper
|
||||||
|
return res, nil
|
||||||
},
|
},
|
||||||
mutator.NewTrampoline(
|
mutator.NewTrampoline(
|
||||||
"python_wheel",
|
"python_wheel",
|
||||||
|
|
Loading…
Reference in New Issue