diff --git a/command/apply_test.go b/command/apply_test.go index 0937eee07..73baba5d4 100644 --- a/command/apply_test.go +++ b/command/apply_test.go @@ -1639,7 +1639,7 @@ func TestApply_terraformEnvNonDefault(t *testing.T) { // Create new env { ui := new(cli.MockUi) - newCmd := &EnvNewCommand{} + newCmd := &WorkspaceNewCommand{} newCmd.Meta = Meta{Ui: ui} if code := newCmd.Run([]string{"test"}); code != 0 { t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter) @@ -1650,7 +1650,7 @@ func TestApply_terraformEnvNonDefault(t *testing.T) { { args := []string{"test"} ui := new(cli.MockUi) - selCmd := &EnvSelectCommand{} + selCmd := &WorkspaceSelectCommand{} selCmd.Meta = Meta{Ui: ui} if code := selCmd.Run(args); code != 0 { t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter) diff --git a/command/env_command.go b/command/env_command.go deleted file mode 100644 index f32e1cb20..000000000 --- a/command/env_command.go +++ /dev/null @@ -1,123 +0,0 @@ -package command - -import ( - "net/url" - "strings" -) - -// EnvCommand is a Command Implementation that manipulates local state -// environments. -type EnvCommand struct { - Meta -} - -func (c *EnvCommand) Run(args []string) int { - args = c.Meta.process(args, true) - - cmdFlags := c.Meta.flagSet("env") - cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } - - c.Ui.Output(c.Help()) - return 0 -} - -func (c *EnvCommand) Help() string { - helpText := ` -Usage: terraform env - - Create, change and delete Terraform environments. - - -Subcommands: - - list List environments. - select Select an environment. - new Create a new environment. - delete Delete an existing environment. -` - return strings.TrimSpace(helpText) -} - -func (c *EnvCommand) Synopsis() string { - return "Environment management" -} - -// validEnvName returns true is this name is valid to use as an environment name. -// Since most named states are accessed via a filesystem path or URL, check if -// escaping the name would be required. -func validEnvName(name string) bool { - return name == url.PathEscape(name) -} - -const ( - envNotSupported = `Backend does not support environments` - - envExists = `Environment %q already exists` - - envDoesNotExist = ` -Environment %q doesn't exist! - -You can create this environment with the "new" option.` - - envChanged = `[reset][green]Switched to environment %q!` - - envCreated = ` -[reset][green][bold]Created and switched to environment %q![reset][green] - -You're now on a new, empty environment. Environments isolate their state, -so if you run "terraform plan" Terraform will not see any existing state -for this configuration. -` - - envDeleted = `[reset][green]Deleted environment %q!` - - envNotEmpty = ` -Environment %[1]q is not empty! - -Deleting %[1]q can result in dangling resources: resources that -exist but are no longer manageable by Terraform. Please destroy -these resources first. If you want to delete this environment -anyways and risk dangling resources, use the '-force' flag. -` - - envWarnNotEmpty = `[reset][yellow]WARNING: %q was non-empty. -The resources managed by the deleted environment may still exist, -but are no longer manageable by Terraform since the state has -been deleted. -` - - envDelCurrent = ` -Environment %[1]q is your active environment! - -You cannot delete the currently active environment. Please switch -to another environment and try again. -` - - envInvalidName = ` -The environment name %q is not allowed. The name must contain only URL safe -characters, and no path separators. -` - - envIsOverriddenNote = ` - -The active environment is being overridden using the TF_ENVIRONMENT environment -variable. -` - - envIsOverriddenSelectError = ` -The environment is currently overridden using the TF_ENVIRONMENT environment -variable. - -To select a new environment, either update this environment variable or unset -it and then run this command again. -` - - envIsOverriddenNewError = ` -The environment is currently overridden using the TF_ENVIRONMENT environment -variable. You cannot create a different environment when using this setting. - -To create a new environment, either unset this environment variable or update it -to match the environment name you are trying to create, and then run this command -again. -` -) diff --git a/command/meta.go b/command/meta.go index acf37e516..018f84636 100644 --- a/command/meta.go +++ b/command/meta.go @@ -455,22 +455,22 @@ func (m *Meta) outputShadowError(err error, output bool) bool { } // EnvironmentNameEnvVar is the name of the environment variable (ie, the POSIX -// feature) that can be used to set the name of the Terraform environment -// (overriding the environment chosen by `terraform env select`). Note that -// this environment variable is ignored by `terraform env new` and `terraform -// env delete`. -const EnvironmentNameEnvVar = "TF_ENVIRONMENT" +// feature) that can be used to set the name of the Terraform workspace +// (overriding the workspace chosen by `terraform workspace select`). Note that +// this environment variable is ignored by `terraform workspace new` and +// `terraform workspace delete`. +const EnvironmentNameEnvVar = "TF_WORKSPACE" -// Env returns the name of the currently configured environment, corresponding +// Env returns the name of the currently configured workspace, corresponding // to the desired named state. func (m *Meta) Env() string { current, _ := m.EnvOverridden() return current } -// EnvOverridden returns the name of the currently configured environment, +// EnvOverridden returns the name of the currently configured workspace, // corresponding to the desired named state, as well as a bool saying whether -// this was set via the TF_ENVIRONMENT environment variable. +// this was set via the TF_WORKSPACE environment variable. func (m *Meta) EnvOverridden() (string, bool) { if envVar := os.Getenv(EnvironmentNameEnvVar); envVar != "" { return envVar, true @@ -488,14 +488,15 @@ func (m *Meta) EnvOverridden() (string, bool) { } if err != nil && !os.IsNotExist(err) { - // always return the default if we can't get an environment name - log.Printf("[ERROR] failed to read current environment: %s", err) + // always return the default if we can't get a workspace name + log.Printf("[ERROR] failed to read current workspace: %s", err) } return current, false } -// SetEnv saves the named environment to the local filesystem. +// SetEnv saves the given name as the current workspace in the local +// filesystem. func (m *Meta) SetEnv(name string) error { dataDir := m.dataDir if m.dataDir == "" { diff --git a/command/meta_backend_migrate.go b/command/meta_backend_migrate.go index 8dce064ad..f0e42d234 100644 --- a/command/meta_backend_migrate.go +++ b/command/meta_backend_migrate.go @@ -117,7 +117,7 @@ func (m *Meta) backendMigrateState_S_S(opts *backendMigrateOpts) error { migrate, err := m.confirm(&terraform.InputOpts{ Id: "backend-migrate-multistate-to-multistate", Query: fmt.Sprintf( - "Do you want to migrate all environments to %q?", + "Do you want to migrate all workspaces to %q?", opts.TwoType), Description: fmt.Sprintf( strings.TrimSpace(inputBackendMigrateMultiToMulti), @@ -171,8 +171,8 @@ func (m *Meta) backendMigrateState_S_s(opts *backendMigrateOpts) error { migrate, err = m.confirm(&terraform.InputOpts{ Id: "backend-migrate-multistate-to-single", Query: fmt.Sprintf( - "Destination state %q doesn't support environments (named states).\n"+ - "Do you want to copy only your current environment?", + "Destination state %q doesn't support workspaces.\n"+ + "Do you want to copy only your current workspace?", opts.TwoType), Description: fmt.Sprintf( strings.TrimSpace(inputBackendMigrateMultiToSingle), @@ -458,17 +458,17 @@ above error and try again. ` const errMigrateMulti = ` -Error migrating the environment %q from %q to %q: +Error migrating the workspace %q from %q to %q: %s -Terraform copies environments in alphabetical order. Any environments -alphabetically earlier than this one have been copied. Any environments -later than this haven't been modified in the destination. No environments +Terraform copies workspaces in alphabetical order. Any workspaces +alphabetically earlier than this one have been copied. Any workspaces +later than this haven't been modified in the destination. No workspaces in the source state have been modified. Please resolve the error above and run the initialization command again. -This will attempt to copy (with permission) all environments again. +This will attempt to copy (with permission) all workspaces again. ` const errBackendStateCopy = ` @@ -497,22 +497,22 @@ and "no" to start with the existing state in %[2]q. ` const inputBackendMigrateMultiToSingle = ` -The existing backend %[1]q supports environments and you currently are -using more than one. The target backend %[2]q doesn't support environments. -If you continue, Terraform will offer to copy your current environment -%[3]q to the default environment in the target. Your existing environments -in the source backend won't be modified. If you want to switch environments, +The existing backend %[1]q supports workspaces and you currently are +using more than one. The target backend %[2]q doesn't support workspaces. +If you continue, Terraform will offer to copy your current workspace +%[3]q to the default workspace in the target. Your existing workspaces +in the source backend won't be modified. If you want to switch workspaces, back them up, or cancel altogether, answer "no" and Terraform will abort. ` const inputBackendMigrateMultiToMulti = ` Both the existing backend %[1]q and the target backend %[2]q support -environments. When migrating between backends, Terraform will copy all -environments (with the same names). THIS WILL OVERWRITE any conflicting +workspaces. When migrating between backends, Terraform will copy all +workspaces (with the same names). THIS WILL OVERWRITE any conflicting states in the destination. -Terraform initialization doesn't currently migrate only select environments. -If you want to migrate a select number of environments, you must manually +Terraform initialization doesn't currently migrate only select workspaces. +If you want to migrate a select number of workspaces, you must manually pull and push those states. If you answer "yes", Terraform will migrate all states. If you answer diff --git a/command/meta_backend_test.go b/command/meta_backend_test.go index aa4a02d2c..c91b72030 100644 --- a/command/meta_backend_test.go +++ b/command/meta_backend_test.go @@ -1249,7 +1249,7 @@ func TestMetaBackend_configuredChangeCopy_multiToSingle(t *testing.T) { t.Fatal("file should not exist") } - // Verify existing environments exist + // Verify existing workspaces exist envPath := filepath.Join(backendlocal.DefaultEnvDir, "env2", backendlocal.DefaultStateFilename) if _, err := os.Stat(envPath); err != nil { t.Fatal("env should exist") @@ -1321,7 +1321,7 @@ func TestMetaBackend_configuredChangeCopy_multiToSingleCurrentEnv(t *testing.T) t.Fatal("file should not exist") } - // Verify existing environments exist + // Verify existing workspaces exist envPath := filepath.Join(backendlocal.DefaultEnvDir, "env2", backendlocal.DefaultStateFilename) if _, err := os.Stat(envPath); err != nil { t.Fatal("env should exist") @@ -1406,7 +1406,7 @@ func TestMetaBackend_configuredChangeCopy_multiToMulti(t *testing.T) { } { - // Verify existing environments exist + // Verify existing workspaces exist envPath := filepath.Join(backendlocal.DefaultEnvDir, "env2", backendlocal.DefaultStateFilename) if _, err := os.Stat(envPath); err != nil { t.Fatal("env should exist") @@ -1414,7 +1414,7 @@ func TestMetaBackend_configuredChangeCopy_multiToMulti(t *testing.T) { } { - // Verify new environments exist + // Verify new workspaces exist envPath := filepath.Join("envdir-new", "env2", backendlocal.DefaultStateFilename) if _, err := os.Stat(envPath); err != nil { t.Fatal("env should exist") diff --git a/command/push.go b/command/push.go index 564889210..1c206aef5 100644 --- a/command/push.go +++ b/command/push.go @@ -51,8 +51,8 @@ func (c *PushCommand) Run(args []string) int { // This is a map of variables specifically from the CLI that we want to overwrite. // We need this because there is a chance that the user is trying to modify - // a variable we don't see in our context, but which exists in this atlas - // environment. + // a variable we don't see in our context, but which exists in this Terraform + // Enterprise workspace. cliVars := make(map[string]string) for k, v := range c.variables { if _, ok := overwriteMap[k]; ok { diff --git a/command/workspace_command.go b/command/workspace_command.go new file mode 100644 index 000000000..f6d584747 --- /dev/null +++ b/command/workspace_command.go @@ -0,0 +1,144 @@ +package command + +import ( + "net/url" + "strings" + + "github.com/mitchellh/cli" +) + +// WorkspaceCommand is a Command Implementation that manipulates workspaces, +// which allow multiple distinct states and variables from a single config. +type WorkspaceCommand struct { + Meta + LegacyName bool +} + +func (c *WorkspaceCommand) Run(args []string) int { + args = c.Meta.process(args, true) + + envCommandShowWarning(c.Ui, c.LegacyName) + + cmdFlags := c.Meta.flagSet("workspace") + cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } + + c.Ui.Output(c.Help()) + return 0 +} + +func (c *WorkspaceCommand) Help() string { + helpText := ` +Usage: terraform workspace + + Create, change and delete Terraform workspaces. + + +Subcommands: + + list List workspaces. + select Select a workspace. + new Create a new workspace. + delete Delete an existing workspace. +` + return strings.TrimSpace(helpText) +} + +func (c *WorkspaceCommand) Synopsis() string { + return "Workspace management" +} + +// validEnvName returns true is this name is valid to use as a workspace name. +// Since most named states are accessed via a filesystem path or URL, check if +// escaping the name would be required. +func validEnvName(name string) bool { + return name == url.PathEscape(name) +} + +func envCommandShowWarning(ui cli.Ui, show bool) { + if !show { + return + } + + ui.Warn(`Warning: the "terraform env" family of commands is deprecated. + +"Workspace" is now the preferred term for what earlier Terraform versions +called "environment", to reduce ambiguity caused by the latter term colliding +with other concepts. + +The "terraform workspace" commands should be used instead. "terraform env" +will be removed in a future Terraform version. +`) +} + +const ( + envNotSupported = `Backend does not support multiple workspaces` + + envExists = `Workspace %q already exists` + + envDoesNotExist = ` +Workspace %q doesn't exist. + +You can create this workspace with the "new" subcommand.` + + envChanged = `[reset][green]Switched to workspace %q.` + + envCreated = ` +[reset][green][bold]Created and switched to workspace %q![reset][green] + +You're now on a new, empty workspace. Workspaces isolate their state, +so if you run "terraform plan" Terraform will not see any existing state +for this configuration. +` + + envDeleted = `[reset][green]Deleted workspace %q!` + + envNotEmpty = ` +Workspace %[1]q is not empty. + +Deleting %[1]q can result in dangling resources: resources that +exist but are no longer manageable by Terraform. Please destroy +these resources first. If you want to delete this workspace +anyway and risk dangling resources, use the '-force' flag. +` + + envWarnNotEmpty = `[reset][yellow]WARNING: %q was non-empty. +The resources managed by the deleted workspace may still exist, +but are no longer manageable by Terraform since the state has +been deleted. +` + + envDelCurrent = ` +Workspace %[1]q is your active workspace. + +You cannot delete the currently active workspace. Please switch +to another workspace and try again. +` + + envInvalidName = ` +The workspace name %q is not allowed. The name must contain only URL safe +characters, and no path separators. +` + + envIsOverriddenNote = ` + +The active workspace is being overridden using the TF_WORKSPACE environment +variable. +` + + envIsOverriddenSelectError = ` +The selected workspace is currently overridden using the TF_WORKSPACE +environment variable. + +To select a new workspace, either update this environment variable or unset +it and then run this command again. +` + + envIsOverriddenNewError = ` +The workspace is currently overridden using the TF_WORKSPACE environment +variable. You cannot create a new workspace when using this setting. + +To create a new workspace, either unset this environment variable or update it +to match the workspace name you are trying to create, and then run this command +again. +` +) diff --git a/command/env_command_test.go b/command/workspace_command_test.go similarity index 82% rename from command/env_command_test.go rename to command/workspace_command_test.go index 5a04d8db0..382c0f935 100644 --- a/command/env_command_test.go +++ b/command/workspace_command_test.go @@ -14,18 +14,18 @@ import ( "github.com/mitchellh/cli" ) -func TestEnv_createAndChange(t *testing.T) { +func TestWorkspace_createAndChange(t *testing.T) { // Create a temporary working directory that is empty td := tempDir(t) os.MkdirAll(td, 0755) defer os.RemoveAll(td) defer testChdir(t, td)() - newCmd := &EnvNewCommand{} + newCmd := &WorkspaceNewCommand{} current := newCmd.Env() if current != backend.DefaultStateName { - t.Fatal("current env should be 'default'") + t.Fatal("current workspace should be 'default'") } args := []string{"test"} @@ -37,10 +37,10 @@ func TestEnv_createAndChange(t *testing.T) { current = newCmd.Env() if current != "test" { - t.Fatalf("current env should be 'test', got %q", current) + t.Fatalf("current workspace should be 'test', got %q", current) } - selCmd := &EnvSelectCommand{} + selCmd := &WorkspaceSelectCommand{} args = []string{backend.DefaultStateName} ui = new(cli.MockUi) selCmd.Meta = Meta{Ui: ui} @@ -50,14 +50,14 @@ func TestEnv_createAndChange(t *testing.T) { current = newCmd.Env() if current != backend.DefaultStateName { - t.Fatal("current env should be 'default'") + t.Fatal("current workspace should be 'default'") } } -// Create some environments and test the list output. +// Create some workspaces and test the list output. // This also ensures we switch to the correct env after each call -func TestEnv_createAndList(t *testing.T) { +func TestWorkspace_createAndList(t *testing.T) { // Create a temporary working directory that is empty td := tempDir(t) os.MkdirAll(td, 0755) @@ -74,11 +74,11 @@ func TestEnv_createAndList(t *testing.T) { t.Fatal(err) } - newCmd := &EnvNewCommand{} + newCmd := &WorkspaceNewCommand{} envs := []string{"test_a", "test_b", "test_c"} - // create multiple envs + // create multiple workspaces for _, env := range envs { ui := new(cli.MockUi) newCmd.Meta = Meta{Ui: ui} @@ -87,7 +87,7 @@ func TestEnv_createAndList(t *testing.T) { } } - listCmd := &EnvListCommand{} + listCmd := &WorkspaceListCommand{} ui := new(cli.MockUi) listCmd.Meta = Meta{Ui: ui} @@ -104,18 +104,18 @@ func TestEnv_createAndList(t *testing.T) { } // Don't allow names that aren't URL safe -func TestEnv_createInvalid(t *testing.T) { +func TestWorkspace_createInvalid(t *testing.T) { // Create a temporary working directory that is empty td := tempDir(t) os.MkdirAll(td, 0755) defer os.RemoveAll(td) defer testChdir(t, td)() - newCmd := &EnvNewCommand{} + newCmd := &WorkspaceNewCommand{} envs := []string{"test_a*", "test_b/foo", "../../../test_c", "好_d"} - // create multiple envs + // create multiple workspaces for _, env := range envs { ui := new(cli.MockUi) newCmd.Meta = Meta{Ui: ui} @@ -124,8 +124,8 @@ func TestEnv_createInvalid(t *testing.T) { } } - // list envs to make sure none were created - listCmd := &EnvListCommand{} + // list workspaces to make sure none were created + listCmd := &WorkspaceListCommand{} ui := new(cli.MockUi) listCmd.Meta = Meta{Ui: ui} @@ -141,7 +141,7 @@ func TestEnv_createInvalid(t *testing.T) { } } -func TestEnv_createWithState(t *testing.T) { +func TestWorkspace_createWithState(t *testing.T) { td := tempDir(t) os.MkdirAll(td, 0755) defer os.RemoveAll(td) @@ -171,7 +171,7 @@ func TestEnv_createWithState(t *testing.T) { args := []string{"-state", "test.tfstate", "test"} ui := new(cli.MockUi) - newCmd := &EnvNewCommand{ + newCmd := &WorkspaceNewCommand{ Meta: Meta{Ui: ui}, } if code := newCmd.Run(args); code != 0 { @@ -191,18 +191,18 @@ func TestEnv_createWithState(t *testing.T) { } } -func TestEnv_delete(t *testing.T) { +func TestWorkspace_delete(t *testing.T) { td := tempDir(t) os.MkdirAll(td, 0755) defer os.RemoveAll(td) defer testChdir(t, td)() - // create the env directories + // create the workspace directories if err := os.MkdirAll(filepath.Join(local.DefaultEnvDir, "test"), 0755); err != nil { t.Fatal(err) } - // create the environment file + // create the workspace file if err := os.MkdirAll(DefaultDataDir, 0755); err != nil { t.Fatal(err) } @@ -211,19 +211,19 @@ func TestEnv_delete(t *testing.T) { } ui := new(cli.MockUi) - delCmd := &EnvDeleteCommand{ + delCmd := &WorkspaceDeleteCommand{ Meta: Meta{Ui: ui}, } current := delCmd.Env() if current != "test" { - t.Fatal("wrong env:", current) + t.Fatal("wrong workspace:", current) } - // we can't delete out current environment + // we can't delete our current workspace args := []string{"test"} if code := delCmd.Run(args); code == 0 { - t.Fatal("expected error deleting current env") + t.Fatal("expected error deleting current workspace") } // change back to default @@ -235,21 +235,21 @@ func TestEnv_delete(t *testing.T) { ui = new(cli.MockUi) delCmd.Meta.Ui = ui if code := delCmd.Run(args); code != 0 { - t.Fatalf("error deleting env: %s", ui.ErrorWriter) + t.Fatalf("error deleting workspace: %s", ui.ErrorWriter) } current = delCmd.Env() if current != backend.DefaultStateName { - t.Fatalf("wrong env: %q", current) + t.Fatalf("wrong workspace: %q", current) } } -func TestEnv_deleteWithState(t *testing.T) { +func TestWorkspace_deleteWithState(t *testing.T) { td := tempDir(t) os.MkdirAll(td, 0755) defer os.RemoveAll(td) defer testChdir(t, td)() - // create the env directories + // create the workspace directories if err := os.MkdirAll(filepath.Join(local.DefaultEnvDir, "test"), 0755); err != nil { t.Fatal(err) } @@ -278,7 +278,7 @@ func TestEnv_deleteWithState(t *testing.T) { } ui := new(cli.MockUi) - delCmd := &EnvDeleteCommand{ + delCmd := &WorkspaceDeleteCommand{ Meta: Meta{Ui: ui}, } args := []string{"test"} diff --git a/command/env_delete.go b/command/workspace_delete.go similarity index 83% rename from command/env_delete.go rename to command/workspace_delete.go index 3975f9157..3d49cfc6e 100644 --- a/command/env_delete.go +++ b/command/workspace_delete.go @@ -10,16 +10,19 @@ import ( "github.com/mitchellh/cli" ) -type EnvDeleteCommand struct { +type WorkspaceDeleteCommand struct { Meta + LegacyName bool } -func (c *EnvDeleteCommand) Run(args []string) int { +func (c *WorkspaceDeleteCommand) Run(args []string) int { args = c.Meta.process(args, true) + envCommandShowWarning(c.Ui, c.LegacyName) + force := false - cmdFlags := c.Meta.flagSet("env") - cmdFlags.BoolVar(&force, "force", false, "force removal of a non-empty environment") + cmdFlags := c.Meta.flagSet("workspace") + cmdFlags.BoolVar(&force, "force", false, "force removal of a non-empty workspace") cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } if err := cmdFlags.Parse(args); err != nil { return 1 @@ -108,7 +111,7 @@ func (c *EnvDeleteCommand) Run(args []string) int { // Lock the state if we can lockInfo := state.NewLockInfo() - lockInfo.Operation = "env delete" + lockInfo.Operation = "workspace delete" lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, c.Ui, c.Colorize()) if err != nil { c.Ui.Error(fmt.Sprintf("Error locking state: %s", err)) @@ -139,20 +142,20 @@ func (c *EnvDeleteCommand) Run(args []string) int { return 0 } -func (c *EnvDeleteCommand) Help() string { +func (c *WorkspaceDeleteCommand) Help() string { helpText := ` -Usage: terraform env delete [OPTIONS] NAME [DIR] +Usage: terraform workspace delete [OPTIONS] NAME [DIR] - Delete a Terraform environment + Delete a Terraform workspace Options: - -force remove a non-empty environment. + -force remove a non-empty workspace. ` return strings.TrimSpace(helpText) } -func (c *EnvDeleteCommand) Synopsis() string { - return "Delete an environment" +func (c *WorkspaceDeleteCommand) Synopsis() string { + return "Delete a workspace" } diff --git a/command/env_list.go b/command/workspace_list.go similarity index 73% rename from command/env_list.go rename to command/workspace_list.go index 793afe9ba..f5b7b2855 100644 --- a/command/env_list.go +++ b/command/workspace_list.go @@ -6,14 +6,17 @@ import ( "strings" ) -type EnvListCommand struct { +type WorkspaceListCommand struct { Meta + LegacyName bool } -func (c *EnvListCommand) Run(args []string) int { +func (c *WorkspaceListCommand) Run(args []string) int { args = c.Meta.process(args, true) - cmdFlags := c.Meta.flagSet("env list") + envCommandShowWarning(c.Ui, c.LegacyName) + + cmdFlags := c.Meta.flagSet("workspace list") cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } if err := cmdFlags.Parse(args); err != nil { return 1 @@ -69,15 +72,15 @@ func (c *EnvListCommand) Run(args []string) int { return 0 } -func (c *EnvListCommand) Help() string { +func (c *WorkspaceListCommand) Help() string { helpText := ` -Usage: terraform env list [DIR] +Usage: terraform workspace list [DIR] - List Terraform environments. + List Terraform workspaces. ` return strings.TrimSpace(helpText) } -func (c *EnvListCommand) Synopsis() string { - return "List Environments" +func (c *WorkspaceListCommand) Synopsis() string { + return "List Workspaces" } diff --git a/command/env_new.go b/command/workspace_new.go similarity index 78% rename from command/env_new.go rename to command/workspace_new.go index 6c6f9cdd8..50846183c 100644 --- a/command/env_new.go +++ b/command/workspace_new.go @@ -12,16 +12,19 @@ import ( "github.com/mitchellh/cli" ) -type EnvNewCommand struct { +type WorkspaceNewCommand struct { Meta + LegacyName bool } -func (c *EnvNewCommand) Run(args []string) int { +func (c *WorkspaceNewCommand) Run(args []string) int { args = c.Meta.process(args, true) + envCommandShowWarning(c.Ui, c.LegacyName) + statePath := "" - cmdFlags := c.Meta.flagSet("env new") + cmdFlags := c.Meta.flagSet("workspace new") cmdFlags.StringVar(&statePath, "state", "", "terraform state file") cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } if err := cmdFlags.Parse(args); err != nil { @@ -40,8 +43,8 @@ func (c *EnvNewCommand) Run(args []string) int { return 1 } - // You can't ask to create an environment when you're overriding the - // environment name to be something different. + // You can't ask to create a workspace when you're overriding the + // workspace name to be something different. if current, isOverridden := c.EnvOverridden(); current != newEnv && isOverridden { c.Ui.Error(envIsOverriddenNewError) return 1 @@ -82,9 +85,9 @@ func (c *EnvNewCommand) Run(args []string) int { return 1 } - // now save the current env locally + // now set the current workspace locally if err := c.SetEnv(newEnv); err != nil { - c.Ui.Error(fmt.Sprintf("error saving new environment name: %s", err)) + c.Ui.Error(fmt.Sprintf("Error selecting new workspace: %s", err)) return 1 } @@ -109,7 +112,7 @@ func (c *EnvNewCommand) Run(args []string) int { // Lock the state if we can lockInfo := state.NewLockInfo() - lockInfo.Operation = "env new" + lockInfo.Operation = "workspace new" lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, c.Ui, c.Colorize()) if err != nil { c.Ui.Error(fmt.Sprintf("Error locking state: %s", err)) @@ -146,20 +149,20 @@ func (c *EnvNewCommand) Run(args []string) int { return 0 } -func (c *EnvNewCommand) Help() string { +func (c *WorkspaceNewCommand) Help() string { helpText := ` -Usage: terraform env new [OPTIONS] NAME [DIR] +Usage: terraform workspace new [OPTIONS] NAME [DIR] - Create a new Terraform environment. + Create a new Terraform workspace. Options: - -state=path Copy an existing state file into the new environment. + -state=path Copy an existing state file into the new workspace. ` return strings.TrimSpace(helpText) } -func (c *EnvNewCommand) Synopsis() string { - return "Create a new environment" +func (c *WorkspaceNewCommand) Synopsis() string { + return "Create a new workspace" } diff --git a/command/env_select.go b/command/workspace_select.go similarity index 76% rename from command/env_select.go rename to command/workspace_select.go index c2f69dc18..f2aa70330 100644 --- a/command/env_select.go +++ b/command/workspace_select.go @@ -7,14 +7,17 @@ import ( "github.com/mitchellh/cli" ) -type EnvSelectCommand struct { +type WorkspaceSelectCommand struct { Meta + LegacyName bool } -func (c *EnvSelectCommand) Run(args []string) int { +func (c *WorkspaceSelectCommand) Run(args []string) int { args = c.Meta.process(args, true) - cmdFlags := c.Meta.flagSet("env select") + envCommandShowWarning(c.Ui, c.LegacyName) + + cmdFlags := c.Meta.flagSet("workspace select") cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } if err := cmdFlags.Parse(args); err != nil { return 1 @@ -65,7 +68,7 @@ func (c *EnvSelectCommand) Run(args []string) int { } if name == current { - // already using this env + // already using this workspace return 0 } @@ -97,15 +100,15 @@ func (c *EnvSelectCommand) Run(args []string) int { return 0 } -func (c *EnvSelectCommand) Help() string { +func (c *WorkspaceSelectCommand) Help() string { helpText := ` -Usage: terraform env select NAME [DIR] +Usage: terraform workspace select NAME [DIR] - Change Terraform environment. + Select a different Terraform workspace. ` return strings.TrimSpace(helpText) } -func (c *EnvSelectCommand) Synopsis() string { - return "Change environments" +func (c *WorkspaceSelectCommand) Synopsis() string { + return "Select a workspace" } diff --git a/commands.go b/commands.go index 780b4652e..7e1468955 100644 --- a/commands.go +++ b/commands.go @@ -72,32 +72,37 @@ func init() { }, "env": func() (cli.Command, error) { - return &command.EnvCommand{ - Meta: meta, + return &command.WorkspaceCommand{ + Meta: meta, + LegacyName: true, }, nil }, "env list": func() (cli.Command, error) { - return &command.EnvListCommand{ - Meta: meta, + return &command.WorkspaceListCommand{ + Meta: meta, + LegacyName: true, }, nil }, "env select": func() (cli.Command, error) { - return &command.EnvSelectCommand{ - Meta: meta, + return &command.WorkspaceSelectCommand{ + Meta: meta, + LegacyName: true, }, nil }, "env new": func() (cli.Command, error) { - return &command.EnvNewCommand{ - Meta: meta, + return &command.WorkspaceNewCommand{ + Meta: meta, + LegacyName: true, }, nil }, "env delete": func() (cli.Command, error) { - return &command.EnvDeleteCommand{ - Meta: meta, + return &command.WorkspaceDeleteCommand{ + Meta: meta, + LegacyName: true, }, nil }, @@ -201,6 +206,36 @@ func init() { }, nil }, + "workspace": func() (cli.Command, error) { + return &command.WorkspaceCommand{ + Meta: meta, + }, nil + }, + + "workspace list": func() (cli.Command, error) { + return &command.WorkspaceListCommand{ + Meta: meta, + }, nil + }, + + "workspace select": func() (cli.Command, error) { + return &command.WorkspaceSelectCommand{ + Meta: meta, + }, nil + }, + + "workspace new": func() (cli.Command, error) { + return &command.WorkspaceNewCommand{ + Meta: meta, + }, nil + }, + + "workspace delete": func() (cli.Command, error) { + return &command.WorkspaceDeleteCommand{ + Meta: meta, + }, nil + }, + //----------------------------------------------------------- // Plumbing //-----------------------------------------------------------