Skip to content

Conversation

joelanford
Copy link
Member

Description

This change fixes an issue to ensure that operator-controller properly handles and compares registry+v1 bundle versions that include build metadata as specified in the semver version.

The intention is that we only treat build metadata as a release value for registry+v1 bundles, which already have this precedent set. If/when operator-controller gains support for new bundle types, the intention is to avoid continuing the practice (and semver violation) of treating version build metadata as comparable/orderable.

Key changes:

  • Introduce VersionRelease type combining semver version with release metadata
  • Update bundle comparison logic to consider build metadata when present
  • Add exact version matching for pinned versions with build metadata
  • Replace GetVersion with GetVersionAndRelease across the codebase
  • Ensure successors are determined based on exact version+release matching

This is particularly important for registry+v1 bundles that encode release information in the build metadata field of their version strings.

🤖 Generated with Claude Code

Reviewer Checklist

  • API Go Documentation
  • Tests: Unit Tests (and E2E Tests, if appropriate)
  • Comprehensive Commit Messages
  • Links to related GitHub Issue(s)

@joelanford joelanford requested a review from a team as a code owner October 16, 2025 17:22
@joelanford joelanford requested review from Copilot and removed request for a team October 16, 2025 17:22
Copy link

netlify bot commented Oct 16, 2025

Deploy Preview for olmv1 ready!

Name Link
🔨 Latest commit b398c34
🔍 Latest deploy log https://app.netlify.com/projects/olmv1/deploys/68f27be3fd3cf800088b98c7
😎 Deploy Preview https://deploy-preview-2273--olmv1.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@openshift-ci openshift-ci bot requested review from anik120 and dtfranz October 16, 2025 17:22
Copy link

openshift-ci bot commented Oct 16, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign kevinrizza for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes bundle version comparison logic to properly handle registry+v1 bundles that use build metadata in their version strings. The implementation introduces a VersionRelease type that treats build metadata as comparable/orderable release information for registry+v1 bundles (a semver spec violation that exists for backward compatibility). The fix ensures exact version+release matching for pinned versions and successor determination.

Key changes:

  • Introduced VersionRelease type combining semver version with release metadata parsed from build metadata
  • Updated comparison and filtering logic to use exact version+release matching instead of semver-only matching
  • Replaced GetVersion with GetVersionAndRelease throughout the codebase

Reviewed Changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
internal/shared/util/slices/slices.go Added generic Map utility function
internal/operator-controller/resolve/resolver.go Updated interface to use VersionRelease instead of semver.Version
internal/operator-controller/resolve/catalog.go Updated to use new comparison functions and moved Map function to shared utilities
internal/operator-controller/controllers/clusterextension_controller.go Added conversion to legacy registry+v1 version format when creating bundle metadata
internal/operator-controller/catalogmetadata/filter/successors_test.go Added test case for exact version matching with build metadata
internal/operator-controller/catalogmetadata/filter/successors.go Implemented exact version+release matching for installed bundle comparison
internal/operator-controller/catalogmetadata/filter/bundle_predicates_test.go Updated test to use new InSemverRange function
internal/operator-controller/catalogmetadata/filter/bundle_predicates.go Replaced Masterminds semver with blang semver and added exact version matching
internal/operator-controller/catalogmetadata/compare/compare_test.go Added tests for NewVersionRange and updated existing tests for new comparison logic
internal/operator-controller/catalogmetadata/compare/compare.go Implemented NewVersionRange with exact build metadata matching and renamed ByVersion to ByVersionAndRelease
internal/operator-controller/bundleutil/bundle_test.go Added comprehensive tests for VersionRelease comparison logic
internal/operator-controller/bundleutil/bundle.go Introduced VersionRelease, Release types and legacy registry+v1 conversion logic

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@joelanford joelanford force-pushed the build-metadata-precedence branch 3 times, most recently from c2cd023 to d352bc0 Compare October 16, 2025 18:24
// then the returned function will match any version that matches the semver version, ignoring the
// build metadata of matched versions.
//
// Otherwise, Masterminds semver constraints semantics are used to match versions.
Copy link
Contributor

Choose a reason for hiding this comment

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

should not both libraries implement semver spec? would it be possible to use just single library?

Copy link
Member Author

@joelanford joelanford Oct 17, 2025

Choose a reason for hiding this comment

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

The main reason we have both is that they have different implementations of version ranges. OLMv0 used blang's version ranges for skipRange semantics, so we need to continue using that for back-compat reasons.

However, blang's semver range semantics have some footguns and are not all that ergonomic. So we chose Masterminds range semantics for spec.source.catalog.version in OLMv1.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks, for the explanation, perhaps you could add to the comment in the code?

Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps instead of leaking that that the function uses Masterminds library under the hood, it would be more helpful to document actually what are all supported version range syntax?

@@ -0,0 +1,9 @@
package slices

func Map[I any, O any](in []I, f func(I) O) []O {
Copy link
Contributor

Choose a reason for hiding this comment

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

this function is available in https://github.com/samber/lo/blob/master/slice.go#L26 - how about to use it instead?

Copy link
Member Author

@joelanford joelanford Oct 17, 2025

Choose a reason for hiding this comment

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

Not strongly opinionated. I do notice that that would be a new dependency to pull in to the project, so I could go either way.

Anyone else have opinions?

@joelanford joelanford force-pushed the build-metadata-precedence branch from d352bc0 to e8571b6 Compare October 17, 2025 03:54
Copy link

codecov bot commented Oct 17, 2025

Codecov Report

❌ Patch coverage is 80.00000% with 25 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.04%. Comparing base (6604f2a) to head (b398c34).
⚠️ Report is 12 commits behind head on main.

Files with missing lines Patch % Lines
...ernal/operator-controller/bundle/versionrelease.go 66.07% 12 Missing and 7 partials ⚠️
...ator-controller/catalogmetadata/compare/compare.go 86.66% 2 Missing and 2 partials ⚠️
...or-controller/catalogmetadata/filter/successors.go 87.50% 1 Missing ⚠️
internal/operator-controller/resolve/resolver.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2273      +/-   ##
==========================================
+ Coverage   72.73%   73.04%   +0.30%     
==========================================
  Files          89       90       +1     
  Lines        8747     8829      +82     
==========================================
+ Hits         6362     6449      +87     
+ Misses       1968     1959       -9     
- Partials      417      421       +4     
Flag Coverage Δ
e2e 39.62% <64.00%> (+0.42%) ⬆️
experimental-e2e 46.91% <64.00%> (+1.04%) ⬆️
unit 58.12% <68.00%> (+0.16%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

This change fixes an issue to ensure that operator-controller properly
handles and compares registry+v1 bundle versions that include build
metadata as specified in the semver version.

The intention is that we only treat build metadata as a release value
for registry+v1 bundles, which already have this precedent set. If/when
operator-controller gains support for new bundle types, the intention is
to avoid continuing the practice (and semver violation) of treating
version build metadata as comparable/orderable.

Key changes:
- Introduce VersionRelease type combining semver version with release metadata
- Update bundle comparison logic to consider build metadata when present
- Add exact version matching for pinned versions with build metadata
- Replace GetVersion with GetVersionAndRelease across the codebase
- Ensure successors are determined based on exact version+release matching

This is particularly important for registry+v1 bundles that encode
release information in the build metadata field of their version strings.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@joelanford joelanford force-pushed the build-metadata-precedence branch from e8571b6 to b398c34 Compare October 17, 2025 17:24
slicesutil "github.com/operator-framework/operator-controller/internal/shared/util/slices"
)

func NewLegacyRegistryV1VersionRelease(vStr string) (*VersionRelease, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

please add the docs.

Release Release
}

func (vr *VersionRelease) Compare(other VersionRelease) int {
Copy link
Contributor

Choose a reason for hiding this comment

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

please document


type Release []bsemver.PRVersion

func (r Release) Compare(other Release) int {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
func (r Release) Compare(other Release) int {
func (r *Release) Compare(other Release) int {

)

func GetVersion(b declcfg.Bundle) (*bsemver.Version, error) {
func GetVersionAndRelease(b declcfg.Bundle) (*bundle.VersionRelease, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

would it make sense to move this function to the new bundle/versionsrelease.go file?

wantErr: true,
},
{
name: "invalid release",
Copy link
Contributor

Choose a reason for hiding this comment

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

can we give here more details why the given release is invalid?

// then the returned function will match any version that matches the semver version, ignoring the
// build metadata of matched versions.
//
// Otherwise, Masterminds semver constraints semantics are used to match versions.
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps instead of leaking that that the function uses Masterminds library under the hood, it would be more helpful to document actually what are all supported version range syntax?

// ByVersionAndRelease is a comparison function that compares bundles by
// version and release. Bundles with lower versions/releases are
// considered less than bundles with higher versions/releases.
func ByVersionAndRelease(b1, b2 declcfg.Bundle) int {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: how about that we implement Compare method on declcfg.Bundle instead?

)

func InMastermindsSemverRange(semverRange *mmsemver.Constraints) filter.Predicate[declcfg.Bundle] {
func ExactVersionRelease(expect bundle.VersionRelease) filter.Predicate[declcfg.Bundle] {
Copy link
Contributor

Choose a reason for hiding this comment

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

please document

}
}

func InSemverRange(versionRange bsemver.Range) filter.Predicate[declcfg.Bundle] {
Copy link
Contributor

Choose a reason for hiding this comment

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

please document

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants