Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
4d4f894
Add namespace format validation to bundle config schema (#2468)
perdasilva Jan 30, 2026
e50144a
:seedling: Bump github.com/klauspost/compress from 1.18.2 to 1.18.3 (…
dependabot[bot] Jan 30, 2026
5c4bf7b
🌱 test: ensure single/own namespace increase coverage for both runtim…
camilamacedo86 Jan 30, 2026
ee4bab5
🐛 fix: Configuration validation errors now show "Failed" status inste…
camilamacedo86 Jan 30, 2026
80dc609
Merge branch 'main' into synchronize
Jan 31, 2026
9eea3ea
UPSTREAM: <carry>: Add OpenShift specific files
dtfranz Oct 26, 2023
adcdebe
UPSTREAM: <carry>: Add new tests for single/own namespaces install modes
camilamacedo86 Oct 6, 2025
01d0707
UPSTREAM: <carry>: Upgrade OCP image from 4.20 to 4.21
camilamacedo86 Oct 13, 2025
e0ac000
UPSTREAM: <carry>: [Default Catalog Tests] - Change logic to get ocp …
camilamacedo86 Oct 13, 2025
3d47a49
UPSTREAM: <carry>: Update OCP catalogs to v4.21
tmshort Oct 13, 2025
1817782
UPSTREAM: <carry>: support singleown cases in disconnected
kuiwang02 Oct 16, 2025
76c90d8
UPSTREAM: <carry>: fix cases 81696 and 74618 for product code changes
kuiwang02 Oct 17, 2025
c9473e2
UPSTREAM: <carry>: Define Default timeouts and apply their usage accr…
camilamacedo86 Oct 22, 2025
945418c
UPSTREAM: <carry>: Update to new feature-gate options in helm
tmshort Oct 22, 2025
29ef106
UPSTREAM: <carry>: Fix flake for single/own ns tests by ensuring uniq…
camilamacedo86 Oct 22, 2025
06d0843
UPSTREAM: <carry>: [OTE]: Enhance single/own ns based on review comme…
camilamacedo86 Oct 24, 2025
b50d215
UPSTREAM: <carry>: Update OwnSingle template to use spec.config.inlin…
kuiwang02 Nov 3, 2025
a85de7c
UPSTREAM: <carry>: [OTE]: Add webhook cleanup validation on extension…
camilamacedo86 Nov 4, 2025
5ed082a
UPSTREAM: <carry>: Add [OTP] to migrated cases
kuiwang02 Nov 7, 2025
e073991
UPSTREAM: <carry>: [OTE]: Upgrade dependencies used
camilamacedo86 Nov 5, 2025
71a12c8
UPSTREAM: <carry>: fix(OTE): fix OpenShift Kubernetes replace version…
camilamacedo86 Nov 10, 2025
93e6889
UPSTREAM: <carry>: [Default Catalog Tests] Upgrade go 1.24.6 and depe…
camilamacedo86 Nov 11, 2025
ef44c58
UPSTREAM: <carry>: add disconnected environment support with custom p…
kuiwang02 Nov 12, 2025
22c2324
UPSTREAM: <carry>: migrate jiazha test cases to OTE
jianzhangbjz Nov 14, 2025
4aaa041
UPSTREAM: <carry>: migrate clustercatalog case to ote
Xia-Zhao-rh Oct 17, 2025
6463d88
UPSTREAM: <carry>: migrate olmv1 QE stress cases
kuiwang02 Nov 20, 2025
23b6255
UPSTREAM: <carry>: Use busybox/httpd to simulate probes
tmshort Nov 25, 2025
f341ffe
UPSTREAM: <carry>: migrate olmv1 QE cases
Xia-Zhao-rh Nov 25, 2025
cb80c13
UPSTREAM: <carry>: add agent for olmv1 qe cases
kuiwang02 Oct 21, 2025
45517e0
UPSTREAM: <carry>: Disable upstream PodDisruptionBudget
tmshort Dec 3, 2025
fff4d0a
UPSTREAM: <carry>: Add AGENTS.md for AI code contributions
rashmigottipati Dec 11, 2025
7525cb9
UPSTREAM: <carry>: address review comments through addl prompts
rashmigottipati Dec 11, 2025
3c45b6d
UPSTREAM: <carry>: addressing some more review comments
rashmigottipati Dec 11, 2025
4b070f8
UPSTREAM: <carry>: remove DCO line
rashmigottipati Dec 11, 2025
83ffc25
UPSTREAM: <carry>: migrate bandrade test cases to OTE
bandrade Nov 18, 2025
3772511
UPSTREAM: <carry>: update metadata
bandrade Dec 3, 2025
e3ce728
UPSTREAM: <carry>: remove originalName
bandrade Dec 3, 2025
3a01914
UPSTREAM: <carry>: update 80458's timeout to 180s
jianzhangbjz Dec 8, 2025
715cc44
UPSTREAM: <carry>: update 83026 to specify the clustercatalog
jianzhangbjz Dec 15, 2025
e71270f
UPSTREAM: <carry>: Update to golang 1.25 and ocp 4.22
oceanc80 Dec 18, 2025
091b278
UPSTREAM: <carry>: Use oc client for running e2e tests
pedjak Jan 13, 2026
e62f9cc
UPSTREAM: <carry>: Run upstream e2e tests tagged with `@catalogd-update`
pedjak Jan 14, 2026
bca8648
UPSTREAM: <carry>: enhance case to make it more stable
kuiwang02 Jan 6, 2026
0c59a15
UPSTREAM: <carry>: add service account to curl job
ehearne-redhat Jan 7, 2026
be020e2
UPSTREAM: <carry>: move sa creation out of buildCurlJob()
ehearne-redhat Jan 8, 2026
a079d19
UPSTREAM: <carry>: comment out delete service account
ehearne-redhat Jan 9, 2026
5901533
UPSTREAM: <carry>: move defercleanup for sa for LIFO
ehearne-redhat Jan 9, 2026
1035788
UPSTREAM: <carry>: add polling so job fully deleted before proceed
ehearne-redhat Jan 12, 2026
2d00bab
UPSTREAM: <carry>: Revert "Merge pull request #594 from ehearne-redha…
sosiouxme Jan 20, 2026
d89cb2f
UPSTREAM: <carry>: Remove openshift-redhat-marketplace catalog tests
camilamacedo86 Jan 8, 2026
c665431
UPSTREAM: <carry>: config watchnamespace cases
kuiwang02 Jan 6, 2026
3753682
UPSTREAM: <carry>: enhance ocp-79770
Xia-Zhao-rh Jan 26, 2026
593dfe4
UPSTREAM: <carry>: upgrade version support case
kuiwang02 Jan 28, 2026
51e0339
UPSTREAM: <drop>: go mod vendor
Jan 31, 2026
67828bf
UPSTREAM: <drop>: remove upstream GitHub configuration
Jan 31, 2026
1e14208
UPSTREAM: <drop>: configure the commit-checker
Jan 31, 2026
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
7 changes: 4 additions & 3 deletions api/v1/common_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ const (
ReasonAbsent = "Absent"

// Progressing reasons
ReasonRollingOut = "RollingOut"
ReasonRetrying = "Retrying"
ReasonBlocked = "Blocked"
ReasonRollingOut = "RollingOut"
ReasonRetrying = "Retrying"
ReasonBlocked = "Blocked"
ReasonInvalidConfiguration = "InvalidConfiguration"

// Deprecation reasons
ReasonDeprecated = "Deprecated"
Expand Down
2 changes: 1 addition & 1 deletion commitchecker.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
expectedMergeBase: fbe909f7ba35a9f771da6ec0431bbde2ac45d5fb
expectedMergeBase: ee4bab558cc0f7f46ff480bfa8917ffe4650a210
upstreamBranch: main
upstreamOrg: operator-framework
upstreamRepo: operator-controller
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ require (
github.com/google/go-containerregistry v0.20.7
github.com/google/renameio/v2 v2.0.2
github.com/gorilla/handlers v1.5.2
github.com/klauspost/compress v1.18.2
github.com/klauspost/compress v1.18.3
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.1
github.com/operator-framework/api v0.37.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw=
github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
Expand Down
3 changes: 2 additions & 1 deletion internal/operator-controller/applier/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/operator-framework/operator-controller/internal/operator-controller/config"
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/bundle/source"
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/render"
errorutil "github.com/operator-framework/operator-controller/internal/shared/util/error"
)

// ManifestProvider returns the manifests that should be applied by OLM given a bundle and its associated ClusterExtension
Expand Down Expand Up @@ -77,7 +78,7 @@ func (r *RegistryV1ManifestProvider) Get(bundleFS fs.FS, ext *ocv1.ClusterExtens
bundleConfigBytes := extensionConfigBytes(ext)
bundleConfig, err := config.UnmarshalConfig(bundleConfigBytes, schema, ext.Spec.Namespace)
if err != nil {
return nil, fmt.Errorf("invalid ClusterExtension configuration: %w", err)
return nil, errorutil.NewTerminalError(ocv1.ReasonInvalidConfiguration, fmt.Errorf("invalid ClusterExtension configuration: %w", err))
}

if watchNS := bundleConfig.GetWatchNamespace(); watchNS != nil {
Expand Down
34 changes: 33 additions & 1 deletion internal/operator-controller/applier/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

"github.com/operator-framework/api/pkg/operators/v1alpha1"

Expand Down Expand Up @@ -100,6 +101,37 @@ func Test_RegistryV1ManifestProvider_Integration(t *testing.T) {
require.Contains(t, err.Error(), "invalid ClusterExtension configuration")
})

t.Run("returns terminal error for invalid config", func(t *testing.T) {
provider := applier.RegistryV1ManifestProvider{
BundleRenderer: render.BundleRenderer{
ResourceGenerators: []render.ResourceGenerator{
func(rv1 *bundle.RegistryV1, opts render.Options) ([]client.Object, error) {
return nil, nil
},
},
},
IsSingleOwnNamespaceEnabled: true,
}

// Bundle with SingleNamespace install mode requiring watchNamespace config
bundleFS := bundlefs.Builder().WithPackageName("test").
WithCSV(clusterserviceversion.Builder().WithInstallModeSupportFor(v1alpha1.InstallModeTypeSingleNamespace).Build()).Build()

// ClusterExtension without required config
ext := &ocv1.ClusterExtension{
Spec: ocv1.ClusterExtensionSpec{
Namespace: "install-namespace",
// No config provided - should fail validation
},
}

_, err := provider.Get(bundleFS, ext)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid ClusterExtension configuration")
// Assert that config validation errors are terminal (not retriable)
require.ErrorIs(t, err, reconcile.TerminalError(nil), "config validation errors should be terminal")
})

t.Run("returns rendered manifests", func(t *testing.T) {
provider := applier.RegistryV1ManifestProvider{
BundleRenderer: registryv1.Renderer,
Expand Down Expand Up @@ -393,7 +425,7 @@ func Test_RegistryV1ManifestProvider_SingleOwnNamespaceSupport(t *testing.T) {
})
require.Error(t, err)
require.Contains(t, err.Error(), "invalid ClusterExtension configuration:")
require.Contains(t, err.Error(), "watchNamespace must be")
require.Contains(t, err.Error(), "must be")
require.Contains(t, err.Error(), "install-namespace")
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ var ConditionReasons = []string{
ocv1.ReasonDeprecationStatusUnknown,
ocv1.ReasonFailed,
ocv1.ReasonBlocked,
ocv1.ReasonInvalidConfiguration,
ocv1.ReasonRetrying,
ocv1.ReasonAbsent,
ocv1.ReasonRollingOut,
Expand Down
59 changes: 40 additions & 19 deletions internal/operator-controller/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"strings"

"github.com/santhosh-tekuri/jsonschema/v6"
"github.com/santhosh-tekuri/jsonschema/v6/kind"
"sigs.k8s.io/yaml"
)

Expand Down Expand Up @@ -208,7 +209,7 @@ func validateConfigWithSchema(configBytes []byte, schema map[string]any, install
return fmt.Errorf("value must be a string")
}
if str != installNamespace {
return fmt.Errorf("invalid value %q: watchNamespace must be %q (the namespace where the operator is installed) because this operator only supports OwnNamespace install mode", str, installNamespace)
return fmt.Errorf("invalid value %q: must be %q (the namespace where the operator is installed) because this operator only supports OwnNamespace install mode", str, installNamespace)
}
return nil
},
Expand All @@ -228,7 +229,7 @@ func validateConfigWithSchema(configBytes []byte, schema map[string]any, install
return fmt.Errorf("value must be a string")
}
if str == installNamespace {
return fmt.Errorf("invalid value %q: watchNamespace must be different from %q (the install namespace) because this operator uses SingleNamespace install mode to watch a different namespace", str, installNamespace)
return fmt.Errorf("invalid value %q: must be different from %q (the install namespace) because this operator uses SingleNamespace install mode to watch a different namespace", str, installNamespace)
}
return nil
},
Expand Down Expand Up @@ -294,25 +295,29 @@ func formatSchemaError(err error) error {

// formatSingleError formats a single validation error from the schema library.
func formatSingleError(errUnit jsonschema.OutputUnit) string {
if errUnit.Error == nil {
return ""
}

// Check the keyword location to identify the error type
switch {
case strings.Contains(errUnit.KeywordLocation, "/required"):
switch errKind := errUnit.Error.Kind.(type) {
case *kind.Required:
// Missing required field
fieldName := extractFieldNameFromMessage(errUnit.Error)
if fieldName != "" {
return fmt.Sprintf("required field %q is missing", fieldName)
}
return "required field is missing"

case strings.Contains(errUnit.KeywordLocation, "/additionalProperties"):
case *kind.AdditionalProperties:
// Unknown/additional field
fieldName := extractFieldNameFromMessage(errUnit.Error)
if fieldName != "" {
return fmt.Sprintf("unknown field %q", fieldName)
}
return "unknown field"

case strings.Contains(errUnit.KeywordLocation, "/type"):
case *kind.Type:
// Type mismatch (e.g., got null, want string)
fieldPath := buildFieldPath(errUnit.InstanceLocation)
if fieldPath != "" {
Expand All @@ -324,16 +329,14 @@ func formatSingleError(errUnit jsonschema.OutputUnit) string {
}
return fmt.Sprintf("invalid type: %s", errUnit.Error.String())

case strings.Contains(errUnit.KeywordLocation, "/format"):
// Custom format validation (e.g., OwnNamespace, SingleNamespace constraints)
// These already have good error messages from our custom validators
if errUnit.Error != nil {
return errUnit.Error.String()
}
case *kind.Format:
fieldPath := buildFieldPath(errUnit.InstanceLocation)
return fmt.Sprintf("invalid format for field %q", fieldPath)
if fieldPath != "" {
return fmt.Sprintf("invalid format for field %q: %s", fieldPath, errUnit.Error.String())
}
return fmt.Sprintf("invalid format: %s", errUnit.Error.String())

case strings.Contains(errUnit.KeywordLocation, "/anyOf"):
case *kind.AnyOf:
// anyOf validation failed - could be null or wrong type
// This happens when a field accepts [null, string] but got something else
fieldPath := buildFieldPath(errUnit.InstanceLocation)
Expand All @@ -342,13 +345,31 @@ func formatSingleError(errUnit jsonschema.OutputUnit) string {
}
return "invalid value"

case *kind.MaxLength:
fieldPath := buildFieldPath(errUnit.InstanceLocation)
if fieldPath != "" {
return fmt.Sprintf("field %q must have maximum length of %d (len=%d)", fieldPath, errKind.Want, errKind.Got)
}
return errUnit.Error.String()

case *kind.MinLength:
fieldPath := buildFieldPath(errUnit.InstanceLocation)
if fieldPath != "" {
return fmt.Sprintf("field %q must have minimum length of %d (len=%d)", fieldPath, errKind.Want, errKind.Got)
}
return errUnit.Error.String()

case *kind.Pattern:
fieldPath := buildFieldPath(errUnit.InstanceLocation)
if fieldPath != "" {
return fmt.Sprintf("field %q must match pattern %q", fieldPath, errKind.Want)
}
return errUnit.Error.String()

default:
// Unknown error type - return the library's error message
// Unhandled error type - return the library's error message
// This serves as a fallback for future schema features we haven't customized yet
if errUnit.Error != nil {
return errUnit.Error.String()
}
return ""
return errUnit.Error.String()
}
}

Expand Down
29 changes: 27 additions & 2 deletions internal/operator-controller/config/error_formatting_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config_test

import (
"strings"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -72,9 +73,9 @@ func Test_ErrorFormatting_SchemaLibraryVersion(t *testing.T) {
supportedInstallModes: []v1alpha1.InstallModeType{v1alpha1.InstallModeTypeOwnNamespace},
installNamespace: "correct-namespace",
expectedErrSubstrings: []string{
"invalid format for field \"watchNamespace\"",
"invalid value",
"wrong-namespace",
"watchNamespace must be",
"correct-namespace",
"the namespace where the operator is installed",
"OwnNamespace install mode",
Expand All @@ -86,14 +87,38 @@ func Test_ErrorFormatting_SchemaLibraryVersion(t *testing.T) {
supportedInstallModes: []v1alpha1.InstallModeType{v1alpha1.InstallModeTypeSingleNamespace},
installNamespace: "install-ns",
expectedErrSubstrings: []string{
"invalid format for field \"watchNamespace\"",
"not valid singleNamespaceInstallMode",
"invalid value",
"install-ns",
"watchNamespace must be different from",
"must be different from",
"the install namespace",
"SingleNamespace install mode",
"watch a different namespace",
},
},
{
name: "SingleNamespace constraint error bad namespace format",
rawConfig: []byte(`{"watchNamespace": "---AAAA-BBBB-super-long-namespace-that-that-is-waaaaaaaaayyy-longer-than-sixty-three-characters"}`),
supportedInstallModes: []v1alpha1.InstallModeType{v1alpha1.InstallModeTypeSingleNamespace},
installNamespace: "install-ns",
expectedErrSubstrings: []string{
"field \"watchNamespace\"",
"must match pattern \"^[a-z0-9]([-a-z0-9]*[a-z0-9])?$\"",
},
},
{
name: "Single- and OwnNamespace constraint error bad namespace format",
rawConfig: []byte(`{"watchNamespace": ` + strings.Repeat("A", 63) + `"}`),
supportedInstallModes: []v1alpha1.InstallModeType{v1alpha1.InstallModeTypeSingleNamespace, v1alpha1.InstallModeTypeOwnNamespace},
installNamespace: "install-ns",
expectedErrSubstrings: []string{
"invalid configuration",
"multiple errors found",
"must have maximum length of 63 (len=64)",
"must match pattern \"^[a-z0-9]([-a-z0-9]*[a-z0-9])?$\"",
},
},
} {
t.Run(tc.name, func(t *testing.T) {
rv1 := bundle.RegistryV1{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package controllers
import (
"cmp"
"context"
"errors"
"fmt"
"io/fs"
"slices"
Expand All @@ -27,6 +28,7 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

ocv1 "github.com/operator-framework/operator-controller/api/v1"
"github.com/operator-framework/operator-controller/internal/operator-controller/labels"
Expand Down Expand Up @@ -114,6 +116,12 @@ func ApplyBundleWithBoxcutter(apply func(ctx context.Context, contentFS fs.FS, e
// If there was an error applying the resolved bundle,
// report the error via the Progressing condition.
setStatusProgressing(ext, wrapErrorWithResolutionInfo(state.resolvedRevisionMetadata.BundleMetadata, err))
// Only set Installed condition for retryable errors.
// For terminal errors (Progressing: False with a terminal reason such as Blocked or InvalidConfiguration),
// the Progressing condition already provides all necessary information about the failure.
if !errors.Is(err, reconcile.TerminalError(nil)) {
setInstalledStatusFromRevisionStates(ext, state.revisionStates)
}
return nil, err
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import (
ocv1 "github.com/operator-framework/operator-controller/api/v1"
"github.com/operator-framework/operator-controller/internal/operator-controller/conditionsets"
"github.com/operator-framework/operator-controller/internal/operator-controller/labels"
errorutil "github.com/operator-framework/operator-controller/internal/shared/util/error"
k8sutil "github.com/operator-framework/operator-controller/internal/shared/util/k8s"
)

Expand Down Expand Up @@ -455,6 +456,19 @@ func (r *ClusterExtensionReconciler) SetupWithManager(mgr ctrl.Manager, opts ...
}

func wrapErrorWithResolutionInfo(resolved ocv1.BundleMetadata, err error) error {
// Preserve TerminalError type and reason through wrapping
if errors.Is(err, reconcile.TerminalError(nil)) {
// Extract the reason if one was provided
reason, hasReason := errorutil.ExtractTerminalReason(err)
// Unwrap to get the inner error, add context
innerErr := errorutil.UnwrapTerminal(err)
wrappedErr := fmt.Errorf("error for resolved bundle %q with version %q: %w", resolved.Name, resolved.Version, innerErr)
// Re-wrap preserving the reason if it existed
if hasReason {
return errorutil.NewTerminalError(reason, wrappedErr)
}
return reconcile.TerminalError(wrappedErr)
}
return fmt.Errorf("error for resolved bundle %q with version %q: %w", resolved.Name, resolved.Version, err)
}

Expand Down
Loading