diff --git a/cmd/kubectx/delete.go b/cmd/kubectx/delete.go index fe0277d..ade6f95 100644 --- a/cmd/kubectx/delete.go +++ b/cmd/kubectx/delete.go @@ -23,7 +23,7 @@ func (op DeleteOp) Run(_, stderr io.Writer) error { } if wasActiveContext { // TODO we don't always run as kubectx (sometimes "kubectl ctx") - printWarning(stderr,"You deleted the current context. use \"kubectx\" to select a different one.") + printWarning(stderr, "You deleted the current context. use \"kubectx\" to select a different one.") } printSuccess(stderr, "deleted context %q", deletedName) @@ -57,4 +57,3 @@ func deleteContext(name string) (deleteName string, wasActiveContext bool, err e } return name, wasActiveContext, errors.Wrap(kc.Save(), "failed to save kubeconfig file") } - diff --git a/cmd/kubectx/env.go b/cmd/kubectx/env.go new file mode 100644 index 0000000..0bbcda9 --- /dev/null +++ b/cmd/kubectx/env.go @@ -0,0 +1,26 @@ +package main + +import "os" + +const ( + // EnvFZFIgnore describes the environment variable to set to disable + // interactive context selection when fzf is installed. + EnvFZFIgnore = "KUBECTX_IGNORE_FZF" + + // EnvForceColor describes the environment variable to disable color usage + // when printing current context in a list. + EnvNoColor = `NO_COLOR` + + // EnvForceColor describes the "internal" environment variable to force + // color usage to show current context in a list. + EnvForceColor = `_KUBECTX_FORCE_COLOR` +) + +func useColors() bool { + if os.Getenv(EnvForceColor) != "" { + return true + } else if os.Getenv(EnvNoColor) != "" { + return false + } + return true +} diff --git a/cmd/kubectx/env_test.go b/cmd/kubectx/env_test.go new file mode 100644 index 0000000..5bac28e --- /dev/null +++ b/cmd/kubectx/env_test.go @@ -0,0 +1,44 @@ +package main + +import ( + "os" + "testing" +) + +func withTestVar(key, value string) func() { + orig, ok := os.LookupEnv(key) + os.Setenv(key, value) + return func() { + if ok { + os.Setenv(key, orig) + } else { + os.Unsetenv(key) + } + } +} + +func Test_useColors_forceColors(t *testing.T) { + defer withTestVar("_KUBECTX_FORCE_COLOR", "1")() + defer withTestVar("NO_COLOR", "1")() + + if !useColors() { + t.Fatal("expected useColors() = true") + } +} + +func Test_useColors_disableColors(t *testing.T) { + defer withTestVar("NO_COLOR", "1")() + + if useColors() { + t.Fatal("expected useColors() = false") + } +} + +func Test_useColors_default(t *testing.T) { + defer withTestVar("NO_COLOR", "")() + defer withTestVar("_KUBECTX_FORCE_COLOR", "")() + + if !useColors() { + t.Fatal("expected useColors() = true") + } +} diff --git a/cmd/kubectx/flags.go b/cmd/kubectx/flags.go index bc5a2aa..11603c9 100644 --- a/cmd/kubectx/flags.go +++ b/cmd/kubectx/flags.go @@ -23,7 +23,7 @@ func (op UnsupportedOp) Run(_, _ io.Writer) error { // and decides which operation should be taken. func parseArgs(argv []string) Op { if len(argv) == 0 { - if isInteractiveMode(os.Stdout){ + if isInteractiveMode(os.Stdout) { return InteractiveSwitchOp{SelfCmd: os.Args[0]} } return ListOp{} diff --git a/cmd/kubectx/flags_test.go b/cmd/kubectx/flags_test.go index 3ca5477..6c6128c 100644 --- a/cmd/kubectx/flags_test.go +++ b/cmd/kubectx/flags_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/pkg/errors" ) func Test_parseArgs_new(t *testing.T) { @@ -59,7 +60,7 @@ func Test_parseArgs_new(t *testing.T) { want: RenameOp{"a", "."}}, {name: "unrecognized flag", args: []string{"-x"}, - want: UnsupportedOp{Args: []string{"-x"}}}, + want: UnsupportedOp{Err: errors.Errorf("unsupported option \"-x\"")}}, // TODO add more UnsupportedOp cases // TODO consider these cases diff --git a/cmd/kubectx/fzf.go b/cmd/kubectx/fzf.go index c02f241..4d466f8 100644 --- a/cmd/kubectx/fzf.go +++ b/cmd/kubectx/fzf.go @@ -13,10 +13,6 @@ import ( "github.com/mattn/go-isatty" ) -const ( - envFZFIgnore = "KUBECTX_IGNORE_FZF" -) - type InteractiveSwitchOp struct { SelfCmd string } @@ -30,7 +26,7 @@ func (op InteractiveSwitchOp) Run(_, stderr io.Writer) error { cmd.Env = append(os.Environ(), fmt.Sprintf("FZF_DEFAULT_COMMAND=%s", op.SelfCmd), - fmt.Sprintf("%s=1", envForceColor)) + fmt.Sprintf("%s=1", EnvForceColor)) if err := cmd.Run(); err != nil { if _, ok := err.(*exec.ExitError); !ok { return err @@ -64,6 +60,6 @@ func fzfInstalled() bool { // isInteractiveMode determines if we can do choosing with fzf. func isInteractiveMode(stdout *os.File) bool { - v := os.Getenv(envFZFIgnore) + v := os.Getenv(EnvFZFIgnore) return v == "" && isTerminal(stdout) && fzfInstalled() } diff --git a/cmd/kubectx/help_test.go b/cmd/kubectx/help_test.go index b8702e7..544939a 100644 --- a/cmd/kubectx/help_test.go +++ b/cmd/kubectx/help_test.go @@ -8,7 +8,9 @@ import ( func TestPrintHelp(t *testing.T) { var buf bytes.Buffer - printHelp(&buf) + if err := (&HelpOp{}).Run(&buf, &buf); err != nil { + t.Fatal(err) + } out := buf.String() if !strings.Contains(out, "USAGE:") { diff --git a/cmd/kubectx/kubeconfig.go b/cmd/kubectx/kubeconfig.go index 91ce5e4..dcca8a3 100644 --- a/cmd/kubectx/kubeconfig.go +++ b/cmd/kubectx/kubeconfig.go @@ -15,13 +15,13 @@ var ( type StandardKubeconfigLoader struct{} -type kubeconfigFile struct { *os.File } +type kubeconfigFile struct{ *os.File } func (kf *kubeconfigFile) Reset() error { - if err := kf.Truncate(0);err!= nil { + if err := kf.Truncate(0); err != nil { return errors.Wrap(err, "failed to truncate file") } - _, err := kf.Seek(0,0) + _, err := kf.Seek(0, 0) return errors.Wrap(err, "failed to seek in file") } diff --git a/cmd/kubectx/kubeconfig/contextmodify_test.go b/cmd/kubectx/kubeconfig/contextmodify_test.go index 1449df4..812b024 100644 --- a/cmd/kubectx/kubeconfig/contextmodify_test.go +++ b/cmd/kubectx/kubeconfig/contextmodify_test.go @@ -46,7 +46,7 @@ func TestKubeconfig_DeleteContextEntry(t *testing.T) { expected := "contexts: [{name: c2}, {name: c3}]\n" out := test.out.String() - if diff := cmp.Diff(expected,out); diff != "" { + if diff := cmp.Diff(expected, out); diff != "" { t.Fatalf("diff: %s", diff) } } @@ -67,9 +67,9 @@ field1: value1`)} } expected := `current-context: foo -field1: value1`+"\n" +field1: value1` + "\n" out := test.out.String() - if diff := cmp.Diff(expected,out); diff != "" { + if diff := cmp.Diff(expected, out); diff != "" { t.Fatalf("diff: %s", diff) } } @@ -90,7 +90,7 @@ func TestKubeconfig_ModifyCurrentContext_fieldMissing(t *testing.T) { expected := `field1: value1` + "\n" + "current-context: foo\n" out := test.out.String() - if diff := cmp.Diff(expected,out); diff != "" { + if diff := cmp.Diff(expected, out); diff != "" { t.Fatalf("diff: %s", diff) } } @@ -123,7 +123,7 @@ func TestKubeconfig_ModifyContextName(t *testing.T) { expected := "contexts: [{name: ccc}, {name: c2}, {name: c3}]\n" out := test.out.String() - if diff := cmp.Diff(expected,out); diff != "" { + if diff := cmp.Diff(expected, out); diff != "" { t.Fatalf("diff: %s", diff) } } diff --git a/cmd/kubectx/kubeconfig/currentcontext.go b/cmd/kubectx/kubeconfig/currentcontext.go index 7225591..131851e 100644 --- a/cmd/kubectx/kubeconfig/currentcontext.go +++ b/cmd/kubectx/kubeconfig/currentcontext.go @@ -2,7 +2,7 @@ package kubeconfig // GetCurrentContext returns "current-context" value in given // kubeconfig object Node, or returns "" if not found. -func (k *Kubeconfig) GetCurrentContext() string { +func (k *Kubeconfig) GetCurrentContext() string { v := valueOf(k.rootNode, "current-context") if v == nil { return "" diff --git a/cmd/kubectx/kubeconfig/kubeconfig.go b/cmd/kubectx/kubeconfig/kubeconfig.go index 0f5ff06..098e400 100644 --- a/cmd/kubectx/kubeconfig/kubeconfig.go +++ b/cmd/kubectx/kubeconfig/kubeconfig.go @@ -7,7 +7,7 @@ import ( "gopkg.in/yaml.v3" ) -type ReadWriteResetCloser interface{ +type ReadWriteResetCloser interface { io.ReadWriteCloser // Reset truncates the file and seeks to the beginning of the file. @@ -19,9 +19,9 @@ type Loader interface { } type Kubeconfig struct { - loader Loader + loader Loader - f ReadWriteResetCloser + f ReadWriteResetCloser rootNode *yaml.Node } diff --git a/cmd/kubectx/kubeconfig_test.go b/cmd/kubectx/kubeconfig_test.go index a1ff3fa..ea7bf2c 100644 --- a/cmd/kubectx/kubeconfig_test.go +++ b/cmd/kubectx/kubeconfig_test.go @@ -19,7 +19,7 @@ func Test_kubeconfigPath_homePath(t *testing.T) { } expected := filepath.Join(filepath.FromSlash("/foo/bar"), ".kube", "config") - if got != expected{ + if got != expected { t.Fatalf("wrong value: expected=%s got=%s", expected, got) } } @@ -36,7 +36,7 @@ func Test_kubeconfigPath_userprofile(t *testing.T) { } expected := filepath.Join(filepath.FromSlash("/foo/bar"), ".kube", "config") - if got != expected{ + if got != expected { t.Fatalf("wrong value: expected=%s got=%s", expected, got) } } @@ -60,19 +60,23 @@ func Test_kubeconfigPath_envOvveride(t *testing.T) { defer os.Unsetenv("KUBECONFIG") v, err := kubeconfigPath() - if err != nil { t.Fatal(err)} + if err != nil { + t.Fatal(err) + } if expected := "foo"; v != expected { t.Fatalf("expected=%q, got=%q", expected, v) } } func Test_kubeconfigPath_envOvverideDoesNotSupportPathSeparator(t *testing.T) { - path := strings.Join([]string{"file1","file2"}, string(os.PathListSeparator)) + path := strings.Join([]string{"file1", "file2"}, string(os.PathListSeparator)) os.Setenv("KUBECONFIG", path) defer os.Unsetenv("KUBECONFIG") _, err := kubeconfigPath() - if err == nil { t.Fatal("expected error")} + if err == nil { + t.Fatal("expected error") + } } func testfile(t *testing.T, contents string) (path string, cleanup func()) { diff --git a/cmd/kubectx/list.go b/cmd/kubectx/list.go index 1ed785b..6e0d46f 100644 --- a/cmd/kubectx/list.go +++ b/cmd/kubectx/list.go @@ -3,7 +3,6 @@ package main import ( "fmt" "io" - "os" "facette.io/natsort" "github.com/fatih/color" @@ -29,13 +28,13 @@ func (_ ListOp) Run(stdout, _ io.Writer) error { // TODO support KUBECTX_CURRENT_BGCOLOR currentColor := color.New(color.FgGreen, color.Bold) - if useColors(){ + if useColors() { currentColor.EnableColor() } else { currentColor.DisableColor() } - cur := kc.GetCurrentContext() + cur := kc.GetCurrentContext() for _, c := range ctxs { s := c if c == cur { @@ -45,17 +44,3 @@ func (_ ListOp) Run(stdout, _ io.Writer) error { } return nil } - -const ( - envForceColor = `_KUBECTX_FORCE_COLOR` - envNoColor = `NO_COLOR` -) - -func useColors() bool { - if os.Getenv(envForceColor) != "" { - return true - } else if os.Getenv(envNoColor) != "" { - return false - } - return true -} diff --git a/cmd/kubectx/main.go b/cmd/kubectx/main.go index fed54e4..45767fd 100644 --- a/cmd/kubectx/main.go +++ b/cmd/kubectx/main.go @@ -30,4 +30,3 @@ func printWarning(w io.Writer, format string, args ...interface{}) { func printSuccess(w io.Writer, format string, args ...interface{}) { fmt.Fprintf(w, color.GreenString(fmt.Sprintf(format+"\n", args...))) } - diff --git a/cmd/kubectx/rename.go b/cmd/kubectx/rename.go index 3f9ca82..680f362 100644 --- a/cmd/kubectx/rename.go +++ b/cmd/kubectx/rename.go @@ -48,7 +48,7 @@ func (op RenameOp) Run(_, stderr io.Writer) error { return errors.Errorf("context %q not found, can't rename it", op.Old) } - if kc.ContextExists( op.New) { + if kc.ContextExists(op.New) { printWarning(stderr, "context %q exists, overwriting it.", op.New) if err := kc.DeleteContextEntry(op.New); err != nil { return errors.Wrap(err, "failed to delete new context to overwrite it") @@ -59,7 +59,7 @@ func (op RenameOp) Run(_, stderr io.Writer) error { return errors.Wrap(err, "failed to change context name") } if op.New == cur { - if err := kc.ModifyCurrentContext( op.New); err != nil { + if err := kc.ModifyCurrentContext(op.New); err != nil { return errors.Wrap(err, "failed to set current-context to new name") } } @@ -69,4 +69,3 @@ func (op RenameOp) Run(_, stderr io.Writer) error { printSuccess(stderr, "Context %q renamed to %q.", op.Old, op.New) return nil } - diff --git a/cmd/kubectx/switch.go b/cmd/kubectx/switch.go index ef78ceb..945f8db 100644 --- a/cmd/kubectx/switch.go +++ b/cmd/kubectx/switch.go @@ -60,7 +60,6 @@ func switchContext(name string) (string, error) { return name, nil } - // swapContext switches to previously switch context. func swapContext() (string, error) { prevCtxFile, err := kubectxPrevCtxFile() diff --git a/cmd/kubectx/unset.go b/cmd/kubectx/unset.go index 816bb40..a3c4377 100644 --- a/cmd/kubectx/unset.go +++ b/cmd/kubectx/unset.go @@ -29,4 +29,3 @@ func (_ UnsetOp) Run(_, stderr io.Writer) error { _, err := fmt.Fprintln(stderr, "Successfully unset the current context") return err } -