Skip to content

Conversation

joelanford
Copy link
Member

@joelanford joelanford commented Oct 16, 2025

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

The bug this fixes was originally reported by Red Hat in https://issues.redhat.com/browse/OCPBUGS-60424

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
@netlify
Copy link

netlify bot commented Oct 16, 2025

Deploy Preview for olmv1 ready!

Name Link
🔨 Latest commit 6372625
🔍 Latest deploy log https://app.netlify.com/projects/olmv1/deploys/68fa6e27a8b2e60009c90d9a
😎 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

@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
@@ -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?

Copy link
Member Author

Choose a reason for hiding this comment

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

Hearing no other opinions, my vote is to leave as is. With this commit moving this function into a new package in the shared/utils space, hopefully future contributions will find this location to add new generic slice methods, and we can revisit the question again when there is more to be gained from pulling in a new dep.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm of two minds on the subject. The reference is to what looks like a personal library, which normally garners a 'no' from me. But it has a mess of contributions, releases, and some kind of community, which relaxes that somewhat.

I'd prefer that this package didn't reuse the same name as a standard library (https://pkg.go.dev/slices).
But otherwise I'm fine with having a minimal utility library here.

Copy link
Contributor

Choose a reason for hiding this comment

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

But it has a mess of contributions, releases, and some kind of community, which relaxes that somewhat.

The library has 20.5k stars which is really a lot and is a very good signal.

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

codecov bot commented Oct 17, 2025

Codecov Report

❌ Patch coverage is 91.48936% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.39%. Comparing base (6604f2a) to head (6372625).
⚠️ Report is 21 commits behind head on main.

Files with missing lines Patch % Lines
...ernal/operator-controller/bundle/versionrelease.go 93.61% 1 Missing and 2 partials ⚠️
...ator-controller/catalogmetadata/compare/compare.go 83.33% 1 Missing and 2 partials ⚠️
...or-controller/catalogmetadata/filter/successors.go 66.66% 1 Missing ⚠️
internal/operator-controller/resolve/resolver.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2273      +/-   ##
==========================================
- Coverage   72.73%   71.39%   -1.34%     
==========================================
  Files          89       92       +3     
  Lines        8747     7052    -1695     
==========================================
- Hits         6362     5035    -1327     
+ Misses       1968     1601     -367     
+ Partials      417      416       -1     
Flag Coverage Δ
e2e 46.12% <68.08%> (+6.93%) ⬆️
experimental-e2e 14.59% <0.00%> (-31.29%) ⬇️
unit 58.91% <79.78%> (+0.95%) ⬆️

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.

@joelanford joelanford force-pushed the build-metadata-precedence branch from e8571b6 to b398c34 Compare October 17, 2025 17:24
)

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?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not strongly opinionated here, but I do I kinda like bundle/versionsrelease.go as a pure implementation of the type without the baggage of the various kinds of things that we might source or derive a VersionRelease from.

// 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?

Copy link
Member Author

Choose a reason for hiding this comment

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

The reason we don't have that right now is because declcfg.Bundle does not actually embed its own deprecation information. So we can't directly compare declcfg.Bundle along deprecation lines.

I suppose we could essentially combine ByVersionAndRelease and ByDeprecationFunc into a single comparison function, but:

  1. It still wouldn't be a method on declcfg.Bundle
  2. It would still require extra declcfg.Deprecation metadata to do the comparison.

@camilamacedo86
Copy link
Contributor

This one seems related to the bug that @grokspawn has been looking on.
I think it would be nice get his review here.

@joelanford joelanford force-pushed the build-metadata-precedence branch from b398c34 to 2cf7680 Compare October 22, 2025 18:05
@joelanford
Copy link
Member Author

crd-diff is failing due to the change in the description of the spec.source.catalog.version field. Assuming folks agree to the updated API semantics, we either need to override the failure or update the crd-diff check to ignore the description change.

I'm personally inclined to specifically override so that future description changes continue to be flagged as potentially breaking so that those changes get extra scrutiny.

Copy link
Contributor

@pedjak pedjak left a comment

Choose a reason for hiding this comment

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

/lgtm a few more functions could be documented.

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Oct 23, 2025
metadata (e.g., "1.0.0+20230101"). This ensures an exact match of both
the semver version and the release. If you specify a version without build
metadata (e.g., "1.0.0"), it will match all bundles with that version
regardless of their release information.
Copy link
Contributor

Choose a reason for hiding this comment

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

We'll need to update this once the bundle release version feature lands, since we will need to mention both approaches, including how one is preferred in future. Right now the bundle release version approach is to use [version]-[release] to express the attribute combo in a string (though the source of truth is always the discrete version and release fields in the olm.package property).

Perhaps this is better resolved in a doc where we can go into more depth?

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 2cf7680 to 72c3a34 Compare October 23, 2025 14:45
@openshift-ci openshift-ci bot removed the lgtm Indicates that a PR is ready to be merged. label Oct 23, 2025
Copy link
Contributor

@pedjak pedjak left a comment

Choose a reason for hiding this comment

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

/lgtm

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Oct 23, 2025
@openshift-ci
Copy link

openshift-ci bot commented Oct 23, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: pedjak
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

func NewLegacyRegistryV1VersionRelease(vStr string) (*VersionRelease, error) {
vers, err := bsemver.Parse(vStr)
if err != nil {
return nil, err
Copy link
Member Author

Choose a reason for hiding this comment

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

This is not back-compat. We should return a releaseless VersionRelease in this case.

…rove VersionRelease parsing

This commit reverts the user-facing semantic changes to the ClusterExtension
version field that were introduced to support exact version pinning with build
metadata. The version field now ignores build metadata when matching versions,
consistent with semver specification.

Additionally, this commit modifies the VersionRelease parsing logic to be more
tolerant of semver versions whose build metadata is not a valid release. When
build metadata cannot be parsed as a release, the full version (including build
metadata) is preserved in the Version field, with an empty Release field.

Changes include:
- Removed documentation about pinning to exact versions with build metadata
- Removed exactVersionMatcher logic that enforced build metadata equality
- Updated NewLegacyRegistryV1VersionRelease to tolerate non-release build metadata
- Updated test expectations to reflect new behavior
@Copilot Copilot AI review requested due to automatic review settings October 23, 2025 18:04
@openshift-ci openshift-ci bot removed the lgtm Indicates that a PR is ready to be merged. label Oct 23, 2025
@openshift-ci
Copy link

openshift-ci bot commented Oct 23, 2025

New changes are detected. LGTM label has been removed.

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

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


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

func compareErrors(err1 error, err2 error) int {
if err1 != nil && err2 == nil {
return 1
return -1
Copy link

Copilot AI Oct 23, 2025

Choose a reason for hiding this comment

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

The comment on line 80 states 'The semantic is that errors are "less than" non-errors' but the implementation has been inverted from the original. The comment should be updated to match the new implementation or the implementation should be corrected to match the comment.

Copilot uses AI. Check for mistakes.

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.

4 participants