@@ -241,7 +241,12 @@ func (i *OperatorInstall) createSubscription(ctx context.Context, pm *operator.P
241241	}
242242
243243	if  i .Version  !=  ""  {
244- 		guessedStartingCSV  :=  guessStartingCSV (pc .CurrentCSV , i .Version )
244+ 		// Use the CSV name of the channel head as a template to guess the CSV name based on 
245+ 		// the desired version. 
246+ 		guessedStartingCSV , err  :=  guessStartingCSV (pc .CurrentCSV , i .Version )
247+ 		if  err  !=  nil  {
248+ 			return  nil , fmt .Errorf ("could not guess startingCSV: %v" , err )
249+ 		}
245250		opts  =  append (opts , subscription .StartingCSV (guessedStartingCSV ))
246251	}
247252
@@ -261,23 +266,20 @@ func (i *OperatorInstall) createSubscription(ctx context.Context, pm *operator.P
261266	return  sub , nil 
262267}
263268
264- func  guessStartingCSV (csvNameExample , desiredVersion  string ) string  {
265- 	csvBaseName , vChar , _  :=  parseCSVName (csvNameExample )
266- 	version  :=  strings .TrimPrefix (desiredVersion , "v" )
267- 	return  fmt .Sprintf ("%s.%s%s" , csvBaseName , vChar , version )
269+ // guessStartingCSV finds the first semver version string in csvNameExample, and replaces all 
270+ // occurrences with desiredVersion, trimming any "v" prefix from desiredVersion prior to making the 
271+ // replacements. If csvNameExample does not contain a semver version string, guessStartingCSV 
272+ // returns an error. 
273+ func  guessStartingCSV (csvNameExample , desiredVersion  string ) (string , error ) {
274+ 	exampleVersion  :=  semverRegexp .FindString (csvNameExample )
275+ 	if  exampleVersion  ==  ""  {
276+ 		return  "" , fmt .Errorf ("could not locate semver version in channel head CSV name %q" , csvNameExample )
277+ 	}
278+ 	desiredVersion  =  strings .TrimPrefix (desiredVersion , "v" )
279+ 	return  strings .ReplaceAll (csvNameExample , exampleVersion , desiredVersion ), nil 
268280}
269281
270- const  (
271- 	operatorNameRegexp  =  `[a-z0-9]([-a-z0-9]*[a-z0-9])?` 
272- 	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-]+)*))?`  //nolint:lll 
273- )
274- 
275- var  csvNameRegexp  =  regexp .MustCompile (`^(`  +  operatorNameRegexp  +  `).(v?)(`  +  semverRegexp  +  `)$` )
276- 
277- func  parseCSVName (csvName  string ) (string , string , string ) {
278- 	matches  :=  csvNameRegexp .FindAllStringSubmatch (csvName , - 1 )
279- 	return  matches [0 ][1 ], matches [0 ][3 ], matches [0 ][4 ]
280- }
282+ var  semverRegexp  =  regexp .MustCompile (`(?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-]+)*))?` ) //nolint:lll 
281283
282284func  (i  * OperatorInstall ) getInstallPlan (ctx  context.Context , sub  * v1alpha1.Subscription ) (* v1alpha1.InstallPlan , error ) {
283285	subKey  :=  objectKeyForObject (sub )
0 commit comments