add label select + bugz fixes
parent
15a9885d16
commit
127414b5e5
|
|
@ -67,8 +67,7 @@ snapcraft:
|
||||||
By leveraging a terminal UI, you can easily traverse Kubernetes resources
|
By leveraging a terminal UI, you can easily traverse Kubernetes resources
|
||||||
and view the state of you clusters in a single powerful session.
|
and view the state of you clusters in a single powerful session.
|
||||||
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
|
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
|
||||||
publish: false
|
publish: true
|
||||||
# publish: true
|
|
||||||
replacements:
|
replacements:
|
||||||
amd64: 64-bit
|
amd64: 64-bit
|
||||||
386: 32-bit
|
386: 32-bit
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s_small.png" align="right" width="200" height="auto"/>
|
||||||
|
|
||||||
|
# Release v0.7.7
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Thank you to all that contributed with flushing out issues with 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 is as always very much appreciated!
|
||||||
|
|
||||||
|
Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Change Logs
|
||||||
|
|
||||||
|
### Labels Filters
|
||||||
|
|
||||||
|
K9s now provides an affordance to filter Kubernetes resources by label (Feature #233. Thank you [Chad Hanley](https://github.com/cchanley2003)). In order to enable filtering by labels, enter the filter mode via `/` on any resource table and enter your label filter via `-l app=fred,env=prod` + `<ENTER>`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Resolved Bugs/Features
|
||||||
|
|
||||||
|
+ [Feature #233](https://github.com/derailed/k9s/issues/233)
|
||||||
|
+ [Issue #232](https://github.com/derailed/k9s/issues/232)
|
||||||
|
+ [Issue #230](https://github.com/derailed/k9s/issues/230)
|
||||||
|
+ [Issue #229](https://github.com/derailed/k9s/issues/229)
|
||||||
|
+ [Issue #226](https://github.com/derailed/k9s/issues/226) Thank you for the excellent PR [Yves Blusseau](https://github.com/JrCs)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/imhotep_logo.png" width="32" height="auto"/> © 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
|
@ -117,7 +117,7 @@ func (a *APIClient) CanIAccess(ns, name, resURL string, verbs []string) (bool, e
|
||||||
sar.Spec.ResourceAttributes.Verb = v
|
sar.Spec.ResourceAttributes.Verb = v
|
||||||
resp, err = a.DialOrDie().AuthorizationV1().SelfSubjectAccessReviews().Create(sar)
|
resp, err = a.DialOrDie().AuthorizationV1().SelfSubjectAccessReviews().Create(sar)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn().Err(err).Msgf("CanIAccess")
|
log.Error().Err(err).Msgf("CanIAccess")
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
log.Debug().Msgf("CHECKING ACCESS group:%q|resource:%q|namespace:%q|name:%q, verb:%s access:%t -- %s", gr.Group, gr.Resource, ns, name, v, resp.Status.Allowed, resp.Status.Reason)
|
log.Debug().Msgf("CHECKING ACCESS group:%q|resource:%q|namespace:%q|name:%q, verb:%s access:%t -- %s", gr.Group, gr.Resource, ns, name, v, resp.Status.Allowed, resp.Status.Reason)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal/k8s"
|
"github.com/derailed/k9s/internal/k8s"
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
|
mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
|
||||||
)
|
)
|
||||||
|
|
@ -175,8 +174,6 @@ func (r *Container) Fields(ns string) Row {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().Msgf("Container %s %v", i.Name, cs.Name)
|
|
||||||
|
|
||||||
ready, state, restarts := "false", MissingValue, "0"
|
ready, state, restarts := "false", MissingValue, "0"
|
||||||
if cs != nil {
|
if cs != nil {
|
||||||
ready, state, restarts = boolToStr(cs.Ready), toState(cs.State), strconv.Itoa(int(cs.RestartCount))
|
ready, state, restarts = boolToStr(cs.Ready), toState(cs.State), strconv.Itoa(int(cs.RestartCount))
|
||||||
|
|
|
||||||
|
|
@ -54,13 +54,11 @@ func (v *logResourceView) getSelection() string {
|
||||||
|
|
||||||
func (v *logResourceView) prevLogsCmd(evt *tcell.EventKey) *tcell.EventKey {
|
func (v *logResourceView) prevLogsCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
v.showLogs(true)
|
v.showLogs(true)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *logResourceView) logsCmd(evt *tcell.EventKey) *tcell.EventKey {
|
func (v *logResourceView) logsCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
v.showLogs(false)
|
v.showLogs(false)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,10 @@ import (
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const containerFmt = "[fg:bg:b]%s([hilite:bg:b]%s[fg:bg:-])"
|
const (
|
||||||
|
containerFmt = "[fg:bg:b]%s([hilite:bg:b]%s[fg:bg:-])"
|
||||||
|
shellCheck = "command -v bash >/dev/null && exec bash || exec sh"
|
||||||
|
)
|
||||||
|
|
||||||
type podView struct {
|
type podView struct {
|
||||||
*resourceView
|
*resourceView
|
||||||
|
|
@ -241,5 +244,5 @@ func computeShellArgs(path, co, context string, kcfg *string) []string {
|
||||||
args = append(args, "-c", co)
|
args = append(args, "-c", co)
|
||||||
}
|
}
|
||||||
|
|
||||||
return append(args, "--", "sh", "-c", "command -v bash >/dev/null && exec bash || exec sh")
|
return append(args, "--", "sh", "-c", shellCheck)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,28 +19,28 @@ func TestComputeShellArgs(t *testing.T) {
|
||||||
"c1",
|
"c1",
|
||||||
"ctx1",
|
"ctx1",
|
||||||
&config,
|
&config,
|
||||||
"exec -it --context ctx1 -n fred blee --kubeconfig coolConfig -c c1 -- sh -c command -v bash >/dev/null && exec bash || exec sh",
|
"exec -it --context ctx1 -n fred blee --kubeconfig coolConfig -c c1 -- sh -c " + shellCheck,
|
||||||
},
|
},
|
||||||
"noconfig": {
|
"noconfig": {
|
||||||
"fred/blee",
|
"fred/blee",
|
||||||
"c1",
|
"c1",
|
||||||
"ctx1",
|
"ctx1",
|
||||||
nil,
|
nil,
|
||||||
"exec -it --context ctx1 -n fred blee -c c1 -- sh -c command -v bash >/dev/null && exec bash || exec sh",
|
"exec -it --context ctx1 -n fred blee -c c1 -- sh -c " + shellCheck,
|
||||||
},
|
},
|
||||||
"emptyConfig": {
|
"emptyConfig": {
|
||||||
"fred/blee",
|
"fred/blee",
|
||||||
"c1",
|
"c1",
|
||||||
"ctx1",
|
"ctx1",
|
||||||
&empty,
|
&empty,
|
||||||
"exec -it --context ctx1 -n fred blee -c c1 -- sh -c command -v bash >/dev/null && exec bash || exec sh",
|
"exec -it --context ctx1 -n fred blee -c c1 -- sh -c " + shellCheck,
|
||||||
},
|
},
|
||||||
"singleContainer": {
|
"singleContainer": {
|
||||||
"fred/blee",
|
"fred/blee",
|
||||||
"",
|
"",
|
||||||
"ctx1",
|
"ctx1",
|
||||||
&empty,
|
&empty,
|
||||||
"exec -it --context ctx1 -n fred blee -- sh -c command -v bash >/dev/null && exec bash || exec sh",
|
"exec -it --context ctx1 -n fred blee -- sh -c " + shellCheck,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,11 @@ type resourceView struct {
|
||||||
parentCtx context.Context
|
parentCtx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *resourceView) filterResource(sel string) {
|
||||||
|
v.list.SetLabelSelector(sel)
|
||||||
|
v.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
func newResourceView(title string, app *appView, list resource.List) resourceViewer {
|
func newResourceView(title string, app *appView, list resource.List) resourceViewer {
|
||||||
v := resourceView{
|
v := resourceView{
|
||||||
app: app,
|
app: app,
|
||||||
|
|
@ -58,6 +63,8 @@ func newResourceView(title string, app *appView, list resource.List) resourceVie
|
||||||
|
|
||||||
tv := newTableView(app, v.title)
|
tv := newTableView(app, v.title)
|
||||||
tv.SetSelectionChangedFunc(v.selChanged)
|
tv.SetSelectionChangedFunc(v.selChanged)
|
||||||
|
tv.filterChanged(v.filterResource)
|
||||||
|
|
||||||
v.AddPage(v.list.GetName(), tv, true, true)
|
v.AddPage(v.list.GetName(), tv, true, true)
|
||||||
|
|
||||||
details := newDetailsView(app, v.backCmd)
|
details := newDetailsView(app, v.backCmd)
|
||||||
|
|
@ -114,9 +121,12 @@ func (v *resourceView) init(ctx context.Context, ns string) {
|
||||||
v.app.clusterInfoView.refresh()
|
v.app.clusterInfoView.refresh()
|
||||||
v.refresh()
|
v.refresh()
|
||||||
if tv, ok := v.CurrentPage().Item.(*tableView); ok {
|
if tv, ok := v.CurrentPage().Item.(*tableView); ok {
|
||||||
|
r, _ := tv.GetSelection()
|
||||||
|
if r == 0 && tv.GetRowCount() > 0 {
|
||||||
tv.Select(1, 0)
|
tv.Select(1, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (v *resourceView) update(ctx context.Context) {
|
func (v *resourceView) update(ctx context.Context) {
|
||||||
go func(ctx context.Context) {
|
go func(ctx context.Context) {
|
||||||
|
|
@ -151,7 +161,6 @@ func (v *resourceView) getSelectedItem() string {
|
||||||
if v.selectedFn != nil {
|
if v.selectedFn != nil {
|
||||||
return v.selectedFn()
|
return v.selectedFn()
|
||||||
}
|
}
|
||||||
|
|
||||||
return v.selectedItem
|
return v.selectedItem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,15 +247,12 @@ func (v *resourceView) showDelete(msg string, done func(bool, bool)) {
|
||||||
SetLabelColor(tcell.ColorAqua).
|
SetLabelColor(tcell.ColorAqua).
|
||||||
SetFieldTextColor(tcell.ColorOrange)
|
SetFieldTextColor(tcell.ColorOrange)
|
||||||
f.AddCheckbox("Cascade:", cascade, func(checked bool) {
|
f.AddCheckbox("Cascade:", cascade, func(checked bool) {
|
||||||
log.Debug().Msgf("Cascade changed: %t", checked)
|
|
||||||
cascade = checked
|
cascade = checked
|
||||||
})
|
})
|
||||||
f.AddCheckbox("Force:", force, func(checked bool) {
|
f.AddCheckbox("Force:", force, func(checked bool) {
|
||||||
log.Debug().Msgf("Force changed: %t", checked)
|
|
||||||
force = checked
|
force = checked
|
||||||
})
|
})
|
||||||
f.AddButton("Cancel", func() {
|
f.AddButton("Cancel", func() {
|
||||||
v.app.flash().info("Canceled!!")
|
|
||||||
v.dismissModal()
|
v.dismissModal()
|
||||||
})
|
})
|
||||||
f.AddButton("OK", func() {
|
f.AddButton("OK", func() {
|
||||||
|
|
@ -292,9 +298,7 @@ func (v *resourceView) describeCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
return evt
|
return evt
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().Msgf("Selected Item %v-%v-%v", v.list.GetNamespace(), v.list.GetName(), v.selectedItem)
|
|
||||||
v.defaultEnter(v.list.GetNamespace(), v.list.GetName(), v.selectedItem)
|
v.defaultEnter(v.list.GetNamespace(), v.list.GetName(), v.selectedItem)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,13 @@ func (s groupSorter) Less(i, j int) bool {
|
||||||
// Helpers...
|
// Helpers...
|
||||||
|
|
||||||
func less(asc bool, c1, c2 string) bool {
|
func less(asc bool, c1, c2 string) bool {
|
||||||
|
if c1 == resource.NAValue && c2 != resource.NAValue {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if c1 != resource.NAValue && c2 == resource.NAValue {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
if o, ok := isMetricSort(asc, c1, c2); ok {
|
if o, ok := isMetricSort(asc, c1, c2); ok {
|
||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,26 @@ func TestRowSort(t *testing.T) {
|
||||||
resource.Rows{resource.Row{"8m4s"}, resource.Row{"31m"}},
|
resource.Rows{resource.Row{"8m4s"}, resource.Row{"31m"}},
|
||||||
resource.Rows{resource.Row{"8m4s"}, resource.Row{"31m"}},
|
resource.Rows{resource.Row{"8m4s"}, resource.Row{"31m"}},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
true,
|
||||||
|
resource.Rows{resource.Row{"n/a"}, resource.Row{"31m"}},
|
||||||
|
resource.Rows{resource.Row{"31m"}, resource.Row{"n/a"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
true,
|
||||||
|
resource.Rows{resource.Row{"31m"}, resource.Row{"n/a"}},
|
||||||
|
resource.Rows{resource.Row{"31m"}, resource.Row{"n/a"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
false,
|
||||||
|
resource.Rows{resource.Row{"n/a"}, resource.Row{"31m"}},
|
||||||
|
resource.Rows{resource.Row{"31m"}, resource.Row{"n/a"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
false,
|
||||||
|
resource.Rows{resource.Row{"31m"}, resource.Row{"n/a"}},
|
||||||
|
resource.Rows{resource.Row{"31m"}, resource.Row{"n/a"}},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, u := range uu {
|
for _, u := range uu {
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ const (
|
||||||
nsTitleFmt = "[fg:bg:b] %s([hilite:bg:b]%s[fg:bg:-])[fg:bg:-][[count:bg:b]%d[fg:bg:-]][fg:bg:-] "
|
nsTitleFmt = "[fg:bg:b] %s([hilite:bg:b]%s[fg:bg:-])[fg:bg:-][[count:bg:b]%d[fg:bg:-]][fg:bg:-] "
|
||||||
descIndicator = "↓"
|
descIndicator = "↓"
|
||||||
ascIndicator = "↑"
|
ascIndicator = "↑"
|
||||||
|
labelSelIndicator = "-l"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -54,8 +55,8 @@ type (
|
||||||
cleanseFn cleanseFn
|
cleanseFn cleanseFn
|
||||||
data resource.TableData
|
data resource.TableData
|
||||||
cmdBuff *cmdBuff
|
cmdBuff *cmdBuff
|
||||||
sortBuff *cmdBuff
|
|
||||||
sortCol sortColumn
|
sortCol sortColumn
|
||||||
|
filterFn func(string)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -89,6 +90,10 @@ func newTableView(app *appView, title string) *tableView {
|
||||||
return &v
|
return &v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *tableView) filterChanged(fn func(string)) {
|
||||||
|
v.filterFn = fn
|
||||||
|
}
|
||||||
|
|
||||||
func (v *tableView) bindKeys() {
|
func (v *tableView) bindKeys() {
|
||||||
v.actions[tcell.KeyCtrlS] = newKeyAction("Save", v.saveCmd, true)
|
v.actions[tcell.KeyCtrlS] = newKeyAction("Save", v.saveCmd, true)
|
||||||
v.actions[KeySlash] = newKeyAction("Filter Mode", v.activateCmd, false)
|
v.actions[KeySlash] = newKeyAction("Filter Mode", v.activateCmd, false)
|
||||||
|
|
@ -191,6 +196,11 @@ func (v *tableView) saveCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
func (v *tableView) filterCmd(evt *tcell.EventKey) *tcell.EventKey {
|
func (v *tableView) filterCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
if v.cmdBuff.isActive() {
|
if v.cmdBuff.isActive() {
|
||||||
v.cmdBuff.setActive(false)
|
v.cmdBuff.setActive(false)
|
||||||
|
cmd := v.cmdBuff.String()
|
||||||
|
if isLabelSelector(cmd) && v.filterFn != nil {
|
||||||
|
v.filterFn(trimLabelSelector(cmd))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
v.refresh()
|
v.refresh()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -210,6 +220,9 @@ func (v *tableView) resetCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
if !v.cmdBuff.empty() {
|
if !v.cmdBuff.empty() {
|
||||||
v.app.flash().info("Clearing filter...")
|
v.app.flash().info("Clearing filter...")
|
||||||
}
|
}
|
||||||
|
if isLabelSelector(v.cmdBuff.String()) {
|
||||||
|
v.filterFn("")
|
||||||
|
}
|
||||||
v.cmdBuff.reset()
|
v.cmdBuff.reset()
|
||||||
v.refresh()
|
v.refresh()
|
||||||
|
|
||||||
|
|
@ -257,6 +270,9 @@ func (v *tableView) activateCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
v.app.flash().info("Filter mode activated.")
|
v.app.flash().info("Filter mode activated.")
|
||||||
|
if isLabelSelector(v.cmdBuff.String()) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
v.cmdBuff.reset()
|
v.cmdBuff.reset()
|
||||||
v.cmdBuff.setActive(true)
|
v.cmdBuff.setActive(true)
|
||||||
|
|
||||||
|
|
@ -308,7 +324,7 @@ func (v *tableView) update(data resource.TableData) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *tableView) filtered() resource.TableData {
|
func (v *tableView) filtered() resource.TableData {
|
||||||
if v.cmdBuff.empty() {
|
if v.cmdBuff.empty() || isLabelSelector(v.cmdBuff.String()) {
|
||||||
return v.data
|
return v.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -496,7 +512,11 @@ func (v *tableView) resetTitle() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !v.cmdBuff.isActive() && !v.cmdBuff.empty() {
|
if !v.cmdBuff.isActive() && !v.cmdBuff.empty() {
|
||||||
title += skinTitle(fmt.Sprintf(searchFmt, v.cmdBuff), v.app.styles.Style)
|
cmd := v.cmdBuff.String()
|
||||||
|
if isLabelSelector(cmd) {
|
||||||
|
cmd = trimLabelSelector(cmd)
|
||||||
|
}
|
||||||
|
title += skinTitle(fmt.Sprintf(searchFmt, cmd), v.app.styles.Style)
|
||||||
}
|
}
|
||||||
v.SetTitle(title)
|
v.SetTitle(title)
|
||||||
}
|
}
|
||||||
|
|
@ -523,3 +543,16 @@ func (v *tableView) active(b bool) {
|
||||||
}
|
}
|
||||||
v.SetBorderColor(tcell.ColorDodgerBlue)
|
v.SetBorderColor(tcell.ColorDodgerBlue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var labelCmd = regexp.MustCompile(`\A\-l`)
|
||||||
|
|
||||||
|
func isLabelSelector(s string) bool {
|
||||||
|
if s == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return labelCmd.MatchString(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func trimLabelSelector(s string) string {
|
||||||
|
return strings.TrimSpace(s[2:])
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,39 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestIsSelector(t *testing.T) {
|
||||||
|
uu := map[string]struct {
|
||||||
|
sel string
|
||||||
|
e bool
|
||||||
|
}{
|
||||||
|
"cool": {"-l app=fred,env=blee", true},
|
||||||
|
"noMode": {"app=fred,env=blee", false},
|
||||||
|
"noSpace": {"-lapp=fred,env=blee", true},
|
||||||
|
"wrongLabel": {"-f app=fred,env=blee", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, u := range uu {
|
||||||
|
t.Run(k, func(t *testing.T) {
|
||||||
|
assert.Equal(t, u.e, isLabelSelector(u.sel))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTrimLabelSelector(t *testing.T) {
|
||||||
|
uu := map[string]struct {
|
||||||
|
sel, e string
|
||||||
|
}{
|
||||||
|
"cool": {"-l app=fred,env=blee", "app=fred,env=blee"},
|
||||||
|
"noSpace": {"-lapp=fred,env=blee", "app=fred,env=blee"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, u := range uu {
|
||||||
|
t.Run(k, func(t *testing.T) {
|
||||||
|
assert.Equal(t, u.e, trimLabelSelector(u.sel))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTVSortRows(t *testing.T) {
|
func TestTVSortRows(t *testing.T) {
|
||||||
uu := []struct {
|
uu := []struct {
|
||||||
rows resource.RowEvents
|
rows resource.RowEvents
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue