mirror of https://github.com/hashicorp/terraform
Refactor `workspace list` human output to use a views-like architecture, so adding JSON output is possible without breaking changes (#38392)
* test: Add a test that asserts human output from workspace commands with colour enabled or disabled * refactor: Update `workspace list` to use cli.Ui in a Views-like way for human output. Update how output is returned by the command to use a single List method. * refactor: Make `workspace list` command parse its arguments using the `arguments` package * refactor: Replace use of `ModulePath` with ` c.WorkingDir.RootModuleDir()` to separate concerns * test: Update tests that feature the `workspace list` command to include a WorkingDir value. This is necessary after the changes in b32b60f6a7854c8f891ef2d78fd02536093ad590 * feat: Detect unexpected arguments and flags using the arguments package. * refactor: Remove duplicate call to c.View.Configure, add code comments explaining code. * fix: Make sure argument parsing errors are handled as soon as the view is usable. * test: Update TestWorkspace_extraArgError to account for new validation via the arguments package * fix: Update outdated copyright headers * test: Update test name * refactor: Reintroduce the old behaviour when unexpected positional arguments were present by using a specific ParseWorkspaceList methodpull/38375/merge
parent
a28750d8d1
commit
c975e0cd78
@ -0,0 +1,47 @@
|
||||
// Copyright IBM Corp. 2014, 2026
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
// Workspace represents the command-line arguments common between all workspace subcommands.
|
||||
//
|
||||
// Subcommands that accept additional arguments should have a specific struct that embeds this struct.
|
||||
type Workspace struct {
|
||||
// ViewType specifies which output format to use
|
||||
ViewType ViewType
|
||||
}
|
||||
|
||||
type WorkspaceList struct {
|
||||
Workspace
|
||||
}
|
||||
|
||||
// ParseWorkspaceList processes CLI arguments, returning a WorkspaceList value and errors.
|
||||
// If errors are encountered, an WorkspaceList value is still returned representing
|
||||
// the best effort interpretation of the arguments.
|
||||
func ParseWorkspaceList(args []string) (*WorkspaceList, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
cmdFlags := defaultFlagSet("workspace list")
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
err.Error(),
|
||||
))
|
||||
}
|
||||
|
||||
// `workspace list` takes no positional arguments. Historically there was a DIR argument that was replaced with the -chdir flag.
|
||||
// Here we replicate the old behaviour of suggesting the user to use -chdir if they provide any positional arguments.
|
||||
args = cmdFlags.Args()
|
||||
if len(args) != 0 {
|
||||
diags = diags.Append(errors.New("Too many command line arguments. Did you mean to use -chdir?"))
|
||||
}
|
||||
|
||||
return &WorkspaceList{Workspace: Workspace{ViewType: ViewHuman}}, diags
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
// Copyright IBM Corp. 2014, 2026
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package arguments
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
func TestParseWorkspaceList_valid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *WorkspaceList
|
||||
}{
|
||||
"defaults": {
|
||||
nil,
|
||||
&WorkspaceList{
|
||||
Workspace: Workspace{
|
||||
ViewType: ViewHuman,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, diags := ParseWorkspaceList(tc.args)
|
||||
if len(diags) > 0 {
|
||||
t.Fatalf("unexpected diags: %v", diags)
|
||||
}
|
||||
if *got != *tc.want {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseWorkspaceList_invalid(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
args []string
|
||||
want *WorkspaceList
|
||||
wantDiags tfdiags.Diagnostics
|
||||
}{
|
||||
"unknown flag": {
|
||||
[]string{"-boop"},
|
||||
&WorkspaceList{
|
||||
Workspace: Workspace{
|
||||
ViewType: ViewHuman,
|
||||
},
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to parse command-line flags",
|
||||
"flag provided but not defined: -boop",
|
||||
),
|
||||
},
|
||||
},
|
||||
"too many arguments": {
|
||||
[]string{"bar", "baz"},
|
||||
&WorkspaceList{
|
||||
Workspace: Workspace{
|
||||
ViewType: ViewHuman,
|
||||
},
|
||||
},
|
||||
tfdiags.Diagnostics{
|
||||
tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Too many command line arguments. Did you mean to use -chdir?",
|
||||
"", // No detail
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got, gotDiags := ParseWorkspaceList(tc.args)
|
||||
if *got != *tc.want {
|
||||
t.Fatalf("unexpected result\n got: %#v\nwant: %#v", got, tc.want)
|
||||
}
|
||||
tfdiags.AssertDiagnosticsMatch(t, gotDiags, tc.wantDiags)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
// Copyright IBM Corp. 2014, 2026
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package views
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
// The WorkspaceList view is used for the `workspace list` subcommand.
|
||||
type WorkspaceList interface {
|
||||
List(selected string, list []string, diags tfdiags.Diagnostics)
|
||||
}
|
||||
Loading…
Reference in new issue