From 3257f31aa70f5fd4422d0b0fecad546bd7c32f53 Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Tue, 16 Feb 2021 07:19:15 -0500 Subject: [PATCH] backend/local: Return diag for refresh empty state The warning diag added when refreshing an empty state file was never rendered, and instead a custom (and incorrect) warning was output to the UI. This commit fixes the dropped diag and removes the custom warning. --- backend/local/backend_refresh.go | 27 +++++++------------ backend/local/backend_refresh_test.go | 37 +++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/backend/local/backend_refresh.go b/backend/local/backend_refresh.go index 83ce3ef31..1562cf677 100644 --- a/backend/local/backend_refresh.go +++ b/backend/local/backend_refresh.go @@ -5,7 +5,6 @@ import ( "fmt" "log" "os" - "strings" "github.com/hashicorp/errwrap" "github.com/hashicorp/terraform/backend" @@ -66,14 +65,11 @@ func (b *Local) opRefresh( // Set our state runningOp.State = opState.State() if !runningOp.State.HasResources() { - if b.CLI != nil { - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Warning, - "Empty or non-existent state", - "There are currently no resources tracked in the state, so there is nothing to refresh.", - )) - b.CLI.Output(b.Colorize().Color(strings.TrimSpace(refreshNoState) + "\n")) - } + diags = diags.Append(tfdiags.Sourceless( + tfdiags.Warning, + "Empty or non-existent state", + "There are currently no resources tracked in the state, so there is nothing to refresh.", + )) } // Perform the refresh in a goroutine so we can be interrupted @@ -90,7 +86,7 @@ func (b *Local) opRefresh( return } - // write the resulting state to the running op + // Write the resulting state to the running op runningOp.State = newState diags = diags.Append(refreshDiags) if refreshDiags.HasErrors() { @@ -104,12 +100,7 @@ func (b *Local) opRefresh( op.ReportResult(runningOp, diags) return } + + // Show any remaining warnings before exiting + op.ReportResult(runningOp, diags) } - -const refreshNoState = ` -[reset][bold][yellow]Empty or non-existent state file.[reset][yellow] - -Refresh will do nothing. Refresh does not error or return an erroneous -exit status because many automation scripts use refresh, plan, then apply -and may not have a state file yet for the first run. -` diff --git a/backend/local/backend_refresh_test.go b/backend/local/backend_refresh_test.go index 14210f790..4556efca5 100644 --- a/backend/local/backend_refresh_test.go +++ b/backend/local/backend_refresh_test.go @@ -3,6 +3,7 @@ package local import ( "context" "fmt" + "strings" "testing" "github.com/hashicorp/terraform/addrs" @@ -214,6 +215,42 @@ func TestLocal_refresh_context_error(t *testing.T) { assertBackendStateUnlocked(t, b) } +func TestLocal_refreshEmptyState(t *testing.T) { + b, cleanup := TestLocal(t) + defer cleanup() + + p := TestLocalProvider(t, b, "test", refreshFixtureSchema()) + testStateFile(t, b.StatePath, states.NewState()) + + p.ReadResourceFn = nil + p.ReadResourceResponse = &providers.ReadResourceResponse{NewState: cty.ObjectVal(map[string]cty.Value{ + "id": cty.StringVal("yes"), + })} + + op, configCleanup := testOperationRefresh(t, "./testdata/refresh") + defer configCleanup() + + record, playback := testRecordDiagnostics(t) + op.ShowDiagnostics = record + + run, err := b.Operation(context.Background(), op) + if err != nil { + t.Fatalf("bad: %s", err) + } + <-run.Done() + + diags := playback() + if diags.HasErrors() { + t.Fatalf("expected only warning diags, got errors: %s", diags.Err()) + } + if got, want := diags.ErrWithWarnings().Error(), "Empty or non-existent state"; !strings.Contains(got, want) { + t.Errorf("wrong diags\n got: %s\nwant: %s", got, want) + } + + // the backend should be unlocked after a run + assertBackendStateUnlocked(t, b) +} + func testOperationRefresh(t *testing.T, configDir string) (*backend.Operation, func()) { t.Helper()