Skip to content

Commit e566a43

Browse files
feat: use dynamic target version in lint check messages
Replace hardcoded "RHOAI 3.x" in lint check condition messages with the actual target version (e.g. "RHOAI 3.0", "RHOAI 3.3") derived from the --target-version flag. - Add version.MajorMinorLabel() helper to format semver as "major.minor" - Embed full check.Target in ComponentRequest and WorkloadRequest so validation callbacks can access target version info - Update validate.Removal() to auto-inject target version label - Update all lint checks to use dynamic version in runtime messages - Static check names/descriptions kept as-is (set at construction time) Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 9ecce54 commit e566a43

File tree

29 files changed

+159
-84
lines changed

29 files changed

+159
-84
lines changed

pkg/lint/check/condition_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -437,14 +437,14 @@ func TestNewCondition_WithMultipleFormatArgs(t *testing.T) {
437437
check.ConditionTypeCompatible,
438438
metav1.ConditionFalse,
439439
check.WithReason(check.ReasonVersionIncompatible),
440-
check.WithMessage("Found %d %s - will be impacted in RHOAI %s", 3, "InferenceServices", "3.x"),
440+
check.WithMessage("Found %d %s - will be impacted in RHOAI %s", 3, "InferenceServices", "3.0"),
441441
)
442442

443443
g.Expect(condition.Condition).To(MatchFields(IgnoreExtras, Fields{
444444
"Type": Equal(check.ConditionTypeCompatible),
445445
"Status": Equal(metav1.ConditionFalse),
446446
"Reason": Equal(check.ReasonVersionIncompatible),
447-
"Message": Equal("Found 3 InferenceServices - will be impacted in RHOAI 3.x"),
447+
"Message": Equal("Found 3 InferenceServices - will be impacted in RHOAI 3.0"),
448448
}))
449449
}
450450

pkg/lint/check/validate/component.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/opendatahub-io/odh-cli/pkg/lint/check/result"
1616
"github.com/opendatahub-io/odh-cli/pkg/util/client"
1717
"github.com/opendatahub-io/odh-cli/pkg/util/components"
18+
"github.com/opendatahub-io/odh-cli/pkg/util/version"
1819
)
1920

2021
// ComponentBuilder provides a fluent API for component-based validation.
@@ -50,7 +51,12 @@ func Component(c check.Check, target check.Target) *ComponentBuilder {
5051
// ComponentRequest contains pre-fetched data for component validation.
5152
// It provides convenient access to commonly needed data without requiring
5253
// callbacks to parse annotations or fetch additional resources.
54+
//
55+
// check.Target is embedded, so fields like Client, TargetVersion, and CurrentVersion
56+
// are directly accessible (e.g. req.Client, req.TargetVersion).
5357
type ComponentRequest struct {
58+
check.Target
59+
5460
// Result is the pre-created DiagnosticResult with auto-populated annotations.
5561
Result *result.DiagnosticResult
5662

@@ -60,9 +66,6 @@ type ComponentRequest struct {
6066
// ManagementState is the component's management state string.
6167
ManagementState string
6268

63-
// Client provides read-only access to the Kubernetes API.
64-
Client client.Reader
65-
6669
// ApplicationsNamespace is populated when WithApplicationsNamespace() is used.
6770
// Empty string if not requested. If DSCI is not found, Run() returns early
6871
// with a "not found" diagnostic result before calling the validation function.
@@ -101,18 +104,18 @@ func (b *ComponentBuilder) WithApplicationsNamespace() *ComponentBuilder {
101104
}
102105

103106
// Removal returns a ComponentValidateFn that sets a compatibility failure condition.
104-
// ManagementState is automatically prepended as the first format argument.
107+
// ManagementState and target version label are automatically supplied as the first two format arguments.
105108
//
106109
// Example:
107110
//
108111
// validate.Component(c, target).
109112
// InState(constants.ManagementStateManaged).
110-
// Run(ctx, validate.Removal("CodeFlare is enabled (state: %s) but will be removed in RHOAI 3.x"))
113+
// Run(ctx, validate.Removal("CodeFlare is enabled (state: %s) but will be removed in RHOAI %s"))
111114
func Removal(format string, opts ...check.ConditionOption) ComponentValidateFn {
112115
return func(_ context.Context, req *ComponentRequest) error {
113116
allOpts := append([]check.ConditionOption{
114117
check.WithReason(check.ReasonVersionIncompatible),
115-
check.WithMessage(format, req.ManagementState),
118+
check.WithMessage(format, req.ManagementState, version.MajorMinorLabel(req.TargetVersion)),
116119
}, opts...)
117120
req.Result.SetCondition(check.NewCondition(
118121
check.ConditionTypeCompatible,
@@ -195,10 +198,10 @@ func (b *ComponentBuilder) Run(
195198

196199
// Create the request with pre-populated data
197200
req := &ComponentRequest{
201+
Target: b.target,
198202
Result: dr,
199203
DSC: dsc,
200204
ManagementState: state,
201-
Client: b.target.Client,
202205
}
203206

204207
// Load applications namespace if requested

pkg/lint/check/validate/workload.go

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,21 @@ import (
1212
"github.com/opendatahub-io/odh-cli/pkg/lint/check/result"
1313
"github.com/opendatahub-io/odh-cli/pkg/resources"
1414
"github.com/opendatahub-io/odh-cli/pkg/util/client"
15-
"github.com/opendatahub-io/odh-cli/pkg/util/iostreams"
1615
"github.com/opendatahub-io/odh-cli/pkg/util/kube"
1716
)
1817

1918
// WorkloadRequest contains the pre-fetched data passed to the workload validation function.
19+
//
20+
// check.Target is embedded, so fields like Client, IO, Debug, TargetVersion, and CurrentVersion
21+
// are directly accessible (e.g. req.Client, req.IO, req.Debug, req.TargetVersion).
2022
type WorkloadRequest[T any] struct {
23+
check.Target
24+
2125
// Result is the pre-created DiagnosticResult with auto-populated annotations.
2226
Result *result.DiagnosticResult
2327

2428
// Items contains the (optionally filtered) workload items.
2529
Items []T
26-
27-
// Client provides read-only access to the Kubernetes API.
28-
Client client.Reader
29-
30-
// IO provides access to input/output streams for verbose logging.
31-
// Use IO.Errorf() for debug output that appears only when --verbose is set.
32-
// May be nil if no IO was provided to the check target.
33-
IO iostreams.Interface
34-
35-
// Debug indicates whether detailed diagnostic logging is enabled.
36-
// When true, checks should emit internal processing logs for troubleshooting.
37-
// When false, only user-facing summary information should be logged via IO.
38-
Debug bool
3930
}
4031

4132
// WorkloadValidateFn is the callback invoked by WorkloadBuilder.Run after listing and filtering.
@@ -144,11 +135,9 @@ func (b *WorkloadBuilder[T]) Run(
144135

145136
// Call the validation function.
146137
req := &WorkloadRequest[T]{
138+
Target: b.target,
147139
Result: dr,
148140
Items: items,
149-
Client: b.target.Client,
150-
IO: b.target.IO,
151-
Debug: b.target.Debug,
152141
}
153142

154143
if err := fn(ctx, req); err != nil {

pkg/lint/checks/components/codeflare/codeflare.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func (c *RemovalCheck) CanApply(ctx context.Context, target check.Target) (bool,
5252
// Validate executes the check against the provided target.
5353
func (c *RemovalCheck) Validate(ctx context.Context, target check.Target) (*result.DiagnosticResult, error) {
5454
return validate.Component(c, target).
55-
Run(ctx, validate.Removal("CodeFlare is enabled (state: %s) but will be removed in RHOAI 3.x",
55+
Run(ctx, validate.Removal("CodeFlare is enabled (state: %s) but will be removed in RHOAI %s",
5656
check.WithImpact(result.ImpactBlocking),
5757
check.WithRemediation(c.CheckRemediation)))
5858
}

pkg/lint/checks/components/codeflare/codeflare_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func TestCodeFlareRemovalCheck_ManagedBlocking(t *testing.T) {
7777
"Type": Equal(check.ConditionTypeCompatible),
7878
"Status": Equal(metav1.ConditionFalse),
7979
"Reason": Equal(check.ReasonVersionIncompatible),
80-
"Message": And(ContainSubstring("enabled"), ContainSubstring("removed in RHOAI 3.x")),
80+
"Message": And(ContainSubstring("enabled"), ContainSubstring("removed in RHOAI 3.0")),
8181
}))
8282
g.Expect(result.Status.Conditions[0].Impact).To(Equal(resultpkg.ImpactBlocking))
8383
g.Expect(result.Annotations).To(And(

pkg/lint/checks/components/datasciencepipelines/renaming.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,14 @@ func (c *RenamingCheck) Validate(ctx context.Context, target check.Target) (*res
5959
}
6060

6161
func newRenamingCondition(_ context.Context, req *validate.ComponentRequest) ([]result.Condition, error) {
62+
tv := version.MajorMinorLabel(req.TargetVersion)
63+
6264
return []result.Condition{
6365
check.NewCondition(
6466
check.ConditionTypeCompatible,
6567
metav1.ConditionFalse,
6668
check.WithReason(check.ReasonComponentRenamed),
67-
check.WithMessage("DataSciencePipelines component (state: %s) will be renamed to AIPipelines in DSC v2 (RHOAI 3.x). The field path changes from '.spec.components.datasciencepipelines' to '.spec.components.aipipelines'", req.ManagementState),
69+
check.WithMessage("DataSciencePipelines component (state: %s) will be renamed to AIPipelines in DSC v2 (RHOAI %s). The field path changes from '.spec.components.datasciencepipelines' to '.spec.components.aipipelines'", req.ManagementState, tv),
6870
check.WithImpact(result.ImpactAdvisory),
6971
check.WithRemediation("No action required - the component will be automatically renamed. Update any automation referencing '.spec.components.datasciencepipelines' to use '.spec.components.aipipelines' after upgrade"),
7072
),

pkg/lint/checks/components/kserve/serverless.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ func (c *ServerlessRemovalCheck) CanApply(ctx context.Context, target check.Targ
5656
func (c *ServerlessRemovalCheck) Validate(ctx context.Context, target check.Target) (*result.DiagnosticResult, error) {
5757
return validate.Component(c, target).
5858
Run(ctx, func(_ context.Context, req *validate.ComponentRequest) error {
59+
tv := version.MajorMinorLabel(req.TargetVersion)
5960
state, err := jq.Query[string](req.DSC, ".spec.components.kserve.serving.managementState")
6061

6162
switch {
@@ -64,7 +65,7 @@ func (c *ServerlessRemovalCheck) Validate(ctx context.Context, target check.Targ
6465
check.ConditionTypeCompatible,
6566
metav1.ConditionTrue,
6667
check.WithReason(check.ReasonVersionCompatible),
67-
check.WithMessage("KServe serverless mode is not configured - ready for RHOAI 3.x upgrade"),
68+
check.WithMessage("KServe serverless mode is not configured - ready for RHOAI %s upgrade", tv),
6869
))
6970
case err != nil:
7071
return fmt.Errorf("querying kserve serving managementState: %w", err)
@@ -73,7 +74,7 @@ func (c *ServerlessRemovalCheck) Validate(ctx context.Context, target check.Targ
7374
check.ConditionTypeCompatible,
7475
metav1.ConditionFalse,
7576
check.WithReason(check.ReasonVersionIncompatible),
76-
check.WithMessage("KServe serverless mode is enabled (state: %s) but will be removed in RHOAI 3.x", state),
77+
check.WithMessage("KServe serverless mode is enabled (state: %s) but will be removed in RHOAI %s", state, tv),
7778
check.WithImpact(result.ImpactBlocking),
7879
check.WithRemediation(c.CheckRemediation),
7980
))
@@ -82,7 +83,7 @@ func (c *ServerlessRemovalCheck) Validate(ctx context.Context, target check.Targ
8283
check.ConditionTypeCompatible,
8384
metav1.ConditionTrue,
8485
check.WithReason(check.ReasonVersionCompatible),
85-
check.WithMessage("KServe serverless mode is disabled (state: %s) - ready for RHOAI 3.x upgrade", state),
86+
check.WithMessage("KServe serverless mode is disabled (state: %s) - ready for RHOAI %s upgrade", state, tv),
8687
))
8788
}
8889

pkg/lint/checks/components/kserve/serverless_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ func TestKServeServerlessRemovalCheck_ServerlessManagedBlocking(t *testing.T) {
156156
"Type": Equal(check.ConditionTypeCompatible),
157157
"Status": Equal(metav1.ConditionFalse),
158158
"Reason": Equal(check.ReasonVersionIncompatible),
159-
"Message": And(ContainSubstring("serverless mode is enabled"), ContainSubstring("removed in RHOAI 3.x")),
159+
"Message": And(ContainSubstring("serverless mode is enabled"), ContainSubstring("removed in RHOAI 3.0")),
160160
}))
161161
g.Expect(result.Status.Conditions[0].Impact).To(Equal(resultpkg.ImpactBlocking))
162162
g.Expect(result.Annotations).To(And(
@@ -253,7 +253,7 @@ func TestKServeServerlessRemovalCheck_ServerlessRemovedReady(t *testing.T) {
253253
"Type": Equal(check.ConditionTypeCompatible),
254254
"Status": Equal(metav1.ConditionTrue),
255255
"Reason": Equal(check.ReasonVersionCompatible),
256-
"Message": And(ContainSubstring("serverless mode is disabled"), ContainSubstring("ready for RHOAI 3.x upgrade")),
256+
"Message": And(ContainSubstring("serverless mode is disabled"), ContainSubstring("ready for RHOAI 3.0 upgrade")),
257257
}))
258258
g.Expect(result.Annotations).To(HaveKeyWithValue(check.AnnotationComponentManagementState, constants.ManagementStateManaged))
259259
}

pkg/lint/checks/components/kueue/kueue.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,15 @@ func (c *ManagementStateCheck) CanApply(ctx context.Context, target check.Target
6363
func (c *ManagementStateCheck) Validate(ctx context.Context, target check.Target) (*result.DiagnosticResult, error) {
6464
return validate.Component(c, target).
6565
Run(ctx, func(_ context.Context, req *validate.ComponentRequest) error {
66+
tv := version.MajorMinorLabel(req.TargetVersion)
67+
6668
switch req.ManagementState {
6769
case constants.ManagementStateManaged:
6870
req.Result.SetCondition(check.NewCondition(
6971
check.ConditionTypeCompatible,
7072
metav1.ConditionFalse,
7173
check.WithReason(check.ReasonVersionIncompatible),
72-
check.WithMessage("Kueue is managed by OpenShift AI (state: %s) but Managed option will be removed in RHOAI 3.x", req.ManagementState),
74+
check.WithMessage("Kueue is managed by OpenShift AI (state: %s) but Managed option will be removed in RHOAI %s", req.ManagementState, tv),
7375
check.WithImpact(result.ImpactBlocking),
7476
check.WithRemediation(c.CheckRemediation),
7577
))
@@ -78,7 +80,7 @@ func (c *ManagementStateCheck) Validate(ctx context.Context, target check.Target
7880
check.ConditionTypeCompatible,
7981
metav1.ConditionTrue,
8082
check.WithReason(check.ReasonVersionCompatible),
81-
check.WithMessage("Kueue managementState is %s — compatible with RHOAI 3.x", req.ManagementState),
83+
check.WithMessage("Kueue managementState is %s — compatible with RHOAI %s", req.ManagementState, tv),
8284
))
8385
}
8486

pkg/lint/checks/components/kueue/kueue_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ func TestManagementStateCheck_UnmanagedAllowed(t *testing.T) {
106106
"Type": Equal(check.ConditionTypeCompatible),
107107
"Status": Equal(metav1.ConditionTrue),
108108
"Reason": Equal(check.ReasonVersionCompatible),
109-
"Message": ContainSubstring("compatible with RHOAI 3.x"),
109+
"Message": ContainSubstring("compatible with RHOAI 3.1"),
110110
}))
111111
}
112112

0 commit comments

Comments
 (0)