Skip to content

Commit 594c2c6

Browse files
authored
Rel v0.50.3 (#3276)
* update linter * spring cleaning - m'o code cleanup - small bugs fixin * fix cust col jq parser support * add context,token to shell args * rel notes
1 parent 630f82c commit 594c2c6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+386
-352
lines changed

.github/workflows/lint.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ jobs:
2020
- name: Lint
2121
uses: golangci/[email protected]
2222
with:
23-
github_token: ${{ secrets.GITHUB_TOKEN }}
24-
reporter: github-pr-check
23+
github-token: ${{ secrets.GITHUB_TOKEN }}
24+
version: v2.1.1

.golangci.yml

+18-17
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ linters:
4141
- goconst
4242
- dogsled
4343
- lll
44-
# - dupl
45-
# - gochecknoinits
46-
# - mnd
4744

4845
settings:
4946
dogsled:
@@ -96,20 +93,24 @@ linters:
9693
goconst:
9794
min-len: 2
9895
min-occurrences: 3
99-
ignore-strings: 'blee|duh|cl-1|ct-1-1'
100-
101-
# gocritic:
102-
# enabled-tags:
103-
# - diagnostic
104-
# - experimental
105-
# - opinionated
106-
# - performance
107-
# - style
108-
# disabled-checks:
109-
# - dupImport # https://github.com/go-critic/go-critic/issues/845
110-
# - ifElseChain
111-
# - octalLiteral
112-
# - whyNoLint
96+
ignore-string-values:
97+
- blee
98+
- duh
99+
- cl-1
100+
- ct-1-1
101+
102+
gocritic:
103+
enabled-tags:
104+
- diagnostic
105+
- experimental
106+
- opinionated
107+
- performance
108+
- style
109+
disabled-checks:
110+
- dupImport # https://github.com/go-critic/go-critic/issues/845
111+
- ifElseChain
112+
- octalLiteral
113+
- whyNoLint
113114

114115
gocyclo:
115116
min-complexity: 35

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ DATE ?= $(shell TZ=UTC date -j -f "%s" ${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:
1111
else
1212
DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ")
1313
endif
14-
VERSION ?= v0.50.2
14+
VERSION ?= v0.50.3
1515
IMG_NAME := derailed/k9s
1616
IMAGE := ${IMG_NAME}:${VERSION}
1717

change_logs/release_v0.50.3.md

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s.png" align="center" width="800" height="auto"/>
2+
3+
# Release v0.50.3
4+
5+
## Notes
6+
7+
Thank you to all that contributed with flushing out issues and enhancements for K9s!
8+
I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev
9+
and see if we're happier with some of the fixes!
10+
If you've filed an issue please help me verify and close.
11+
12+
Your support, kindness and awesome suggestions to make K9s better are, as ever, very much noted and appreciated!
13+
Also big thanks to all that have allocated their own time to help others on both slack and on this repo!!
14+
15+
As you may know, K9s is not pimped out by corps with deep pockets, thus if you feel K9s is helping your Kubernetes journey,
16+
please consider joining our [sponsorship program](https://github.com/sponsors/derailed) and/or make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
17+
18+
On Slack? Please join us [K9slackers](https://join.slack.com/t/k9sers/shared_invite/zt-3360a389v-ElLHrb0Dp1kAXqYUItSAFA)
19+
20+
## Maintenance Release!
21+
22+
A bit more code spring cleaning/TLC and address a few bugs:
23+
24+
1. [RBAC View] Fix issue bombing out on RBAC cluster roles
25+
2. [Custom Views] Fix issue with parsing `jq` filters and bombing out (Big Thanks to Pierre for flagging it!)
26+
27+
---
28+
29+
## Contributed PRs
30+
31+
Please be sure to give `Big Thanks!` and `ATTA Girls/Boys!` to all the fine contributors for making K9s better for all of us!!
32+
33+
* [#3273](https://github.com/derailed/k9s/pull/3273) k9s plugin scopes containers issue
34+
* [#3169](https://github.com/derailed/k9s/pull/3169) feat: pass context and token flags to kubectl exec commands
35+
36+
37+
---
38+
<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)

internal/client/gvr.go

+19-5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"github.com/derailed/k9s/internal/slogs"
1313
"github.com/fvbommel/sortorder"
14+
"gopkg.in/yaml.v3"
1415
apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
1516
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1617
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -43,9 +44,9 @@ func (c gvrCache) get(gvrs string) *GVR {
4344
var gvrsCache = make(gvrCache)
4445

4546
// NewGVR builds a new gvr from a group, version, resource.
46-
func NewGVR(path string) *GVR {
47-
raw := path
48-
tokens := strings.Split(path, ":")
47+
func NewGVR(s string) *GVR {
48+
raw := s
49+
tokens := strings.Split(s, ":")
4950
var g, v, r, sr string
5051
if len(tokens) == 2 {
5152
raw, sr = tokens[0], tokens[1]
@@ -59,10 +60,10 @@ func NewGVR(path string) *GVR {
5960
case 1:
6061
r = tokens[0]
6162
default:
62-
slog.Error("GVR init failed!", slogs.Error, fmt.Errorf("can't parse GVR %q", path))
63+
slog.Error("GVR init failed!", slogs.Error, fmt.Errorf("can't parse GVR %q", s))
6364
}
6465

65-
gvr := GVR{raw: path, g: g, v: v, r: r, sr: sr}
66+
gvr := GVR{raw: s, g: g, v: v, r: r, sr: sr}
6667
if cgvr := gvrsCache.get(gvr.String()); cgvr != nil {
6768
return cgvr
6869
}
@@ -204,6 +205,19 @@ func (g *GVR) IsDecodable() bool {
204205
return g.GVK().Kind == "secrets"
205206
}
206207

208+
var _ = yaml.Marshaler((*GVR)(nil))
209+
var _ = yaml.Unmarshaler((*GVR)(nil))
210+
211+
func (g *GVR) MarshalYAML() (any, error) {
212+
return g.String(), nil
213+
}
214+
215+
func (g *GVR) UnmarshalYAML(n *yaml.Node) error {
216+
*g = *NewGVR(n.Value)
217+
218+
return nil
219+
}
220+
207221
// GVRs represents a collection of gvr.
208222
type GVRs []*GVR
209223

internal/client/helpers.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1616
)
1717

18-
var toFileName = regexp.MustCompile(`[^(\w/\.)]`)
18+
var toFileName = regexp.MustCompile(`[^(\w/.)]`)
1919

2020
// IsClusterWide returns true if ns designates cluster scope, false otherwise.
2121
func IsClusterWide(ns string) bool {

internal/client/metrics.go

+8-6
Original file line numberDiff line numberDiff line change
@@ -318,17 +318,19 @@ func ToMB(v int64) int64 {
318318
}
319319

320320
// ToPercentage computes percentage as string otherwise n/aa.
321-
func ToPercentage(v1, v2 int64) int {
322-
if v2 == 0 {
321+
func ToPercentage(v, dv int64) int {
322+
if dv == 0 {
323323
return 0
324324
}
325-
return int(math.Floor((float64(v1) / float64(v2)) * 100))
325+
326+
return int(math.Floor((float64(v) / float64(dv)) * 100))
326327
}
327328

328329
// ToPercentageStr computes percentage, but if v2 is 0, it will return NAValue instead of 0.
329-
func ToPercentageStr(v1, v2 int64) string {
330-
if v2 == 0 {
330+
func ToPercentageStr(v, dv int64) string {
331+
if dv == 0 {
331332
return NA
332333
}
333-
return strconv.Itoa(ToPercentage(v1, v2))
334+
335+
return strconv.Itoa(ToPercentage(v, dv))
334336
}

internal/config/alias.go

+20-32
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,19 @@ import (
1919
"k8s.io/apimachinery/pkg/util/sets"
2020
)
2121

22-
// Alias tracks shortname to GVR mappings.
23-
type Alias map[string]*client.GVR
22+
type (
23+
// Alias tracks shortname to GVR mappings.
24+
Alias map[string]*client.GVR
2425

25-
// ShortNames represents a collection of shortnames for aliases.
26-
type ShortNames map[*client.GVR][]string
26+
// ShortNames represents a collection of shortnames for aliases.
27+
ShortNames map[*client.GVR][]string
2728

28-
// Aliases represents a collection of aliases.
29-
type Aliases struct {
30-
Alias Alias `yaml:"aliases"`
31-
mx sync.RWMutex
32-
}
29+
// Aliases represents a collection of aliases.
30+
Aliases struct {
31+
Alias Alias `yaml:"aliases"`
32+
mx sync.RWMutex
33+
}
34+
)
3335

3436
// NewAliases return a new alias.
3537
func NewAliases() *Aliases {
@@ -108,6 +110,7 @@ func (a *Aliases) Get(alias string) (*client.GVR, bool) {
108110
func (a *Aliases) Define(gvr *client.GVR, aliases ...string) {
109111
a.mx.Lock()
110112
defer a.mx.Unlock()
113+
111114
for _, alias := range aliases {
112115
if _, ok := a.Alias[alias]; !ok && alias != "" {
113116
a.Alias[alias] = gvr
@@ -131,16 +134,6 @@ func (a *Aliases) Load(path string) error {
131134
return a.LoadFile(path)
132135
}
133136

134-
type aliases struct {
135-
Alias map[string]string `yaml:"aliases"`
136-
}
137-
138-
func newAliases(s int) aliases {
139-
return aliases{
140-
Alias: make(map[string]string, s),
141-
}
142-
}
143-
144137
// LoadFile loads alias from a given file.
145138
func (a *Aliases) LoadFile(path string) error {
146139
if _, err := os.Stat(path); errors.Is(err, fs.ErrNotExist) {
@@ -155,14 +148,10 @@ func (a *Aliases) LoadFile(path string) error {
155148
slog.Warn("Aliases validation failed", slogs.Error, err)
156149
}
157150

158-
var aa aliases
159-
if err := yaml.Unmarshal(bb, &aa); err != nil {
160-
return err
161-
}
162151
a.mx.Lock()
163152
defer a.mx.Unlock()
164-
for alias, cmd := range aa.Alias {
165-
a.Alias[alias] = client.NewGVR(cmd)
153+
if err := yaml.Unmarshal(bb, a); err != nil {
154+
return err
166155
}
167156

168157
return nil
@@ -198,18 +187,17 @@ func (a *Aliases) loadDefaultAliases() {
198187
// Save alias to disk.
199188
func (a *Aliases) Save() error {
200189
slog.Debug("Saving Aliases...")
201-
return a.SaveAliases(AppAliasesFile)
190+
a.mx.RLock()
191+
defer a.mx.RUnlock()
192+
193+
return a.saveAliases(AppAliasesFile)
202194
}
203195

204196
// SaveAliases saves aliases to a given file.
205-
func (a *Aliases) SaveAliases(path string) error {
197+
func (a *Aliases) saveAliases(path string) error {
206198
if err := data.EnsureDirPath(path, data.DefaultDirMod); err != nil {
207199
return err
208200
}
209-
aa := newAliases(len(a.Alias))
210-
for alias, gvr := range a.Alias {
211-
aa.Alias[alias] = gvr.String()
212-
}
213201

214-
return data.SaveYAML(path, aa)
202+
return data.SaveYAML(path, a)
215203
}

internal/config/config.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -186,16 +186,16 @@ func (c *Config) ActiveView() string {
186186
if err != nil {
187187
return data.DefaultView
188188
}
189-
cmd := ct.View.Active
189+
v := ct.View.Active
190190
if c.K9s.manualCommand != nil && *c.K9s.manualCommand != "" {
191-
cmd = *c.K9s.manualCommand
191+
v = *c.K9s.manualCommand
192192
// We reset the manualCommand property because
193193
// the command-line switch should only be considered once,
194194
// on startup.
195195
*c.K9s.manualCommand = ""
196196
}
197197

198-
return cmd
198+
return v
199199
}
200200

201201
func (c *Config) ResetActiveView() {

internal/dao/accessor.go

+30-30
Original file line numberDiff line numberDiff line change
@@ -8,44 +8,44 @@ import (
88
)
99

1010
var accessors = Accessors{
11-
*client.WkGVR: new(Workload),
12-
*client.CtGVR: new(Context),
13-
*client.CoGVR: new(Container),
14-
*client.ScnGVR: new(ImageScan),
15-
*client.SdGVR: new(ScreenDump),
16-
*client.BeGVR: new(Benchmark),
17-
*client.PfGVR: new(PortForward),
18-
*client.DirGVR: new(Dir),
19-
20-
*client.SvcGVR: new(Service),
21-
*client.PodGVR: new(Pod),
22-
*client.NodeGVR: new(Node),
23-
*client.NsGVR: new(Namespace),
24-
*client.CmGVR: new(ConfigMap),
25-
*client.SecGVR: new(Secret),
26-
27-
*client.DpGVR: new(Deployment),
28-
*client.DsGVR: new(DaemonSet),
29-
*client.StsGVR: new(StatefulSet),
30-
*client.RsGVR: new(ReplicaSet),
31-
32-
*client.CjGVR: new(CronJob),
33-
*client.JobGVR: new(Job),
34-
35-
*client.HmGVR: new(HelmChart),
36-
*client.HmhGVR: new(HelmHistory),
37-
38-
*client.CrdGVR: new(CustomResourceDefinition),
11+
client.WkGVR: new(Workload),
12+
client.CtGVR: new(Context),
13+
client.CoGVR: new(Container),
14+
client.ScnGVR: new(ImageScan),
15+
client.SdGVR: new(ScreenDump),
16+
client.BeGVR: new(Benchmark),
17+
client.PfGVR: new(PortForward),
18+
client.DirGVR: new(Dir),
19+
20+
client.SvcGVR: new(Service),
21+
client.PodGVR: new(Pod),
22+
client.NodeGVR: new(Node),
23+
client.NsGVR: new(Namespace),
24+
client.CmGVR: new(ConfigMap),
25+
client.SecGVR: new(Secret),
26+
27+
client.DpGVR: new(Deployment),
28+
client.DsGVR: new(DaemonSet),
29+
client.StsGVR: new(StatefulSet),
30+
client.RsGVR: new(ReplicaSet),
31+
32+
client.CjGVR: new(CronJob),
33+
client.JobGVR: new(Job),
34+
35+
client.HmGVR: new(HelmChart),
36+
client.HmhGVR: new(HelmHistory),
37+
38+
client.CrdGVR: new(CustomResourceDefinition),
3939
}
4040

4141
// Accessors represents a collection of dao accessors.
42-
type Accessors map[client.GVR]Accessor
42+
type Accessors map[*client.GVR]Accessor
4343

4444
// AccessorFor returns a client accessor for a resource if registered.
4545
// Otherwise it returns a generic accessor.
4646
// Customize here for non resource types or types with metrics or logs.
4747
func AccessorFor(f Factory, gvr *client.GVR) (Accessor, error) {
48-
r, ok := accessors[*gvr]
48+
r, ok := accessors[gvr]
4949
if !ok {
5050
r = new(Scaler)
5151
slog.Debug("No DAO registry entry. Using generics!", slogs.GVR, gvr)

0 commit comments

Comments
 (0)