Skip to content

Commit 5ed515f

Browse files
author
Mikalai Radchuk
committed
Add initial SemVer upgrade support
OLM will now use SemVer to determine next upgrade. In this iteration we only support upgrade within the same major versions: e.g 1.0.1 can be upgraded to 1.0.2 or 1.3.2, but not 2.0.0. Signed-off-by: Mikalai Radchuk <[email protected]>
1 parent 205a487 commit 5ed515f

File tree

2 files changed

+54
-1
lines changed

2 files changed

+54
-1
lines changed

internal/resolution/variablesources/installed_package.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ import (
55
"fmt"
66
"sort"
77

8+
mmsemver "github.com/Masterminds/semver/v3"
89
"github.com/operator-framework/deppy/pkg/deppy"
910
"github.com/operator-framework/deppy/pkg/deppy/input"
1011

1112
"github.com/operator-framework/operator-controller/internal/catalogmetadata"
1213
catalogfilter "github.com/operator-framework/operator-controller/internal/catalogmetadata/filter"
1314
catalogsort "github.com/operator-framework/operator-controller/internal/catalogmetadata/sort"
1415
"github.com/operator-framework/operator-controller/internal/resolution/variables"
16+
"github.com/operator-framework/operator-controller/pkg/features"
1517
)
1618

1719
var _ input.VariableSource = &InstalledPackageVariableSource{}
@@ -59,10 +61,15 @@ func (r *InstalledPackageVariableSource) notFoundError() error {
5961
}
6062

6163
func NewInstalledPackageVariableSource(catalogClient BundleProvider, bundleImage string) (*InstalledPackageVariableSource, error) {
64+
successors := legacySemanticsSuccessors
65+
if features.OperatorControllerFeatureGate.Enabled(features.ForceSemverUpgradeConstraints) {
66+
successors = semverSuccessors
67+
}
68+
6269
return &InstalledPackageVariableSource{
6370
catalogClient: catalogClient,
6471
bundleImage: bundleImage,
65-
successors: legacySemanticsSuccessors,
72+
successors: successors,
6673
}, nil
6774
}
6875

@@ -83,3 +90,28 @@ func legacySemanticsSuccessors(allBundles []*catalogmetadata.Bundle, installedBu
8390

8491
return upgradeEdges, nil
8592
}
93+
94+
// semverSuccessors returns successors based on Semver.
95+
// Successors will not include versions outside the major version of the
96+
// installed bundle as major version is intended to indicate breaking changes.
97+
func semverSuccessors(allBundles []*catalogmetadata.Bundle, installedBundle *catalogmetadata.Bundle) ([]*catalogmetadata.Bundle, error) {
98+
currentVersion, err := installedBundle.Version()
99+
if err != nil {
100+
return nil, err
101+
}
102+
103+
// Based on current version create a caret range comparison constraint
104+
// to allow only major and patch version as successors and exclude current version.
105+
constraintStr := fmt.Sprintf("^%s, != %s", currentVersion.String(), currentVersion.String())
106+
wantedVersionRangeConstraint, err := mmsemver.NewConstraint(constraintStr)
107+
if err != nil {
108+
return nil, err
109+
}
110+
111+
upgradeEdges := catalogfilter.Filter(allBundles, catalogfilter.InMastermindsSemverRange(wantedVersionRangeConstraint))
112+
sort.SliceStable(upgradeEdges, func(i, j int) bool {
113+
return catalogsort.ByVersion(upgradeEdges[i], upgradeEdges[j])
114+
})
115+
116+
return upgradeEdges, nil
117+
}

internal/resolution/variablesources/installed_package_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,27 @@ func TestInstalledPackageVariableSource(t *testing.T) {
121121
const bundleImage = "registry.io/repo/[email protected]"
122122
fakeCatalogClient := testutil.NewFakeCatalogClient(bundleList)
123123

124+
t.Run("with ForceSemverUpgradeConstraints feature gate enabled", func(t *testing.T) {
125+
defer featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.ForceSemverUpgradeConstraints, true)()
126+
127+
ipvs, err := variablesources.NewInstalledPackageVariableSource(&fakeCatalogClient, bundleImage)
128+
require.NoError(t, err)
129+
130+
variables, err := ipvs.GetVariables(context.TODO())
131+
require.NoError(t, err)
132+
require.Len(t, variables, 1)
133+
packageVariable, ok := variables[0].(*olmvariables.InstalledPackageVariable)
134+
assert.True(t, ok)
135+
assert.Equal(t, deppy.IdentifierFromString("installed package test-package"), packageVariable.Identifier())
136+
137+
// ensure bundles are in version order (high to low)
138+
bundles := packageVariable.Bundles()
139+
require.Len(t, bundles, 3)
140+
assert.Equal(t, "test-package.v2.2.0", packageVariable.Bundles()[0].Name)
141+
assert.Equal(t, "test-package.v2.1.0", packageVariable.Bundles()[1].Name)
142+
assert.Equal(t, "test-package.v2.0.0", packageVariable.Bundles()[2].Name)
143+
})
144+
124145
t.Run("with ForceSemverUpgradeConstraints feature gate disabled", func(t *testing.T) {
125146
defer featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.ForceSemverUpgradeConstraints, false)()
126147

0 commit comments

Comments
 (0)