diff --git a/backend/local/backend_apply.go b/backend/local/backend_apply.go index b12448718836..8604d3ff93f6 100644 --- a/backend/local/backend_apply.go +++ b/backend/local/backend_apply.go @@ -76,9 +76,9 @@ func (b *Local) opApply( // Perform the plan log.Printf("[INFO] backend/local: apply calling Plan") - plan, err := tfCtx.Plan() - if err != nil { - diags = diags.Append(err) + plan, planDiags := tfCtx.Plan() + diags = diags.Append(planDiags) + if planDiags.HasErrors() { b.ReportResult(runningOp, diags) return } @@ -112,6 +112,13 @@ func (b *Local) opApply( b.CLI.Output("") } + // We'll show any accumulated warnings before we display the prompt, + // so the user can consider them when deciding how to answer. + if len(diags) > 0 { + b.ShowDiagnostics(diags) + diags = nil // reset so we won't show the same diagnostics again later + } + v, err := op.UIIn.Input(stopCtx, &terraform.InputOpts{ Id: "approve", Query: query, diff --git a/terraform/context.go b/terraform/context.go index 065cf92954a0..76be6dfc5117 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -467,6 +467,17 @@ func (c *Context) Apply() (*states.State, tfdiags.Diagnostics) { c.state.PruneResourceHusks() } + if len(c.targets) > 0 { + diags = diags.Append(tfdiags.Sourceless( + tfdiags.Warning, + "Applied changes may be incomplete", + `The plan was created with the -target option in effect, so some changes requested in the configuration may have been ignored and the output values may not be fully updated. Run the following command to verify that no other changes are pending: + terraform plan + +Note that the -target option is not suitable for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`, + )) + } + return c.state, diags } @@ -483,6 +494,16 @@ func (c *Context) Plan() (*plans.Plan, tfdiags.Diagnostics) { var diags tfdiags.Diagnostics + if len(c.targets) > 0 { + diags = diags.Append(tfdiags.Sourceless( + tfdiags.Warning, + "Resource targeting is in effect", + `You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the current configuration. + +The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`, + )) + } + varVals := make(map[string]plans.DynamicValue, len(c.variables)) for k, iv := range c.variables { // We use cty.DynamicPseudoType here so that we'll save both the diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index bd362668f3f0..39e4ef175230 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -6824,15 +6824,34 @@ func TestContext2Apply_destroyTargetWithModuleVariableAndCount(t *testing.T) { }, }) - _, err := ctx.Plan() - if err != nil { - t.Fatalf("plan err: %s", err) + _, diags := ctx.Plan() + if diags.HasErrors() { + t.Fatalf("plan err: %s", diags) + } + if len(diags) != 1 { + // Should have one warning that -target is in effect. + t.Fatalf("got %d diagnostics in plan; want 1", len(diags)) + } + if got, want := diags[0].Severity(), tfdiags.Warning; got != want { + t.Errorf("wrong diagnostic severity %#v; want %#v", got, want) + } + if got, want := diags[0].Description().Summary, "Resource targeting is in effect"; got != want { + t.Errorf("wrong diagnostic summary %#v; want %#v", got, want) } // Destroy, targeting the module explicitly - state, err = ctx.Apply() - if err != nil { - t.Fatalf("destroy apply err: %s", err) + state, diags = ctx.Apply() + if diags.HasErrors() { + t.Fatalf("destroy apply err: %s", diags) + } + if len(diags) != 1 { + t.Fatalf("got %d diagnostics; want 1", len(diags)) + } + if got, want := diags[0].Severity(), tfdiags.Warning; got != want { + t.Errorf("wrong diagnostic severity %#v; want %#v", got, want) + } + if got, want := diags[0].Description().Summary, "Applied changes may be incomplete"; got != want { + t.Errorf("wrong diagnostic summary %#v; want %#v", got, want) } } diff --git a/terraform/context_plan_test.go b/terraform/context_plan_test.go index 8d15078f0d73..edb3828608ec 100644 --- a/terraform/context_plan_test.go +++ b/terraform/context_plan_test.go @@ -4690,9 +4690,18 @@ func TestContext2Plan_outputContainsTargetedResource(t *testing.T) { }, }) - _, err := ctx.Plan() - if err != nil { - t.Fatalf("err: %s", err) + _, diags := ctx.Plan() + if diags.HasErrors() { + t.Fatalf("err: %s", diags) + } + if len(diags) != 1 { + t.Fatalf("got %d diagnostics; want 1", diags) + } + if got, want := diags[0].Severity(), tfdiags.Warning; got != want { + t.Errorf("wrong diagnostic severity %#v; want %#v", got, want) + } + if got, want := diags[0].Description().Summary, "Resource targeting is in effect"; got != want { + t.Errorf("wrong diagnostic summary %#v; want %#v", got, want) } }