forked from operator-framework/operator-controller
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: dtfranz <[email protected]>
- Loading branch information
Showing
3 changed files
with
199 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package sort | ||
|
||
import ( | ||
"strings" | ||
|
||
"github.com/operator-framework/operator-controller/internal/catalogmetadata" | ||
) | ||
|
||
// ByChannelAndVersion is a sort function that orders bundles by package, | ||
// channel (default channel at the head), and inverse version (higher versions on top). | ||
// If a property does not exist for one of the entities, the one missing the property | ||
// is pushed down; if both entities are missing the same property they are ordered by id. | ||
func ByChannelAndVersion(b1, b2 *catalogmetadata.Bundle) bool { | ||
// first sort package lexical order | ||
pkgOrder := packageOrder(b1, b2) | ||
if pkgOrder != 0 { | ||
return pkgOrder < 0 | ||
} | ||
|
||
// todo(perdasilva): handle default channel in ordering once it is being exposed by the entity | ||
channelOrder := channelOrder(b1, b2) | ||
if channelOrder != 0 { | ||
return channelOrder < 0 | ||
} | ||
|
||
// order version from highest to lowest (favor the latest release) | ||
versionOrder := versionOrder(b1, b2) | ||
return versionOrder > 0 | ||
} | ||
|
||
func compareErrors(err1 error, err2 error) int { | ||
if err1 != nil && err2 == nil { | ||
return 1 | ||
} | ||
|
||
if err1 == nil && err2 != nil { | ||
return -1 | ||
} | ||
return 0 | ||
} | ||
|
||
func packageOrder(b1, b2 *catalogmetadata.Bundle) int { | ||
name1, err1 := b1.PackageName() | ||
name2, err2 := b2.PackageName() | ||
errComp := compareErrors(err1, err2) | ||
if errComp != 0 { | ||
return errComp | ||
} | ||
return strings.Compare(name1, name2) | ||
} | ||
|
||
func channelOrder(b1, b2 *catalogmetadata.Bundle) int { | ||
channelProperties1, err1 := b1.Channel() | ||
channelProperties2, err2 := b2.Channel() | ||
errComp := compareErrors(err1, err2) | ||
if errComp != 0 { | ||
return errComp | ||
} | ||
if channelProperties1.Priority != channelProperties2.Priority { | ||
return channelProperties1.Priority - channelProperties2.Priority | ||
} | ||
return strings.Compare(channelProperties1.ChannelName, channelProperties2.ChannelName) | ||
} | ||
|
||
func versionOrder(b1, b2 *catalogmetadata.Bundle) int { | ||
ver1, err1 := b1.Version() | ||
ver2, err2 := b2.Version() | ||
errComp := compareErrors(err1, err2) | ||
if errComp != 0 { | ||
// the sign gets inverted because version is sorted | ||
// from highest to lowest | ||
return -1 * errComp | ||
} | ||
return ver1.Compare(*ver2) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package sort_test | ||
|
||
import ( | ||
"encoding/json" | ||
"sort" | ||
"testing" | ||
|
||
"github.com/operator-framework/operator-controller/internal/catalogmetadata" | ||
metadatasort "github.com/operator-framework/operator-controller/internal/catalogmetadata/sort" | ||
"github.com/operator-framework/operator-registry/alpha/declcfg" | ||
"github.com/operator-framework/operator-registry/alpha/property" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestSortByPackage(t *testing.T) { | ||
b1 := catalogmetadata.Bundle{Bundle: declcfg.Bundle{Properties: []property.Property{ | ||
{Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "package-a", "version": "1.0.0"}`)}, | ||
}}} | ||
b2 := catalogmetadata.Bundle{Bundle: declcfg.Bundle{Properties: []property.Property{ | ||
{Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "package-b", "version": "1.0.0"}`)}, | ||
}}} | ||
b3 := catalogmetadata.Bundle{Bundle: declcfg.Bundle{Properties: []property.Property{ | ||
{Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "package-c", "version": "1.0.0"}`)}, | ||
}}} | ||
|
||
bundles := []*catalogmetadata.Bundle{&b2, &b3, &b1} | ||
sort.Slice(bundles, func(i, j int) bool { | ||
return metadatasort.ByChannelAndVersion(bundles[i], bundles[j]) | ||
}) | ||
assert.Equal(t, bundles[0], &b1) | ||
assert.Equal(t, bundles[1], &b2) | ||
assert.Equal(t, bundles[2], &b3) | ||
} | ||
|
||
func TestSortByChannelName(t *testing.T) { | ||
b1 := catalogmetadata.Bundle{Bundle: declcfg.Bundle{Properties: []property.Property{ | ||
{Type: property.TypeChannel, Value: json.RawMessage(`{"channelName":"alpha","priority":0}`)}, | ||
}}} | ||
b2 := catalogmetadata.Bundle{Bundle: declcfg.Bundle{Properties: []property.Property{ | ||
{Type: property.TypeChannel, Value: json.RawMessage(`{"channelName":"beta","priority":0}`)}, | ||
}}} | ||
b3 := catalogmetadata.Bundle{Bundle: declcfg.Bundle{Properties: []property.Property{ | ||
{Type: property.TypeChannel, Value: json.RawMessage(`{"channelName":"gamma","priority":0}`)}, | ||
}}} | ||
|
||
bundles := []*catalogmetadata.Bundle{&b3, &b2, &b1} | ||
sort.Slice(bundles, func(i, j int) bool { | ||
return metadatasort.ByChannelAndVersion(bundles[i], bundles[j]) | ||
}) | ||
assert.Equal(t, bundles[0], &b1) | ||
assert.Equal(t, bundles[1], &b2) | ||
assert.Equal(t, bundles[2], &b3) | ||
} | ||
|
||
func TestSortByChannelPriority(t *testing.T) { | ||
b1 := catalogmetadata.Bundle{Bundle: declcfg.Bundle{Properties: []property.Property{ | ||
{Type: property.TypeChannel, Value: json.RawMessage(`{"channelName":"alpha","priority":0}`)}, | ||
}}} | ||
b2 := catalogmetadata.Bundle{Bundle: declcfg.Bundle{Properties: []property.Property{ | ||
{Type: property.TypeChannel, Value: json.RawMessage(`{"channelName":"alpha","priority":1}`)}, | ||
}}} | ||
b3 := catalogmetadata.Bundle{Bundle: declcfg.Bundle{Properties: []property.Property{ | ||
{Type: property.TypeChannel, Value: json.RawMessage(`{"channelName":"alpha","priority":2}`)}, | ||
}}} | ||
|
||
bundles := []*catalogmetadata.Bundle{&b3, &b1, &b2} | ||
sort.Slice(bundles, func(i, j int) bool { | ||
return metadatasort.ByChannelAndVersion(bundles[i], bundles[j]) | ||
}) | ||
assert.Equal(t, bundles[0], &b1) | ||
assert.Equal(t, bundles[1], &b2) | ||
assert.Equal(t, bundles[2], &b3) | ||
} | ||
|
||
func TestSortByVersion(t *testing.T) { | ||
b1 := catalogmetadata.Bundle{Bundle: declcfg.Bundle{Properties: []property.Property{ | ||
{Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "package-a", "version": "1.0.0"}`)}, | ||
{Type: property.TypeChannel, Value: json.RawMessage(`{"channelName":"alpha","priority":0}`)}, | ||
}}} | ||
b2 := catalogmetadata.Bundle{Bundle: declcfg.Bundle{Properties: []property.Property{ | ||
{Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "package-a", "version": "1.0.1"}`)}, | ||
{Type: property.TypeChannel, Value: json.RawMessage(`{"channelName":"alpha","priority":0}`)}, | ||
}}} | ||
b3 := catalogmetadata.Bundle{Bundle: declcfg.Bundle{Properties: []property.Property{ | ||
{Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "package-a", "version": "2.0.0"}`)}, | ||
{Type: property.TypeChannel, Value: json.RawMessage(`{"channelName":"alpha","priority":0}`)}, | ||
}}} | ||
|
||
bundles := []*catalogmetadata.Bundle{&b2, &b3, &b1} | ||
sort.Slice(bundles, func(i, j int) bool { | ||
return metadatasort.ByChannelAndVersion(bundles[i], bundles[j]) | ||
}) | ||
assert.Equal(t, bundles[0], &b3) | ||
assert.Equal(t, bundles[1], &b2) | ||
assert.Equal(t, bundles[2], &b1) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters