From 142282b584bdf5f579e4571703defb3a18e535f2 Mon Sep 17 00:00:00 2001 From: Fernand Galiana Date: Wed, 9 Apr 2025 23:58:37 -0600 Subject: [PATCH] Rel v0.50.1 - HotFix ;( (#3263) * v0.50.0 hotfix * rel notes --- Makefile | 2 +- change_logs/release_v0.50.1.md | 42 ++++++++++++++++ internal/client/gvr.go | 4 ++ internal/config/alias.go | 27 +++++++---- internal/config/config_test.go | 38 +++++++++------ internal/config/data/context_test.go | 4 +- internal/config/k9s.go | 4 +- internal/config/k9s_test.go | 4 +- internal/config/mock/test_helpers.go | 10 ++-- internal/dao/alias.go | 16 ++----- internal/dao/alias_test.go | 23 ++++++++- internal/render/pod.go | 28 ++--------- internal/ui/app_test.go | 12 ++--- internal/ui/config_test.go | 2 +- internal/ui/flash_test.go | 2 +- internal/ui/indicator_test.go | 8 ++-- internal/view/alias_test.go | 10 ++-- internal/view/app.go | 2 +- internal/view/app_test.go | 2 +- internal/view/cm_test.go | 2 +- internal/view/cmd/interpreter.go | 4 ++ internal/view/command.go | 9 +--- internal/view/command_test.go | 71 ++++++++++++++++++++++++++++ internal/view/container_test.go | 2 +- internal/view/context_test.go | 2 +- internal/view/dir_test.go | 2 +- internal/view/dp_test.go | 2 +- internal/view/ds_test.go | 2 +- internal/view/exec.go | 5 ++ internal/view/help_test.go | 2 +- internal/view/helpers_test.go | 2 +- internal/view/live_view_test.go | 2 +- internal/view/log_int_test.go | 10 ++-- internal/view/log_test.go | 16 +++---- internal/view/ns.go | 2 +- internal/view/ns_test.go | 2 +- internal/view/pf_test.go | 2 +- internal/view/pod_test.go | 6 +-- internal/view/priorityclass_test.go | 2 +- internal/view/pvc_test.go | 2 +- internal/view/rbac_test.go | 2 +- internal/view/reference.go | 2 +- internal/view/reference_test.go | 2 +- internal/view/screen_dump_test.go | 2 +- internal/view/secret_test.go | 2 +- internal/view/sts_test.go | 2 +- internal/view/svc_test.go | 2 +- internal/view/table_int_test.go | 12 ++--- internal/view/workload.go | 2 +- snap/snapcraft.yaml | 2 +- 50 files changed, 277 insertions(+), 142 deletions(-) create mode 100644 change_logs/release_v0.50.1.md create mode 100644 internal/view/command_test.go diff --git a/Makefile b/Makefile index 2a42a91a..99c87e6f 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ DATE ?= $(shell TZ=UTC date -j -f "%s" ${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H: else DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ") endif -VERSION ?= v0.50.0 +VERSION ?= v0.50.1 IMG_NAME := derailed/k9s IMAGE := ${IMG_NAME}:${VERSION} diff --git a/change_logs/release_v0.50.1.md b/change_logs/release_v0.50.1.md new file mode 100644 index 00000000..32f707a2 --- /dev/null +++ b/change_logs/release_v0.50.1.md @@ -0,0 +1,42 @@ + + +# Release v0.51 + +## Notes + +Thank you to all that contributed with flushing out issues and enhancements for K9s! +I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev +and see if we're happier with some of the fixes! +If you've filed an issue please help me verify and close. + +Your support, kindness and awesome suggestions to make K9s better are, as ever, very much noted and appreciated! +Also big thanks to all that have allocated their own time to help others on both slack and on this repo!! + +As you may know, K9s is not pimped out by corps with deep pockets, thus if you feel K9s is helping your Kubernetes journey, +please consider joining our [sponsorship program](https://github.com/sponsors/derailed) and/or make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer) + +On Slack? Please join us [K9slackers](https://join.slack.com/t/k9sers/shared_invite/enQtOTA5MDEyNzI5MTU0LWQ1ZGI3MzliYzZhZWEyNzYxYzA3NjE0YTk1YmFmNzViZjIyNzhkZGI0MmJjYzhlNjdlMGJhYzE2ZGU1NjkyNTM) + +## 5-0, 5-0 HotFix! + +It looks like we've broken a few things in the clean up process 😳 +Apologizes for the `disruption in the farce`. Hopefully happier on v0.50.1... +Crossing fingers and toes! + +☠️ Careful on this upgrade! 🏴‍☠️ +We've gone thru lots of code revamp/refactor in the v0.50.0, so mileage may vary... + +--- + +## Resolved Issues + +* [#3262](https://github.com/derailed/k9s/issues/3262) Crash when no shellPod is defined in config file +* [#3261](https://github.com/derailed/k9s/issues/3261) aliases with namespace and/or labels produce an error +* [#3258](https://github.com/derailed/k9s/issues/3258) mac silicon 0.50.0 runtime error +* [#3257](https://github.com/derailed/k9s/issues/3257) pods are reported to run on nodes they are not running on +* [#3256](https://github.com/derailed/k9s/issues/3256) Pods view seems broken in 0.50.0 +* [#3255](https://github.com/derailed/k9s/issues/3255) Custom view does not work randomly + + +--- + © 2025 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0) \ No newline at end of file diff --git a/internal/client/gvr.go b/internal/client/gvr.go index f1ea041c..f8f944b6 100644 --- a/internal/client/gvr.go +++ b/internal/client/gvr.go @@ -71,6 +71,10 @@ func NewGVR(path string) *GVR { return &gvr } +func (g *GVR) IsCommand() bool { + return g != nil && strings.Contains(g.raw, " ") +} + func (g *GVR) IsK8sRes() bool { return strings.Contains(g.raw, "/") } diff --git a/internal/config/alias.go b/internal/config/alias.go index 05d85cdd..2f506ff6 100644 --- a/internal/config/alias.go +++ b/internal/config/alias.go @@ -5,7 +5,6 @@ package config import ( "errors" - "fmt" "io/fs" "log/slog" "os" @@ -15,6 +14,7 @@ import ( "github.com/derailed/k9s/internal/config/data" "github.com/derailed/k9s/internal/config/json" "github.com/derailed/k9s/internal/slogs" + "github.com/derailed/k9s/internal/view/cmd" "gopkg.in/yaml.v3" "k8s.io/apimachinery/pkg/util/sets" ) @@ -79,26 +79,35 @@ func (a *Aliases) Clear() { } } +func (a *Aliases) Resolve(command string) (*client.GVR, string, bool) { + agvr, ok := a.Get(command) + if !ok { + return nil, "", false + } + if agvr.IsCommand() { + p := cmd.NewInterpreter(agvr.String()) + gvr, ok := a.Get(p.Cmd()) + if !ok { + return nil, "", false + } + return gvr, p.Args(), true + } + + return agvr, "", true +} + // Get retrieves an alias. func (a *Aliases) Get(alias string) (*client.GVR, bool) { a.mx.RLock() defer a.mx.RUnlock() gvr, ok := a.Alias[alias] - if ok && !gvr.IsK8sRes() { - if rgvr, found := a.Alias[gvr.String()]; found { - return rgvr, found - } - } return gvr, ok } // Define declares a new alias. func (a *Aliases) Define(gvr *client.GVR, aliases ...string) { - if gvr.String() == "deployment" { - fmt.Println("!!YO!!") - } a.mx.Lock() defer a.mx.Unlock() for _, alias := range aliases { diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 031eb742..37f5ee0b 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -53,7 +53,7 @@ func TestConfigSave(t *testing.T) { xdg.Reload() u := uu[k] t.Run(k, func(t *testing.T) { - c := mock.NewMockConfig() + c := mock.NewMockConfig(t) _, err := c.K9s.ActivateContext(u.ct) require.NoError(t, err) if u.flags != nil { @@ -113,7 +113,7 @@ func TestSetActiveView(t *testing.T) { for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { - c := mock.NewMockConfig() + c := mock.NewMockConfig(t) _, _ = c.K9s.ActivateContext(u.ct) if u.flags != nil { require.NoError(t, c.Refine(u.flags, nil, client.NewConfig(u.flags))) @@ -156,7 +156,7 @@ func TestActiveContextName(t *testing.T) { for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { - c := mock.NewMockConfig() + c := mock.NewMockConfig(t) _, _ = c.K9s.ActivateContext(u.ct) if u.flags != nil { require.NoError(t, c.Refine(u.flags, nil, client.NewConfig(u.flags))) @@ -182,14 +182,22 @@ func TestActiveView(t *testing.T) { "empty": { e: data.DefaultView, }, + "not-exists": { ct: "fred", e: data.DefaultView, }, + "happy": { ct: "ct-1-1", e: data.DefaultView, }, + + "happy1": { + ct: "ct-1-2", + e: data.DefaultView, + }, + "cli-override": { flags: &genericclioptions.ConfigFlags{ KubeConfig: &cfgFile, @@ -204,7 +212,7 @@ func TestActiveView(t *testing.T) { for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { - c := mock.NewMockConfig() + c := mock.NewMockConfig(t) _, _ = c.K9s.ActivateContext(u.ct) if u.flags != nil { require.NoError(t, c.Refine(u.flags, nil, client.NewConfig(u.flags))) @@ -233,7 +241,7 @@ func TestFavNamespaces(t *testing.T) { for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { - c := mock.NewMockConfig() + c := mock.NewMockConfig(t) _, _ = c.K9s.ActivateContext(u.ct) assert.Equal(t, u.e, c.FavNamespaces()) }) @@ -258,7 +266,7 @@ func TestContextAliasesPath(t *testing.T) { for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { - c := mock.NewMockConfig() + c := mock.NewMockConfig(t) _, _ = c.K9s.ActivateContext(u.ct) assert.Equal(t, u.e, c.ContextAliasesPath()) }) @@ -286,7 +294,7 @@ func TestContextPluginsPath(t *testing.T) { for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { - c := mock.NewMockConfig() + c := mock.NewMockConfig(t) _, _ = c.K9s.ActivateContext(u.ct) s, err := c.ContextPluginsPath() if err != nil { @@ -344,7 +352,7 @@ func TestConfigActivateContext(t *testing.T) { for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { - cfg := mock.NewMockConfig() + cfg := mock.NewMockConfig(t) ct, err := cfg.ActivateContext(u.ct) if err != nil { assert.Equal(t, u.err, err.Error()) @@ -391,7 +399,7 @@ func TestConfigCurrentContext(t *testing.T) { for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { - cfg := mock.NewMockConfig() + cfg := mock.NewMockConfig(t) err := cfg.Refine(u.flags, nil, client.NewConfig(u.flags)) require.NoError(t, err) @@ -511,7 +519,7 @@ func TestConfigRefine(t *testing.T) { for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { - cfg := mock.NewMockConfig() + cfg := mock.NewMockConfig(t) err := cfg.Refine(u.flags, u.k9sFlags, client.NewConfig(u.flags)) if err != nil { @@ -526,7 +534,7 @@ func TestConfigRefine(t *testing.T) { } func TestConfigValidate(t *testing.T) { - cfg := mock.NewMockConfig() + cfg := mock.NewMockConfig(t) cfg.SetConnection(mock.NewMockConnection()) require.NoError(t, cfg.Load("testdata/configs/k9s.yaml", true)) @@ -534,7 +542,7 @@ func TestConfigValidate(t *testing.T) { } func TestConfigLoad(t *testing.T) { - cfg := mock.NewMockConfig() + cfg := mock.NewMockConfig(t) require.NoError(t, cfg.Load("testdata/configs/k9s.yaml", true)) assert.Equal(t, 2, cfg.K9s.RefreshRate) @@ -543,13 +551,13 @@ func TestConfigLoad(t *testing.T) { } func TestConfigLoadCrap(t *testing.T) { - cfg := mock.NewMockConfig() + cfg := mock.NewMockConfig(t) assert.Error(t, cfg.Load("testdata/configs/k9s_not_there.yaml", true)) } func TestConfigSaveFile(t *testing.T) { - cfg := mock.NewMockConfig() + cfg := mock.NewMockConfig(t) require.NoError(t, cfg.Load("testdata/configs/k9s.yaml", true)) @@ -570,7 +578,7 @@ func TestConfigSaveFile(t *testing.T) { } func TestConfigReset(t *testing.T) { - cfg := mock.NewMockConfig() + cfg := mock.NewMockConfig(t) require.NoError(t, cfg.Load("testdata/configs/k9s.yaml", true)) cfg.Reset() cfg.Validate("ct-1-1", "cl-1") diff --git a/internal/config/data/context_test.go b/internal/config/data/context_test.go index 8f313df5..21e4cffd 100644 --- a/internal/config/data/context_test.go +++ b/internal/config/data/context_test.go @@ -15,7 +15,7 @@ func TestClusterValidate(t *testing.T) { c := data.NewContext() c.Validate(mock.NewMockConnection(), "ct-1", "cl-1") - assert.Equal(t, "po", c.View.Active) + assert.Equal(t, data.DefaultView, c.View.Active) assert.Equal(t, "default", c.Namespace.Active) assert.Len(t, c.Namespace.Favorites, 1) assert.Equal(t, []string{"default"}, c.Namespace.Favorites) @@ -25,7 +25,7 @@ func TestClusterValidateEmpty(t *testing.T) { c := data.NewContext() c.Validate(mock.NewMockConnection(), "ct-1", "cl-1") - assert.Equal(t, "po", c.View.Active) + assert.Equal(t, data.DefaultView, c.View.Active) assert.Equal(t, "default", c.Namespace.Active) assert.Len(t, c.Namespace.Favorites, 1) assert.Equal(t, []string{"default"}, c.Namespace.Favorites) diff --git a/internal/config/k9s.go b/internal/config/k9s.go index df2752de..f32e0dfa 100644 --- a/internal/config/k9s.go +++ b/internal/config/k9s.go @@ -386,7 +386,9 @@ func (k *K9s) Validate(c client.Connection, contextName, clusterName string) { if k.getActiveConfig() == nil { _, _ = k.ActivateContext(contextName) } - k.ShellPod.Validate() + if k.ShellPod != nil { + k.ShellPod.Validate() + } k.Logger = k.Logger.Validate() k.Thresholds = k.Thresholds.Validate() diff --git a/internal/config/k9s_test.go b/internal/config/k9s_test.go index 6afc155a..d4bd21eb 100644 --- a/internal/config/k9s_test.go +++ b/internal/config/k9s_test.go @@ -133,7 +133,7 @@ func TestK9sMerge(t *testing.T) { } func TestContextScreenDumpDir(t *testing.T) { - cfg := mock.NewMockConfig() + cfg := mock.NewMockConfig(t) _, err := cfg.K9s.ActivateContext("ct-1-1") require.NoError(t, err) @@ -142,7 +142,7 @@ func TestContextScreenDumpDir(t *testing.T) { } func TestAppScreenDumpDir(t *testing.T) { - cfg := mock.NewMockConfig() + cfg := mock.NewMockConfig(t) require.NoError(t, cfg.Load("testdata/configs/k9s.yaml", true)) assert.Equal(t, "/tmp/k9s-test/screen-dumps", cfg.K9s.AppScreenDumpDir()) diff --git a/internal/config/mock/test_helpers.go b/internal/config/mock/test_helpers.go index 97ab1f65..10dcdf53 100644 --- a/internal/config/mock/test_helpers.go +++ b/internal/config/mock/test_helpers.go @@ -11,9 +11,11 @@ import ( "net/url" "os" "strings" + "testing" "github.com/derailed/k9s/internal/client" "github.com/derailed/k9s/internal/config" + "github.com/stretchr/testify/require" version "k8s.io/apimachinery/pkg/version" "k8s.io/cli-runtime/pkg/genericclioptions" disk "k8s.io/client-go/discovery/cached/disk" @@ -35,9 +37,11 @@ func EnsureDir(d string) error { return os.MkdirAll(d, 0700) } -func NewMockConfig() *config.Config { - if _, err := os.Stat("/tmp/test"); errors.Is(err, os.ErrExist) { - _ = os.RemoveAll("/tmp/test") +func NewMockConfig(t testing.TB) *config.Config { + if _, err := os.Stat("/tmp/test"); err == nil { + if e := os.RemoveAll("/tmp/test"); e != nil { + require.NoError(t, e) + } } config.AppContextsDir = "/tmp/test" cl, ct := "cl-1", "ct-1-1" diff --git a/internal/dao/alias.go b/internal/dao/alias.go index c6f48b20..651d22a1 100644 --- a/internal/dao/alias.go +++ b/internal/dao/alias.go @@ -63,14 +63,7 @@ func (*Alias) List(ctx context.Context, _ string) ([]runtime.Object, error) { // AsGVR returns a matching gvr if it exists. func (a *Alias) AsGVR(alias string) (*client.GVR, string, bool) { - gvr, ok := a.Aliases.Get(alias) - if ok { - if pgvr := MetaAccess.Lookup(alias); pgvr != client.NoGVR { - return pgvr, "", ok - } - } - - return gvr, "", ok + return a.Resolve(alias) } // Get fetch a resource. @@ -106,10 +99,9 @@ func (a *Alias) load(path string) error { } a.Define(gvr, gvr.AsResourceName()) - // Allow single shot commands for k8s resources only! - if isStandardGroup(gvr.GVSub()) { - a.Define(gvr, meta.Name) - a.Define(gvr, meta.SingularName) + // Allow single shot commands for k8s resources only expect for metrics resource which override pods and nodes ;(! + if isStandardGroup(gvr.GVSub()) && gvr.G() != "metrics.k8s.io" { + a.Define(gvr, meta.Name, meta.SingularName) } if len(meta.ShortNames) > 0 { a.Define(gvr, meta.ShortNames...) diff --git a/internal/dao/alias_test.go b/internal/dao/alias_test.go index 0d59ee08..7cd41f9a 100644 --- a/internal/dao/alias_test.go +++ b/internal/dao/alias_test.go @@ -20,39 +20,60 @@ func TestAsGVR(t *testing.T) { a := dao.NewAlias(makeFactory()) a.Define(client.PodGVR, "po", "pod", "pods") a.Define(client.WkGVR, client.WkGVR.String(), "workload", "wkl") + a.Define(client.NewGVR("pod default"), "pp") + a.Define(client.NewGVR("pod default @fred"), "ppc") uu := map[string]struct { cmd string ok bool gvr *client.GVR + exp string }{ "ok": { cmd: "pods", ok: true, gvr: client.PodGVR, }, + "ok-short": { cmd: "po", ok: true, gvr: client.PodGVR, }, + "missing": { cmd: "zorg", }, + "alias": { cmd: "wkl", ok: true, gvr: client.WkGVR, }, + + "ns-alias": { + cmd: "pp", + ok: true, + gvr: client.PodGVR, + exp: "default", + }, + + "full-alias": { + cmd: "ppc", + ok: true, + gvr: client.PodGVR, + exp: "default @fred", + }, } for k := range uu { u := uu[k] t.Run(k, func(t *testing.T) { - gvr, _, ok := a.AsGVR(u.cmd) + gvr, exp, ok := a.AsGVR(u.cmd) assert.Equal(t, u.ok, ok) if u.ok { assert.Equal(t, u.gvr, gvr) + assert.Equal(t, u.exp, exp) } }) } diff --git a/internal/render/pod.go b/internal/render/pod.go index 0c8b0d2d..5aa5ca9a 100644 --- a/internal/render/pod.go +++ b/internal/render/pod.go @@ -7,7 +7,6 @@ import ( "fmt" "strconv" "strings" - "time" "github.com/derailed/k9s/internal/client" "github.com/derailed/k9s/internal/model1" @@ -19,7 +18,6 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/cache" mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1" ) @@ -76,22 +74,15 @@ var defaultPodHeader = model1.Header{ model1.HeaderColumn{Name: "AGE", Attrs: model1.Attrs{Time: true}}, } -const ( - cacheSize = 5_000 - expiration = 5 * time.Minute -) - // Pod renders a K8s Pod to screen. type Pod struct { *Base - cache *cache.LRUExpireCache } // NewPod returns a new instance. func NewPod() *Pod { return &Pod{ - Base: new(Base), - cache: cache.NewLRUExpireCache(cacheSize), + Base: new(Base), } } @@ -157,22 +148,9 @@ func (p *Pod) defaultRow(pwm *PodWithMetrics, row *model1.Row) error { if err := runtime.DefaultUnstructuredConverter.FromUnstructured(pwm.Raw.Object["status"].(map[string]any), &st); err != nil { return err } - key := pwm.Raw.GetUID() - for _, o := range pwm.Raw.GetOwnerReferences() { - if o.Controller != nil && *o.Controller { - key = o.UID - break - } - } - spec := new(v1.PodSpec) - if cspec, ok := p.cache.Get(key); ok { - spec = cspec.(*v1.PodSpec) - } else { - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(pwm.Raw.Object["spec"].(map[string]any), spec); err != nil { - return err - } - p.cache.Add(key, spec, expiration) + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(pwm.Raw.Object["spec"].(map[string]any), spec); err != nil { + return err } dt := pwm.Raw.GetDeletionTimestamp() diff --git a/internal/ui/app_test.go b/internal/ui/app_test.go index 0725561a..eb1934e8 100644 --- a/internal/ui/app_test.go +++ b/internal/ui/app_test.go @@ -12,7 +12,7 @@ import ( ) func TestAppGetCmd(t *testing.T) { - a := ui.NewApp(mock.NewMockConfig(), "") + a := ui.NewApp(mock.NewMockConfig(t), "") a.Init() a.CmdBuff().SetText("blee", "") @@ -20,7 +20,7 @@ func TestAppGetCmd(t *testing.T) { } func TestAppInCmdMode(t *testing.T) { - a := ui.NewApp(mock.NewMockConfig(), "") + a := ui.NewApp(mock.NewMockConfig(t), "") a.Init() a.CmdBuff().SetText("blee", "") assert.False(t, a.InCmdMode()) @@ -30,7 +30,7 @@ func TestAppInCmdMode(t *testing.T) { } func TestAppResetCmd(t *testing.T) { - a := ui.NewApp(mock.NewMockConfig(), "") + a := ui.NewApp(mock.NewMockConfig(t), "") a.Init() a.CmdBuff().SetText("blee", "") @@ -40,7 +40,7 @@ func TestAppResetCmd(t *testing.T) { } func TestAppHasCmd(t *testing.T) { - a := ui.NewApp(mock.NewMockConfig(), "") + a := ui.NewApp(mock.NewMockConfig(t), "") a.Init() a.ActivateCmd(true) @@ -51,7 +51,7 @@ func TestAppHasCmd(t *testing.T) { } func TestAppGetActions(t *testing.T) { - a := ui.NewApp(mock.NewMockConfig(), "") + a := ui.NewApp(mock.NewMockConfig(t), "") a.Init() a.GetActions().Add(ui.KeyZ, ui.KeyAction{Description: "zorg"}) @@ -60,7 +60,7 @@ func TestAppGetActions(t *testing.T) { } func TestAppViews(t *testing.T) { - a := ui.NewApp(mock.NewMockConfig(), "") + a := ui.NewApp(mock.NewMockConfig(t), "") a.Init() vv := []string{"crumbs", "logo", "prompt", "menu"} diff --git a/internal/ui/config_test.go b/internal/ui/config_test.go index 9bc34292..9b1967ab 100644 --- a/internal/ui/config_test.go +++ b/internal/ui/config_test.go @@ -33,7 +33,7 @@ func TestSkinnedContext(t *testing.T) { require.NoError(t, os.WriteFile(tf, raw, data.DefaultFileMod)) var cfg ui.Configurator - cfg.Config = mock.NewMockConfig() + cfg.Config = mock.NewMockConfig(t) cl, ct := "cl-1", "ct-1" flags := genericclioptions.ConfigFlags{ ClusterName: &cl, diff --git a/internal/ui/flash_test.go b/internal/ui/flash_test.go index 5122152e..92bc48e6 100644 --- a/internal/ui/flash_test.go +++ b/internal/ui/flash_test.go @@ -25,7 +25,7 @@ func TestFlash(t *testing.T) { "err": {l: model.FlashErr, i: "hello", e: "😡 hello\n"}, } - a := ui.NewApp(mock.NewMockConfig(), "test") + a := ui.NewApp(mock.NewMockConfig(t), "test") f := ui.NewFlash(a) f.SetTestMode(true) ctx, cancel := context.WithCancel(context.Background()) diff --git a/internal/ui/indicator_test.go b/internal/ui/indicator_test.go index 40032517..3e67714b 100644 --- a/internal/ui/indicator_test.go +++ b/internal/ui/indicator_test.go @@ -13,7 +13,7 @@ import ( ) func TestIndicatorReset(t *testing.T) { - i := ui.NewStatusIndicator(ui.NewApp(mock.NewMockConfig(), ""), config.NewStyles()) + i := ui.NewStatusIndicator(ui.NewApp(mock.NewMockConfig(t), ""), config.NewStyles()) i.SetPermanent("Blee") i.Info("duh") i.Reset() @@ -22,21 +22,21 @@ func TestIndicatorReset(t *testing.T) { } func TestIndicatorInfo(t *testing.T) { - i := ui.NewStatusIndicator(ui.NewApp(mock.NewMockConfig(), ""), config.NewStyles()) + i := ui.NewStatusIndicator(ui.NewApp(mock.NewMockConfig(t), ""), config.NewStyles()) i.Info("Blee") assert.Equal(t, "[lawngreen::b] \n", i.GetText(false)) } func TestIndicatorWarn(t *testing.T) { - i := ui.NewStatusIndicator(ui.NewApp(mock.NewMockConfig(), ""), config.NewStyles()) + i := ui.NewStatusIndicator(ui.NewApp(mock.NewMockConfig(t), ""), config.NewStyles()) i.Warn("Blee") assert.Equal(t, "[mediumvioletred::b] \n", i.GetText(false)) } func TestIndicatorErr(t *testing.T) { - i := ui.NewStatusIndicator(ui.NewApp(mock.NewMockConfig(), ""), config.NewStyles()) + i := ui.NewStatusIndicator(ui.NewApp(mock.NewMockConfig(t), ""), config.NewStyles()) i.Err("Blee") assert.Equal(t, "[orangered::b] \n", i.GetText(false)) diff --git a/internal/view/alias_test.go b/internal/view/alias_test.go index 06a611a6..09a959ad 100644 --- a/internal/view/alias_test.go +++ b/internal/view/alias_test.go @@ -27,14 +27,14 @@ import ( func TestAliasNew(t *testing.T) { v := view.NewAlias(client.AliGVR) - require.NoError(t, v.Init(makeContext())) + require.NoError(t, v.Init(makeContext(t))) assert.Equal(t, "Aliases", v.Name()) assert.Len(t, v.Hints(), 6) } func TestAliasSearch(t *testing.T) { v := view.NewAlias(client.AliGVR) - require.NoError(t, v.Init(makeContext())) + require.NoError(t, v.Init(makeContext(t))) v.GetTable().SetModel(&mockModel{}) v.GetTable().Refresh() v.App().Prompt().SetModel(v.GetTable().CmdBuff()) @@ -46,7 +46,7 @@ func TestAliasSearch(t *testing.T) { func TestAliasGoto(t *testing.T) { v := view.NewAlias(client.AliGVR) - require.NoError(t, v.Init(makeContext())) + require.NoError(t, v.Init(makeContext(t))) v.GetTable().Select(0, 0) b := buffL{} @@ -74,8 +74,8 @@ func (b *buffL) BufferActive(bool, model.BufferKind) { b.active++ } -func makeContext() context.Context { - a := view.NewApp(mock.NewMockConfig()) +func makeContext(t testing.TB) context.Context { + a := view.NewApp(mock.NewMockConfig(t)) ctx := context.WithValue(context.Background(), internal.KeyApp, a) return context.WithValue(ctx, internal.KeyStyles, a.Styles) } diff --git a/internal/view/app.go b/internal/view/app.go index 8735b41c..a5bb8e9b 100644 --- a/internal/view/app.go +++ b/internal/view/app.go @@ -466,7 +466,7 @@ func (a *App) switchContext(ci *cmd.Interpreter, force bool) error { p := cmd.NewInterpreter(a.Config.ActiveView()) p.ResetContextArg() if p.IsContextCmd() { - a.Config.SetActiveView("pod") + a.Config.SetActiveView(client.PodGVR.String()) } ns := a.Config.ActiveNamespace() if !a.Conn().IsValidNamespace(ns) { diff --git a/internal/view/app_test.go b/internal/view/app_test.go index f6b9663d..24d8d7fa 100644 --- a/internal/view/app_test.go +++ b/internal/view/app_test.go @@ -12,7 +12,7 @@ import ( ) func TestAppNew(t *testing.T) { - a := view.NewApp(mock.NewMockConfig()) + a := view.NewApp(mock.NewMockConfig(t)) _ = a.Init("blee", 10) assert.Equal(t, 15, a.GetActions().Len()) diff --git a/internal/view/cm_test.go b/internal/view/cm_test.go index 158484f8..c7c8bf80 100644 --- a/internal/view/cm_test.go +++ b/internal/view/cm_test.go @@ -15,7 +15,7 @@ import ( func TestConfigMapNew(t *testing.T) { s := view.NewConfigMap(client.CmGVR) - require.NoError(t, s.Init(makeCtx())) + require.NoError(t, s.Init(makeCtx(t))) assert.Equal(t, "ConfigMaps", s.Name()) assert.Len(t, s.Hints(), 7) } diff --git a/internal/view/cmd/interpreter.go b/internal/view/cmd/interpreter.go index beaf8c1f..9ca80ca7 100644 --- a/internal/view/cmd/interpreter.go +++ b/internal/view/cmd/interpreter.go @@ -48,6 +48,10 @@ func (c *Interpreter) Cmd() string { return c.cmd } +func (c *Interpreter) Args() string { + return strings.TrimSpace(strings.Replace(c.line, c.cmd, "", 1)) +} + // IsBlank returns true if prompt is empty. func (c *Interpreter) IsBlank() bool { return c.line == "" diff --git a/internal/view/command.go b/internal/view/command.go index 4d44c842..2e746477 100644 --- a/internal/view/command.go +++ b/internal/view/command.go @@ -9,7 +9,6 @@ import ( "log/slog" "regexp" "runtime/debug" - "strings" "sync" "github.com/derailed/k9s/internal/client" @@ -21,7 +20,7 @@ import ( ) const ( - podCmd = "pod" + podCmd = "v1/pods" ctxCmd = "ctx" ) @@ -291,11 +290,7 @@ func (c *Command) viewMetaFor(p *cmd.Interpreter) (*client.GVR, *MetaViewer, err return client.NoGVR, nil, fmt.Errorf("`%s` command not found", p.Cmd()) } if exp != "" { - ff := strings.Fields(exp) - ff[0] = gvr.String() - ap := cmd.NewInterpreter(strings.Join(ff, " ")) - gvr = client.NewGVR(ap.Cmd()) - p.Amend(ap) + p.Amend(cmd.NewInterpreter(gvr.String() + " " + exp)) } v := MetaViewer{ diff --git a/internal/view/command_test.go b/internal/view/command_test.go new file mode 100644 index 00000000..0007bac4 --- /dev/null +++ b/internal/view/command_test.go @@ -0,0 +1,71 @@ +package view + +import ( + "errors" + "testing" + + "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/config" + "github.com/derailed/k9s/internal/dao" + "github.com/derailed/k9s/internal/view/cmd" + "github.com/stretchr/testify/assert" +) + +func Test_viewMetaFor(t *testing.T) { + uu := map[string]struct { + cmd string + gvr *client.GVR + err error + }{ + "empty": { + cmd: "", + gvr: client.PodGVR, + err: errors.New("`` command not found"), + }, + + "toast-cmd": { + cmd: "v1/pd", + gvr: client.PodGVR, + err: errors.New("`v1/pd` command not found"), + }, + + "gvr-cmd": { + cmd: "v1/pods", + gvr: client.PodGVR, + err: errors.New("blah"), + }, + + "alias-cmd": { + cmd: "po", + gvr: client.PodGVR, + err: errors.New("blee"), + }, + + "full-cmd": { + cmd: "pdl", + gvr: client.PodGVR, + err: errors.New("blee"), + }, + } + + c := &Command{ + alias: &dao.Alias{ + Aliases: config.NewAliases(), + }, + } + c.alias.Define(client.PodGVR, "po", "pod", "pods", client.PodGVR.String()) + c.alias.Define(client.NewGVR("pod default"), "pd") + c.alias.Define(client.NewGVR("pod default app=blee @fred"), "pdl") + + for k, u := range uu { + t.Run(k, func(t *testing.T) { + p := cmd.NewInterpreter(u.cmd) + gvr, _, err := c.viewMetaFor(p) + if err != nil { + assert.Equal(t, u.err.Error(), err.Error()) + } else { + assert.Equal(t, u.gvr, gvr) + } + }) + } +} diff --git a/internal/view/container_test.go b/internal/view/container_test.go index 39c3abab..d46da494 100644 --- a/internal/view/container_test.go +++ b/internal/view/container_test.go @@ -15,7 +15,7 @@ import ( func TestContainerNew(t *testing.T) { c := view.NewContainer(client.CoGVR) - require.NoError(t, c.Init(makeCtx())) + require.NoError(t, c.Init(makeCtx(t))) assert.Equal(t, "Containers", c.Name()) assert.Len(t, c.Hints(), 19) } diff --git a/internal/view/context_test.go b/internal/view/context_test.go index 42fe5e60..3fac43b7 100644 --- a/internal/view/context_test.go +++ b/internal/view/context_test.go @@ -15,7 +15,7 @@ import ( func TestContext(t *testing.T) { ctx := view.NewContext(client.CtGVR) - require.NoError(t, ctx.Init(makeCtx())) + require.NoError(t, ctx.Init(makeCtx(t))) assert.Equal(t, "Contexts", ctx.Name()) assert.Len(t, ctx.Hints(), 5) } diff --git a/internal/view/dir_test.go b/internal/view/dir_test.go index f00dc355..53818dfa 100644 --- a/internal/view/dir_test.go +++ b/internal/view/dir_test.go @@ -14,7 +14,7 @@ import ( func TestDir(t *testing.T) { v := view.NewDir("/fred") - require.NoError(t, v.Init(makeCtx())) + require.NoError(t, v.Init(makeCtx(t))) assert.Equal(t, "Directory", v.Name()) assert.Len(t, v.Hints(), 7) } diff --git a/internal/view/dp_test.go b/internal/view/dp_test.go index 270646d1..43cfd594 100644 --- a/internal/view/dp_test.go +++ b/internal/view/dp_test.go @@ -15,7 +15,7 @@ import ( func TestDeploy(t *testing.T) { v := view.NewDeploy(client.DpGVR) - require.NoError(t, v.Init(makeCtx())) + require.NoError(t, v.Init(makeCtx(t))) assert.Equal(t, "Deployments", v.Name()) assert.Len(t, v.Hints(), 16) } diff --git a/internal/view/ds_test.go b/internal/view/ds_test.go index 62e8da20..9f2787cf 100644 --- a/internal/view/ds_test.go +++ b/internal/view/ds_test.go @@ -15,7 +15,7 @@ import ( func TestDaemonSet(t *testing.T) { v := view.NewDaemonSet(client.DsGVR) - require.NoError(t, v.Init(makeCtx())) + require.NoError(t, v.Init(makeCtx(t))) assert.Equal(t, "DaemonSets", v.Name()) assert.Len(t, v.Hints(), 17) } diff --git a/internal/view/exec.go b/internal/view/exec.go index 35b041b2..3ecc67f6 100644 --- a/internal/view/exec.go +++ b/internal/view/exec.go @@ -321,6 +321,11 @@ func launchNodeShell(v model.Igniter, a *App, node string) { } func launchPodShell(v model.Igniter, a *App) { + if a.Config.K9s.ShellPod == nil { + slog.Error("Shell pod not configured!") + return + } + defer func() { if err := nukeK9sShell(a); err != nil { a.Flash().Errf("Launching node shell failed: %s", err) diff --git a/internal/view/help_test.go b/internal/view/help_test.go index 1f850169..c43cc531 100644 --- a/internal/view/help_test.go +++ b/internal/view/help_test.go @@ -15,7 +15,7 @@ import ( ) func TestHelp(t *testing.T) { - ctx := makeCtx() + ctx := makeCtx(t) app := ctx.Value(internal.KeyApp).(*view.App) po := view.NewPod(client.PodGVR) diff --git a/internal/view/helpers_test.go b/internal/view/helpers_test.go index 9f941178..1c1ddac4 100644 --- a/internal/view/helpers_test.go +++ b/internal/view/helpers_test.go @@ -61,7 +61,7 @@ func TestParsePFAnn(t *testing.T) { } func TestExtractApp(t *testing.T) { - app := NewApp(mock.NewMockConfig()) + app := NewApp(mock.NewMockConfig(t)) uu := map[string]struct { app *App diff --git a/internal/view/live_view_test.go b/internal/view/live_view_test.go index d3771bdc..7ea74f7f 100644 --- a/internal/view/live_view_test.go +++ b/internal/view/live_view_test.go @@ -20,7 +20,7 @@ apiVersion: v1 the secret name you want to quote to use tls.","title":"secretName","type":"string"}},"required":["http","class","classInSpec"],"type":"object"} ` - v := NewLiveView(NewApp(mock.NewMockConfig()), "fred", nil) + v := NewLiveView(NewApp(mock.NewMockConfig(t)), "fred", nil) require.NoError(t, v.Init(context.Background())) v.text.SetText(colorizeYAML(config.Yaml{}, s)) diff --git a/internal/view/log_int_test.go b/internal/view/log_int_test.go index 64b3ae22..9630416c 100644 --- a/internal/view/log_int_test.go +++ b/internal/view/log_int_test.go @@ -21,7 +21,7 @@ func TestLogAutoScroll(t *testing.T) { SingleContainer: true, } v := NewLog(client.PodGVR, &opts) - require.NoError(t, v.Init(makeContext())) + require.NoError(t, v.Init(makeContext(t))) ii := dao.NewLogItems() ii.Add(dao.NewLogItemFromString("blee"), dao.NewLogItemFromString("bozo")) v.GetModel().Set(ii) @@ -39,7 +39,7 @@ func TestLogViewNav(t *testing.T) { Container: "blee", } v := NewLog(client.PodGVR, &opts) - require.NoError(t, v.Init(makeContext())) + require.NoError(t, v.Init(makeContext(t))) buff := dao.NewLogItems() for i := range 100 { @@ -58,7 +58,7 @@ func TestLogViewClear(t *testing.T) { Container: "blee", } v := NewLog(client.PodGVR, &opts) - require.NoError(t, v.Init(makeContext())) + require.NoError(t, v.Init(makeContext(t))) v.toggleAutoScrollCmd(nil) v.Logs().SetText("blee\nblah") @@ -73,7 +73,7 @@ func TestLogTimestamp(t *testing.T) { Container: "c1", } l := NewLog(client.NewGVR("test"), &opts) - require.NoError(t, l.Init(makeContext())) + require.NoError(t, l.Init(makeContext(t))) ii := dao.NewLogItems() ii.Add( &dao.LogItem{ @@ -103,7 +103,7 @@ func TestLogFilter(t *testing.T) { Container: "c1", } l := NewLog(client.NewGVR("test"), &opts) - require.NoError(t, l.Init(makeContext())) + require.NoError(t, l.Init(makeContext(t))) buff := dao.NewLogItems() buff.Add( dao.NewLogItemFromString("duh"), diff --git a/internal/view/log_test.go b/internal/view/log_test.go index 0708960a..318396b0 100644 --- a/internal/view/log_test.go +++ b/internal/view/log_test.go @@ -28,7 +28,7 @@ func TestLog(t *testing.T) { Container: "blee", } v := view.NewLog(client.PodGVR, &opts) - require.NoError(t, v.Init(makeContext())) + require.NoError(t, v.Init(makeContext(t))) ii := dao.NewLogItems() ii.Add(dao.NewLogItemFromString("blee\n"), dao.NewLogItemFromString("bozo\n")) @@ -45,7 +45,7 @@ func TestLogFlush(t *testing.T) { Container: "blee", } v := view.NewLog(client.PodGVR, &opts) - require.NoError(t, v.Init(makeContext())) + require.NoError(t, v.Init(makeContext(t))) items := dao.NewLogItems() items.Add( @@ -65,7 +65,7 @@ func BenchmarkLogFlush(b *testing.B) { Container: "blee", } v := view.NewLog(client.PodGVR, &opts) - _ = v.Init(makeContext()) + _ = v.Init(makeContext(b)) items := dao.NewLogItems() items.Add( @@ -103,9 +103,9 @@ func TestLogViewSave(t *testing.T) { Container: "blee", } v := view.NewLog(client.PodGVR, &opts) - require.NoError(t, v.Init(makeContext())) + require.NoError(t, v.Init(makeContext(t))) - app := makeApp() + app := makeApp(t) ii := dao.NewLogItems() ii.Add(dao.NewLogItemFromString("blee"), dao.NewLogItemFromString("bozo")) ll := make([][]byte, ii.Len()) @@ -141,7 +141,7 @@ func TestAllContainerKeyBinding(t *testing.T) { u := uu[k] t.Run(k, func(t *testing.T) { v := view.NewLog(client.PodGVR, u.opts) - require.NoError(t, v.Init(makeContext())) + require.NoError(t, v.Init(makeContext(t))) _, got := v.Logs().Actions().Get(ui.KeyA) assert.Equal(t, u.e, got) }) @@ -151,8 +151,8 @@ func TestAllContainerKeyBinding(t *testing.T) { // ---------------------------------------------------------------------------- // Helpers... -func makeApp() *view.App { - return view.NewApp(mock.NewMockConfig()) +func makeApp(t *testing.T) *view.App { + return view.NewApp(mock.NewMockConfig(t)) } func ensureDumpDir(n string) error { diff --git a/internal/view/ns.go b/internal/view/ns.go index 6453176b..fb67feb8 100644 --- a/internal/view/ns.go +++ b/internal/view/ns.go @@ -41,7 +41,7 @@ func (n *Namespace) bindKeys(aa *ui.KeyActions) { func (n *Namespace) switchNs(app *App, _ ui.Tabular, _ *client.GVR, path string) { n.useNamespace(path) - app.gotoResource("pods", "", false, true) + app.gotoResource(client.PodGVR.String(), "", false, true) } func (n *Namespace) useNsCmd(*tcell.EventKey) *tcell.EventKey { diff --git a/internal/view/ns_test.go b/internal/view/ns_test.go index 5ab3e281..3cd81374 100644 --- a/internal/view/ns_test.go +++ b/internal/view/ns_test.go @@ -15,7 +15,7 @@ import ( func TestNSCleanser(t *testing.T) { ns := view.NewNamespace(client.NsGVR) - require.NoError(t, ns.Init(makeCtx())) + require.NoError(t, ns.Init(makeCtx(t))) assert.Equal(t, "Namespaces", ns.Name()) assert.Len(t, ns.Hints(), 7) } diff --git a/internal/view/pf_test.go b/internal/view/pf_test.go index ef04b9e3..ebc030ce 100644 --- a/internal/view/pf_test.go +++ b/internal/view/pf_test.go @@ -15,7 +15,7 @@ import ( func TestPortForwardNew(t *testing.T) { pf := view.NewPortForward(client.PfGVR) - require.NoError(t, pf.Init(makeCtx())) + require.NoError(t, pf.Init(makeCtx(t))) assert.Equal(t, "PortForwards", pf.Name()) assert.Len(t, pf.Hints(), 10) } diff --git a/internal/view/pod_test.go b/internal/view/pod_test.go index c1aee845..fa637f7a 100644 --- a/internal/view/pod_test.go +++ b/internal/view/pod_test.go @@ -18,14 +18,14 @@ import ( func TestPodNew(t *testing.T) { po := view.NewPod(client.PodGVR) - require.NoError(t, po.Init(makeCtx())) + require.NoError(t, po.Init(makeCtx(t))) assert.Equal(t, "Pods", po.Name()) assert.Len(t, po.Hints(), 28) } // Helpers... -func makeCtx() context.Context { - cfg := mock.NewMockConfig() +func makeCtx(t testing.TB) context.Context { + cfg := mock.NewMockConfig(t) return context.WithValue(context.Background(), internal.KeyApp, view.NewApp(cfg)) } diff --git a/internal/view/priorityclass_test.go b/internal/view/priorityclass_test.go index 0819ce67..b3e4f0ea 100644 --- a/internal/view/priorityclass_test.go +++ b/internal/view/priorityclass_test.go @@ -15,7 +15,7 @@ import ( func TestPriorityClassNew(t *testing.T) { s := view.NewPriorityClass(client.PcGVR) - require.NoError(t, s.Init(makeCtx())) + require.NoError(t, s.Init(makeCtx(t))) assert.Equal(t, "PriorityClass", s.Name()) assert.Len(t, s.Hints(), 6) } diff --git a/internal/view/pvc_test.go b/internal/view/pvc_test.go index bbd7112e..56723e96 100644 --- a/internal/view/pvc_test.go +++ b/internal/view/pvc_test.go @@ -15,7 +15,7 @@ import ( func TestPVCNew(t *testing.T) { v := view.NewPersistentVolumeClaim(client.PvcGVR) - require.NoError(t, v.Init(makeCtx())) + require.NoError(t, v.Init(makeCtx(t))) assert.Equal(t, "PersistentVolumeClaims", v.Name()) assert.Len(t, v.Hints(), 11) } diff --git a/internal/view/rbac_test.go b/internal/view/rbac_test.go index 169ec0c6..2ff06571 100644 --- a/internal/view/rbac_test.go +++ b/internal/view/rbac_test.go @@ -15,7 +15,7 @@ import ( func TestRbacNew(t *testing.T) { v := view.NewRbac(client.RbacGVR) - require.NoError(t, v.Init(makeCtx())) + require.NoError(t, v.Init(makeCtx(t))) assert.Equal(t, "Rbac", v.Name()) assert.Len(t, v.Hints(), 5) } diff --git a/internal/view/reference.go b/internal/view/reference.go index da248931..3bb7b450 100644 --- a/internal/view/reference.go +++ b/internal/view/reference.go @@ -56,7 +56,7 @@ func (r *Reference) gotoCmd(evt *tcell.EventKey) *tcell.EventKey { path := r.GetTable().GetSelectedItem() ns, _ := client.Namespaced(path) gvr := ui.TrimCell(r.GetTable().SelectTable, row, 2) - r.App().gotoResource(client.NewGVR(gvr).R()+" "+ns, path, false, true) + r.App().gotoResource(client.NewGVR(gvr).String()+" "+ns, path, false, true) return evt } diff --git a/internal/view/reference_test.go b/internal/view/reference_test.go index 359e0037..63188f73 100644 --- a/internal/view/reference_test.go +++ b/internal/view/reference_test.go @@ -15,7 +15,7 @@ import ( func TestReferenceNew(t *testing.T) { s := view.NewReference(client.RefGVR) - require.NoError(t, s.Init(makeCtx())) + require.NoError(t, s.Init(makeCtx(t))) assert.Equal(t, "References", s.Name()) assert.Len(t, s.Hints(), 4) } diff --git a/internal/view/screen_dump_test.go b/internal/view/screen_dump_test.go index 96af8bb2..06740fc6 100644 --- a/internal/view/screen_dump_test.go +++ b/internal/view/screen_dump_test.go @@ -15,7 +15,7 @@ import ( func TestScreenDumpNew(t *testing.T) { po := view.NewScreenDump(client.SdGVR) - require.NoError(t, po.Init(makeCtx())) + require.NoError(t, po.Init(makeCtx(t))) assert.Equal(t, "ScreenDumps", po.Name()) assert.Len(t, po.Hints(), 5) } diff --git a/internal/view/secret_test.go b/internal/view/secret_test.go index 7e28ab62..0b76e597 100644 --- a/internal/view/secret_test.go +++ b/internal/view/secret_test.go @@ -15,7 +15,7 @@ import ( func TestSecretNew(t *testing.T) { s := view.NewSecret(client.SecGVR) - require.NoError(t, s.Init(makeCtx())) + require.NoError(t, s.Init(makeCtx(t))) assert.Equal(t, "Secrets", s.Name()) assert.Len(t, s.Hints(), 8) } diff --git a/internal/view/sts_test.go b/internal/view/sts_test.go index 119e8d02..0ff5d12d 100644 --- a/internal/view/sts_test.go +++ b/internal/view/sts_test.go @@ -15,7 +15,7 @@ import ( func TestStatefulSetNew(t *testing.T) { s := view.NewStatefulSet(client.StsGVR) - require.NoError(t, s.Init(makeCtx())) + require.NoError(t, s.Init(makeCtx(t))) assert.Equal(t, "StatefulSets", s.Name()) assert.Len(t, s.Hints(), 14) } diff --git a/internal/view/svc_test.go b/internal/view/svc_test.go index 5e0f3ffc..3682fc56 100644 --- a/internal/view/svc_test.go +++ b/internal/view/svc_test.go @@ -172,7 +172,7 @@ func init() { func TestServiceNew(t *testing.T) { s := view.NewService(client.SvcGVR) - require.NoError(t, s.Init(makeCtx())) + require.NoError(t, s.Init(makeCtx(t))) assert.Equal(t, "Services", s.Name()) assert.Len(t, s.Hints(), 12) } diff --git a/internal/view/table_int_test.go b/internal/view/table_int_test.go index 29966e89..5d2652e0 100644 --- a/internal/view/table_int_test.go +++ b/internal/view/table_int_test.go @@ -29,7 +29,7 @@ import ( func TestTableSave(t *testing.T) { v := NewTable(client.NewGVR("test")) - require.NoError(t, v.Init(makeContext())) + require.NoError(t, v.Init(makeContext(t))) v.SetTitle("k9s-test") require.NoError(t, ensureDumpDir("/tmp/test-dumps")) @@ -43,7 +43,7 @@ func TestTableSave(t *testing.T) { func TestTableNew(t *testing.T) { v := NewTable(client.NewGVR("test")) - require.NoError(t, v.Init(makeContext())) + require.NoError(t, v.Init(makeContext(t))) data := model1.NewTableDataWithRows( client.NewGVR("test"), @@ -74,7 +74,7 @@ func TestTableNew(t *testing.T) { func TestTableViewFilter(t *testing.T) { v := NewTable(client.NewGVR("test")) - require.NoError(t, v.Init(makeContext())) + require.NoError(t, v.Init(makeContext(t))) v.SetModel(&mockTableModel{}) v.Refresh() @@ -86,7 +86,7 @@ func TestTableViewFilter(t *testing.T) { func TestTableViewSort(t *testing.T) { v := NewTable(client.NewGVR("test")) - require.NoError(t, v.Init(makeContext())) + require.NoError(t, v.Init(makeContext(t))) v.SetModel(new(mockTableModel)) uu := map[string]struct { @@ -199,8 +199,8 @@ func makeTableData() *model1.TableData { ) } -func makeContext() context.Context { - a := NewApp(mock.NewMockConfig()) +func makeContext(t *testing.T) context.Context { + a := NewApp(mock.NewMockConfig(t)) ctx := context.WithValue(context.Background(), internal.KeyApp, a) return context.WithValue(ctx, internal.KeyStyles, a.Styles) } diff --git a/internal/view/workload.go b/internal/view/workload.go index 72aaf727..c4f6479f 100644 --- a/internal/view/workload.go +++ b/internal/view/workload.go @@ -83,7 +83,7 @@ func (*Workload) showRes(app *App, _ ui.Tabular, _ *client.GVR, path string) { app.Flash().Err(fmt.Errorf("unable to parse path: %q", path)) return } - app.gotoResource(gvr.R(), fqn, false, true) + app.gotoResource(gvr.String(), fqn, false, true) } func (w *Workload) deleteCmd(evt *tcell.EventKey) *tcell.EventKey { diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 00174b88..2dff457e 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,6 +1,6 @@ name: k9s base: core22 -version: 'v0.50.0' +version: 'v0.50.1' summary: K9s is a CLI to view and manage your Kubernetes clusters. description: | K9s is a CLI to view and manage your Kubernetes clusters. By leveraging a terminal UI, you can easily traverse Kubernetes resources and view the state of your clusters in a single powerful session.