Skip to content

✨ Add support for parsing and persisting explicit pkg.Release field#2543

Open
rashmigottipati wants to merge 4 commits intooperator-framework:mainfrom
rashmigottipati:oprun-4277-implementation
Open

✨ Add support for parsing and persisting explicit pkg.Release field#2543
rashmigottipati wants to merge 4 commits intooperator-framework:mainfrom
rashmigottipati:oprun-4277-implementation

Conversation

@rashmigottipati
Copy link
Copy Markdown
Member

@rashmigottipati rashmigottipati commented Mar 6, 2026

Description

Summary

Adds support for parsing the explicit pkg.Release field from bundle metadata and persisting it through cluster storage (roundtripping). This is gated by the new BundleReleaseSupport alpha feature gate (disabled by default).

Changes

  • Added BundleReleaseSupport alpha feature gate (disabled by default)
  • Added Release field to BundleMetadata CRD type
  • Added BundleReleaseKey label constant for annotation storage
  • Updated bundleutil.parseVersionRelease() to: Parse explicit pkg.Release when feature gate enabled and field present. Fall back to legacy registry+v1 behavior (release in build metadata) otherwise
  • Updated bundleutil.MetadataFor() to serialize release value from VersionRelease
  • Added roundtripping support: store release in CRD field and annotations, read it back in filters and controllers

Feature Gate Behavior

When enabled:

  • Bundles with explicit pkg.Release field: release parsed separately, build metadata preserved for proper semver purpose
  • Bundles without explicit release: falls back to registry+v1 parsing (release from build metadata)

When feature gate disabled:

  • All bundles use registry+v1 parsing (release from build metadata)
  • Explicit pkg.Release field ignored

Reviewer Checklist

  • API Go Documentation
  • Tests: Unit Tests
  • Comprehensive Commit Messages
  • Links to related GitHub Issue(s)

Link to Github Issue: #2495
Epic: #2479

Copilot AI review requested due to automatic review settings March 6, 2026 16:37
@openshift-ci openshift-ci bot requested review from joelanford and perdasilva March 6, 2026 16:37
@netlify
Copy link
Copy Markdown

netlify bot commented Mar 6, 2026

Deploy Preview for olmv1 ready!

Name Link
🔨 Latest commit f1985dc
🔍 Latest deploy log https://app.netlify.com/projects/olmv1/deploys/69de9986e9b1ab0008d564be
😎 Deploy Preview https://deploy-preview-2543--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
Copy link
Copy Markdown

openshift-ci bot commented Mar 6, 2026

[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.

Details 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
Copy Markdown
Contributor

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 introduces an alpha feature gate to allow OLMv1 upgrade resolution to treat “re-released” bundles (same semver, higher release/build value like 2.0.0+1 -> 2.0.0+2) as valid successors when explicitly enabled.

Changes:

  • Added ReleaseVersionPriority feature gate (Alpha, default disabled).
  • Added SameVersionHigherRelease() predicate and integrated it into SuccessorsOf() behind the feature gate.
  • Added unit tests for SameVersionHigherRelease() and for SuccessorsOf() with the gate disabled.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
internal/operator-controller/features/features.go Defines the new ReleaseVersionPriority feature gate and its spec.
internal/operator-controller/catalogmetadata/filter/successors.go Conditionally expands successor matching to include same-version/higher-release bundles when gated on.
internal/operator-controller/catalogmetadata/filter/bundle_predicates.go Adds the SameVersionHigherRelease() predicate.
internal/operator-controller/catalogmetadata/filter/bundle_predicates_test.go Adds predicate unit tests including edge cases.
internal/operator-controller/catalogmetadata/filter/successors_test.go Adds a regression test to ensure default (gate-off) behavior does not accept higher-release bundles.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/operator-controller/catalogmetadata/filter/successors.go Outdated
Comment thread internal/operator-controller/catalogmetadata/filter/successors_test.go Outdated
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 6, 2026

Codecov Report

❌ Patch coverage is 74.71264% with 22 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.00%. Comparing base (dd2e1f6) to head (f1985dc).

Files with missing lines Patch % Lines
...ernal/operator-controller/bundle/versionrelease.go 0.00% 7 Missing ⚠️
api/v1/zz_generated.deepcopy.go 33.33% 3 Missing and 1 partial ⚠️
...ontroller/controllers/boxcutter_reconcile_steps.go 0.00% 2 Missing and 2 partials ⚠️
applyconfigurations/api/v1/bundlemetadata.go 0.00% 3 Missing ⚠️
internal/operator-controller/bundleutil/bundle.go 95.00% 1 Missing and 1 partial ⚠️
...er/controllers/clusterextension_reconcile_steps.go 33.33% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2543      +/-   ##
==========================================
+ Coverage   68.92%   69.00%   +0.07%     
==========================================
  Files         141      141              
  Lines       10005    10078      +73     
==========================================
+ Hits         6896     6954      +58     
- Misses       2594     2605      +11     
- Partials      515      519       +4     
Flag Coverage Δ
e2e 37.27% <19.54%> (+0.11%) ⬆️
experimental-e2e 52.15% <24.13%> (-0.36%) ⬇️
unit 53.83% <72.41%> (+0.17%) ⬆️

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.

Copilot AI review requested due to automatic review settings March 6, 2026 17:34
Copy link
Copy Markdown
Contributor

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 5 out of 5 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/operator-controller/catalogmetadata/filter/successors_test.go Outdated
@joelanford
Copy link
Copy Markdown
Member

If I understand this correctly, it looks like this introduces the new behavior that an explicit upgrade edge doesn't actually have to exist in the catalog to upgrade to a bundle that has the same version and a higher release. Is that the intent? (If so let's make that clear in the PR description).

Is it also the intent that we'll inherit the upgrade edges of the first release of the version?

Comment thread internal/operator-controller/catalogmetadata/filter/bundle_predicates_test.go Outdated
Comment thread internal/operator-controller/catalogmetadata/filter/successors.go Outdated
Comment thread internal/operator-controller/catalogmetadata/filter/bundle_predicates.go Outdated
@grokspawn
Copy link
Copy Markdown
Contributor

grokspawn commented Mar 9, 2026

We discussed earlier today. I think the first step is to essentially revert #2273 so that we're not attempting to interpret build metadata as release info anymore. Any catalogs built with tooling that supports release versioning will automagically propagate the build metadata into the CSV's spec.release field anyway, so regardless of whether the operator author used the old build metadata approach or the new spec.release approach, they would still have spec.release here.

The next step is to ensure that we're sorting successors using the CompositeVersion, which is easily performed if using the Bundle comparator during the sort.

This will prefer version+release over version.

#2273 makes the claim that future bundle types will drop this approach, not that registry+v1 bundles should. So that's my bad.
From the perspective of fulfilling handling precedents for registry+v1 bundles, we need to retain the ability to differentiate/order them by build metadata. :(

@grokspawn
Copy link
Copy Markdown
Contributor

If I understand this correctly, it looks like this introduces the new behavior that an explicit upgrade edge doesn't actually have to exist in the catalog to upgrade to a bundle that has the same version and a higher release. Is that the intent? (If so let's make that clear in the PR description).

Is it also the intent that we'll inherit the upgrade edges of the first release of the version?

Sadly, we have to rely on the presence of existing graph edges or we break assumptions users have with the registry+v1 bundle format, coming from v0.

So even though we have the ability to prefer version+release over version, since replaces/skips use named bundles instead of bundle versions we have to support the older behavior.

@joelanford
Copy link
Copy Markdown
Member

I think the first step is to essentially revert #2273 so that we're not attempting to interpret build metadata as release info anymore.

That would be a regression of a bug fix that #2273 made though, right?

Sadly, we have to rely on the presence of existing graph edges or we break assumptions users have with the registry+v1 bundle format, coming from v0.

So even though we have the ability to prefer version+release over version, since replaces/skips use named bundles instead of bundle versions we have to support the older behavior.

Yeah, agreed. I reached the same conclusion after thinking about this more.

So if I understand correctly now:

  1. The existing code on main already honors the upgrade graph and orders "same version, different release" correctly when parsing from build metadata
  2. The existing code on main knows nothing about the new release field.

So the change we need now is "look for release in the olm.package property, and if present, prefer it over build metadata"?

Copilot AI review requested due to automatic review settings March 12, 2026 19:55
@rashmigottipati rashmigottipati force-pushed the oprun-4277-implementation branch from 5681488 to 8dcab49 Compare March 12, 2026 20:00
Copy link
Copy Markdown
Contributor

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 5 out of 5 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/operator-controller/catalogmetadata/filter/successors.go Outdated
Comment thread internal/operator-controller/catalogmetadata/filter/bundle_predicates_test.go Outdated
Comment thread internal/operator-controller/resolve/resolver.go
Comment thread internal/operator-controller/catalogmetadata/filter/successors.go Outdated
@grokspawn
Copy link
Copy Markdown
Contributor

Adjusted my comments. I missed the part of the #2273 description when it said that we wouldn't divert from semver ordering for any new bundle formats.
From the perspective of registry+v1 bundles, this is precedent and we should support the new case with .spec.release is available, otherwise falling back on the 'is it bundle metadata' ordering logic.

@rashmigottipati rashmigottipati force-pushed the oprun-4277-implementation branch from a2e5062 to 1e9cded Compare April 2, 2026 20:52
Copilot AI review requested due to automatic review settings April 2, 2026 20:52
Copy link
Copy Markdown
Contributor

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 19 out of 19 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/operator-controller/bundleutil/bundle.go Outdated
Comment thread internal/operator-controller/controllers/clusterextension_reconcile_steps.go Outdated
Comment thread internal/operator-controller/controllers/boxcutter_reconcile_steps.go Outdated
Comment thread internal/operator-controller/bundleutil/bundle_test.go Outdated
@rashmigottipati rashmigottipati force-pushed the oprun-4277-implementation branch from a833002 to 3b933d4 Compare April 11, 2026 02:12
Copilot AI review requested due to automatic review settings April 11, 2026 02:17
@rashmigottipati rashmigottipati force-pushed the oprun-4277-implementation branch from 3b933d4 to d13ce71 Compare April 11, 2026 02:17
Copy link
Copy Markdown
Contributor

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 19 out of 19 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/operator-controller/controllers/clusterextension_reconcile_steps.go Outdated
Comment thread internal/operator-controller/controllers/boxcutter_reconcile_steps.go Outdated
Comment thread internal/operator-controller/bundleutil/bundle.go
Comment thread internal/operator-controller/bundleutil/bundle_test.go
Copy link
Copy Markdown
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.

Deep Review: Roundtrip Correctness and Ungated API Change

The core design (separating release from version, feature-gating the new parsing path) is sound. The CRD field documentation, validation regex, and deep-copy generation all look correct.

However, I traced the full data lifecycle through all paths (resolve → MetadataFor → annotations → GetRevisionStates → SuccessorsOf → ExactVersionRelease) and found two issues that need attention before merge:

  1. Ungated Version field change — The MetadataFor signature change strips build metadata from the Version field for all users, not just those with BundleReleaseSupport enabled. Standard CRD users lose release information entirely (the release field is pruned by the API server).

  2. Roundtrip correctness bug during controller upgrade — Writing BundleReleaseKey unconditionally creates a nil-vs-empty-string Release ambiguity that causes ExactVersionRelease to fail matching the installed bundle against itself in the catalog.

Both issues and suggested fixes are detailed in the inline comments below.

Comment thread internal/operator-controller/controllers/clusterextension_reconcile_steps.go Outdated
Comment thread internal/operator-controller/controllers/clusterextension_reconcile_steps.go Outdated
Comment thread internal/operator-controller/controllers/boxcutter_reconcile_steps.go Outdated
Comment thread internal/operator-controller/catalogmetadata/filter/successors.go Outdated
Signed-off-by: Rashmi Gottipati <rgottipa@redhat.com>
Signed-off-by: Rashmi Gottipati <rgottipa@redhat.com>
Copilot AI review requested due to automatic review settings April 14, 2026 18:16
@rashmigottipati rashmigottipati force-pushed the oprun-4277-implementation branch from 0601331 to 3af1ee4 Compare April 14, 2026 18:16
Copy link
Copy Markdown
Contributor

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 19 out of 19 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/operator-controller/catalogmetadata/filter/successors.go Outdated
Comment thread internal/operator-controller/catalogmetadata/filter/successors.go
Comment thread internal/operator-controller/controllers/clusterextension_reconcile_steps.go Outdated
Signed-off-by: Rashmi Gottipati <rgottipa@redhat.com>
@rashmigottipati rashmigottipati force-pushed the oprun-4277-implementation branch from 3af1ee4 to 8644489 Compare April 14, 2026 18:45
Copilot AI review requested due to automatic review settings April 14, 2026 19:32
Copy link
Copy Markdown
Contributor

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 19 out of 19 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/operator-controller/labels/labels.go Outdated
Signed-off-by: Rashmi Gottipati <rgottipa@redhat.com>
// +optional
// <opcon:experimental>
// +kubebuilder:validation:XValidation:rule="self.matches(\"^$|^(0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)(\\\\.(0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*$\")",message="release must be empty or consist of dot-separated identifiers (numeric without leading zeros, or alphanumeric)"
Release *string `json:"release,omitempty"`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I was planning to do this in a follow-up PR, because I think it ultimately should be based on op-reg Release type instead of op-con Release type.
This is neither.

Do we have any concern if a later PR makes this explicitly declcfg.Release type?

Please align the type+validation with api and my follow-on PR in operator-registry.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Unless there is meaning between nil and empty, we generally prefer to do

Suggested change
Release *string `json:"release,omitempty"`
Release string `json:"release,omitzero"`

I don't think there's any difference between these cases for this type. If the release is empty or omitted then it equates to no release value.

var rel bundle.Release
if releaseStr == "" {
// Explicit empty release: use empty slice (not nil)
rel = bundle.Release([]bsemver.PRVersion{})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This goes against bundle.NewRelease handling, which returns nil if given an empty string.
I've also aligned with that approach here.

return nil, fmt.Errorf("error unmarshalling package property: %w", err)
}

// Check if release field is explicitly present in JSON (even if empty).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since Package.Release is defined in operator-registry as string with omitzero, isn't the salient test whether the unmarshaled Package at 28 has a non-empty Release or not?

If we are worried about the scenario where the feature is disabled, but a bundle with a release version is in the catalog, then we can explicitly clear the field.

Is there another scenario that's important?

Name: bundleName,
Version: vr.Version.String(),
}
if vr.Release != nil {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This looks like we could skip it if we we move to omitempty instead of a pointer with omitzero, and furthermore could be omitted if we're using an explicit type instead of a string.
(I don't think we can use an explicit type yet, unless the bundle.Release supports marshaling/unmarshaling.)

Version: rev.Annotations[labels.BundleVersionKey],
},
}
// Only set Release if the annotation key exists (to distinguish "not set" from "explicitly empty")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think these are different cases. The value is only salient if it exists and is non-empty. Otherwise, there is no effective release.

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.

6 participants