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.8
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.9
Choose a head ref
  • 4 commits
  • 29 files changed
  • 5 contributors

Commits on Mar 12, 2025

  1. fix(coloring): invalid color application for rows with VALID column (#…

    …3137)
    
    * fix(coloring): invalid color application for rows with VALID column
    
    Signed-off-by: aaronschweig <aaron.schweig@gmail.com>
    
    * tests(pod): new valid function needs different test fixtures
    
    Signed-off-by: aaronschweig <aaron.schweig@gmail.com>
    
    * fix: fix tests without introducing a regression bug
    
    Signed-off-by: aaronschweig <aaron.schweig@gmail.com>
    
    ---------
    
    Signed-off-by: aaronschweig <aaron.schweig@gmail.com>
    aaronschweig authored Mar 12, 2025
    Copy the full SHA
    ee674d3 View commit details
  2. chore(deps): bump golangci/golangci-lint-action from 6.3.2 to 6.5.0 (#…

    …3127)
    
    Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 6.3.2 to 6.5.0.
    - [Release notes](https://github.com/golangci/golangci-lint-action/releases)
    - [Commits](golangci/golangci-lint-action@v6.3.2...v6.5.0)
    
    ---
    updated-dependencies:
    - dependency-name: golangci/golangci-lint-action
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    Co-authored-by: Fernand Galiana <fernand.galiana@gmail.com>
    dependabot[bot] and derailed authored Mar 12, 2025
    Copy the full SHA
    74ff6d4 View commit details
  3. Extend the argocd plugin by refresh and en/dis-abling of app sync (#3142

    )
    
    * Extend the argocd plugin by refresh and en/dis-abling of app sync
    
    * Add argocd plugin to plugins readme
    
    ---------
    
    Co-authored-by: Lorenz Boguhn <Lorenz.Boguhn@ppi.de>
    lorenzboguhn and lobo-ppi authored Mar 12, 2025
    Copy the full SHA
    39eef03 View commit details

Commits on Mar 15, 2025

  1. Rel v0.40.9 (#3205)

    * update write icon
    
    * fix#3202
    
    * rel docs
    
    * update linter
    
    * lint
    
    * test
    
    * lint
    derailed authored Mar 15, 2025
    Copy the full SHA
    fc5f190 View commit details
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ jobs:
cache-dependency-path: go.sum

- name: Lint
uses: golangci/golangci-lint-action@v6.3.2
uses: golangci/golangci-lint-action@v6.5.1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
reporter: github-pr-check
26 changes: 7 additions & 19 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -50,7 +50,12 @@ linters-settings:
goimports:
local-prefixes: github.com/cilium/cilium
unused:
go: "1.23"
parameters-are-used: true
local-variables-are-used: true
field-writes-are-uses: true
post-statements-are-reads: true
exported-fields-are-used: true
generated-is-used: true
goheader:
values:
regexp:
@@ -61,23 +66,6 @@ linters-settings:
gosec:
includes:
- G402
gomodguard:
blocked:
modules:
- github.com/miekg/dns:
recommendations:
- github.com/cilium/dns
reason: "use the cilium fork directly to avoid replace directives in go.mod, see https://github.com/cilium/cilium/pull/27582"
- gopkg.in/check.v1:
recommendations:
- testing
- github.com/stretchr/testify/assert
reason: "gocheck has been deprecated, see https://docs.cilium.io/en/latest/contributing/testing/unit/#migrating-tests-off-of-gopkg-in-check-v1"
- go.uber.org/multierr:
recommendations:
- errors
reason: "Go 1.20+ has support for combining multiple errors, see https://go.dev/doc/go1.20#errors"

sloglint:
# Enforce not mixing key-value pairs and attributes.
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-mixed-arguments
@@ -138,7 +126,7 @@ issues:

# default is true. Enables skipping of directories:
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
skip-dirs-use-default: true
exclude-dirs-use-default: true

# Excluding configuration per-path, per-linter, per-text and per-source
exclude-rules:
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.8
VERSION ?= v0.40.9
IMG_NAME := derailed/k9s
IMAGE := ${IMG_NAME}:${VERSION}

54 changes: 50 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -726,7 +726,15 @@ views:
## Plugins
K9s allows you to extend your command line and tooling by defining your very own cluster commands via plugins. K9s will look at `$XDG_CONFIG_HOME/k9s/plugins.yaml` to locate all available plugins.
K9s allows you to extend your command line and tooling by defining your very own cluster commands via plugins.
Minimally we look at `$XDG_CONFIG_HOME/k9s/plugins.yaml` to locate all available plugins.
Additionally, K9s will scan the following directories for additional plugins:
* `$XDG_CONFIG_HOME/k9s/plugins`
* `$XDG_DATA_HOME/k9s/plugins`
* `$XDG_DATA_DIRS/k9s/plugins`
The plugin file content can be either a single plugin snippet, a collections of snippets or a complete plugins definition (see examples below...).
A plugin is defined as follows:
@@ -760,12 +768,15 @@ K9s does provide additional environment variables for you to customize your plug
Curly braces can be used to embed an environment variable inside another string, or if the column name contains special characters. (e.g. `${NAME}-example` or `${COL-%CPU/L}`)
### Plugin Example
### Plugin Examples
Define several plugins and host them in a single file. These can leave in the K9s root config so that they are available on any clusters. Additionally, you can define cluster/context specific plugins for your clusters of choice by adding clusterA/contextB/plugins.yaml file.
This defines a plugin for viewing logs on a selected pod using `ctrl-l` as shortcut.
The following defines a plugin for viewing logs on a selected pod using `ctrl-l` as shortcut.
```yaml
# $XDG_DATA_HOME/k9s/plugins.yaml
# Define several plugins in a single file in the K9s root configuration
# $XDG_DATA_HOME/k9s/plugins.yaml
plugins:
# Defines a plugin to provide a `ctrl-l` shortcut to tail the logs while in pod view.
fred:
@@ -789,6 +800,41 @@ plugins:
- $CONTEXT
```
Similarly you can define the plugin above in a directory using either a file per plugin or several plugins per files as follow...
The following defines two plugins namely fred and zorg.
```yaml
# Multiple plugins in a single file...
# Note: as of v0.40.9 you can have ad-hoc plugin dirs
# Loads plugins fred and zorg
# $XDG_DATA_HOME/k9s/plugins/misc-plugins/blee.yaml
fred:
shortCut: Shift-B
description: Bozo
scopes:
- deploy
command: bozo
zorg:
shortCut: Shift-Z
description: Pod logs
scopes:
- svc
command: zorg
```
Lastly you can define plugin snippets in their own file. The snippet will be named from the file name. In this case, we define a `bozo` plugin using a plugin snippet.
```yaml
# $XDG_DATA_HOME/k9s/plugins/schtuff/bozo.yaml
shortCut: Shift-B
description: Bozo
scopes:
- deploy
command: bozo
```
> NOTE: This is an experimental feature! Options and layout may change in future K9s releases as this feature solidifies.
---
44 changes: 44 additions & 0 deletions change_logs/release_v0.40.9.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s.png" align="center" width="800" height="auto"/>

# Release v0.40.9

## 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!

* 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)
1 change: 1 addition & 0 deletions internal/config/helpers.go
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@ func isStringSet(s *string) bool {

func isYamlFile(file string) bool {
ext := filepath.Ext(file)

return ext == ".yml" || ext == ".yaml"
}

9 changes: 9 additions & 0 deletions internal/config/json/schemas/plugin-multi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "K9s plugin-multi schema",
"type": "object",
"additionalProperties": {
"$ref": "file://internal/config/json/schemas/plugin.json",
"additionalProperties": false
}
}
25 changes: 25 additions & 0 deletions internal/config/json/schemas/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "K9s plugin schema",
"type": "object",
"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"]
}
23 changes: 2 additions & 21 deletions internal/config/json/schemas/plugins.json
Original file line number Diff line number Diff line change
@@ -7,27 +7,8 @@
"plugins": {
"type": "object",
"additionalProperties": {
"type": "object",
"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"]
"$ref": "file://internal/config/json/schemas/plugin.json",
"additionalProperties": false
},
"required": []
}
10 changes: 10 additions & 0 deletions internal/config/json/testdata/plugins/snippet.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
shortCut: g
confirm: false
description: blee
scopes:
- namespaces
command: sh
background: false
args:
- -c
- "blee bla"
23 changes: 23 additions & 0 deletions internal/config/json/testdata/plugins/snippets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
blee:
shortCut: g
confirm: false
description: blee
scopes:
- namespaces
command: sh
background: false
args:
- -c
- "blee bla"

duh:
shortCut: h
confirm: true
description: duh
scopes:
- all
command: sh
background: true
args:
- -c
- "duh fred"
46 changes: 37 additions & 9 deletions internal/config/json/validator.go
Original file line number Diff line number Diff line change
@@ -20,6 +20,12 @@ const (
// PluginsSchema describes plugins schema.
PluginsSchema = "plugins.json"

// PluginSchema describes a plugin snippet schema.
PluginSchema = "plugin.json"

// PluginMultiSchema describes plugin snippets schema.
PluginMultiSchema = "plugin-multi.json"

// AliasesSchema describes aliases schema.
AliasesSchema = "aliases.json"

@@ -41,8 +47,14 @@ const (

var (
//go:embed schemas/plugins.json
pluginsSchema string

//go:embed schemas/plugin.json
pluginSchema string

//go:embed schemas/plugin-multi.json
pluginMultiSchema string

//go:embed schemas/aliases.json
aliasSchema string

@@ -72,13 +84,15 @@ type Validator struct {
func NewValidator() *Validator {
v := Validator{
schemas: map[string]gojsonschema.JSONLoader{
K9sSchema: gojsonschema.NewStringLoader(k9sSchema),
ContextSchema: gojsonschema.NewStringLoader(contextSchema),
AliasesSchema: gojsonschema.NewStringLoader(aliasSchema),
ViewsSchema: gojsonschema.NewStringLoader(viewsSchema),
PluginsSchema: gojsonschema.NewStringLoader(pluginSchema),
HotkeysSchema: gojsonschema.NewStringLoader(hotkeysSchema),
SkinSchema: gojsonschema.NewStringLoader(skinSchema),
K9sSchema: gojsonschema.NewStringLoader(k9sSchema),
ContextSchema: gojsonschema.NewStringLoader(contextSchema),
AliasesSchema: gojsonschema.NewStringLoader(aliasSchema),
ViewsSchema: gojsonschema.NewStringLoader(viewsSchema),
PluginsSchema: gojsonschema.NewStringLoader(pluginsSchema),
PluginSchema: gojsonschema.NewStringLoader(pluginSchema),
PluginMultiSchema: gojsonschema.NewStringLoader(pluginMultiSchema),
HotkeysSchema: gojsonschema.NewStringLoader(hotkeysSchema),
SkinSchema: gojsonschema.NewStringLoader(skinSchema),
},
}
v.register()
@@ -92,7 +106,6 @@ func (v *Validator) register() {
v.loader.Validate = true

clog := slog.With(slogs.Subsys, "schema")

for k, s := range v.schemas {
if err := v.loader.AddSchema(k, s); err != nil {
clog.Error("Schema initialization failed",
@@ -103,9 +116,24 @@ func (v *Validator) register() {
}
}

// ValidatePlugins validates plugins schema.
// Checks for full, snippet and multi snippets schemas.
func (v *Validator) ValidatePlugins(bb []byte) (string, error) {
var errs error
for _, k := range []string{PluginsSchema, PluginSchema, PluginMultiSchema} {
if err := v.Validate(k, bb); err != nil {
errs = errors.Join(errs, err)
continue
}
return k, nil
}

return "", errs
}

// Validate runs document thru given schema validation.
func (v *Validator) Validate(k string, bb []byte) error {
var m interface{}
var m any
err := yaml.Unmarshal(bb, &m)
if err != nil {
return err
Loading