Skip to content

Commit 24737fb

Browse files
authored
revert channel-scoped semver template expansion to edge-scoped (#1813)
* revert channel-scoped semver template expansion to edge-scoped Signed-off-by: grokspawn <jordan@nimblewidget.com> * review updates Signed-off-by: grokspawn <jordan@nimblewidget.com> --------- Signed-off-by: grokspawn <jordan@nimblewidget.com>
1 parent b8def28 commit 24737fb

File tree

3 files changed

+186
-94
lines changed

3 files changed

+186
-94
lines changed

alpha/template/semver/semver.go

Lines changed: 80 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"github.com/blang/semver/v4"
1212
"k8s.io/apimachinery/pkg/util/errors"
13+
"k8s.io/apimachinery/pkg/util/sets"
1314
"sigs.k8s.io/yaml"
1415

1516
"github.com/operator-framework/operator-registry/alpha/declcfg"
@@ -225,6 +226,7 @@ func (sv *semverTemplate) generateChannels(semverChannels *bundleVersions) []dec
225226
hwc := highwaterChannel{archetype: archetypesByPriority[0], version: semver.Version{Major: 0, Minor: 0}}
226227

227228
unlinkedChannels := make(map[string]*declcfg.Channel)
229+
unassociatedEdges := []entryTuple{}
228230

229231
for _, archetype := range archetypesByPriority {
230232
bundles := (*semverChannels)[archetype]
@@ -272,83 +274,103 @@ func (sv *semverTemplate) generateChannels(semverChannels *bundleVersions) []dec
272274
}
273275
}
274276
ch.Entries = append(ch.Entries, declcfg.ChannelEntry{Name: bundleName})
277+
unassociatedEdges = append(unassociatedEdges, entryTuple{arch: archetype, kind: cKey, parent: cName, name: bundleName, version: bundles[bundleName], index: len(ch.Entries) - 1})
275278
}
276279
}
277280
}
278281

279282
// save off the name of the high-water-mark channel for the default for this package
280283
sv.defaultChannel = hwc.name
281284

282-
outChannels = append(outChannels, sv.linkChannels(unlinkedChannels, semverChannels)...)
285+
outChannels = append(outChannels, sv.linkChannels(unlinkedChannels, unassociatedEdges)...)
283286

284287
return outChannels
285288
}
286289

287-
func (sv *semverTemplate) linkChannels(unlinkedChannels map[string]*declcfg.Channel, harvestedVersions *bundleVersions) []declcfg.Channel {
288-
// bundle --> version lookup
289-
bundleVersions := make(map[string]semver.Version)
290-
for _, vs := range *harvestedVersions {
291-
for b, v := range vs {
292-
if _, ok := bundleVersions[b]; !ok {
293-
bundleVersions[b] = v
294-
}
295-
}
296-
}
290+
func (sv *semverTemplate) linkChannels(unlinkedChannels map[string]*declcfg.Channel, entries []entryTuple) []declcfg.Channel {
291+
channels := []declcfg.Channel{}
297292

298-
channels := make([]declcfg.Channel, 0, len(unlinkedChannels))
299-
for _, channel := range unlinkedChannels {
300-
entries := &channel.Entries
301-
sort.Slice(*entries, func(i, j int) bool {
302-
return bundleVersions[(*entries)[i].Name].LT(bundleVersions[(*entries)[j].Name])
303-
})
293+
// sort to force partitioning by archetype --> kind --> semver
294+
sort.Slice(entries, func(i, j int) bool {
295+
if channelPriorities[entries[i].arch] != channelPriorities[entries[j].arch] {
296+
return channelPriorities[entries[i].arch] < channelPriorities[entries[j].arch]
297+
}
298+
if streamTypePriorities[entries[i].kind] != streamTypePriorities[entries[j].kind] {
299+
return streamTypePriorities[entries[i].kind] < streamTypePriorities[entries[j].kind]
300+
}
301+
return entries[i].version.LT(entries[j].version)
302+
})
304303

305-
// "inchworm" through the sorted entries, iterating curEdge but extending yProbe to the next Y-transition
306-
// then catch up curEdge to yProbe as 'skips', and repeat until we reach the end of the entries
307-
// finally, because the inchworm will always fail to pick up the last Y-transition, we test for it and link it up as a 'replaces'
308-
curEdge, yProbe := 0, 0
309-
zmaxQueue := ""
310-
entryCount := len(*entries)
311-
312-
for curEdge < entryCount {
313-
for yProbe < entryCount {
314-
curVersion := bundleVersions[(*entries)[curEdge].Name]
315-
yProbeVersion := bundleVersions[(*entries)[yProbe].Name]
316-
if getMinorVersion(yProbeVersion).EQ(getMinorVersion(curVersion)) {
317-
yProbe += 1
318-
} else {
319-
break
320-
}
304+
prevZMax := ""
305+
var curSkips = sets.Set[string]{}
306+
307+
// iterate over the entries, starting from the second
308+
// write any skips/replaces for the previous entry to the current entry
309+
// then accumulate the skips/replaces for the current entry to be used in subsequent iterations
310+
for index := 1; index < len(entries); index++ {
311+
prevTuple := entries[index-1]
312+
curTuple := entries[index]
313+
prevX := getMajorVersion(prevTuple.version)
314+
prevY := getMinorVersion(prevTuple.version)
315+
curX := getMajorVersion(curTuple.version)
316+
curY := getMinorVersion(curTuple.version)
317+
318+
archChange := curTuple.arch != prevTuple.arch
319+
kindChange := curTuple.kind != prevTuple.kind
320+
xChange := !prevX.EQ(curX)
321+
yChange := !prevY.EQ(curY)
322+
323+
if archChange || kindChange || xChange || yChange {
324+
// if we passed any kind of change besides Z, then we need to set skips/replaces for previous max-Z
325+
prevChannel := unlinkedChannels[prevTuple.parent]
326+
finalEntry := &prevChannel.Entries[prevTuple.index]
327+
finalEntry.Replaces = prevZMax
328+
skips := sets.List(curSkips.Difference(sets.New(finalEntry.Replaces)))
329+
if len(skips) > 0 {
330+
finalEntry.Skips = skips
321331
}
322-
// if yProbe crossed a threshold, the previous entry is the last of the previous Y-stream
323-
preChangeIndex := yProbe - 1
332+
}
324333

325-
if curEdge != yProbe {
326-
if zmaxQueue != "" {
327-
(*entries)[preChangeIndex].Replaces = zmaxQueue
328-
}
329-
zmaxQueue = (*entries)[preChangeIndex].Name
330-
}
331-
for curEdge < preChangeIndex {
332-
// add skips edges to y-1 from z < y
333-
if (*entries)[preChangeIndex].Replaces != (*entries)[curEdge].Name {
334-
(*entries)[preChangeIndex].Skips = append((*entries)[preChangeIndex].Skips, (*entries)[curEdge].Name)
335-
}
336-
curEdge += 1
334+
if archChange || kindChange || xChange {
335+
// we don't maintain skips/replaces over these transitions
336+
curSkips = sets.Set[string]{}
337+
prevZMax = ""
338+
} else {
339+
if yChange {
340+
prevZMax = prevTuple.name
337341
}
338-
curEdge += 1
339-
yProbe = curEdge + 1
342+
curSkips.Insert(prevTuple.name)
340343
}
341-
// since probe will always fail to pick up a y-change in the last item, test for it
342-
if entryCount > 1 {
343-
penultimateEntry := &(*entries)[len(*entries)-2]
344-
ultimateEntry := &(*entries)[len(*entries)-1]
345-
penultimateVersion := bundleVersions[penultimateEntry.Name]
346-
ultimateVersion := bundleVersions[ultimateEntry.Name]
347-
if ultimateVersion.Minor != penultimateVersion.Minor {
348-
ultimateEntry.Replaces = penultimateEntry.Name
344+
}
345+
346+
if len(entries) > 1 {
347+
// add edges for the last entry
348+
// note: this is substantially similar to the main iteration, but there are some subtle differences since the main loop mode
349+
// design is to write the edges and then accumulate new info for subsequent edges (and this is the last edge):
350+
// - we only need to watch for arch/kind/x change
351+
// - we don't need to accumulate skips/replaces, since we're not writing edges for subsequent entries
352+
lastTuple := entries[len(entries)-1]
353+
penultimateTuple := entries[len(entries)-2]
354+
prevX := getMajorVersion(penultimateTuple.version)
355+
curX := getMajorVersion(lastTuple.version)
356+
357+
archChange := penultimateTuple.arch != lastTuple.arch
358+
kindChange := penultimateTuple.kind != lastTuple.kind
359+
xChange := !prevX.EQ(curX)
360+
// for arch / kind / x changes, we don't maintain skips/replaces
361+
if !archChange && !kindChange && !xChange {
362+
prevChannel := unlinkedChannels[lastTuple.parent]
363+
finalEntry := &prevChannel.Entries[lastTuple.index]
364+
finalEntry.Replaces = prevZMax
365+
skips := sets.List(curSkips.Difference(sets.New(finalEntry.Replaces)))
366+
if len(skips) > 0 {
367+
finalEntry.Skips = skips
349368
}
350369
}
351-
channels = append(channels, *channel)
370+
}
371+
372+
for _, ch := range unlinkedChannels {
373+
channels = append(channels, *ch)
352374
}
353375

354376
slices.SortFunc(channels, func(a, b declcfg.Channel) int {

0 commit comments

Comments
 (0)