Skip to content

Commit 7629c6f

Browse files
authored
resolve channel collisions by a preferred channel type, where they are otherwise identical (#1095)
* minorly-kludgy approach, but functional Signed-off-by: Jordan Keister <[email protected]> * review comments Signed-off-by: Jordan Keister <[email protected]> * retool flag checks and defaulting Signed-off-by: Jordan Keister <[email protected]> * more review updates Signed-off-by: Jordan Keister <[email protected]> --------- Signed-off-by: Jordan Keister <[email protected]>
1 parent e1eebae commit 7629c6f

File tree

4 files changed

+293
-112
lines changed

4 files changed

+293
-112
lines changed

alpha/template/composite/builder_test.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ func TestSemverBuilder(t *testing.T) {
435435
defer file.Close()
436436
fileData, err := io.ReadAll(file)
437437
require.NoError(t, err)
438-
require.Equal(t, string(fileData), semverBuiltFbcYaml)
438+
require.Equal(t, semverBuiltFbcYaml, string(fileData))
439439
},
440440
validateAssertions: func(t *testing.T, validateErr error) {
441441
require.NoError(t, validateErr)
@@ -466,7 +466,7 @@ func TestSemverBuilder(t *testing.T) {
466466
defer file.Close()
467467
fileData, err := io.ReadAll(file)
468468
require.NoError(t, err)
469-
require.Equal(t, string(fileData), semverBuiltFbcJson)
469+
require.Equal(t, semverBuiltFbcJson, string(fileData))
470470
},
471471
validateAssertions: func(t *testing.T, validateErr error) {
472472
require.NoError(t, validateErr)
@@ -565,8 +565,8 @@ func TestSemverBuilder(t *testing.T) {
565565
buildAssertions: func(t *testing.T, dir string, buildErr error) {
566566
require.Error(t, buildErr)
567567
require.Equal(t,
568-
buildErr.Error(),
569-
"semver template configuration is invalid: semver template config must have a non-empty output (templateDefinition.config.output)")
568+
"semver template configuration is invalid: semver template config must have a non-empty output (templateDefinition.config.output)",
569+
buildErr.Error())
570570
},
571571
},
572572
{
@@ -584,8 +584,9 @@ func TestSemverBuilder(t *testing.T) {
584584
buildAssertions: func(t *testing.T, dir string, buildErr error) {
585585
require.Error(t, buildErr)
586586
require.Equal(t,
587+
"semver template configuration is invalid: semver template config must have a non-empty input (templateDefinition.config.input),semver template config must have a non-empty output (templateDefinition.config.output)",
587588
buildErr.Error(),
588-
"semver template configuration is invalid: semver template config must have a non-empty input (templateDefinition.config.input),semver template config must have a non-empty output (templateDefinition.config.output)")
589+
)
589590
},
590591
},
591592
}
@@ -638,7 +639,7 @@ Stable:
638639
`
639640

640641
const semverBuiltFbcYaml = `---
641-
defaultChannel: stable-v0
642+
defaultChannel: stable-v0.0
642643
name: webhook-operator
643644
schema: olm.package
644645
---
@@ -694,7 +695,7 @@ schema: olm.bundle
694695
const semverBuiltFbcJson = `{
695696
"schema": "olm.package",
696697
"name": "webhook-operator",
697-
"defaultChannel": "stable-v0"
698+
"defaultChannel": "stable-v0.0"
698699
}
699700
{
700701
"schema": "olm.channel",

alpha/template/semver/semver.go

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,17 +75,42 @@ func readFile(reader io.Reader) (*semverTemplate, error) {
7575
return nil, err
7676
}
7777

78-
// default behavior is to generate only minor channels
79-
sv := semverTemplate{
80-
GenerateMajorChannels: false,
81-
GenerateMinorChannels: true,
82-
}
78+
sv := semverTemplate{}
8379
if err := yaml.UnmarshalStrict(data, &sv); err != nil {
8480
return nil, err
8581
}
82+
8683
if sv.Schema != schema {
8784
return nil, fmt.Errorf("readFile: input file has unknown schema, should be %q", schema)
8885
}
86+
87+
// if no generate option is selected, default to GenerateMinorChannels
88+
if !sv.GenerateMajorChannels && !sv.GenerateMinorChannels {
89+
sv.GenerateMinorChannels = true
90+
}
91+
92+
// for default channel preference,
93+
// if un-set, default to align to the selected generate option
94+
// if set, error out if we mismatch the two
95+
switch sv.DefaultChannelTypePreference {
96+
case defaultStreamType:
97+
if sv.GenerateMinorChannels {
98+
sv.DefaultChannelTypePreference = minorStreamType
99+
} else if sv.GenerateMajorChannels {
100+
sv.DefaultChannelTypePreference = majorStreamType
101+
}
102+
case minorStreamType:
103+
if !sv.GenerateMinorChannels {
104+
return nil, fmt.Errorf("schema attribute mismatch: DefaultChannelTypePreference set to 'minor' doesn't make sense if not generating minor-version channels")
105+
}
106+
case majorStreamType:
107+
if !sv.GenerateMajorChannels {
108+
return nil, fmt.Errorf("schema attribute mismatch: DefaultChannelTypePreference set to 'major' doesn't make sense if not generating major-version channels")
109+
}
110+
default:
111+
return nil, fmt.Errorf("unknown DefaultChannelTypePreference: %q\nValid values are 'major' or 'minor'", sv.DefaultChannelTypePreference)
112+
}
113+
89114
return &sv, nil
90115
}
91116

@@ -241,8 +266,8 @@ func (sv *semverTemplate) generateChannels(semverChannels *bundleVersions) []dec
241266

242267
unlinkedChannels[cName] = ch
243268

244-
hwcCandidate := highwaterChannel{archetype: archetype, version: bundles[bundleName], name: cName}
245-
if hwcCandidate.gt(&hwc) {
269+
hwcCandidate := highwaterChannel{archetype: archetype, kind: cKey, version: bundles[bundleName], name: cName}
270+
if hwcCandidate.gt(&hwc, sv.DefaultChannelTypePreference) {
246271
hwc = hwcCandidate
247272
}
248273
}
@@ -420,3 +445,31 @@ func stripBuildMetadata(v semver.Version) string {
420445
v.Build = nil
421446
return v.String()
422447
}
448+
449+
// prefer (in descending order of preference):
450+
// - higher-rank archetype,
451+
// - semver version,
452+
// - a channel type matching the set preference, or
453+
// - a 'better' (higher value) channel type
454+
func (h *highwaterChannel) gt(ih *highwaterChannel, pref streamType) bool {
455+
if channelPriorities[h.archetype] != channelPriorities[ih.archetype] {
456+
return channelPriorities[h.archetype] > channelPriorities[ih.archetype]
457+
}
458+
if h.version.NE(ih.version) {
459+
return h.version.GT(ih.version)
460+
}
461+
if h.kind != ih.kind {
462+
if h.kind == pref {
463+
return true
464+
}
465+
if ih.kind == pref {
466+
return false
467+
}
468+
return h.kind.gt((*ih).kind)
469+
}
470+
return false
471+
}
472+
473+
func (t streamType) gt(in streamType) bool {
474+
return streamTypePriorities[t] > streamTypePriorities[in]
475+
}

0 commit comments

Comments
 (0)