diff --git a/cmd/harbor/root/project/list.go b/cmd/harbor/root/project/list.go index 825d4e9a6..5b55804bb 100644 --- a/cmd/harbor/root/project/list.go +++ b/cmd/harbor/root/project/list.go @@ -34,10 +34,14 @@ func ListProjectCommand() *cobra.Command { allProjects []*models.Project err error // For querying, opts.Q - fuzzy []string - match []string - ranges []string + fuzzy []string + match []string + ranges []string + and []string + or []string + validKeys = []string{"name", "project_id", "public", "creation_time", "owner_id"} ) + cmd := &cobra.Command{ Use: "list", Short: "List projects", @@ -72,9 +76,7 @@ func ListProjectCommand() *cobra.Command { } if len(fuzzy) != 0 || len(match) != 0 || len(ranges) != 0 { // Only Building Query if a param exists - q, qErr := utils.BuildQueryParam(fuzzy, match, ranges, - []string{"name", "project_id", "public", "creation_time", "owner_id"}, - ) + q, qErr := utils.BuildQueryParam(fuzzy, match, ranges, validKeys) if qErr != nil { return qErr } @@ -108,6 +110,15 @@ func ListProjectCommand() *cobra.Command { }, } + // Adding Query Description + var qDesc string + if cmd.Long != "" { + qDesc = "\n\n" + utils.GenerateQueryDocs(validKeys) + } else { + qDesc = utils.GenerateQueryDocs(validKeys) + } + cmd.Long += qDesc + flags := cmd.Flags() flags.StringVarP(&opts.Name, "name", "", "", "Name of the project") flags.Int64VarP(&opts.Page, "page", "", 1, "Page number") @@ -115,9 +126,7 @@ func ListProjectCommand() *cobra.Command { flags.BoolVarP(&private, "private", "", false, "Show only private projects") flags.BoolVarP(&public, "public", "", false, "Show only public projects") flags.StringVarP(&opts.Sort, "sort", "", "", "Sort the resource list in ascending or descending order") - flags.StringSliceVar(&fuzzy, "fuzzy", nil, "Fuzzy match filter (key=value)") - flags.StringSliceVar(&match, "match", nil, "exact match filter (key=value)") - flags.StringSliceVar(&ranges, "range", nil, "range filter (key=min~max)") + utils.SetQueryFlags(flags, &match, &fuzzy, &ranges, &and, &or) // Adds the 5 query flags return cmd } diff --git a/pkg/utils/query.go b/pkg/utils/query.go index 5dd57d454..32ff0e354 100644 --- a/pkg/utils/query.go +++ b/pkg/utils/query.go @@ -16,6 +16,8 @@ package utils import ( "fmt" "strings" + + "github.com/spf13/pflag" ) // Builds the `q` param for List API's @@ -73,6 +75,55 @@ func BuildQueryParam(fuzzy, match, ranges []string, validKeys []string) (string, return strings.Join(parts, ","), nil } +func GenerateQueryDocs(validKeys []string) string { + keys := strings.Join(validKeys, ", ") + + doc := fmt.Sprintf(` +Query Filters + +The following flags can be used to filter results. + +Supported query types: + + --exact key=value + Match an exact value. + + --fuzzy key=value + Perform a fuzzy match (partial match). + + --range key=min:max + Match values within a range. + + --all key=v1,v2 + Match resources that contain ALL specified values. + + --any key=v1,v2 + Match resources that contain ANY of the specified values. + +Examples: + + --exact project_id=12 + --fuzzy name=test + --range update_time=2024-01-01:2024-02-01 + --any tag=v1,v2 + --all label=prod,stable + +Valid keys for this command: + + %s +`, keys) + + return strings.TrimSpace(doc) +} + +func SetQueryFlags(f *pflag.FlagSet, match, fuzzy, ranges, and, or *[]string) { + f.StringSliceVar(fuzzy, "fuzzy", nil, "Fuzzy match filter (key=value)") + f.StringSliceVar(match, "match", nil, "exact match filter (key=value)") + f.StringSliceVar(ranges, "range", nil, "range filter (key=min~max)") + f.StringSliceVar(and, "all", nil, "match-all filter (key=v1,v2,v3)") + f.StringSliceVar(or, "any", nil, "match-any filter (key=v1,v2,v3)") +} + // Validates Key provided by user for ListFlags.Q func validateKey(key string, validKeys []string) error { found := false