Run apply -refresh-state instead of refresh
When a user runs `terraform refresh` we give them an error message that tells them to run `terraform apply -refresh-state`. We could just run that command for them, though. That is what this PR does.
This commit is contained in:
parent
bf02b5cb53
commit
edbc84420c
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/hashicorp/terraform-svchost/disco"
|
||||
"github.com/hashicorp/terraform/internal/backend"
|
||||
"github.com/hashicorp/terraform/internal/configs/configschema"
|
||||
"github.com/hashicorp/terraform/internal/plans"
|
||||
"github.com/hashicorp/terraform/internal/states/remote"
|
||||
"github.com/hashicorp/terraform/internal/states/statemgr"
|
||||
"github.com/hashicorp/terraform/internal/terraform"
|
||||
|
@ -643,9 +644,16 @@ func (b *Cloud) Operation(ctx context.Context, op *backend.Operation) (*backend.
|
|||
case backend.OperationTypeApply:
|
||||
f = b.opApply
|
||||
case backend.OperationTypeRefresh:
|
||||
return nil, fmt.Errorf(
|
||||
"\n\nThe \"refresh\" operation is not supported when using Terraform Cloud. " +
|
||||
"Use \"terraform apply -refresh-only\" instead.")
|
||||
// The `terraform refresh` command has been deprecated in favor of `terraform apply -refresh-state`.
|
||||
// Rather than respond with an error telling the user to run the other command we can just run
|
||||
// that command instead. We will tell the user what we are doing, and then do it.
|
||||
if b.CLI != nil {
|
||||
b.CLI.Output(b.Colorize().Color(strings.TrimSpace(refreshToApplyRefresh) + "\n"))
|
||||
}
|
||||
op.PlanMode = plans.RefreshOnlyMode
|
||||
op.PlanRefresh = true
|
||||
op.AutoApprove = true
|
||||
f = b.opApply
|
||||
default:
|
||||
return nil, fmt.Errorf(
|
||||
"\n\nTerraform Cloud does not support the %q operation.", op.Type)
|
||||
|
@ -982,6 +990,8 @@ const operationNotCanceled = `
|
|||
[reset][red]The remote operation was not cancelled.[reset]
|
||||
`
|
||||
|
||||
const refreshToApplyRefresh = `[bold][yellow]Proceeding with 'terraform apply -refresh-only -auto-approve'.[reset]`
|
||||
|
||||
var (
|
||||
workspaceConfigurationHelp = fmt.Sprintf(
|
||||
`The 'workspaces' block configures how Terraform CLI maps its workspaces for this single
|
||||
|
|
|
@ -87,7 +87,7 @@ func (b *Cloud) opPlan(stopCtx, cancelCtx context.Context, op *backend.Operation
|
|||
func (b *Cloud) plan(stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
|
||||
if b.CLI != nil {
|
||||
header := planDefaultHeader
|
||||
if op.Type == backend.OperationTypeApply {
|
||||
if op.Type == backend.OperationTypeApply || op.Type == backend.OperationTypeRefresh {
|
||||
header = applyDefaultHeader
|
||||
}
|
||||
b.CLI.Output(b.Colorize().Color(strings.TrimSpace(header) + "\n"))
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
package cloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/backend"
|
||||
"github.com/hashicorp/terraform/internal/command/arguments"
|
||||
"github.com/hashicorp/terraform/internal/command/clistate"
|
||||
"github.com/hashicorp/terraform/internal/command/views"
|
||||
"github.com/hashicorp/terraform/internal/initwd"
|
||||
"github.com/hashicorp/terraform/internal/plans"
|
||||
"github.com/hashicorp/terraform/internal/states/statemgr"
|
||||
"github.com/hashicorp/terraform/internal/terminal"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
func testOperationRefresh(t *testing.T, configDir string) (*backend.Operation, func(), func(*testing.T) *terminal.TestOutput) {
|
||||
t.Helper()
|
||||
|
||||
return testOperationRefreshWithTimeout(t, configDir, 0)
|
||||
}
|
||||
|
||||
func testOperationRefreshWithTimeout(t *testing.T, configDir string, timeout time.Duration) (*backend.Operation, func(), func(*testing.T) *terminal.TestOutput) {
|
||||
t.Helper()
|
||||
|
||||
_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
|
||||
|
||||
streams, done := terminal.StreamsForTesting(t)
|
||||
view := views.NewView(streams)
|
||||
stateLockerView := views.NewStateLocker(arguments.ViewHuman, view)
|
||||
operationView := views.NewOperation(arguments.ViewHuman, false, view)
|
||||
|
||||
return &backend.Operation{
|
||||
ConfigDir: configDir,
|
||||
ConfigLoader: configLoader,
|
||||
PlanRefresh: true,
|
||||
StateLocker: clistate.NewLocker(timeout, stateLockerView),
|
||||
Type: backend.OperationTypeRefresh,
|
||||
View: operationView,
|
||||
}, configCleanup, done
|
||||
}
|
||||
|
||||
func TestCloud_refreshBasicActuallyRunsApplyRefresh(t *testing.T) {
|
||||
b, bCleanup := testBackendWithName(t)
|
||||
defer bCleanup()
|
||||
|
||||
op, configCleanup, done := testOperationRefresh(t, "./testdata/refresh")
|
||||
defer configCleanup()
|
||||
defer done(t)
|
||||
|
||||
op.UIOut = b.CLI
|
||||
b.CLIColor = b.cliColorize()
|
||||
op.PlanMode = plans.RefreshOnlyMode
|
||||
op.Workspace = testBackendSingleWorkspaceName
|
||||
|
||||
run, err := b.Operation(context.Background(), op)
|
||||
if err != nil {
|
||||
t.Fatalf("error starting operation: %v", err)
|
||||
}
|
||||
|
||||
<-run.Done()
|
||||
if run.Result != backend.OperationSuccess {
|
||||
t.Fatalf("operation failed: %s", b.CLI.(*cli.MockUi).ErrorWriter.String())
|
||||
}
|
||||
|
||||
output := b.CLI.(*cli.MockUi).OutputWriter.String()
|
||||
if !strings.Contains(output, "Proceeding with 'terraform apply -refresh-only -auto-approve'") {
|
||||
t.Fatalf("expected TFC header in output: %s", output)
|
||||
}
|
||||
|
||||
stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName)
|
||||
// An error suggests that the state was not unlocked after apply
|
||||
if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil {
|
||||
t.Fatalf("unexpected error locking state after apply: %s", err.Error())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
resource "random_pet" "always_new" {
|
||||
keepers = {
|
||||
uuid = uuid() # Force a new name each time
|
||||
}
|
||||
length = 3
|
||||
}
|
|
@ -17,10 +17,17 @@ type RefreshCommand struct {
|
|||
}
|
||||
|
||||
func (c *RefreshCommand) Run(rawArgs []string) int {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
// Parse and apply global view arguments
|
||||
common, rawArgs := arguments.ParseView(rawArgs)
|
||||
c.View.Configure(common)
|
||||
|
||||
// Propagate -no-color for the remote backend's legacy use of Ui. This
|
||||
// should be removed when the remote backend is migrated to views.
|
||||
c.Meta.color = !common.NoColor
|
||||
c.Meta.Color = c.Meta.color
|
||||
|
||||
// Parse and validate flags
|
||||
args, diags := arguments.ParseRefresh(rawArgs)
|
||||
|
||||
|
|
Loading…
Reference in New Issue