diff --git a/internal/cloud/backend.go b/internal/cloud/backend.go index 09a9995c7b..22adb98d17 100644 --- a/internal/cloud/backend.go +++ b/internal/cloud/backend.go @@ -64,9 +64,9 @@ type Cloud struct { // organization is the organization that contains the target workspaces. organization string - // workspaceMapping contains strategies for mapping CLI workspaces in the working directory + // WorkspaceMapping contains strategies for mapping CLI workspaces in the working directory // to remote Terraform Cloud workspaces. - workspaceMapping workspaceMapping + WorkspaceMapping WorkspaceMapping // services is used for service discovery services *disco.Disco @@ -157,28 +157,28 @@ func (b *Cloud) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) { diags = diags.Append(invalidOrganizationConfigMissingValue) } - workspaceMapping := workspaceMapping{} + WorkspaceMapping := WorkspaceMapping{} if workspaces := obj.GetAttr("workspaces"); !workspaces.IsNull() { if val := workspaces.GetAttr("name"); !val.IsNull() { - workspaceMapping.name = val.AsString() + WorkspaceMapping.Name = val.AsString() } if val := workspaces.GetAttr("prefix"); !val.IsNull() { - workspaceMapping.prefix = val.AsString() + WorkspaceMapping.Prefix = val.AsString() } if val := workspaces.GetAttr("tags"); !val.IsNull() { - err := gocty.FromCtyValue(val, &workspaceMapping.tags) + err := gocty.FromCtyValue(val, &WorkspaceMapping.Tags) if err != nil { log.Panicf("An unxpected error occurred: %s", err) } } } - switch workspaceMapping.strategy() { + switch WorkspaceMapping.Strategy() { // Make sure have a workspace mapping strategy present - case workspaceNoneStrategy: + case WorkspaceNoneStrategy: diags = diags.Append(invalidWorkspaceConfigMissingValues) // Make sure that only one of workspace name or a prefix is configured. - case workspaceInvalidStrategy: + case WorkspaceInvalidStrategy: diags = diags.Append(invalidWorkspaceConfigMisconfiguration) } @@ -335,10 +335,10 @@ func (b *Cloud) setConfigurationFields(obj cty.Value) tfdiags.Diagnostics { // PrepareConfig checks that you cannot set both of these. if val := workspaces.GetAttr("name"); !val.IsNull() { - b.workspaceMapping.name = val.AsString() + b.WorkspaceMapping.Name = val.AsString() } if val := workspaces.GetAttr("prefix"); !val.IsNull() { - b.workspaceMapping.prefix = val.AsString() + b.WorkspaceMapping.Prefix = val.AsString() } if val := workspaces.GetAttr("tags"); !val.IsNull() { var tags []string @@ -347,7 +347,7 @@ func (b *Cloud) setConfigurationFields(obj cty.Value) tfdiags.Diagnostics { log.Panicf("An unxpected error occurred: %s", err) } - b.workspaceMapping.tags = tags + b.WorkspaceMapping.Tags = tags } } @@ -530,31 +530,30 @@ func (b *Cloud) retryLogHook(attemptNum int, resp *http.Response) { } } -// Workspaces implements backend.Enhanced. +// Workspaces implements backend.Enhanced, returning a filtered list of workspace names according to +// the workspace mapping strategy configured. func (b *Cloud) Workspaces() ([]string, error) { - if b.workspaceMapping.strategy() == workspaceNameStrategy { - return nil, backend.ErrWorkspacesNotSupported + // Create a slice to contain all the names. + var names []string + + // If configured for a single workspace, return that exact name only. The StateMgr for this + // backend will automatically create the remote workspace if it does not yet exist. + if b.WorkspaceMapping.Strategy() == WorkspaceNameStrategy { + names = append(names, b.WorkspaceMapping.Name) + return names, nil } - return b.workspaces() -} -// workspaces returns a filtered list of remote workspace names according to the workspace mapping -// strategy configured. -func (b *Cloud) workspaces() ([]string, error) { + // Otherwise, multiple workspaces are being mapped. Query Terraform Cloud for all the remote + // workspaces by the provided mapping strategy. options := tfe.WorkspaceListOptions{} - switch b.workspaceMapping.strategy() { - case workspaceNameStrategy: - options.Search = tfe.String(b.workspaceMapping.name) - case workspacePrefixStrategy: - options.Search = tfe.String(b.workspaceMapping.prefix) - case workspaceTagsStrategy: - taglist := strings.Join(b.workspaceMapping.tags, ",") + switch b.WorkspaceMapping.Strategy() { + case WorkspacePrefixStrategy: + options.Search = tfe.String(b.WorkspaceMapping.Prefix) + case WorkspaceTagsStrategy: + taglist := strings.Join(b.WorkspaceMapping.Tags, ",") options.Tags = &taglist } - // Create a slice to contain all the names. - var names []string - for { wl, err := b.client.Workspaces.List(context.Background(), b.organization, options) if err != nil { @@ -562,20 +561,15 @@ func (b *Cloud) workspaces() ([]string, error) { } for _, w := range wl.Items { - switch b.workspaceMapping.strategy() { - case workspaceNameStrategy: - if w.Name == b.workspaceMapping.name { - names = append(names, backend.DefaultStateName) - continue - } - case workspacePrefixStrategy: - if strings.HasPrefix(w.Name, b.workspaceMapping.prefix) { - names = append(names, strings.TrimPrefix(w.Name, b.workspaceMapping.prefix)) + switch b.WorkspaceMapping.Strategy() { + case WorkspacePrefixStrategy: + if strings.HasPrefix(w.Name, b.WorkspaceMapping.Prefix) { + names = append(names, strings.TrimPrefix(w.Name, b.WorkspaceMapping.Prefix)) continue } default: - // Pass-through. "name" and "prefix" strategies are naive and do - // client-side filtering above, but for tags and any other future + // Pass-through. The "prefix" strategy is naive and does + // client-side filtering, but for tags and any other future // strategy this filtering should be left to the API. names = append(names, w.Name) } @@ -598,19 +592,18 @@ func (b *Cloud) workspaces() ([]string, error) { // DeleteWorkspace implements backend.Enhanced. func (b *Cloud) DeleteWorkspace(name string) error { - if b.workspaceMapping.strategy() != workspaceNameStrategy && name == backend.DefaultStateName { + if name == backend.DefaultStateName { return backend.ErrDefaultWorkspaceNotSupported } - if b.workspaceMapping.strategy() == workspaceNameStrategy && name != backend.DefaultStateName { + + if b.WorkspaceMapping.Strategy() == WorkspaceNameStrategy { return backend.ErrWorkspacesNotSupported } // Configure the remote workspace name. switch { - case name == backend.DefaultStateName: - name = b.workspaceMapping.name - case b.workspaceMapping.strategy() == workspacePrefixStrategy && !strings.HasPrefix(name, b.workspaceMapping.prefix): - name = b.workspaceMapping.prefix + name + case b.WorkspaceMapping.Strategy() == WorkspacePrefixStrategy && !strings.HasPrefix(name, b.WorkspaceMapping.Prefix): + name = b.WorkspaceMapping.Prefix + name } client := &remoteClient{ @@ -626,19 +619,17 @@ func (b *Cloud) DeleteWorkspace(name string) error { // StateMgr implements backend.Enhanced. func (b *Cloud) StateMgr(name string) (statemgr.Full, error) { - if b.workspaceMapping.strategy() != workspaceNameStrategy && name == backend.DefaultStateName { + if name == backend.DefaultStateName { return nil, backend.ErrDefaultWorkspaceNotSupported } - if b.workspaceMapping.strategy() == workspaceNameStrategy && name != backend.DefaultStateName { + + if b.WorkspaceMapping.Strategy() == WorkspaceNameStrategy && name != b.WorkspaceMapping.Name { return nil, backend.ErrWorkspacesNotSupported } - // Configure the remote workspace name. - switch { - case name == backend.DefaultStateName: - name = b.workspaceMapping.name - case b.workspaceMapping.strategy() == workspacePrefixStrategy && !strings.HasPrefix(name, b.workspaceMapping.prefix): - name = b.workspaceMapping.prefix + name + // If the prefix strategy is used, translate the local name to the TFC workspace name. + if b.WorkspaceMapping.Strategy() == WorkspacePrefixStrategy { + name = b.WorkspaceMapping.Prefix + name } workspace, err := b.client.Workspaces.Read(context.Background(), b.organization, name) @@ -652,7 +643,7 @@ func (b *Cloud) StateMgr(name string) (statemgr.Full, error) { } var tags []*tfe.Tag - for _, tag := range b.workspaceMapping.tags { + for _, tag := range b.WorkspaceMapping.Tags { t := tfe.Tag{Name: tag} tags = append(tags, &t) } @@ -698,13 +689,11 @@ func (b *Cloud) StateMgr(name string) (statemgr.Full, error) { // Operation implements backend.Enhanced. func (b *Cloud) Operation(ctx context.Context, op *backend.Operation) (*backend.RunningOperation, error) { - // Get the remote workspace name. name := op.Workspace - switch { - case op.Workspace == backend.DefaultStateName: - name = b.workspaceMapping.name - case b.workspaceMapping.strategy() == workspacePrefixStrategy && !strings.HasPrefix(op.Workspace, b.workspaceMapping.prefix): - name = b.workspaceMapping.prefix + op.Workspace + + // If the prefix strategy is used, translate the local name to the TFC workspace name. + if b.WorkspaceMapping.Strategy() == WorkspacePrefixStrategy { + name = b.WorkspaceMapping.Prefix + op.Workspace } // Retrieve the workspace for this operation. @@ -1014,35 +1003,35 @@ func (b *Cloud) cliColorize() *colorstring.Colorize { } } -type workspaceMapping struct { - name string - prefix string - tags []string +type WorkspaceMapping struct { + Name string + Prefix string + Tags []string } type workspaceStrategy string const ( - workspaceTagsStrategy workspaceStrategy = "tags" - workspaceNameStrategy workspaceStrategy = "name" - workspacePrefixStrategy workspaceStrategy = "prefix" - workspaceNoneStrategy workspaceStrategy = "none" - workspaceInvalidStrategy workspaceStrategy = "invalid" + WorkspaceTagsStrategy workspaceStrategy = "tags" + WorkspaceNameStrategy workspaceStrategy = "name" + WorkspacePrefixStrategy workspaceStrategy = "prefix" + WorkspaceNoneStrategy workspaceStrategy = "none" + WorkspaceInvalidStrategy workspaceStrategy = "invalid" ) -func (wm workspaceMapping) strategy() workspaceStrategy { +func (wm WorkspaceMapping) Strategy() workspaceStrategy { switch { - case len(wm.tags) > 0 && wm.name == "" && wm.prefix == "": - return workspaceTagsStrategy - case len(wm.tags) == 0 && wm.name != "" && wm.prefix == "": - return workspaceNameStrategy - case len(wm.tags) == 0 && wm.name == "" && wm.prefix != "": - return workspacePrefixStrategy - case len(wm.tags) == 0 && wm.name == "" && wm.prefix == "": - return workspaceNoneStrategy + case len(wm.Tags) > 0 && wm.Name == "" && wm.Prefix == "": + return WorkspaceTagsStrategy + case len(wm.Tags) == 0 && wm.Name != "" && wm.Prefix == "": + return WorkspaceNameStrategy + case len(wm.Tags) == 0 && wm.Name == "" && wm.Prefix != "": + return WorkspacePrefixStrategy + case len(wm.Tags) == 0 && wm.Name == "" && wm.Prefix == "": + return WorkspaceNoneStrategy default: // Any other combination is invalid as each strategy is mutually exclusive - return workspaceInvalidStrategy + return WorkspaceInvalidStrategy } } diff --git a/internal/cloud/backend_apply_test.go b/internal/cloud/backend_apply_test.go index 1af4b4726a..9f464c3f37 100644 --- a/internal/cloud/backend_apply_test.go +++ b/internal/cloud/backend_apply_test.go @@ -67,7 +67,7 @@ func TestCloud_applyBasic(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -97,7 +97,7 @@ func TestCloud_applyBasic(t *testing.T) { t.Fatalf("expected apply summery in output: %s", output) } - stateMgr, _ := b.StateMgr(backend.DefaultStateName) + 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()) @@ -112,7 +112,7 @@ func TestCloud_applyCanceled(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -127,7 +127,7 @@ func TestCloud_applyCanceled(t *testing.T) { t.Fatal("expected apply operation to fail") } - stateMgr, _ := b.StateMgr(backend.DefaultStateName) + stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName) if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil { t.Fatalf("unexpected error locking state after cancelling apply: %s", err.Error()) } @@ -142,7 +142,7 @@ func TestCloud_applyWithoutPermissions(t *testing.T) { context.Background(), b.organization, tfe.WorkspaceCreateOptions{ - Name: tfe.String(b.workspaceMapping.prefix + "prod"), + Name: tfe.String(b.WorkspaceMapping.Prefix + "prod"), }, ) if err != nil { @@ -182,7 +182,7 @@ func TestCloud_applyWithVCS(t *testing.T) { context.Background(), b.organization, tfe.WorkspaceCreateOptions{ - Name: tfe.String(b.workspaceMapping.prefix + "prod"), + Name: tfe.String(b.WorkspaceMapping.Prefix + "prod"), VCSRepo: &tfe.VCSRepoOptions{}, }, ) @@ -226,7 +226,7 @@ func TestCloud_applyWithParallelism(t *testing.T) { b.ContextOpts = &terraform.ContextOpts{} } b.ContextOpts.Parallelism = 3 - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -253,7 +253,7 @@ func TestCloud_applyWithPlan(t *testing.T) { defer configCleanup() op.PlanFile = &planfile.Reader{} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -284,7 +284,7 @@ func TestCloud_applyWithoutRefresh(t *testing.T) { defer done(t) op.PlanRefresh = false - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -322,7 +322,7 @@ func TestCloud_applyWithoutRefreshIncompatibleAPIVersion(t *testing.T) { b.client.SetFakeRemoteAPIVersion("2.3") op.PlanRefresh = false - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -353,7 +353,7 @@ func TestCloud_applyWithRefreshOnly(t *testing.T) { defer done(t) op.PlanMode = plans.RefreshOnlyMode - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -391,7 +391,7 @@ func TestCloud_applyWithRefreshOnlyIncompatibleAPIVersion(t *testing.T) { b.client.SetFakeRemoteAPIVersion("2.3") op.PlanMode = plans.RefreshOnlyMode - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -424,7 +424,7 @@ func TestCloud_applyWithTarget(t *testing.T) { addr, _ := addrs.ParseAbsResourceStr("null_resource.foo") op.Targets = []addrs.Targetable{addr} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -466,7 +466,7 @@ func TestCloud_applyWithTargetIncompatibleAPIVersion(t *testing.T) { addr, _ := addrs.ParseAbsResourceStr("null_resource.foo") op.Targets = []addrs.Targetable{addr} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -499,7 +499,7 @@ func TestCloud_applyWithReplace(t *testing.T) { addr, _ := addrs.ParseAbsResourceInstanceStr("null_resource.foo") op.ForceReplace = []addrs.AbsResourceInstance{addr} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -539,7 +539,7 @@ func TestCloud_applyWithReplaceIncompatibleAPIVersion(t *testing.T) { addr, _ := addrs.ParseAbsResourceInstanceStr("null_resource.foo") op.ForceReplace = []addrs.AbsResourceInstance{addr} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -569,7 +569,7 @@ func TestCloud_applyWithVariables(t *testing.T) { defer configCleanup() op.Variables = testVariables(terraform.ValueFromNamedFile, "foo", "bar") - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -595,7 +595,7 @@ func TestCloud_applyNoConfig(t *testing.T) { op, configCleanup, done := testOperationApply(t, "./testdata/empty") defer configCleanup() - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -616,7 +616,7 @@ func TestCloud_applyNoConfig(t *testing.T) { t.Fatalf("expected configuration files error, got: %v", errOutput) } - stateMgr, _ := b.StateMgr(backend.DefaultStateName) + 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 failed apply: %s", err.Error()) @@ -631,7 +631,7 @@ func TestCloud_applyNoChanges(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -668,7 +668,7 @@ func TestCloud_applyNoApprove(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -709,7 +709,7 @@ func TestCloud_applyAutoApprove(t *testing.T) { op.AutoApprove = true op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -754,7 +754,7 @@ func TestCloud_applyApprovedExternally(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName ctx := context.Background() @@ -828,7 +828,7 @@ func TestCloud_applyDiscardedExternally(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName ctx := context.Background() @@ -898,7 +898,7 @@ func TestCloud_applyWithAutoApply(t *testing.T) { b.organization, tfe.WorkspaceCreateOptions{ AutoApply: tfe.Bool(true), - Name: tfe.String(b.workspaceMapping.prefix + "prod"), + Name: tfe.String(b.WorkspaceMapping.Prefix + "prod"), }, ) if err != nil { @@ -967,7 +967,7 @@ func TestCloud_applyForceLocal(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName streams, done := terminal.StreamsForTesting(t) view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams)) @@ -1013,7 +1013,7 @@ func TestCloud_applyWorkspaceWithoutOperations(t *testing.T) { ctx, b.organization, tfe.WorkspaceCreateOptions{ - Name: tfe.String(b.workspaceMapping.prefix + "no-operations"), + Name: tfe.String(b.WorkspaceMapping.Prefix + "no-operations"), }, ) if err != nil { @@ -1072,7 +1072,7 @@ func TestCloud_applyLockTimeout(t *testing.T) { ctx := context.Background() // Retrieve the workspace used to run this operation in. - w, err := b.client.Workspaces.Read(ctx, b.organization, b.workspaceMapping.name) + w, err := b.client.Workspaces.Read(ctx, b.organization, b.WorkspaceMapping.Name) if err != nil { t.Fatalf("error retrieving workspace: %v", err) } @@ -1103,7 +1103,7 @@ func TestCloud_applyLockTimeout(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName _, err = b.Operation(context.Background(), op) if err != nil { @@ -1154,7 +1154,7 @@ func TestCloud_applyDestroy(t *testing.T) { op.PlanMode = plans.DestroyMode op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1200,7 +1200,7 @@ func TestCloud_applyDestroyNoConfig(t *testing.T) { op.PlanMode = plans.DestroyMode op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1234,7 +1234,7 @@ func TestCloud_applyPolicyPass(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1281,7 +1281,7 @@ func TestCloud_applyPolicyHardFail(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1337,7 +1337,7 @@ func TestCloud_applyPolicySoftFail(t *testing.T) { op.AutoApprove = false op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1383,7 +1383,7 @@ func TestCloud_applyPolicySoftFailAutoApproveSuccess(t *testing.T) { op.AutoApprove = true op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1432,7 +1432,7 @@ func TestCloud_applyPolicySoftFailAutoApply(t *testing.T) { b.organization, tfe.WorkspaceCreateOptions{ AutoApply: tfe.Bool(true), - Name: tfe.String(b.workspaceMapping.prefix + "prod"), + Name: tfe.String(b.WorkspaceMapping.Prefix + "prod"), }, ) if err != nil { @@ -1492,7 +1492,7 @@ func TestCloud_applyWithRemoteError(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1581,7 +1581,7 @@ func TestCloud_applyVersionCheck(t *testing.T) { _, err := b.client.Workspaces.Update( ctx, b.organization, - b.workspaceMapping.name, + b.WorkspaceMapping.Name, tfe.WorkspaceUpdateOptions{ Operations: tfe.Bool(tc.hasOperations), TerraformVersion: tfe.String(tc.remoteVersion), @@ -1606,7 +1606,7 @@ func TestCloud_applyVersionCheck(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(ctx, op) if err != nil { diff --git a/internal/cloud/backend_context.go b/internal/cloud/backend_context.go index 32a1e52a25..95c80c5cbf 100644 --- a/internal/cloud/backend_context.go +++ b/internal/cloud/backend_context.go @@ -143,9 +143,9 @@ func (b *Cloud) getRemoteWorkspaceName(localWorkspaceName string) string { // The default workspace name is a special case, for when the backend // is configured to with to an exact remote workspace rather than with // a remote workspace _prefix_. - return b.workspaceMapping.name - case b.workspaceMapping.prefix != "" && !strings.HasPrefix(localWorkspaceName, b.workspaceMapping.prefix): - return b.workspaceMapping.prefix + localWorkspaceName + return b.WorkspaceMapping.Name + case b.WorkspaceMapping.Prefix != "" && !strings.HasPrefix(localWorkspaceName, b.WorkspaceMapping.Prefix): + return b.WorkspaceMapping.Prefix + localWorkspaceName default: return localWorkspaceName } diff --git a/internal/cloud/backend_context_test.go b/internal/cloud/backend_context_test.go index 683ad98eba..7a7668a83a 100644 --- a/internal/cloud/backend_context_test.go +++ b/internal/cloud/backend_context_test.go @@ -182,7 +182,7 @@ func TestRemoteContextWithVars(t *testing.T) { _, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir) defer configCleanup() - workspaceID, err := b.getRemoteWorkspaceID(context.Background(), backend.DefaultStateName) + workspaceID, err := b.getRemoteWorkspaceID(context.Background(), testBackendSingleWorkspaceName) if err != nil { t.Fatal(err) } @@ -194,7 +194,7 @@ func TestRemoteContextWithVars(t *testing.T) { ConfigDir: configDir, ConfigLoader: configLoader, StateLocker: clistate.NewLocker(0, view), - Workspace: backend.DefaultStateName, + Workspace: testBackendSingleWorkspaceName, } v := test.Opts @@ -216,7 +216,7 @@ func TestRemoteContextWithVars(t *testing.T) { } // When Context() returns an error, it should unlock the state, // so re-locking it is expected to succeed. - stateMgr, _ := b.StateMgr(backend.DefaultStateName) + stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName) if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil { t.Fatalf("unexpected error locking state: %s", err.Error()) } @@ -225,7 +225,7 @@ func TestRemoteContextWithVars(t *testing.T) { t.Fatalf("unexpected error\ngot: %s\nwant: ", diags.Err().Error()) } // When Context() succeeds, this should fail w/ "workspace already locked" - stateMgr, _ := b.StateMgr(backend.DefaultStateName) + stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName) if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err == nil { t.Fatal("unexpected success locking state after Context") } diff --git a/internal/cloud/backend_plan_test.go b/internal/cloud/backend_plan_test.go index 1dcfdeb07c..a76841f2b2 100644 --- a/internal/cloud/backend_plan_test.go +++ b/internal/cloud/backend_plan_test.go @@ -59,7 +59,7 @@ func TestCloud_planBasic(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -82,7 +82,7 @@ func TestCloud_planBasic(t *testing.T) { t.Fatalf("expected plan summary in output: %s", output) } - stateMgr, _ := b.StateMgr(backend.DefaultStateName) + stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName) // An error suggests that the state was not unlocked after the operation finished if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil { t.Fatalf("unexpected error locking state after successful plan: %s", err.Error()) @@ -97,7 +97,7 @@ func TestCloud_planCanceled(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -112,7 +112,7 @@ func TestCloud_planCanceled(t *testing.T) { t.Fatal("expected plan operation to fail") } - stateMgr, _ := b.StateMgr(backend.DefaultStateName) + stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName) // An error suggests that the state was not unlocked after the operation finished if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil { t.Fatalf("unexpected error locking state after cancelled plan: %s", err.Error()) @@ -127,7 +127,7 @@ func TestCloud_planLongLine(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -160,7 +160,7 @@ func TestCloud_planWithoutPermissions(t *testing.T) { context.Background(), b.organization, tfe.WorkspaceCreateOptions{ - Name: tfe.String(b.workspaceMapping.prefix + "prod"), + Name: tfe.String(b.WorkspaceMapping.Prefix + "prod"), }, ) if err != nil { @@ -201,7 +201,7 @@ func TestCloud_planWithParallelism(t *testing.T) { b.ContextOpts = &terraform.ContextOpts{} } b.ContextOpts.Parallelism = 3 - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -228,7 +228,7 @@ func TestCloud_planWithPlan(t *testing.T) { defer configCleanup() op.PlanFile = &planfile.Reader{} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -258,7 +258,7 @@ func TestCloud_planWithPath(t *testing.T) { defer configCleanup() op.PlanOutPath = "./testdata/plan" - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -289,7 +289,7 @@ func TestCloud_planWithoutRefresh(t *testing.T) { defer done(t) op.PlanRefresh = false - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -327,7 +327,7 @@ func TestCloud_planWithoutRefreshIncompatibleAPIVersion(t *testing.T) { b.client.SetFakeRemoteAPIVersion("2.3") op.PlanRefresh = false - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -358,7 +358,7 @@ func TestCloud_planWithRefreshOnly(t *testing.T) { defer done(t) op.PlanMode = plans.RefreshOnlyMode - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -396,7 +396,7 @@ func TestCloud_planWithRefreshOnlyIncompatibleAPIVersion(t *testing.T) { b.client.SetFakeRemoteAPIVersion("2.3") op.PlanMode = plans.RefreshOnlyMode - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -452,7 +452,7 @@ func TestCloud_planWithTarget(t *testing.T) { addr, _ := addrs.ParseAbsResourceStr("null_resource.foo") op.Targets = []addrs.Targetable{addr} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -501,7 +501,7 @@ func TestCloud_planWithTargetIncompatibleAPIVersion(t *testing.T) { addr, _ := addrs.ParseAbsResourceStr("null_resource.foo") op.Targets = []addrs.Targetable{addr} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -534,7 +534,7 @@ func TestCloud_planWithReplace(t *testing.T) { addr, _ := addrs.ParseAbsResourceInstanceStr("null_resource.foo") op.ForceReplace = []addrs.AbsResourceInstance{addr} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -574,7 +574,7 @@ func TestCloud_planWithReplaceIncompatibleAPIVersion(t *testing.T) { addr, _ := addrs.ParseAbsResourceInstanceStr("null_resource.foo") op.ForceReplace = []addrs.AbsResourceInstance{addr} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -604,7 +604,7 @@ func TestCloud_planWithVariables(t *testing.T) { defer configCleanup() op.Variables = testVariables(terraform.ValueFromCLIArg, "foo", "bar") - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -630,7 +630,7 @@ func TestCloud_planNoConfig(t *testing.T) { op, configCleanup, done := testOperationPlan(t, "./testdata/empty") defer configCleanup() - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -660,7 +660,7 @@ func TestCloud_planNoChanges(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -699,7 +699,7 @@ func TestCloud_planForceLocal(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName streams, done := terminal.StreamsForTesting(t) view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams)) @@ -735,7 +735,7 @@ func TestCloud_planWithoutOperationsEntitlement(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName streams, done := terminal.StreamsForTesting(t) view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams)) @@ -774,7 +774,7 @@ func TestCloud_planWorkspaceWithoutOperations(t *testing.T) { ctx, b.organization, tfe.WorkspaceCreateOptions{ - Name: tfe.String(b.workspaceMapping.prefix + "no-operations"), + Name: tfe.String(b.WorkspaceMapping.Prefix + "no-operations"), }, ) if err != nil { @@ -820,7 +820,7 @@ func TestCloud_planLockTimeout(t *testing.T) { ctx := context.Background() // Retrieve the workspace used to run this operation in. - w, err := b.client.Workspaces.Read(ctx, b.organization, b.workspaceMapping.name) + w, err := b.client.Workspaces.Read(ctx, b.organization, b.WorkspaceMapping.Name) if err != nil { t.Fatalf("error retrieving workspace: %v", err) } @@ -851,7 +851,7 @@ func TestCloud_planLockTimeout(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName _, err = b.Operation(context.Background(), op) if err != nil { @@ -893,7 +893,7 @@ func TestCloud_planDestroy(t *testing.T) { defer done(t) op.PlanMode = plans.DestroyMode - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -918,7 +918,7 @@ func TestCloud_planDestroyNoConfig(t *testing.T) { defer done(t) op.PlanMode = plans.DestroyMode - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -943,7 +943,7 @@ func TestCloud_planWithWorkingDirectory(t *testing.T) { } // Configure the workspace to use a custom working directory. - _, err := b.client.Workspaces.Update(context.Background(), b.organization, b.workspaceMapping.name, options) + _, err := b.client.Workspaces.Update(context.Background(), b.organization, b.WorkspaceMapping.Name, options) if err != nil { t.Fatalf("error configuring working directory: %v", err) } @@ -952,7 +952,7 @@ func TestCloud_planWithWorkingDirectory(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -988,7 +988,7 @@ func TestCloud_planWithWorkingDirectoryFromCurrentPath(t *testing.T) { } // Configure the workspace to use a custom working directory. - _, err := b.client.Workspaces.Update(context.Background(), b.organization, b.workspaceMapping.name, options) + _, err := b.client.Workspaces.Update(context.Background(), b.organization, b.WorkspaceMapping.Name, options) if err != nil { t.Fatalf("error configuring working directory: %v", err) } @@ -1011,7 +1011,7 @@ func TestCloud_planWithWorkingDirectoryFromCurrentPath(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1043,7 +1043,7 @@ func TestCloud_planCostEstimation(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1078,7 +1078,7 @@ func TestCloud_planPolicyPass(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1112,7 +1112,7 @@ func TestCloud_planPolicyHardFail(t *testing.T) { op, configCleanup, done := testOperationPlan(t, "./testdata/plan-policy-hard-failed") defer configCleanup() - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1152,7 +1152,7 @@ func TestCloud_planPolicySoftFail(t *testing.T) { op, configCleanup, done := testOperationPlan(t, "./testdata/plan-policy-soft-failed") defer configCleanup() - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1193,7 +1193,7 @@ func TestCloud_planWithRemoteError(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { diff --git a/internal/cloud/backend_state_test.go b/internal/cloud/backend_state_test.go index a94c60c6ee..e39dd211f1 100644 --- a/internal/cloud/backend_state_test.go +++ b/internal/cloud/backend_state_test.go @@ -5,7 +5,6 @@ import ( "os" "testing" - "github.com/hashicorp/terraform/internal/backend" "github.com/hashicorp/terraform/internal/states" "github.com/hashicorp/terraform/internal/states/remote" "github.com/hashicorp/terraform/internal/states/statefile" @@ -24,12 +23,12 @@ func TestRemoteClient_stateLock(t *testing.T) { b, bCleanup := testBackendDefault(t) defer bCleanup() - s1, err := b.StateMgr(backend.DefaultStateName) + s1, err := b.StateMgr(testBackendSingleWorkspaceName) if err != nil { t.Fatalf("expected no error, got %v", err) } - s2, err := b.StateMgr(backend.DefaultStateName) + s2, err := b.StateMgr(testBackendSingleWorkspaceName) if err != nil { t.Fatalf("expected no error, got %v", err) } diff --git a/internal/cloud/backend_test.go b/internal/cloud/backend_test.go index 928182b535..9f1a5190b2 100644 --- a/internal/cloud/backend_test.go +++ b/internal/cloud/backend_test.go @@ -24,13 +24,30 @@ func TestCloud(t *testing.T) { var _ backend.CLI = New(nil) } -func TestCloud_backendDefault(t *testing.T) { +func TestCloud_backendWithName(t *testing.T) { b, bCleanup := testBackendDefault(t) defer bCleanup() - backend.TestBackendStates(t, b) - backend.TestBackendStateLocks(t, b, b) - backend.TestBackendStateForceUnlock(t, b, b) + workspaces, err := b.Workspaces() + if err != nil { + t.Fatalf("error: %v", err) + } + + if len(workspaces) != 1 || workspaces[0] != testBackendSingleWorkspaceName { + t.Fatalf("should only have a single configured workspace matching the configured 'name' strategy, but got: %#v", workspaces) + } + + if _, err := b.StateMgr("foo"); err != backend.ErrWorkspacesNotSupported { + t.Fatalf("expected fetching a state which is NOT the single configured workspace to have an ErrWorkspacesNotSupported error, but got: %v", err) + } + + if err := b.DeleteWorkspace(testBackendSingleWorkspaceName); err != backend.ErrWorkspacesNotSupported { + t.Fatalf("expected deleting the single configured workspace name to result in an error, but got: %v", err) + } + + if err := b.DeleteWorkspace("foo"); err != backend.ErrWorkspacesNotSupported { + t.Fatalf("expected deleting a workspace which is NOT the configured workspace name to result in an error, but got: %v", err) + } } func TestCloud_backendWithPrefix(t *testing.T) { @@ -428,15 +445,15 @@ func TestCloud_setConfigurationFields(t *testing.T) { if tc.expectedOrganziation != "" && b.organization != tc.expectedOrganziation { t.Fatalf("%s: expected organization (%s) to match configured organization (%s)", name, b.organization, tc.expectedOrganziation) } - if tc.expectedWorkspacePrefix != "" && b.workspaceMapping.prefix != tc.expectedWorkspacePrefix { - t.Fatalf("%s: expected workspace prefix mapping (%s) to match configured workspace prefix (%s)", name, b.workspaceMapping.prefix, tc.expectedWorkspacePrefix) + if tc.expectedWorkspacePrefix != "" && b.WorkspaceMapping.Prefix != tc.expectedWorkspacePrefix { + t.Fatalf("%s: expected workspace prefix mapping (%s) to match configured workspace prefix (%s)", name, b.WorkspaceMapping.Prefix, tc.expectedWorkspacePrefix) } - if tc.expectedWorkspaceName != "" && b.workspaceMapping.name != tc.expectedWorkspaceName { - t.Fatalf("%s: expected workspace name mapping (%s) to match configured workspace name (%s)", name, b.workspaceMapping.name, tc.expectedWorkspaceName) + if tc.expectedWorkspaceName != "" && b.WorkspaceMapping.Name != tc.expectedWorkspaceName { + t.Fatalf("%s: expected workspace name mapping (%s) to match configured workspace name (%s)", name, b.WorkspaceMapping.Name, tc.expectedWorkspaceName) } if len(tc.expectedWorkspaceTags) > 0 { presentSet := make(map[string]struct{}) - for _, tag := range b.workspaceMapping.tags { + for _, tag := range b.WorkspaceMapping.Tags { presentSet[tag] = struct{}{} } @@ -454,18 +471,18 @@ func TestCloud_setConfigurationFields(t *testing.T) { } } - for _, actual := range b.workspaceMapping.tags { + for _, actual := range b.WorkspaceMapping.Tags { if _, ok := expectedSet[actual]; !ok { unexpected = append(missing, actual) } } if len(missing) > 0 { - t.Fatalf("%s: expected workspace tag mapping (%s) to contain the following tags: %s", name, b.workspaceMapping.tags, missing) + t.Fatalf("%s: expected workspace tag mapping (%s) to contain the following tags: %s", name, b.WorkspaceMapping.Tags, missing) } if len(unexpected) > 0 { - t.Fatalf("%s: expected workspace tag mapping (%s) to NOT contain the following tags: %s", name, b.workspaceMapping.tags, unexpected) + t.Fatalf("%s: expected workspace tag mapping (%s) to NOT contain the following tags: %s", name, b.WorkspaceMapping.Tags, unexpected) } } @@ -575,28 +592,16 @@ func TestCloud_addAndRemoveWorkspacesDefault(t *testing.T) { b, bCleanup := testBackendDefault(t) defer bCleanup() - if _, err := b.Workspaces(); err != backend.ErrWorkspacesNotSupported { - t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err) - } - - if _, err := b.StateMgr(backend.DefaultStateName); err != nil { - t.Fatalf("expected no error, got %v", err) - } - - if _, err := b.StateMgr("prod"); err != backend.ErrWorkspacesNotSupported { - t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err) - } - - if err := b.DeleteWorkspace(backend.DefaultStateName); err != nil { + if _, err := b.StateMgr(testBackendSingleWorkspaceName); err != nil { t.Fatalf("expected no error, got %v", err) } - if err := b.DeleteWorkspace("prod"); err != backend.ErrWorkspacesNotSupported { + if err := b.DeleteWorkspace(testBackendSingleWorkspaceName); err != backend.ErrWorkspacesNotSupported { t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err) } } -func TestCloud_addAndRemoveWorkspacesNoDefault(t *testing.T) { +func TestCloud_addAndRemoveWorkspacesWithPrefix(t *testing.T) { b, bCleanup := testBackendWithPrefix(t) defer bCleanup() @@ -808,7 +813,7 @@ func TestCloud_StateMgr_versionCheck(t *testing.T) { if _, err := b.client.Workspaces.Update( context.Background(), b.organization, - b.workspaceMapping.name, + b.WorkspaceMapping.Name, tfe.WorkspaceUpdateOptions{ TerraformVersion: tfe.String(v0140.String()), }, @@ -817,7 +822,7 @@ func TestCloud_StateMgr_versionCheck(t *testing.T) { } // This should succeed - if _, err := b.StateMgr(backend.DefaultStateName); err != nil { + if _, err := b.StateMgr(testBackendSingleWorkspaceName); err != nil { t.Fatalf("expected no error, got %v", err) } @@ -825,7 +830,7 @@ func TestCloud_StateMgr_versionCheck(t *testing.T) { if _, err := b.client.Workspaces.Update( context.Background(), b.organization, - b.workspaceMapping.name, + b.WorkspaceMapping.Name, tfe.WorkspaceUpdateOptions{ TerraformVersion: tfe.String(v0135.String()), }, @@ -835,7 +840,7 @@ func TestCloud_StateMgr_versionCheck(t *testing.T) { // This should fail want := `Remote workspace Terraform version "0.13.5" does not match local Terraform version "0.14.0"` - if _, err := b.StateMgr(backend.DefaultStateName); err.Error() != want { + if _, err := b.StateMgr(testBackendSingleWorkspaceName); err.Error() != want { t.Fatalf("wrong error\n got: %v\nwant: %v", err.Error(), want) } } @@ -865,7 +870,7 @@ func TestCloud_StateMgr_versionCheckLatest(t *testing.T) { if _, err := b.client.Workspaces.Update( context.Background(), b.organization, - b.workspaceMapping.name, + b.WorkspaceMapping.Name, tfe.WorkspaceUpdateOptions{ TerraformVersion: tfe.String("latest"), }, @@ -874,7 +879,7 @@ func TestCloud_StateMgr_versionCheckLatest(t *testing.T) { } // This should succeed despite not being a string match - if _, err := b.StateMgr(backend.DefaultStateName); err != nil { + if _, err := b.StateMgr(testBackendSingleWorkspaceName); err != nil { t.Fatalf("expected no error, got %v", err) } } @@ -923,7 +928,7 @@ func TestCloud_VerifyWorkspaceTerraformVersion(t *testing.T) { if _, err := b.client.Workspaces.Update( context.Background(), b.organization, - b.workspaceMapping.name, + b.WorkspaceMapping.Name, tfe.WorkspaceUpdateOptions{ Operations: tfe.Bool(tc.operations), TerraformVersion: tfe.String(tc.remote), @@ -974,7 +979,7 @@ func TestCloud_VerifyWorkspaceTerraformVersion_workspaceErrors(t *testing.T) { if _, err := b.client.Workspaces.Update( context.Background(), b.organization, - b.workspaceMapping.name, + b.WorkspaceMapping.Name, tfe.WorkspaceUpdateOptions{ TerraformVersion: tfe.String("1.0.cheetarah"), }, @@ -1022,7 +1027,7 @@ func TestCloud_VerifyWorkspaceTerraformVersion_ignoreFlagSet(t *testing.T) { if _, err := b.client.Workspaces.Update( context.Background(), b.organization, - b.workspaceMapping.name, + b.WorkspaceMapping.Name, tfe.WorkspaceUpdateOptions{ TerraformVersion: tfe.String(remote.String()), }, @@ -1041,7 +1046,7 @@ func TestCloud_VerifyWorkspaceTerraformVersion_ignoreFlagSet(t *testing.T) { if got, want := diags[0].Description().Summary, "Terraform version mismatch"; got != want { t.Errorf("wrong summary: got %s, want %s", got, want) } - wantDetail := "The local Terraform version (0.14.0) does not match the configured version for remote workspace hashicorp/prod (0.13.5)." + wantDetail := "The local Terraform version (0.14.0) does not match the configured version for remote workspace hashicorp/app-prod (0.13.5)." if got := diags[0].Description().Detail; got != wantDetail { t.Errorf("wrong summary: got %s, want %s", got, wantDetail) } diff --git a/internal/cloud/testing.go b/internal/cloud/testing.go index d289a42c2d..9dd570e693 100644 --- a/internal/cloud/testing.go +++ b/internal/cloud/testing.go @@ -38,6 +38,7 @@ var ( credsSrc = auth.StaticCredentialsSource(map[svchost.Hostname]map[string]interface{}{ tfeHost: {"token": testCred}, }) + testBackendSingleWorkspaceName = "app-prod" ) // mockInput is a mock implementation of terraform.UIInput. @@ -70,7 +71,7 @@ func testBackendDefault(t *testing.T) (*Cloud, func()) { "organization": cty.StringVal("hashicorp"), "token": cty.NullVal(cty.String), "workspaces": cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("prod"), + "name": cty.StringVal(testBackendSingleWorkspaceName), "prefix": cty.NullVal(cty.String), "tags": cty.NullVal(cty.Set(cty.String)), }), @@ -116,7 +117,7 @@ func testBackendNoOperations(t *testing.T) (*Cloud, func()) { "organization": cty.StringVal("no-operations"), "token": cty.NullVal(cty.String), "workspaces": cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("prod"), + "name": cty.StringVal(testBackendSingleWorkspaceName), "prefix": cty.NullVal(cty.String), "tags": cty.NullVal(cty.Set(cty.String)), }), @@ -128,7 +129,7 @@ func testRemoteClient(t *testing.T) remote.Client { b, bCleanup := testBackendDefault(t) defer bCleanup() - raw, err := b.StateMgr(backend.DefaultStateName) + raw, err := b.StateMgr(testBackendSingleWorkspaceName) if err != nil { t.Fatalf("error: %v", err) } @@ -182,9 +183,9 @@ func testBackend(t *testing.T, obj cty.Value) (*Cloud, func()) { } // Create the default workspace if required. - if b.workspaceMapping.name != "" { + if b.WorkspaceMapping.Name != "" { _, err = b.client.Workspaces.Create(ctx, b.organization, tfe.WorkspaceCreateOptions{ - Name: tfe.String(b.workspaceMapping.name), + Name: tfe.String(b.WorkspaceMapping.Name), }) if err != nil { t.Fatalf("error: %v", err)