Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: derailed/k9s
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.40.9
Choose a base ref
...
head repository: derailed/k9s
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.40.10
Choose a head ref
  • 3 commits
  • 12 files changed
  • 2 contributors

Commits on Mar 15, 2025

  1. chore(deps): bump golang.org/x/net from 0.35.0 to 0.36.0 (#3200)

    Bumps [golang.org/x/net](https://github.com/golang/net) from 0.35.0 to 0.36.0.
    - [Commits](golang/net@v0.35.0...v0.36.0)
    
    ---
    updated-dependencies:
    - dependency-name: golang.org/x/net
      dependency-type: indirect
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Mar 15, 2025

    Unverified

    This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
    Copy the full SHA
    a05496a View commit details

Commits on Mar 16, 2025

  1. update docs

    derailed committed Mar 16, 2025

    Unverified

    This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
    Copy the full SHA
    78c7787 View commit details
  2. Rel v0.40.10 (#3206)

    * [HOTFIX] Broke plugins ;(
    
    * add support for cust cols on alias+ns
    
    * rel notes
    derailed authored Mar 16, 2025
    Copy the full SHA
    35361bb View commit details
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -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}

2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -86,8 +86,6 @@ Below are organizations that have opted to show their support and sponsor K9s.
<br/>
<br/>

> NOTE! K9s neither vouches for nor endorses these companies or products.
---

## Installation
46 changes: 46 additions & 0 deletions change_logs/release_v0.40.10.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s.png" align="center" width="800" height="auto"/>

# 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

---

<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/imhotep_logo.png" width="32" height="auto"/> © 2025 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -313,10 +313,10 @@ require (
go.opentelemetry.io/otel/sdk/metric v1.29.0 // indirect
go.opentelemetry.io/otel/trace v1.33.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.33.0 // indirect
golang.org/x/crypto v0.35.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/mod v0.23.0 // indirect
golang.org/x/net v0.35.0 // indirect
golang.org/x/net v0.36.0 // indirect
golang.org/x/oauth2 v0.25.0 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.30.0 // indirect
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1291,8 +1291,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1393,8 +1393,8 @@ golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfS
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
21 changes: 19 additions & 2 deletions internal/config/json/schemas/plugin-multi.json
Original file line number Diff line number Diff line change
@@ -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"]
}
}
21 changes: 19 additions & 2 deletions internal/config/json/schemas/plugins.json
Original file line number Diff line number Diff line change
@@ -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": []
}
8 changes: 1 addition & 7 deletions internal/config/json/validator_test.go
Original file line number Diff line number Diff line change
@@ -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))
}
}

34 changes: 7 additions & 27 deletions internal/config/plugin_test.go
Original file line number Diff line number Diff line change
@@ -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()
15 changes: 14 additions & 1 deletion internal/config/views.go
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion internal/render/cust_cols.go
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion snap/snapcraft.yaml
Original file line number Diff line number Diff line change
@@ -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.