From bdb1f3cd31564739bbb05421ecf3bb82a73b7227 Mon Sep 17 00:00:00 2001 From: astraw99 Date: Sun, 4 Sep 2022 18:16:18 +0800 Subject: [PATCH] Support search plugins by name and description --- .gitignore | 3 ++ cmd/krew/cmd/search.go | 39 +++++++++++++++++++------ cmd/krew/cmd/search_test.go | 58 +++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 cmd/krew/cmd/search_test.go diff --git a/.gitignore b/.gitignore index 7b795414..b4456a98 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ *.so *.dylib +# Files generated by JetBrains IDEs, e.g. IntelliJ IDEA +.idea/ + # Test binary, build with `go test -c` *.test diff --git a/cmd/krew/cmd/search.go b/cmd/krew/cmd/search.go index bb5daba8..7a72e68d 100644 --- a/cmd/krew/cmd/search.go +++ b/cmd/krew/cmd/search.go @@ -63,10 +63,12 @@ Examples: } pluginCanonicalNames := make([]string, len(plugins)) + pluginDescriptions := make([]string, len(plugins)) pluginCanonicalNameMap := make(map[string]pluginEntry, len(plugins)) for i, p := range plugins { cn := canonicalName(p.p, p.indexName) pluginCanonicalNames[i] = cn + pluginDescriptions[i] = p.p.Spec.ShortDescription pluginCanonicalNameMap[cn] = p } @@ -80,15 +82,8 @@ Examples: installed[cn] = true } - var searchResults []string - if len(args) > 0 { - matches := fuzzy.Find(strings.Join(args, ""), pluginCanonicalNames) - for _, m := range matches { - searchResults = append(searchResults, m.Str) - } - } else { - searchResults = pluginCanonicalNames - } + keyword := strings.Join(args, "") + searchResults := searchByNameAndDesc(keyword, pluginCanonicalNames, pluginDescriptions) // No plugins found if len(searchResults) == 0 { @@ -118,6 +113,32 @@ Examples: PreRunE: checkIndex, } +func searchByNameAndDesc(keyword string, names, descs []string) []string { + var searchResults []string + if keyword == "" { + return names + } + + // find by names + matches := fuzzy.Find(keyword, names) + searchResultsMap := make(map[int]bool) + for _, m := range matches { + searchResults = append(searchResults, m.Str) + searchResultsMap[m.Index] = true + } + + // find by short descriptions + fuzzyMatches := fuzzy.Find(keyword, descs) + for _, m := range fuzzyMatches { + // use map to deduplicate and score > 0 to match more accurately + if _, exist := searchResultsMap[m.Index]; !exist && m.Score > 0 { + searchResults = append(searchResults, names[m.Index]) + } + } + + return searchResults +} + func limitString(s string, length int) string { if len(s) > length && length > 3 { s = s[:length-3] + "..." diff --git a/cmd/krew/cmd/search_test.go b/cmd/krew/cmd/search_test.go new file mode 100644 index 00000000..d2cfc7b7 --- /dev/null +++ b/cmd/krew/cmd/search_test.go @@ -0,0 +1,58 @@ +// Copyright 2019 The Kubernetes Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func Test_searchByNameAndDesc(t *testing.T) { + keyword := "config" + testPlugins := []struct { + names []string + descs []string + expected []string + }{ + { + names: []string{"switch-config", "ctx", "kc"}, + descs: []string{ + " Switches between kubeconfig files", + "Switch between contexts in your kubeconfig", + "Interactive CRUD operations to manage kubeconfig", + }, + expected: []string{"switch-config", "ctx", "kc"}, + }, + { + names: []string{"ns", "ctx", "kc"}, + descs: []string{ + "Switch between Kubernetes namespaces", + "Switch between contexts in your kubeconfig", + "Interactive CRUD operations to manage kubeconfig", + }, + expected: []string{"ctx", "kc"}, + }, + } + + for _, tp := range testPlugins { + t.Run(tp.names[0], func(t *testing.T) { + result := searchByNameAndDesc(keyword, tp.names, tp.descs) + if diff := cmp.Diff(tp.expected, result); diff != "" { + t.Fatalf("expected %v does not match got %v", tp.expected, result) + } + }) + } +}