From 35361bb23822761200fcc977653818faf054adad Mon Sep 17 00:00:00 2001 From: Fernand Galiana Date: Sun, 16 Mar 2025 10:01:13 -0600 Subject: [PATCH] Rel v0.40.10 (#3206) * [HOTFIX] Broke plugins ;( * add support for cust cols on alias+ns * rel notes --- Makefile | 2 +- change_logs/release_v0.40.10.md | 46 +++++++++++++++++++ .../config/json/schemas/plugin-multi.json | 21 ++++++++- internal/config/json/schemas/plugins.json | 21 ++++++++- internal/config/json/validator_test.go | 8 +--- internal/config/plugin_test.go | 34 +++----------- internal/config/views.go | 15 +++++- internal/render/cust_cols.go | 2 +- snap/snapcraft.yaml | 2 +- 9 files changed, 109 insertions(+), 42 deletions(-) create mode 100644 change_logs/release_v0.40.10.md diff --git a/Makefile b/Makefile index 2b9571d0..7f72af67 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.40.9 +VERSION ?= v0.40.10 IMG_NAME := derailed/k9s IMAGE := ${IMG_NAME}:${VERSION} diff --git a/change_logs/release_v0.40.10.md b/change_logs/release_v0.40.10.md new file mode 100644 index 00000000..8a343695 --- /dev/null +++ b/change_logs/release_v0.40.10.md @@ -0,0 +1,46 @@ + + +# Release v0.40.10 + +## 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) + +## Maintenance Release! + +Sounds like I did hose plugins after all... With feelings! + +* Refactored plugins implementation, hopefully we didn't hose them 😳 +* Updated plugins docs +* Apparently when it comes to icons, I've chosen... poorly 🙀 + Updated `write` icon 🔓->✍️, hopefully for the better 👀?? + +## Videos Are In The Can! + +Please dial [K9s Channel](https://www.youtube.com/channel/UC897uwPygni4QIjkPCpgjmw) for up coming content... + +* [K9s v0.40.0 -Column Blow- Sneak peek](https://youtu.be/iy6RDozAM4A) +* [K9s v0.31.0 Configs+Sneak peek](https://youtu.be/X3444KfjguE) +* [K9s v0.30.0 Sneak peek](https://youtu.be/mVBc1XneRJ4) +* [Vulnerability Scans](https://youtu.be/ULkl0MsaidU) + +--- + +## Resolved Issues + +* [#3202](https://github.com/derailed/k9s/issues/3202) 0.40.8 breaks plugins loading + +--- + + © 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/config/json/schemas/plugin-multi.json b/internal/config/json/schemas/plugin-multi.json index 1c773c5c..37004c15 100644 --- a/internal/config/json/schemas/plugin-multi.json +++ b/internal/config/json/schemas/plugin-multi.json @@ -3,7 +3,24 @@ "title": "K9s plugin-multi schema", "type": "object", "additionalProperties": { - "$ref": "file://internal/config/json/schemas/plugin.json", - "additionalProperties": false + "properties": { + "shortCut": { "type": "string" }, + "override": { "type": "boolean" }, + "description": { "type": "string" }, + "confirm": { "type": "boolean" }, + "dangerous": { "type": "boolean" }, + "scopes": { + "type": "array", + "items": { "type": "string" } + }, + "command": { "type": "string" }, + "background": { "type": "boolean" }, + "overwriteOutput": { "type": "boolean" }, + "args": { + "type": "array", + "items": { "type": ["string", "number"] } + } + }, + "required": ["shortCut", "description", "scopes", "command"] } } diff --git a/internal/config/json/schemas/plugins.json b/internal/config/json/schemas/plugins.json index 20deaede..092991bf 100644 --- a/internal/config/json/schemas/plugins.json +++ b/internal/config/json/schemas/plugins.json @@ -7,8 +7,25 @@ "plugins": { "type": "object", "additionalProperties": { - "$ref": "file://internal/config/json/schemas/plugin.json", - "additionalProperties": false + "properties": { + "shortCut": { "type": "string" }, + "override": { "type": "boolean" }, + "description": { "type": "string" }, + "confirm": { "type": "boolean" }, + "dangerous": { "type": "boolean" }, + "scopes": { + "type": "array", + "items": { "type": "string" } + }, + "command": { "type": "string" }, + "background": { "type": "boolean" }, + "overwriteOutput": { "type": "boolean" }, + "args": { + "type": "array", + "items": { "type": ["string", "number"] } + } + }, + "required": ["shortCut", "description", "scopes", "command"] }, "required": [] } diff --git a/internal/config/json/validator_test.go b/internal/config/json/validator_test.go index aa7221ef..7b78f251 100644 --- a/internal/config/json/validator_test.go +++ b/internal/config/json/validator_test.go @@ -35,7 +35,7 @@ func TestValidatePlugins(t *testing.T) { "toast": { path: "testdata/plugins/toast.yaml", schema: json.PluginsSchema, - err: "Additional property shortCuts is not allowed\nscopes is required\nshortCut is required", + err: "scopes is required\nshortCut is required", }, "cool-snippet": { path: "testdata/plugins/snippet.yaml", @@ -52,13 +52,10 @@ func TestValidatePlugins(t *testing.T) { t.Run(k, func(t *testing.T) { bb, err := os.ReadFile(u.path) assert.NoError(t, err) - dir, _ := os.Getwd() - assert.NoError(t, os.Chdir("../../..")) v := json.NewValidator() if err := v.Validate(u.schema, bb); err != nil { assert.Equal(t, u.err, err.Error()) } - assert.NoError(t, os.Chdir(dir)) }) } } @@ -80,11 +77,8 @@ func TestValidatePluginDir(t *testing.T) { bb, err := os.ReadFile(filepath.Join(plugDir, e.Name())) assert.NoError(t, err) - dir, _ := os.Getwd() - assert.NoError(t, os.Chdir("../../..")) p := json.NewValidator() assert.NoError(t, p.Validate(json.PluginsSchema, bb), e.Name()) - assert.NoError(t, os.Chdir(dir)) } } diff --git a/internal/config/plugin_test.go b/internal/config/plugin_test.go index 24303a53..3bbbc08a 100644 --- a/internal/config/plugin_test.go +++ b/internal/config/plugin_test.go @@ -4,9 +4,6 @@ package config import ( - "os" - "path" - "strings" "testing" "github.com/stretchr/testify/assert" @@ -79,22 +76,16 @@ func TestPluginLoad(t *testing.T) { "toast-invalid": { path: "testdata/plugins/plugins-toast.yaml", ee: NewPlugins(), - err: "Additional property scoped is not allowed\nscopes is required\nAdditional property plugins is not allowed\ncommand is required\ndescription is required\nscopes is required\nshortCut is required\nAdditional property blah is not allowed\ncommand is required\ndescription is required\nscopes is required\nshortCut is required", + err: "plugin validation failed for testdata/plugins/plugins-toast.yaml: scopes is required\nAdditional property plugins is not allowed\ncommand is required\ndescription is required\nscopes is required\nshortCut is required\ncommand is required\ndescription is required\nscopes is required\nshortCut is required", }, } - dir, _ := os.Getwd() - assert.NoError(t, os.Chdir("../..")) - defer func() { - assert.NoError(t, os.Chdir(dir)) - }() for k, u := range uu { t.Run(k, func(t *testing.T) { p := NewPlugins() - err := p.Load(path.Join(dir, u.path), false) + err := p.Load(u.path, false) if err != nil { - idx := strings.Index(err.Error(), ":") - assert.Equal(t, u.err, err.Error()[idx+2:]) + assert.Equal(t, u.err, err.Error()) } assert.Equal(t, u.ee, p) }) @@ -111,15 +102,9 @@ func TestSinglePluginFileLoad(t *testing.T) { Confirm: true, } - dir, _ := os.Getwd() - assert.NoError(t, os.Chdir("../..")) - defer func() { - assert.NoError(t, os.Chdir(dir)) - }() - p := NewPlugins() - assert.NoError(t, p.load(path.Join(dir, "testdata/plugins/plugins.yaml"))) - assert.NoError(t, p.loadDir(path.Join(dir, "/random/dir/not/exist"))) + assert.NoError(t, p.load("testdata/plugins/plugins.yaml")) + assert.NoError(t, p.loadDir("/random/dir/not/exist")) assert.Equal(t, 1, len(p.Plugins)) v, ok := p.Plugins["blah"] @@ -135,8 +120,8 @@ func TestMultiplePluginFilesLoad(t *testing.T) { ee Plugins }{ "empty": { - path: "internal/config/testdata/plugins/plugins.yaml", - dir: "internal/config/testdata/plugins/dir", + path: "testdata/plugins/plugins.yaml", + dir: "testdata/plugins/dir", ee: Plugins{ Plugins: plugins{ "blah": { @@ -181,11 +166,6 @@ func TestMultiplePluginFilesLoad(t *testing.T) { }, } - dir, _ := os.Getwd() - assert.NoError(t, os.Chdir("../..")) - defer func() { - assert.NoError(t, os.Chdir(dir)) - }() for k, u := range uu { t.Run(k, func(t *testing.T) { p := NewPlugins() diff --git a/internal/config/views.go b/internal/config/views.go index de3ad028..5fdd6820 100644 --- a/internal/config/views.go +++ b/internal/config/views.go @@ -185,7 +185,7 @@ func (v *CustomView) getVS(gvr, ns string) *ViewSetting { }) slices.Reverse(kk) for _, key := range kk { - if !strings.HasPrefix(key, gvr) { + if !strings.HasPrefix(key, gvr) && !strings.HasPrefix(gvr, key) { continue } @@ -203,10 +203,23 @@ func (v *CustomView) getVS(gvr, ns string) *ViewSetting { vs := v.Views[key] return &vs } + case strings.HasPrefix(k, key): + kk := strings.Fields(k) + if len(kk) == 2 { + if v, ok := v.Views[kk[0]+"@"+kk[1]]; ok { + return &v + } + if key == kk[0] { + vs := v.Views[key] + return &vs + } + } + fallthrough case key == k: vs := v.Views[key] return &vs } + } return nil diff --git a/internal/render/cust_cols.go b/internal/render/cust_cols.go index b3026ffc..86129770 100644 --- a/internal/render/cust_cols.go +++ b/internal/render/cust_cols.go @@ -151,7 +151,7 @@ func hydrate(o runtime.Object, cc ColumnSpecs, parsers []*jsonpath.JSONPath, rh Header: cc[idx].Header, Value: NAValue, } - slog.Warn("Unable to find column %s", slogs.Name, cc[idx].Header.Name) + slog.Warn("Unable to find custom column", slogs.Name, cc[idx].Header.Name) continue } var v string diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 6b4929af..244c986c 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,6 +1,6 @@ name: k9s base: core22 -version: 'v0.40.9' +version: 'v0.40.10' 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.