github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/cli/cmd/kubeblocks/list_versions.go (about)

     1  /*
     2  Copyright (C) 2022-2023 ApeCloud Co., Ltd
     3  
     4  This file is part of KubeBlocks project
     5  
     6  This program is free software: you can redistribute it and/or modify
     7  it under the terms of the GNU Affero General Public License as published by
     8  the Free Software Foundation, either version 3 of the License, or
     9  (at your option) any later version.
    10  
    11  This program is distributed in the hope that it will be useful
    12  but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  GNU Affero General Public License for more details.
    15  
    16  You should have received a copy of the GNU Affero General Public License
    17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    18  */
    19  
    20  package kubeblocks
    21  
    22  import (
    23  	"fmt"
    24  	"sort"
    25  
    26  	"github.com/Masterminds/semver/v3"
    27  	"github.com/pkg/errors"
    28  	"github.com/spf13/cobra"
    29  	"k8s.io/cli-runtime/pkg/genericiooptions"
    30  	"k8s.io/kubectl/pkg/util/templates"
    31  
    32  	"github.com/1aal/kubeblocks/pkg/cli/printer"
    33  	"github.com/1aal/kubeblocks/pkg/cli/types"
    34  	"github.com/1aal/kubeblocks/pkg/cli/util"
    35  )
    36  
    37  const (
    38  	defaultLimit = 10
    39  )
    40  
    41  var (
    42  	listVersionsExample = templates.Examples(`
    43  	# list KubeBlocks release versions
    44  	kbcli kubeblocks list-versions
    45  	
    46  	# list KubeBlocks versions including development versions, such as alpha, beta and release candidate
    47  	kbcli kubeblocks list-versions --devel`)
    48  )
    49  
    50  type listVersionsOption struct {
    51  	genericiooptions.IOStreams
    52  	version string
    53  	devel   bool
    54  	limit   int
    55  }
    56  
    57  func newListVersionsCmd(streams genericiooptions.IOStreams) *cobra.Command {
    58  	o := listVersionsOption{IOStreams: streams}
    59  	cmd := &cobra.Command{
    60  		Use:     "list-versions",
    61  		Short:   "List KubeBlocks versions.",
    62  		Aliases: []string{"ls-versions"},
    63  		Args:    cobra.NoArgs,
    64  		Example: listVersionsExample,
    65  		Run: func(cmd *cobra.Command, args []string) {
    66  			util.CheckErr(o.listVersions())
    67  		},
    68  	}
    69  
    70  	cmd.Flags().BoolVar(&o.devel, "devel", false, "Use development versions (alpha, beta, and release candidate releases), too. Equivalent to version '>0.0.0-0'.")
    71  	cmd.Flags().IntVar(&o.limit, "limit", defaultLimit, fmt.Sprintf("Maximum rows of versions to return, 0 means no limit (default %d)", defaultLimit))
    72  	return cmd
    73  }
    74  
    75  func (o *listVersionsOption) listVersions() error {
    76  	if o.limit < 0 {
    77  		return fmt.Errorf("limit should be greater than or equal to 0")
    78  	}
    79  
    80  	// get chart versions
    81  	versions, err := getHelmChartVersions(types.KubeBlocksChartName)
    82  	if err != nil {
    83  		return err
    84  	}
    85  
    86  	// sort version descending and select the versions that meet the constraint
    87  	o.setupSearchedVersion()
    88  	sort.Sort(sort.Reverse(semver.Collection(versions)))
    89  	versions, err = o.applyConstraint(versions)
    90  	if err != nil {
    91  		return err
    92  	}
    93  
    94  	// print result
    95  	num := 0
    96  	tbl := printer.NewTablePrinter(o.Out)
    97  	tbl.SetHeader("VERSION", "RELEASE-NOTES")
    98  	for _, v := range versions {
    99  		tbl.AddRow(v.String(), fmt.Sprintf("https://github.com/1aal/kubeblocks/releases/tag/v%s", v))
   100  		num += 1
   101  		if num == o.limit {
   102  			break
   103  		}
   104  	}
   105  	tbl.Print()
   106  	return nil
   107  }
   108  
   109  func (o *listVersionsOption) setupSearchedVersion() {
   110  	if o.devel {
   111  		o.version = ">0.0.0-0"
   112  	} else {
   113  		o.version = ">0.0.0"
   114  	}
   115  }
   116  
   117  func (o *listVersionsOption) applyConstraint(versions []*semver.Version) ([]*semver.Version, error) {
   118  	constraint, err := semver.NewConstraint(o.version)
   119  	if err != nil {
   120  		return nil, errors.Wrap(err, "an invalid version/constraint format")
   121  	}
   122  
   123  	var res []*semver.Version
   124  	found := map[string]bool{}
   125  	for _, version := range versions {
   126  		if found[version.String()] {
   127  			continue
   128  		}
   129  		if constraint.Check(version) {
   130  			res = append(res, version)
   131  			found[version.String()] = true
   132  		}
   133  	}
   134  	return res, nil
   135  }