diff --git a/bundle/deploy/terraform/plan_deploy.go b/bundle/deploy/terraform/plan_deploy.go index 87217eaa..c28e47ae 100644 --- a/bundle/deploy/terraform/plan_deploy.go +++ b/bundle/deploy/terraform/plan_deploy.go @@ -65,7 +65,8 @@ func (p *planDeploy) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnosti if !approved { // We error here to terminate the control flow and prevent the current // process from modifying any deployment state. - return diag.Errorf("deployment terminated. No changes were made.") + cmdio.LogString(ctx, "No changes are being made...") + return diag.FromErr(bundle.ErrorBreakSequence) } return nil diff --git a/bundle/deploy/terraform/plan_destroy.go b/bundle/deploy/terraform/plan_destroy.go index f7b5bd72..f82da250 100644 --- a/bundle/deploy/terraform/plan_destroy.go +++ b/bundle/deploy/terraform/plan_destroy.go @@ -47,6 +47,8 @@ func (p *planDestroy) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnost for _, a := range deleteActions { cmdio.Log(ctx, a) } + // Log new line for better presentation. + cmdio.LogString(ctx, "") } // TODO: write e2e integration tests / unit tests to check this property. @@ -57,8 +59,11 @@ func (p *planDestroy) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnost } // If the root path exists, show warning. - if _, err := f.Stat(ctx, ""); err == nil { + _, err = f.Stat(ctx, "") + if err == nil { cmdio.LogString(ctx, fmt.Sprintf("All files and directories at %s will be deleted.", b.Config.Workspace.RootPath)) + // Log new line for better presentation. + cmdio.LogString(ctx, "") } // If the `--auto-approve` flag is set, we don't need to ask for approval. @@ -73,7 +78,8 @@ func (p *planDestroy) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnost // TODO: Remove the previous flag for deployment in the bundle tree? if !approved { - return diag.Errorf("destroy terminated. No changes were made.") + cmdio.LogString(ctx, "No changes are being made...") + return diag.FromErr(bundle.ErrorBreakSequence) } return nil diff --git a/bundle/seq.go b/bundle/seq.go index c1260a3f..bc9a3a06 100644 --- a/bundle/seq.go +++ b/bundle/seq.go @@ -2,6 +2,7 @@ package bundle import ( "context" + "errors" "github.com/databricks/cli/libs/diag" ) @@ -14,11 +15,23 @@ func (s *seqMutator) Name() string { return "seq" } +// Control signal error that can be used to break out of a sequence of mutators. +var ErrorBreakSequence = errors.New("break sequence") + func (s *seqMutator) Apply(ctx context.Context, b *Bundle) diag.Diagnostics { var diags diag.Diagnostics for _, m := range s.mutators { - diags = diags.Extend(Apply(ctx, b, m)) + nd := Apply(ctx, b, m) + + // Break out of the sequence. Filter the ErrorBreakSequence error so that + // it does not show up to the user. + if nd.ContainsError(ErrorBreakSequence) { + diags.Extend(nd.FilterError(ErrorBreakSequence)) + break + } + if diags.HasError() { + diags.Extend(nd) break } } diff --git a/libs/diag/diagnostic.go b/libs/diag/diagnostic.go index 62152755..3f5cb959 100644 --- a/libs/diag/diagnostic.go +++ b/libs/diag/diagnostic.go @@ -112,3 +112,25 @@ func (ds Diagnostics) Filter(severity Severity) Diagnostics { } return out } + +// TODO: Add tests for breaking ErrorSequence. +// TODO: Add tests for the new methods introduced. +func (ds Diagnostics) ContainsError(err error) bool { + for _, d := range ds { + if d.Severity == Error && d.Summary == err.Error() { + return true + } + } + return false +} + +// Filter returns a new list of diagnostics that do not contain the specified error +func (ds Diagnostics) FilterError(err error) Diagnostics { + var out Diagnostics + for _, d := range ds { + if d.Severity != Error || d.Summary != err.Error() { + out = append(out, d) + } + } + return out +}