@@ -3,6 +3,8 @@ package action
33import (
44 "context"
55 "fmt"
6+ "regexp"
7+ "strings"
68 "time"
79
810 v1 "github.com/operator-framework/api/pkg/operators/v1"
@@ -24,7 +26,7 @@ type OperatorInstall struct {
2426
2527 Package string
2628 Channel string
27- StartingCSV string
29+ Version string
2830 Approval subscription.ApprovalValue
2931 InstallMode operator.InstallMode
3032 InstallTimeout time.Duration
@@ -41,11 +43,11 @@ func NewOperatorInstall(cfg *Configuration) *OperatorInstall {
4143func (i * OperatorInstall ) BindFlags (fs * pflag.FlagSet ) {
4244 fs .StringVarP (& i .Channel , "channel" , "c" , "" , "subscription channel" )
4345 fs .VarP (& i .Approval , "approval" , "a" , fmt .Sprintf ("approval (%s or %s)" , v1alpha1 .ApprovalManual , v1alpha1 .ApprovalAutomatic ))
44- fs .StringVarP (& i .StartingCSV , "starting-csv " , "s " , "" , "install specific csv for operator" )
46+ fs .StringVarP (& i .Version , "version " , "v " , "" , "install specific version for operator (default latest) " )
4547 fs .VarP (& i .InstallMode , "install-mode" , "i" , "install mode" )
4648 fs .DurationVarP (& i .InstallTimeout , "timeout" , "t" , time .Minute , "the amount of time to wait before cancelling the install" )
4749 fs .DurationVar (& i .CleanupTimeout , "cleanup-timeout" , time .Minute , "the amount to time to wait before cancelling cleanup" )
48- fs .BoolVar (& i .CreateOperatorGroup , "create-operator-group" , false , "create operator group if necessary" )
50+ fs .BoolVarP (& i .CreateOperatorGroup , "create-operator-group" , "C " , false , "create operator group if necessary" )
4951}
5052
5153func (i * OperatorInstall ) Run (ctx context.Context ) (* v1alpha1.ClusterServiceVersion , error ) {
@@ -84,7 +86,7 @@ func (i *OperatorInstall) Run(ctx context.Context) (*v1alpha1.ClusterServiceVers
8486 return nil , err
8587 }
8688
87- sub , err := i .createSubscription (ctx , pm )
89+ sub , err := i .createSubscription (ctx , pm , pc )
8890 if err != nil {
8991 return nil , err
9092 }
@@ -208,12 +210,14 @@ func (i *OperatorInstall) getPackageChannel(pm *operatorsv1.PackageManifest) (*o
208210 return packageChannel , nil
209211}
210212
211- func (i * OperatorInstall ) createSubscription (ctx context.Context , pm * operatorsv1.PackageManifest ) (* v1alpha1.Subscription , error ) {
213+ func (i * OperatorInstall ) createSubscription (ctx context.Context , pm * operatorsv1.PackageManifest , pc * operatorsv1. PackageChannel ) (* v1alpha1.Subscription , error ) {
212214 opts := []subscription.Option {
213215 subscription .InstallPlanApproval (i .Approval .Approval ),
214216 }
215- if i .StartingCSV != "" {
216- opts = append (opts , subscription .StartingCSV (i .StartingCSV ))
217+
218+ if i .Version != "" {
219+ guessedStartingCSV := guessStartingCSV (pc .CurrentCSV , i .Version )
220+ opts = append (opts , subscription .StartingCSV (guessedStartingCSV ))
217221 }
218222
219223 subKey := types.NamespacedName {
@@ -232,6 +236,24 @@ func (i *OperatorInstall) createSubscription(ctx context.Context, pm *operatorsv
232236 return sub , nil
233237}
234238
239+ func guessStartingCSV (csvNameExample , desiredVersion string ) string {
240+ csvBaseName , vChar , _ := parseCSVName (csvNameExample )
241+ version := strings .TrimPrefix (desiredVersion , "v" )
242+ return fmt .Sprintf ("%s.%s%s" , csvBaseName , vChar , version )
243+ }
244+
245+ const (
246+ operatorNameRegexp = `[a-z0-9]([-a-z0-9]*[a-z0-9])?`
247+ semverRegexp = `(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?`
248+ )
249+
250+ var csvNameRegexp = regexp .MustCompile (`^(` + operatorNameRegexp + `).(v?)(` + semverRegexp + `)$` )
251+
252+ func parseCSVName (csvName string ) (string , string , string ) {
253+ matches := csvNameRegexp .FindAllStringSubmatch (csvName , - 1 )
254+ return matches [0 ][1 ], matches [0 ][3 ], matches [0 ][4 ]
255+ }
256+
235257func (i * OperatorInstall ) getInstallPlan (ctx context.Context , sub * v1alpha1.Subscription ) (* v1alpha1.InstallPlan , error ) {
236258 subKey := types.NamespacedName {
237259 Namespace : sub .GetNamespace (),
0 commit comments