Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 28 additions & 10 deletions internal/operator-controller/resolve/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,14 @@ func (r *CatalogResolver) Resolve(ctx context.Context, ext *ocv1.ClusterExtensio
// Check for ambiguity
if len(resolvedBundles) != 1 {
l.Info("resolution failed", "stats", catStats)
upgradePolicyEnforced := ext.Spec.Source.Catalog.UpgradeConstraintPolicy != ocv1.UpgradeConstraintPolicySelfCertified && installedBundle != nil
return nil, nil, nil, resolutionError{
PackageName: packageName,
Version: versionRange,
Channels: channels,
InstalledBundle: installedBundle,
ResolvedBundles: resolvedBundles,
PackageName: packageName,
Version: versionRange,
Channels: channels,
InstalledBundle: installedBundle,
ResolvedBundles: resolvedBundles,
UpgradePolicyEnforced: upgradePolicyEnforced,
}
}
resolvedBundle := resolvedBundles[0].bundle
Expand All @@ -210,11 +212,12 @@ func (r *CatalogResolver) Resolve(ctx context.Context, ext *ocv1.ClusterExtensio
}

type resolutionError struct {
PackageName string
Version string
Channels []string
InstalledBundle *ocv1.BundleMetadata
ResolvedBundles []foundBundle
PackageName string
Version string
Channels []string
InstalledBundle *ocv1.BundleMetadata
ResolvedBundles []foundBundle
UpgradePolicyEnforced bool
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new field UpgradePolicyEnforced introduces additional state tracking into the error structure. While this field is correctly computed based on the upgrade policy and presence of an installed bundle, this represents adding a new dimension to track state that could alternatively be derived from existing fields (InstalledBundle != nil and comparing against the policy enum). Consider whether this field is necessary or if the error message generation logic could make the same determination from the existing fields to avoid redundant state tracking.

Copilot uses AI. Check for mistakes.
}

func (rei resolutionError) Error() string {
Expand All @@ -223,6 +226,21 @@ func (rei resolutionError) Error() string {
sb.WriteString(fmt.Sprintf("error upgrading from currently installed version %q: ", rei.InstalledBundle.Version))
}

// When upgrade policy is enforced and no bundles were found, provide a clearer message
// indicating that the version doesn't match any successor
if rei.UpgradePolicyEnforced && len(rei.ResolvedBundles) == 0 {
sb.WriteString(fmt.Sprintf("desired package %q ", rei.PackageName))
if rei.Version != "" {
sb.WriteString(fmt.Sprintf("with version range %q ", rei.Version))
}
sb.WriteString(fmt.Sprintf("does not match any successor of %q", rei.InstalledBundle.Version))
if len(rei.Channels) > 0 {
sb.WriteString(fmt.Sprintf(" in channels %v", rei.Channels))
}
return sb.String()
}

// Default error message for other scenarios
if len(rei.ResolvedBundles) > 1 {
sb.WriteString(fmt.Sprintf("found bundles for package %q ", rei.PackageName))
} else {
Expand Down
2 changes: 1 addition & 1 deletion internal/operator-controller/resolve/catalog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ func TestUpgradeNotFoundLegacy(t *testing.T) {
}
// 0.1.0 only upgrades to 1.0.x with its legacy upgrade edges, so this fails.
_, _, _, err := r.Resolve(context.Background(), ce, installedBundle)
assert.EqualError(t, err, fmt.Sprintf(`error upgrading from currently installed version "0.1.0": no bundles found for package %q matching version "<1.0.0 >=2.0.0"`, pkgName))
assert.EqualError(t, err, fmt.Sprintf(`error upgrading from currently installed version "0.1.0": desired package %q with version range "<1.0.0 >=2.0.0" does not match any successor of "0.1.0"`, pkgName))
}

func TestDowngradeFound(t *testing.T) {
Expand Down
Loading