chore: list command namespace (#1370)

* chore: list command namespace

- Adds namespace test to list command
- Moves namespace flag into list command for
  - Better help text
  - Easier testing
- Sets static default namespace for flag to "default"

* regen docs

* list test default from kubeconfig
This commit is contained in:
Luke Kingland 2022-11-01 04:59:13 +09:00 committed by GitHub
parent 7e75157373
commit f9dc8b659f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 107 additions and 23 deletions

View File

@ -14,6 +14,7 @@ import (
"gopkg.in/yaml.v2"
fn "knative.dev/func"
"knative.dev/func/config"
)
func NewListCmd(newClient ClientFactory) *cobra.Command {
@ -35,12 +36,18 @@ Lists all deployed functions in a given namespace.
{{.Name}} list --all-namespaces --output json
`,
SuggestFor: []string{"ls", "lsit"},
PreRunE: bindEnv("all-namespaces", "output"),
PreRunE: bindEnv("all-namespaces", "output", "namespace"),
}
// Config
cfg, err := config.NewDefault()
if err != nil {
fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.File(), err)
}
// Flags
cmd.Flags().BoolP("all-namespaces", "A", false, "List functions in all namespaces. If set, the --namespace flag is ignored.")
cmd.Flags().StringP("namespace", "n", "", "The namespace for which to list functions. (Env: $FUNC_NAMESPACE)")
cmd.Flags().StringP("namespace", "n", cfg.Namespace, "The namespace for which to list functions. (Env: $FUNC_NAMESPACE)")
cmd.Flags().StringP("output", "o", "human", "Output format (human|plain|json|xml|yaml) (Env: $FUNC_OUTPUT)")
if err := cmd.RegisterFlagCompletionFunc("output", CompleteOutputFormatList); err != nil {
@ -57,13 +64,13 @@ Lists all deployed functions in a given namespace.
}
func runList(cmd *cobra.Command, _ []string, newClient ClientFactory) (err error) {
config := newListConfig()
cfg := newListConfig()
if err := config.Validate(); err != nil {
if err := cfg.Validate(cmd); err != nil {
return err
}
client, done := newClient(ClientConfig{Namespace: config.Namespace, Verbose: config.Verbose})
client, done := newClient(ClientConfig{Namespace: cfg.Namespace, Verbose: cfg.Verbose})
defer done()
items, err := client.List(cmd.Context())
@ -72,18 +79,15 @@ func runList(cmd *cobra.Command, _ []string, newClient ClientFactory) (err error
}
if len(items) == 0 {
// TODO(lkingland): this isn't particularly script friendly. Suggest this
// prints bo only on --verbose. Possible future tweak, as I don't want to
// make functional changes during a refactor.
if config.Namespace != "" && !config.AllNamespaces {
fmt.Printf("no functions found in namespace '%v'\n", config.Namespace)
if cfg.Namespace != "" {
fmt.Printf("no functions found in namespace '%v'\n", cfg.Namespace)
} else {
fmt.Println("no functions found")
}
return
}
write(os.Stdout, listItems(items), config.Output)
write(os.Stdout, listItems(items), cfg.Output)
return
}
@ -92,23 +96,28 @@ func runList(cmd *cobra.Command, _ []string, newClient ClientFactory) (err error
// ------------------------------
type listConfig struct {
Namespace string
Output string
AllNamespaces bool
Verbose bool
Namespace string
Output string
Verbose bool
}
func newListConfig() listConfig {
return listConfig{
Namespace: viper.GetString("namespace"),
Output: viper.GetString("output"),
AllNamespaces: viper.GetBool("all-namespaces"),
Verbose: viper.GetBool("verbose"),
c := listConfig{
Namespace: viper.GetString("namespace"),
Output: viper.GetString("output"),
Verbose: viper.GetBool("verbose"),
}
// Lister instantiated by newClient explicitly expects "" namespace to
// inidicate it should list from all namespaces, so remove default "default"
// when -A.
if viper.GetBool("all-namespaces") {
c.Namespace = ""
}
return c
}
func (c listConfig) Validate() error {
if c.Namespace != "" && c.AllNamespaces {
func (c listConfig) Validate(cmd *cobra.Command) error {
if cmd.Flags().Changed("namespace") && viper.GetBool("all-namespaces") {
return errors.New("Both --namespace and --all-namespaces specified.")
}
return nil

75
cmd/list_test.go Normal file
View File

@ -0,0 +1,75 @@
package cmd
import (
"testing"
fn "knative.dev/func"
"knative.dev/func/mock"
)
// TestList_Namespace ensures that list command options for specifying a
// namespace (--namespace) or all namespaces (--all-namespacs) are properly
// evaluated.
func TestList_Namespace(t *testing.T) {
_ = fromTempDirectory(t)
tests := []struct {
name string
all bool // --all-namespaces
namespace string // use specific namespace
expected string // expected
err bool // expected error
}{
{
name: "default",
expected: "func", // see ./testdata/default_kubeconfig
},
{
name: "namespace provided",
namespace: "ns",
expected: "ns",
},
{
name: "all namespaces",
all: true,
expected: "", // blank is implemented by lister as meaning all
},
{
name: "both flags error",
namespace: "ns",
all: true,
err: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
var (
lister = mock.NewLister()
client = fn.New(fn.WithLister(lister))
)
cmd := NewListCmd(func(cc ClientConfig, options ...fn.Option) (*fn.Client, func()) {
if cc.Namespace != test.expected {
t.Fatalf("expected '%v', got '%v'", test.expected, cc.Namespace)
}
return client, func() {}
})
args := []string{}
if test.namespace != "" {
args = append(args, "--namespace", test.namespace)
}
if test.all {
args = append(args, "-A")
}
cmd.SetArgs(args)
err := cmd.Execute()
if err != nil && !test.err {
// TODO: typed error for --namespace with -A. Perhaps ErrFlagConflict?
t.Fatalf("unexpected error: %v", err)
}
if err == nil && test.err {
t.Fatalf("did not receive expected error ")
}
})
}
}

View File

@ -33,7 +33,7 @@ func list --all-namespaces --output json
```
-A, --all-namespaces List functions in all namespaces. If set, the --namespace flag is ignored.
-h, --help help for list
-n, --namespace string The namespace for which to list functions. (Env: $FUNC_NAMESPACE)
-n, --namespace string The namespace for which to list functions. (Env: $FUNC_NAMESPACE) (default "default")
-o, --output string Output format (human|plain|json|xml|yaml) (Env: $FUNC_OUTPUT) (default "human")
```