@@ -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