terraform/internal/command/workspace_select.go
Sarah French ae14dc3ea8
refactor: Stop workspace new, show, and select commands using ModulePath method to determine the working directory (#38358)
* test: Add test defining how workspace subcommands react to unexpected arguments.

* refactor: Update `workspace new` and `select` commands to access the config path using `c.WorkingDir.RootModuleDir()`

* refactor: Update `workspace delete` command to access the config path using `c.WorkingDir.RootModuleDir()`

This results in test failures because the delete command's implementation doesn't indirectly invoke the (Meta).fixupMissingWorkingDir method. Other workspace subcommands do invoke the fixup method via calling (Meta).Workspace, which causes (Meta).DataDir to be invoked, which invokes the fixup.

* tests: Update all workspace tests to include a `WorkingDir` value in the `Meta`.

Prior to this change some commands would fixup this missing data, and depending on whether the meta was reused or not that would impact testing other commands. Commands that tested only the delete command would fail due to a missing workspace due to this.
2026-04-08 12:02:55 -04:00

146 lines
2.9 KiB
Go

// Copyright IBM Corp. 2014, 2026
// SPDX-License-Identifier: BUSL-1.1
package command
import (
"fmt"
"strings"
"github.com/hashicorp/cli"
"github.com/hashicorp/terraform/internal/command/arguments"
"github.com/posener/complete"
)
type WorkspaceSelectCommand struct {
Meta
LegacyName bool
}
func (c *WorkspaceSelectCommand) Run(args []string) int {
args = c.Meta.process(args)
envCommandShowWarning(c.Ui, c.LegacyName)
var orCreate bool
cmdFlags := c.Meta.defaultFlagSet("workspace select")
cmdFlags.BoolVar(&orCreate, "or-create", false, "create workspace if it does not exist")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1
}
args = cmdFlags.Args()
if len(args) != 1 {
c.Ui.Error("Expected a single argument: NAME.\n")
return cli.RunResultHelp
}
current, isOverridden := c.WorkspaceOverridden()
if isOverridden {
c.Ui.Error(envIsOverriddenSelectError)
return 1
}
// Load the backend
view := arguments.ViewHuman
configPath := c.WorkingDir.RootModuleDir()
b, diags := c.backend(configPath, view)
if diags.HasErrors() {
c.showDiagnostics(diags)
return 1
}
// This command will not write state
c.ignoreRemoteVersionConflict(b)
name := args[0]
if !validWorkspaceName(name) {
c.Ui.Error(fmt.Sprintf(envInvalidName, name))
return 1
}
states, wDiags := b.Workspaces()
if wDiags.HasErrors() {
c.Ui.Error(wDiags.Err().Error())
return 1
}
c.showDiagnostics(diags) // output warnings, if any
if name == current {
// already using this workspace
return 0
}
found := false
for _, s := range states {
if name == s {
found = true
break
}
}
var newState bool
if !found {
if orCreate {
_, sDiags := b.StateMgr(name)
if sDiags.HasErrors() {
c.Ui.Error(sDiags.Err().Error())
return 1
}
newState = true
} else {
c.Ui.Error(fmt.Sprintf(envDoesNotExist, name))
return 1
}
}
err := c.SetWorkspace(name)
if err != nil {
c.Ui.Error(err.Error())
return 1
}
if newState {
c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
strings.TrimSpace(envCreated), name)))
} else {
c.Ui.Output(
c.Colorize().Color(
fmt.Sprintf(envChanged, name),
),
)
}
return 0
}
func (c *WorkspaceSelectCommand) AutocompleteArgs() complete.Predictor {
return completePredictSequence{
c.completePredictWorkspaceName(),
complete.PredictDirs(""),
}
}
func (c *WorkspaceSelectCommand) AutocompleteFlags() complete.Flags {
return nil
}
func (c *WorkspaceSelectCommand) Help() string {
helpText := `
Usage: terraform [global options] workspace select NAME
Select a different Terraform workspace.
Options:
-or-create=false Create the Terraform workspace if it doesn't exist.
`
return strings.TrimSpace(helpText)
}
func (c *WorkspaceSelectCommand) Synopsis() string {
return "Select a workspace"
}