mirror of
https://github.com/ahmetb/kubectx.git
synced 2025-06-21 21:24:24 +00:00
Extract env vars to a file + test
Signed-off-by: Ahmet Alp Balkan <ahmetb@google.com>
This commit is contained in:
parent
91e00f9867
commit
37ba52f357
@ -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")
|
||||
}
|
||||
|
||||
|
26
cmd/kubectx/env.go
Normal file
26
cmd/kubectx/env.go
Normal file
@ -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
|
||||
}
|
44
cmd/kubectx/env_test.go
Normal file
44
cmd/kubectx/env_test.go
Normal file
@ -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")
|
||||
}
|
||||
}
|
@ -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{}
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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:") {
|
||||
|
@ -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")
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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 ""
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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...)))
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -29,4 +29,3 @@ func (_ UnsetOp) Run(_, stderr io.Writer) error {
|
||||
_, err := fmt.Fprintln(stderr, "Successfully unset the current context")
|
||||
return err
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user