From aa9638798f68669a9c5a4ab65da2ce6e56f40d18 Mon Sep 17 00:00:00 2001 From: Joe Lee Date: Thu, 29 Aug 2024 17:30:26 +0800 Subject: [PATCH] add filter (#4) --- cmd/root.go | 49 ++++++++++++++++++++++++++++++++++++++++-------- cmd/root_test.go | 6 +++++- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index e1d586c..3f482e6 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -7,6 +7,7 @@ import ( "os" "os/exec" "regexp" + "slices" "strings" "time" @@ -15,6 +16,8 @@ import ( "github.com/spf13/cobra" ) +var formats = []string{"csv", "table"} + func newRootCmd(version string) *cobra.Command { var clean = Clean{} var rootCmd = &cobra.Command{ @@ -28,8 +31,11 @@ Examples: # List all release which was updated before 240h helm clean -A -b 240h - # List release was create by chart-1 - helm clean -A -b 240h -f chart-1 + # List release which was created by chart that matched chart-1 + helm clean -A -b 240h -I chart-1 + + # List release was not created by chart that matched chart-1 + helm clean -A -b 240h -E chart-1 # Exclude namespace match pattern helm clean -A -b 240h -e kube-system @@ -42,14 +48,28 @@ Examples: `, Version: version, RunE: func(cmd *cobra.Command, args []string) error { + return clean.Run(os.Stdout) }, + PreRunE: func(cmd *cobra.Command, args []string) error { + output, _ := cmd.Flags().GetString("output") + + if !slices.Contains(formats, output) { + return fmt.Errorf("invalid format type [%s] for [-o, --output] flag", output) + } + return nil + }, } rootCmd.Flags().DurationVarP(&clean.Before, "before", "b", 0, "The last updated time before now, eg: 8h, (default 0) equal `helm list`") rootCmd.Flags().BoolVarP(&clean.DryRun, "dry-run", "d", true, "Dry run mode only print the release info") rootCmd.Flags().BoolVarP(&clean.AllNamespace, "all-namespaces", "A", false, "Check releases across all namespaces") - rootCmd.Flags().StringSliceVarP(&clean.Filter, "filter", "f", []string{}, `Regular expression, the chart of releases that matched the + rootCmd.Flags().StringVarP(&clean.Output, "output", "o", "table", "prints the output in the specified format. Allowed values: table, csv") + rootCmd.Flags().StringSliceVarP(&clean.IncludeChart, "include-chart", "I", []string{}, `Regular expression, the chart of releases that matched the expression will be included in the result only (can specify multiple)`) + rootCmd.Flags().StringSliceVarP(&clean.ExcludeChart, "exclude-chart", "E", []string{}, `Regular expression, the chart of releases that matched the +expression will be excluded from the result (can specify multiple)`) + rootCmd.Flags().StringSliceVarP(&clean.Include, "include", "i", []string{}, `Regular expression ':', the matched +release and namespace will be included in result only (can specify multiple)`) rootCmd.Flags().StringSliceVarP(&clean.Exclude, "exclude", "e", []string{}, `Regular expression ':', the matched release and namespace will be excluded from the result (can specify multiple)`) return rootCmd @@ -65,9 +85,12 @@ func Execute(version string) { type Clean struct { Before time.Duration DryRun bool - Filter []string AllNamespace bool + ExcludeChart []string + IncludeChart []string Exclude []string + Include []string + Output string } type Release struct { @@ -94,12 +117,15 @@ func (c *Clean) ListRelease() (ReleaseList, error) { } now := time.Now() var result ReleaseList - pattern := regexp.MustCompile(strings.Join(c.Filter, "|")) loc, err := time.LoadLocation("Local") if err != nil { return nil, err } + includeChart := regexp.MustCompile(strings.Join(c.IncludeChart, "|")) + excludeChart := regexp.MustCompile(strings.Join(c.ExcludeChart, "|")) + checkExcludeChart := len(c.ExcludeChart) > 0 + include := regexp.MustCompile(strings.Join(c.Include, "|")) exclude := regexp.MustCompile(strings.Join(c.Exclude, "|")) checkExclude := len(c.Exclude) > 0 @@ -108,8 +134,9 @@ func (c *Clean) ListRelease() (ReleaseList, error) { if err != nil { return nil, err } - if now.After(t.Add(c.Before)) && pattern.MatchString(release.Chart) { - if checkExclude && exclude.MatchString(fmt.Sprintf("%s:%s", release.Namespace, release.Name)) { + rn := fmt.Sprintf("%s:%s", release.Namespace, release.Name) + if now.After(t.Add(c.Before)) && includeChart.MatchString(release.Chart) && include.MatchString(rn) { + if (checkExclude && exclude.MatchString(rn)) || (checkExcludeChart && excludeChart.MatchString(release.Chart)) { continue } result = append(result, release) @@ -130,7 +157,13 @@ func (c *Clean) Run(w io.Writer) error { for _, release := range rList { t.AppendRow(table.Row{release.Namespace, release.Name, release.Updated, release.Chart, release.AppVersion}) } - t.RenderCSV() + t.SortBy([]table.SortBy{{Name: "NAMESPACE", Mode: table.Asc}, {Name: "NAME", Mode: table.Asc}}) + switch c.Output { + case "table": + t.Render() + case "csv": + t.RenderCSV() + } } else { for _, release := range rList { diff --git a/cmd/root_test.go b/cmd/root_test.go index f396140..a502ae7 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -39,7 +39,7 @@ func TestListRelease(t *testing.T) { func TestRun(t *testing.T) { mockHelm(t) duration, _ := time.ParseDuration("240h") - c := Clean{Before: duration, DryRun: true, AllNamespace: true} + c := Clean{Before: duration, DryRun: true, AllNamespace: true, Output: "csv"} var w bytes.Buffer c.Run(&w) if !strings.Contains(w.String(), "ns-2,release-c") { @@ -78,4 +78,8 @@ func TestNewRootCmd(t *testing.T) { if !strings.Contains(err.Error(), "missing unit in duration") { t.Errorf("expect missing unit in duration, but got: %s", err) } + _, _, err = newCmd([]string{"-o", "x"}) + if !strings.Contains(err.Error(), "invalid format type") { + t.Errorf("expect invalid format type, but got: %s", err) + } }