Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
8 changes: 8 additions & 0 deletions api/v1/clusterextension_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,14 @@ type CatalogFilter struct {
// "0.6.0", which means "only install version 0.6.0 and never
// upgrade from this version".
//
// For registry+v1 bundles that include release information in the build
// metadata field (e.g., "1.0.0+20230101"), you can pin to an exact version
// including the release by specifying the full version string with build
// 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.
//
// # Basic Comparison Operators
//
// The basic comparison operators and their meanings are:
Expand Down
2 changes: 1 addition & 1 deletion docs/api-reference/olmv1-api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ _Appears in:_
| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `packageName` _string_ | packageName is a reference to the name of the package to be installed<br />and is used to filter the content from catalogs.<br /><br />packageName is required, immutable, and follows the DNS subdomain standard<br />as defined in [RFC 1123]. It must contain only lowercase alphanumeric characters,<br />hyphens (-) or periods (.), start and end with an alphanumeric character,<br />and be no longer than 253 characters.<br /><br />Some examples of valid values are:<br /> - some-package<br /> - 123-package<br /> - 1-package-2<br /> - somepackage<br /><br />Some examples of invalid values are:<br /> - -some-package<br /> - some-package-<br /> - thisisareallylongpackagenamethatisgreaterthanthemaximumlength<br /> - some.package<br /><br />[RFC 1123]: https://tools.ietf.org/html/rfc1123 | | MaxLength: 253 <br />Required: \{\} <br /> |
| `version` _string_ | version is an optional semver constraint (a specific version or range of versions). When unspecified, the latest version available will be installed.<br /><br />Acceptable version ranges are no longer than 64 characters.<br />Version ranges are composed of comma- or space-delimited values and one or<br />more comparison operators, known as comparison strings. Additional<br />comparison strings can be added using the OR operator (\|\|).<br /><br /># Range Comparisons<br /><br />To specify a version range, you can use a comparison string like ">=3.0,<br /><3.6". When specifying a range, automatic updates will occur within that<br />range. The example comparison string means "install any version greater than<br />or equal to 3.0.0 but less than 3.6.0.". It also states intent that if any<br />upgrades are available within the version range after initial installation,<br />those upgrades should be automatically performed.<br /><br /># Pinned Versions<br /><br />To specify an exact version to install you can use a version range that<br />"pins" to a specific version. When pinning to a specific version, no<br />automatic updates will occur. An example of a pinned version range is<br />"0.6.0", which means "only install version 0.6.0 and never<br />upgrade from this version".<br /><br /># Basic Comparison Operators<br /><br />The basic comparison operators and their meanings are:<br /> - "=", equal (not aliased to an operator)<br /> - "!=", not equal<br /> - "<", less than<br /> - ">", greater than<br /> - ">=", greater than OR equal to<br /> - "<=", less than OR equal to<br /><br /># Wildcard Comparisons<br /><br />You can use the "x", "X", and "*" characters as wildcard characters in all<br />comparison operations. Some examples of using the wildcard characters:<br /> - "1.2.x", "1.2.X", and "1.2.*" is equivalent to ">=1.2.0, < 1.3.0"<br /> - ">= 1.2.x", ">= 1.2.X", and ">= 1.2.*" is equivalent to ">= 1.2.0"<br /> - "<= 2.x", "<= 2.X", and "<= 2.*" is equivalent to "< 3"<br /> - "x", "X", and "*" is equivalent to ">= 0.0.0"<br /><br /># Patch Release Comparisons<br /><br />When you want to specify a minor version up to the next major version you<br />can use the "~" character to perform patch comparisons. Some examples:<br /> - "~1.2.3" is equivalent to ">=1.2.3, <1.3.0"<br /> - "~1" and "~1.x" is equivalent to ">=1, <2"<br /> - "~2.3" is equivalent to ">=2.3, <2.4"<br /> - "~1.2.x" is equivalent to ">=1.2.0, <1.3.0"<br /><br /># Major Release Comparisons<br /><br />You can use the "^" character to make major release comparisons after a<br />stable 1.0.0 version is published. If there is no stable version published, // minor versions define the stability level. Some examples:<br /> - "^1.2.3" is equivalent to ">=1.2.3, <2.0.0"<br /> - "^1.2.x" is equivalent to ">=1.2.0, <2.0.0"<br /> - "^2.3" is equivalent to ">=2.3, <3"<br /> - "^2.x" is equivalent to ">=2.0.0, <3"<br /> - "^0.2.3" is equivalent to ">=0.2.3, <0.3.0"<br /> - "^0.2" is equivalent to ">=0.2.0, <0.3.0"<br /> - "^0.0.3" is equvalent to ">=0.0.3, <0.0.4"<br /> - "^0.0" is equivalent to ">=0.0.0, <0.1.0"<br /> - "^0" is equivalent to ">=0.0.0, <1.0.0"<br /><br /># OR Comparisons<br />You can use the "\|\|" character to represent an OR operation in the version<br />range. Some examples:<br /> - ">=1.2.3, <2.0.0 \|\| >3.0.0"<br /> - "^0 \|\| ^3 \|\| ^5"<br /><br />For more information on semver, please see https://semver.org/ | | MaxLength: 64 <br /> |
| `version` _string_ | version is an optional semver constraint (a specific version or range of versions). When unspecified, the latest version available will be installed.<br /><br />Acceptable version ranges are no longer than 64 characters.<br />Version ranges are composed of comma- or space-delimited values and one or<br />more comparison operators, known as comparison strings. Additional<br />comparison strings can be added using the OR operator (\|\|).<br /><br /># Range Comparisons<br /><br />To specify a version range, you can use a comparison string like ">=3.0,<br /><3.6". When specifying a range, automatic updates will occur within that<br />range. The example comparison string means "install any version greater than<br />or equal to 3.0.0 but less than 3.6.0.". It also states intent that if any<br />upgrades are available within the version range after initial installation,<br />those upgrades should be automatically performed.<br /><br /># Pinned Versions<br /><br />To specify an exact version to install you can use a version range that<br />"pins" to a specific version. When pinning to a specific version, no<br />automatic updates will occur. An example of a pinned version range is<br />"0.6.0", which means "only install version 0.6.0 and never<br />upgrade from this version".<br /><br />For registry+v1 bundles that include release information in the build<br />metadata field (e.g., "1.0.0+20230101"), you can pin to an exact version<br />including the release by specifying the full version string with build<br />metadata (e.g., "1.0.0+20230101"). This ensures an exact match of both<br />the semver version and the release. If you specify a version without build<br />metadata (e.g., "1.0.0"), it will match all bundles with that version<br />regardless of their release information.<br /><br /># Basic Comparison Operators<br /><br />The basic comparison operators and their meanings are:<br /> - "=", equal (not aliased to an operator)<br /> - "!=", not equal<br /> - "<", less than<br /> - ">", greater than<br /> - ">=", greater than OR equal to<br /> - "<=", less than OR equal to<br /><br /># Wildcard Comparisons<br /><br />You can use the "x", "X", and "*" characters as wildcard characters in all<br />comparison operations. Some examples of using the wildcard characters:<br /> - "1.2.x", "1.2.X", and "1.2.*" is equivalent to ">=1.2.0, < 1.3.0"<br /> - ">= 1.2.x", ">= 1.2.X", and ">= 1.2.*" is equivalent to ">= 1.2.0"<br /> - "<= 2.x", "<= 2.X", and "<= 2.*" is equivalent to "< 3"<br /> - "x", "X", and "*" is equivalent to ">= 0.0.0"<br /><br /># Patch Release Comparisons<br /><br />When you want to specify a minor version up to the next major version you<br />can use the "~" character to perform patch comparisons. Some examples:<br /> - "~1.2.3" is equivalent to ">=1.2.3, <1.3.0"<br /> - "~1" and "~1.x" is equivalent to ">=1, <2"<br /> - "~2.3" is equivalent to ">=2.3, <2.4"<br /> - "~1.2.x" is equivalent to ">=1.2.0, <1.3.0"<br /><br /># Major Release Comparisons<br /><br />You can use the "^" character to make major release comparisons after a<br />stable 1.0.0 version is published. If there is no stable version published, // minor versions define the stability level. Some examples:<br /> - "^1.2.3" is equivalent to ">=1.2.3, <2.0.0"<br /> - "^1.2.x" is equivalent to ">=1.2.0, <2.0.0"<br /> - "^2.3" is equivalent to ">=2.3, <3"<br /> - "^2.x" is equivalent to ">=2.0.0, <3"<br /> - "^0.2.3" is equivalent to ">=0.2.3, <0.3.0"<br /> - "^0.2" is equivalent to ">=0.2.0, <0.3.0"<br /> - "^0.0.3" is equvalent to ">=0.0.3, <0.0.4"<br /> - "^0.0" is equivalent to ">=0.0.0, <0.1.0"<br /> - "^0" is equivalent to ">=0.0.0, <1.0.0"<br /><br /># OR Comparisons<br />You can use the "\|\|" character to represent an OR operation in the version<br />range. Some examples:<br /> - ">=1.2.3, <2.0.0 \|\| >3.0.0"<br /> - "^0 \|\| ^3 \|\| ^5"<br /><br />For more information on semver, please see https://semver.org/ | | MaxLength: 64 <br /> |
| `channels` _string array_ | channels is an optional reference to a set of channels belonging to<br />the package specified in the packageName field.<br /><br />A "channel" is a package-author-defined stream of updates for an extension.<br /><br />Each channel in the list must follow the DNS subdomain standard<br />as defined in [RFC 1123]. It must contain only lowercase alphanumeric characters,<br />hyphens (-) or periods (.), start and end with an alphanumeric character,<br />and be no longer than 253 characters. No more than 256 channels can be specified.<br /><br />When specified, it is used to constrain the set of installable bundles and<br />the automated upgrade path. This constraint is an AND operation with the<br />version field. For example:<br /> - Given channel is set to "foo"<br /> - Given version is set to ">=1.0.0, <1.5.0"<br /> - Only bundles that exist in channel "foo" AND satisfy the version range comparison will be considered installable<br /> - Automatic upgrades will be constrained to upgrade edges defined by the selected channel<br /><br />When unspecified, upgrade edges across all channels will be used to identify valid automatic upgrade paths.<br /><br />Some examples of valid values are:<br /> - 1.1.x<br /> - alpha<br /> - stable<br /> - stable-v1<br /> - v1-stable<br /> - dev-preview<br /> - preview<br /> - community<br /><br />Some examples of invalid values are:<br /> - -some-channel<br /> - some-channel-<br /> - thisisareallylongchannelnamethatisgreaterthanthemaximumlength<br /> - original_40<br /> - --default-channel<br /><br />[RFC 1123]: https://tools.ietf.org/html/rfc1123 | | MaxItems: 256 <br /> |
| `selector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#labelselector-v1-meta)_ | selector is an optional field that can be used<br />to filter the set of ClusterCatalogs used in the bundle<br />selection process.<br /><br />When unspecified, all ClusterCatalogs will be used in<br />the bundle selection process. | | |
| `upgradeConstraintPolicy` _[UpgradeConstraintPolicy](#upgradeconstraintpolicy)_ | upgradeConstraintPolicy is an optional field that controls whether<br />the upgrade path(s) defined in the catalog are enforced for the package<br />referenced in the packageName field.<br /><br />Allowed values are: "CatalogProvided" or "SelfCertified", or omitted.<br /><br />When this field is set to "CatalogProvided", automatic upgrades will only occur<br />when upgrade constraints specified by the package author are met.<br /><br />When this field is set to "SelfCertified", the upgrade constraints specified by<br />the package author are ignored. This allows for upgrades and downgrades to<br />any version of the package. This is considered a dangerous operation as it<br />can lead to unknown and potentially disastrous outcomes, such as data<br />loss. It is assumed that users have independently verified changes when<br />using this option.<br /><br />When this field is omitted, the default value is "CatalogProvided". | CatalogProvided | Enum: [CatalogProvided SelfCertified] <br /> |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,14 @@ spec:
"0.6.0", which means "only install version 0.6.0 and never
upgrade from this version".

For registry+v1 bundles that include release information in the build
metadata field (e.g., "1.0.0+20230101"), you can pin to an exact version
including the release by specifying the full version string with build
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?


# Basic Comparison Operators

The basic comparison operators and their meanings are:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,14 @@ spec:
"0.6.0", which means "only install version 0.6.0 and never
upgrade from this version".

For registry+v1 bundles that include release information in the build
metadata field (e.g., "1.0.0+20230101"), you can pin to an exact version
including the release by specifying the full version string with build
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.

# Basic Comparison Operators

The basic comparison operators and their meanings are:
Expand Down
116 changes: 116 additions & 0 deletions internal/operator-controller/bundle/versionrelease.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package bundle

import (
"errors"
"fmt"
"strings"

bsemver "github.com/blang/semver/v4"

slicesutil "github.com/operator-framework/operator-controller/internal/shared/util/slices"
)

// NewLegacyRegistryV1VersionRelease parses a registry+v1 bundle version string and returns
// a VersionRelease. For registry+v1 bundles, the build metadata field of the semver version
// is treated as release information (a semver spec violation maintained for backward compatibility).
// The returned VersionRelease has the build metadata extracted into the Release field, and the
// Version field has its Build metadata cleared.
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.

}

rel, err := NewRelease(strings.Join(vers.Build, "."))
if err != nil {
return nil, err
}
vers.Build = nil

return &VersionRelease{
Version: vers,
Release: rel,
}, nil
}

type VersionRelease struct {
Version bsemver.Version
Release Release
}

// Compare compares two VersionRelease values. It returns:
//
// -1 if vr < other
// 0 if vr == other
// +1 if vr > other
//
// Comparison is done first by Version, then by Release if versions are equal.
func (vr *VersionRelease) Compare(other VersionRelease) int {
if vCmp := vr.Version.Compare(other.Version); vCmp != 0 {
return vCmp
}
return vr.Release.Compare(other.Release)
}

func (vr *VersionRelease) AsLegacyRegistryV1Version() bsemver.Version {
return bsemver.Version{
Major: vr.Version.Major,
Minor: vr.Version.Minor,
Patch: vr.Version.Patch,
Pre: vr.Version.Pre,
Build: slicesutil.Map(vr.Release, func(i bsemver.PRVersion) string { return i.String() }),
}
}

type Release []bsemver.PRVersion

// Compare compares two Release values. It returns:
//
// -1 if r < other
// 0 if r == other
// +1 if r > other
//
// Comparison is done segment by segment from left to right. Numeric segments are
// compared numerically, and alphanumeric segments are compared lexically in ASCII
// sort order. A shorter release is considered less than a longer release if all
// corresponding segments are equal.
func (r Release) Compare(other Release) int {
if len(r) == 0 && len(other) > 0 {
return -1
}
if len(other) == 0 && len(r) > 0 {
return 1
}
a := bsemver.Version{Pre: r}
b := bsemver.Version{Pre: other}
return a.Compare(b)
}

// NewRelease parses a release string into a Release. The release string should be
// a dot-separated sequence of non-empty identifiers, where each identifier contains
// only ASCII alphanumerics and hyphens [0-9A-Za-z-]. Numeric identifiers (those
// containing only digits) must not have leading zeros. An empty string returns a nil
// Release. Returns an error if any segment is invalid.
func NewRelease(relStr string) (Release, error) {
if relStr == "" {
return nil, nil
}

var (
segments = strings.Split(relStr, ".")
r = make(Release, 0, len(segments))
errs []error
)
for i, segment := range segments {
prVer, err := bsemver.NewPRVersion(segment)
if err != nil {
errs = append(errs, fmt.Errorf("segment %d: %v", i, err))
continue
}
r = append(r, prVer)
}
if err := errors.Join(errs...); err != nil {
return nil, fmt.Errorf("invalid release %q: %v", relStr, err)
}
return r, nil
}
Loading
Loading