diff --git a/cmd/kubectx/fzf.go b/cmd/kubectx/fzf.go index bd4f462..6943a02 100644 --- a/cmd/kubectx/fzf.go +++ b/cmd/kubectx/fzf.go @@ -13,6 +13,7 @@ import ( "github.com/mattn/go-isatty" "github.com/ahmetb/kubectx/internal/env" + "github.com/ahmetb/kubectx/internal/kubeconfig" "github.com/ahmetb/kubectx/internal/printer" ) @@ -21,6 +22,17 @@ type InteractiveSwitchOp struct { } func (op InteractiveSwitchOp) Run(_, stderr io.Writer) error { + // parse kubeconfig just to see if it can be loaded + kc := new(kubeconfig.Kubeconfig).WithLoader(defaultLoader) + if err := kc.Parse(); err != nil { + if isENOENT(err) { + printer.Warning(stderr, "kubeconfig file not found") + return nil + } + return errors.Wrap(err, "kubeconfig error") + } + kc.Close() + cmd := exec.Command("fzf", "--ansi", "--no-preview") var out bytes.Buffer cmd.Stdin = os.Stdin diff --git a/cmd/kubectx/kubeconfig.go b/cmd/kubectx/kubeconfig.go index beac789..d3d5e05 100644 --- a/cmd/kubectx/kubeconfig.go +++ b/cmd/kubectx/kubeconfig.go @@ -33,7 +33,7 @@ func (*StandardKubeconfigLoader) Load() (kubeconfig.ReadWriteResetCloser, error) f, err := os.OpenFile(cfgPath, os.O_RDWR, 0) if err != nil { if os.IsNotExist(err) { - return nil, errors.Errorf("kubeconfig file not found at %s", cfgPath) + return nil, errors.Wrap(err, "kubeconfig file not found") } return nil, errors.Wrap(err, "failed to open file") } diff --git a/cmd/kubectx/kubeconfig_test.go b/cmd/kubectx/kubeconfig_test.go index 1630b32..cc396bd 100644 --- a/cmd/kubectx/kubeconfig_test.go +++ b/cmd/kubectx/kubeconfig_test.go @@ -6,8 +6,9 @@ import ( "path/filepath" "strings" "testing" -) + "github.com/ahmetb/kubectx/internal/kubeconfig" +) func withTestVar(key, value string) func() { // TODO(ahmetb) this method is currently duplicated @@ -131,6 +132,18 @@ func Test_kubeconfigPath_envOvverideDoesNotSupportPathSeparator(t *testing.T) { } } +func TestStandardKubeconfigLoader_returnsNotFoundErr(t *testing.T) { + defer withTestVar("KUBECONFIG", "foo")() + kc := new(kubeconfig.Kubeconfig).WithLoader(defaultLoader) + err := kc.Parse() + if err == nil { + t.Fatal("expected err") + } + if !isENOENT(err) { + t.Fatalf("expected ENOENT error; got=%v", err) + } +} + func testfile(t *testing.T, contents string) (path string, cleanup func()) { t.Helper() diff --git a/cmd/kubectx/list.go b/cmd/kubectx/list.go index e1a9530..e39d063 100644 --- a/cmd/kubectx/list.go +++ b/cmd/kubectx/list.go @@ -3,6 +3,7 @@ package main import ( "fmt" "io" + "os" "facette.io/natsort" "github.com/fatih/color" @@ -15,10 +16,14 @@ import ( // ListOp describes listing contexts. type ListOp struct{} -func (_ ListOp) Run(stdout, _ io.Writer) error { +func (_ ListOp) Run(stdout, stderr io.Writer) error { kc := new(kubeconfig.Kubeconfig).WithLoader(defaultLoader) defer kc.Close() if err := kc.Parse(); err != nil { + if isENOENT(err) { + printer.Warning(stderr, "kubeconfig file not found") + return nil + } return errors.Wrap(err, "kubeconfig error") } @@ -45,3 +50,14 @@ func (_ ListOp) Run(stdout, _ io.Writer) error { } return nil } + +// isENOENT determines if the underlying error is os.IsNotExist. Right now +// errors from github.com/pkg/errors doesn't work with os.IsNotExist. +func isENOENT(err error) bool { + for e := err; e != nil; e = errors.Unwrap(e) { + if os.IsNotExist(e) { + return true + } + } + return false +} diff --git a/go.mod b/go.mod index 808bf9d..0d7c924 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,6 @@ require ( github.com/fatih/color v1.9.0 github.com/google/go-cmp v0.4.0 github.com/mattn/go-isatty v0.0.12 - github.com/mattn/go-tty v0.0.3 // indirect github.com/pkg/errors v0.9.1 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c ) diff --git a/test/kubectx.bats b/test/kubectx.bats index 220f510..bacb82a 100644 --- a/test/kubectx.bats +++ b/test/kubectx.bats @@ -1,6 +1,6 @@ #!/usr/bin/env bats -COMMAND="$BATS_TEST_DIRNAME/../kubectx" +COMMAND="${COMMAND:-$BATS_TEST_DIRNAME/../kubectx}" load common @@ -29,7 +29,7 @@ load common run ${COMMAND} echo "$output" [ "$status" -eq 0 ] - [[ "$output" = "" ]] + [[ "$output" = "warning: kubeconfig file not found" ]] } @test "get one context and list contexts" { diff --git a/test/kubens.bats b/test/kubens.bats index a439d86..6bbcb09 100644 --- a/test/kubens.bats +++ b/test/kubens.bats @@ -1,6 +1,6 @@ #!/usr/bin/env bats -COMMAND="${BATS_TEST_DIRNAME}/../kubens" +COMMAND="${COMMAND:-$BATS_TEST_DIRNAME/../kubens}" export KUBECTL="$BATS_TEST_DIRNAME/../test/mock-kubectl" load common