Skip to content

Commit 753f644

Browse files
committed
predicate error tracking sketch
Signed-off-by: Jordan Keister <jordan@nimblewidget.com>
1 parent f301f55 commit 753f644

File tree

5 files changed

+857
-48
lines changed

5 files changed

+857
-48
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package filter
22

33
import (
4+
"fmt"
5+
46
mmsemver "github.com/Masterminds/semver/v3"
57
bsemver "github.com/blang/semver/v4"
68

@@ -11,59 +13,80 @@ import (
1113
)
1214

1315
func WithPackageName(packageName string) Predicate[catalogmetadata.Bundle] {
14-
return func(bundle *catalogmetadata.Bundle) bool {
15-
return bundle.Package == packageName
16+
return func(bundle *catalogmetadata.Bundle) (bool, []string) {
17+
value := bundle.Package == packageName
18+
if !value {
19+
return false, []string{packageName}
20+
}
21+
return value, nil
1622
}
1723
}
1824

1925
func InMastermindsSemverRange(semverRange *mmsemver.Constraints) Predicate[catalogmetadata.Bundle] {
20-
return func(bundle *catalogmetadata.Bundle) bool {
26+
return func(bundle *catalogmetadata.Bundle) (bool, []string) {
2127
bVersion, err := bundle.Version()
2228
if err != nil {
23-
return false
29+
return false, []string{err.Error()}
2430
}
2531
// No error should occur here because the simple version was successfully parsed by blang
2632
// We are unaware of any tests cases that would cause one to fail but not the other
2733
// This will cause code coverage to drop for this line. We don't ignore the error because
2834
// there might be that one extreme edge case that might cause one to fail but not the other
2935
mVersion, err := mmsemver.NewVersion(bVersion.String())
3036
if err != nil {
31-
return false
37+
return false, []string{err.Error()}
38+
}
39+
res := semverRange.Check(mVersion)
40+
if !res {
41+
return false, []string{fmt.Sprintf("no package %q matching version %q found", bundle.Package, semverRange.String())}
3242
}
33-
return semverRange.Check(mVersion)
43+
return true, nil
3444
}
3545
}
3646

37-
func InBlangSemverRange(semverRange bsemver.Range) Predicate[catalogmetadata.Bundle] {
38-
return func(bundle *catalogmetadata.Bundle) bool {
47+
func InBlangSemverRange(semverRange bsemver.Range, semverRangeString string) Predicate[catalogmetadata.Bundle] {
48+
return func(bundle *catalogmetadata.Bundle) (bool, []string) {
3949
bundleVersion, err := bundle.Version()
4050
if err != nil {
41-
return false
51+
return false, []string{err.Error()}
4252
}
43-
return semverRange(*bundleVersion)
53+
if !semverRange(*bundleVersion) {
54+
return false, []string{fmt.Sprintf("no package %q matching version %q found", bundle.Package, semverRangeString)}
55+
}
56+
return true, nil
4457
}
4558
}
4659

4760
func InChannel(channelName string) Predicate[catalogmetadata.Bundle] {
48-
return func(bundle *catalogmetadata.Bundle) bool {
61+
return func(bundle *catalogmetadata.Bundle) (bool, []string) {
4962
for _, ch := range bundle.InChannels {
5063
if ch.Name == channelName {
51-
return true
64+
return true, nil
5265
}
5366
}
54-
return false
67+
return false, []string{fmt.Sprintf("no package %q found in channel %q", bundle.Package, channelName)}
5568
}
5669
}
5770

5871
func WithBundleImage(bundleImage string) Predicate[catalogmetadata.Bundle] {
59-
return func(bundle *catalogmetadata.Bundle) bool {
60-
return bundle.Image == bundleImage
72+
return func(bundle *catalogmetadata.Bundle) (bool, []string) {
73+
res := bundle.Image == bundleImage
74+
if !res {
75+
return false, []string{fmt.Sprintf("no matching bundle image %q found for package %s", bundleImage, bundle.Package)}
76+
} else {
77+
return true, nil
78+
}
6179
}
6280
}
6381

6482
func WithBundleName(bundleName string) Predicate[catalogmetadata.Bundle] {
65-
return func(bundle *catalogmetadata.Bundle) bool {
66-
return bundle.Name == bundleName
83+
return func(bundle *catalogmetadata.Bundle) (bool, []string) {
84+
res := bundle.Name == bundleName
85+
if !res {
86+
return false, []string{fmt.Sprintf("no matching bundle name %q found for package %s", bundleName, bundle.Package)}
87+
} else {
88+
return true, nil
89+
}
6790
}
6891
}
6992

@@ -87,20 +110,25 @@ func LegacySuccessor(installedBundle *ocv1alpha1.BundleMetadata) Predicate[catal
87110
return false
88111
}
89112

90-
return func(candidateBundle *catalogmetadata.Bundle) bool {
113+
return func(candidateBundle *catalogmetadata.Bundle) (bool, []string) {
91114
for _, ch := range candidateBundle.InChannels {
92115
for _, chEntry := range ch.Entries {
93116
if candidateBundle.Name == chEntry.Name && isSuccessor(chEntry) {
94-
return true
117+
return true, nil
95118
}
96119
}
97120
}
98-
return false
121+
return false, []string{fmt.Sprintf("no legacy successor found for bundle name %q", candidateBundle.Name)}
99122
}
100123
}
101124

102125
func WithDeprecation(deprecated bool) Predicate[catalogmetadata.Bundle] {
103-
return func(bundle *catalogmetadata.Bundle) bool {
104-
return bundle.HasDeprecation() == deprecated
126+
return func(bundle *catalogmetadata.Bundle) (bool, []string) {
127+
res := bundle.HasDeprecation() == deprecated
128+
if !res {
129+
return false, []string{fmt.Sprintf("no bundle %q found with desired deprecation status %t", bundle.Name, deprecated)}
130+
} else {
131+
return true, nil
132+
}
105133
}
106134
}

internal/catalogmetadata/filter/bundle_predicates_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func TestInBlangSemverRange(t *testing.T) {
9292

9393
vRange := bsemver.MustParseRange(">=1.0.0")
9494

95-
f := filter.InBlangSemverRange(vRange)
95+
f := filter.InBlangSemverRange(vRange, ">=1.0.0")
9696

9797
assert.True(t, f(b1))
9898
assert.False(t, f(b2))

internal/catalogmetadata/filter/filter.go

+25-14
Original file line numberDiff line numberDiff line change
@@ -5,43 +5,54 @@ import (
55
)
66

77
// Predicate returns true if the object should be kept when filtering
8-
type Predicate[T catalogmetadata.Schemas] func(entity *T) bool
8+
type Predicate[T catalogmetadata.Schemas] func(entity *T) (bool, []string)
99

1010
// Filter filters a slice accordingly to
11-
func Filter[T catalogmetadata.Schemas](in []*T, test Predicate[T]) []*T {
11+
func Filter[T catalogmetadata.Schemas](in []*T, test Predicate[T]) ([]*T, []string) {
1212
out := []*T{}
13+
var errs []string
1314
for i := range in {
14-
if test(in[i]) {
15+
res, e := test(in[i])
16+
if res {
1517
out = append(out, in[i])
18+
} else {
19+
errs = append(errs, e...)
1620
}
1721
}
18-
return out
22+
return out, errs
1923
}
2024

2125
func And[T catalogmetadata.Schemas](predicates ...Predicate[T]) Predicate[T] {
22-
return func(obj *T) bool {
26+
return func(obj *T) (bool, []string) {
2327
for _, predicate := range predicates {
24-
if !predicate(obj) {
25-
return false
28+
if res, errs := predicate(obj); !res {
29+
return false, errs
2630
}
2731
}
28-
return true
32+
return true, nil
2933
}
3034
}
3135

3236
func Or[T catalogmetadata.Schemas](predicates ...Predicate[T]) Predicate[T] {
33-
return func(obj *T) bool {
37+
return func(obj *T) (bool, []string) {
38+
var errs []string
3439
for _, predicate := range predicates {
35-
if predicate(obj) {
36-
return true
40+
if res, e := predicate(obj); !res {
41+
errs = append(errs, e...)
42+
} else {
43+
return true, nil
3744
}
3845
}
39-
return false
46+
return false, errs
4047
}
4148
}
4249

4350
func Not[T catalogmetadata.Schemas](predicate Predicate[T]) Predicate[T] {
44-
return func(obj *T) bool {
45-
return !predicate(obj)
51+
return func(obj *T) (bool, []string) {
52+
predicateTrue, errs := predicate(obj)
53+
if predicateTrue {
54+
return false, errs
55+
}
56+
return true, nil
4657
}
4758
}

internal/controllers/clusterextension_controller.go

+12-11
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ func (r *ClusterExtensionReconciler) resolve(ctx context.Context, ext ocv1alpha1
402402
predicates = append(predicates, upgradePredicate)
403403
}
404404

405-
resultSet := catalogfilter.Filter(allBundles, catalogfilter.And(predicates...))
405+
resultSet, errs := catalogfilter.Filter(allBundles, catalogfilter.And(predicates...))
406406

407407
var upgradeErrorPrefix string
408408
if installedBundle != nil {
@@ -413,16 +413,17 @@ func (r *ClusterExtensionReconciler) resolve(ctx context.Context, ext ocv1alpha1
413413
upgradeErrorPrefix = fmt.Sprintf("error upgrading from currently installed version %q: ", installedBundleVersion.String())
414414
}
415415
if len(resultSet) == 0 {
416-
switch {
417-
case versionRange != "" && channelName != "":
418-
return nil, fmt.Errorf("%sno package %q matching version %q in channel %q found", upgradeErrorPrefix, packageName, versionRange, channelName)
419-
case versionRange != "":
420-
return nil, fmt.Errorf("%sno package %q matching version %q found", upgradeErrorPrefix, packageName, versionRange)
421-
case channelName != "":
422-
return nil, fmt.Errorf("%sno package %q in channel %q found", upgradeErrorPrefix, packageName, channelName)
423-
default:
424-
return nil, fmt.Errorf("%sno package %q found", upgradeErrorPrefix, packageName)
425-
}
416+
return nil, fmt.Errorf("%s %s", upgradeErrorPrefix, errs)
417+
// switch {
418+
// case versionRange != "" && channelName != "":
419+
// return nil, fmt.Errorf("%sno package %q matching version %q in channel %q found", upgradeErrorPrefix, packageName, versionRange, channelName)
420+
// case versionRange != "":
421+
// return nil, fmt.Errorf("%sno package %q matching version %q found", upgradeErrorPrefix, packageName, versionRange)
422+
// case channelName != "":
423+
// return nil, fmt.Errorf("%sno package %q in channel %q found", upgradeErrorPrefix, packageName, channelName)
424+
// default:
425+
// return nil, fmt.Errorf("%sno package %q found", upgradeErrorPrefix, packageName)
426+
// }
426427
}
427428

428429
sort.SliceStable(resultSet, func(i, j int) bool {

0 commit comments

Comments
 (0)