Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
93 changes: 93 additions & 0 deletions api/v1/clusterextensionrevision_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ type ClusterExtensionRevisionSpec struct {
// <opcon:experimental>
ProgressDeadlineMinutes int32 `json:"progressDeadlineMinutes,omitempty"`

// +optional
// +kubebuilder:validation:MaxItems=20
ProgressionProbes []ProgressionProbe `json:"progressionProbes,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

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

Hi @dtfranz

See that the kube-lint-api is telling us about new issues introduced with the changes in the API.
Could we try to address those?


=== NEW ISSUES ===
api/v1/clusterextensionrevision_types.go:109:2:kubeapilinter:commentstart: godoc for field ClusterExtensionRevisionSpec.ProgressionProbes should start with 'progressionProbes ...'
api/v1/clusterextensionrevision_types.go:111:2:kubeapilinter:ssatags: ClusterExtensionRevisionSpec.ProgressionProbes should have a listType marker for proper Server-Side Apply behavior (atomic, set, or map)
api/v1/clusterextensionrevision_types.go:128:2:kubeapilinter:commentstart: godoc for field ProgressionProbe.Selector should start with 'selector ...'
api/v1/clusterextensionrevision_types.go:129:2:kubeapilinter:requiredfields: field ProgressionProbe.Selector does not allow the zero value. It must have the omitzero tag.
api/v1/clusterextensionrevision_types.go:131:2:kubeapilinter:commentstart: godoc for field ProgressionProbe.Assertions should start with 'assertions ...'
api/v1/clusterextensionrevision_types.go:133:2:kubeapilinter:ssatags: ProgressionProbe.Assertions should have a listType marker for proper Server-Side Apply behavior (atomic, set, or map)
api/v1/clusterextensionrevision_types.go:140:2:kubeapilinter:commentstart: godoc for field ProbeSelector.SelectorType should start with 'type ...'
api/v1/clusterextensionrevision_types.go:145:2:kubeapilinter:commentstart: godoc for field ProbeSelector.GroupKind should start with 'groupKind ...'
api/v1/clusterextensionrevision_types.go:149:2:kubeapilinter:commentstart: godoc for field ProbeSelector.Label should start with 'label ...'
api/v1/clusterextensionrevision_types.go:174:2:kubeapilinter:commentstart: godoc for field ProbeAssertion.ProbeType should start with 'type ...'
api/v1/clusterextensionrevision_types.go:179:2:kubeapilinter:commentstart: godoc for field ProbeAssertion.Condition should start with 'condition ...'
api/v1/clusterextensionrevision_types.go:181:2:kubeapilinter:nonpointerstructs: field ProbeAssertion.Condition is a non-pointer struct with required fields. It must be marked as required.
api/v1/clusterextensionrevision_types.go:183:2:kubeapilinter:commentstart: godoc for field ProbeAssertion.FieldsEqual should start with 'fieldsEqual ...'
api/v1/clusterextensionrevision_types.go:185:2:kubeapilinter:nonpointerstructs: field ProbeAssertion.FieldsEqual is a non-pointer struct with required fields. It must be marked as required.
api/v1/clusterextensionrevision_types.go:187:2:kubeapilinter:commentstart: godoc for field ProbeAssertion.FieldValue should start with 'fieldValue ...'
api/v1/clusterextensionrevision_types.go:189:2:kubeapilinter:nonpointerstructs: field ProbeAssertion.FieldValue is a non-pointer struct with required fields. It must be marked as required.
api/v1/clusterextensionrevision_types.go:193:2:kubeapilinter:commentstart: godoc for field ConditionProbe.Type should start with 'type ...'
api/v1/clusterextensionrevision_types.go:194:2:kubeapilinter:requiredfields: field ConditionProbe.Type has a valid zero value (""), but the validation is not complete (e.g. minimum length). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.
api/v1/clusterextensionrevision_types.go:196:2:kubeapilinter:commentstart: godoc for field ConditionProbe.Status should start with 'status ...'
api/v1/clusterextensionrevision_types.go:197:2:kubeapilinter:requiredfields: field ConditionProbe.Status has a valid zero value (""), but the validation is not complete (e.g. minimum length). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.
api/v1/clusterextensionrevision_types.go:201:2:kubeapilinter:commentstart: godoc for field FieldsEqualProbe.FieldA should start with 'fieldA ...'
api/v1/clusterextensionrevision_types.go:202:2:kubeapilinter:requiredfields: field FieldsEqualProbe.FieldA has a valid zero value (""), but the validation is not complete (e.g. minimum length). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.
api/v1/clusterextensionrevision_types.go:204:2:kubeapilinter:commentstart: godoc for field FieldsEqualProbe.FieldB should start with 'fieldB ...'
api/v1/clusterextensionrevision_types.go:205:2:kubeapilinter:requiredfields: field FieldsEqualProbe.FieldB has a valid zero value (""), but the validation is not complete (e.g. minimum length). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.
api/v1/clusterextensionrevision_types.go:209:2:kubeapilinter:commentstart: godoc for field FieldValueProbe.FieldPath should start with 'fieldPath ...'
api/v1/clusterextensionrevision_types.go:210:2:kubeapilinter:requiredfields: field FieldValueProbe.FieldPath has a valid zero value (""), but the validation is not complete (e.g. minimum length). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.
api/v1/clusterextensionrevision_types.go:212:2:kubeapilinter:commentstart: godoc for field FieldValueProbe.Value should start with 'value ...'
api/v1/clusterextensionrevision_types.go:213:2:kubeapilinter:requiredfields: field FieldValueProbe.Value has a valid zero value (""), but the validation is not complete (e.g. minimum length). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.

=== PRE-EXISTING ISSUES ===
api/v1/clustercatalog_types.go:63:2:kubeapilinter:optionalorrequired: embedded field ClusterCatalog.metav1.ObjectMeta must be marked as optional or required
api/v1/clustercatalog_types.go:68:2:kubeapilinter:requiredfields: field ClusterCatalog.Spec does not allow the zero value. It must have the omitzero tag.
api/v1/clustercatalog_types.go:75:2:kubeapilinter:optionalfields: field ClusterCatalog.Status has a valid zero value ({}), but the validation is not complete (e.g. min properties/adding required fields). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.
api/v1/clustercatalog_types.go:111:2:kubeapilinter:requiredfields: field ClusterCatalogSpec.Source does not allow the zero value. It must have the omitzero tag.
api/v1/clustercatalog_types.go:133:2:kubeapilinter:optionalfields: field ClusterCatalogSpec.Priority has a valid zero value (0) and should be a pointer.
api/v1/clustercatalog_types.go:177:2:kubeapilinter:conditions: Conditions field in ClusterCatalogStatus is missing the following markers: patchStrategy=merge, patchMergeKey=type
api/v1/clustercatalog_types.go:180:2:kubeapilinter:optionalfields: field ClusterCatalogStatus.ResolvedSource does not allow the zero value. It must have the omitzero tag.
api/v1/clustercatalog_types.go:208:2:kubeapilinter:requiredfields: field ClusterCatalogURLs.Base has a valid zero value (""), but the validation is not complete (e.g. minimum length). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.
api/v1/clustercatalog_types.go:226:2:kubeapilinter:requiredfields: field CatalogSource.Type should have the omitempty tag.
api/v1/clustercatalog_types.go:247:2:kubeapilinter:requiredfields: field ResolvedCatalogSource.Type should have the omitempty tag.
api/v1/clustercatalog_types.go:250:2:kubeapilinter:optionalorrequired: field ResolvedCatalogSource.Image must be marked as optional or required
api/v1/clustercatalog_types.go:266:2:kubeapilinter:requiredfields: field ResolvedImageSource.Ref has a valid zero value (""), but the validation is not complete (e.g. minimum length). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.
api/v1/clustercatalog_types.go:322:2:kubeapilinter:requiredfields: field ImageSource.Ref has a valid zero value (""), but the validation is not complete (e.g. minimum length). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.
api/v1/clustercatalog_types.go:330:2:kubeapilinter:integers: field ImageSource.PollIntervalMinutes pointer should not use an int, int8 or int16. Use int32 or int64 depending on bounding requirements
api/v1/clusterextension_types.go:67:2:kubeapilinter:requiredfields: field ClusterExtensionSpec.Namespace has a valid zero value (""), but the validation is not complete (e.g. minimum length). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.
api/v1/clusterextension_types.go:76:2:kubeapilinter:requiredfields: field ClusterExtensionSpec.ServiceAccount has a valid zero value ({"name": ""}) and should be a pointer.
api/v1/clusterextension_types.go:92:2:kubeapilinter:requiredfields: field ClusterExtensionSpec.Source does not allow the zero value. It must have the omitzero tag.
api/v1/clusterextension_types.go:109:2:kubeapilinter:optionalfields: field ClusterExtensionSpec.Config does not allow the zero value. It must have the omitzero tag.
api/v1/clusterextension_types.go:141:2:kubeapilinter:requiredfields: field SourceConfig.SourceType should have the omitempty tag.
api/v1/clusterextension_types.go:181:2:kubeapilinter:requiredfields: field ClusterExtensionConfig.ConfigType should have the omitempty tag.
api/v1/clusterextension_types.go:224:2:kubeapilinter:requiredfields: field CatalogFilter.PackageName has a valid zero value (""), but the validation is not complete (e.g. minimum length). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.
api/v1/clusterextension_types.go:304:2:kubeapilinter:optionalfields: field CatalogFilter.Version has a valid zero value (""), but the validation is not complete (e.g. minimum length). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.
api/v1/clusterextension_types.go:348:2:kubeapilinter:ssatags: CatalogFilter.Channels should have a listType marker for proper Server-Side Apply behavior (atomic, set, or map)
api/v1/clusterextension_types.go:407:2:kubeapilinter:requiredfields: field ServiceAccountReference.Name has a valid zero value (""), but the validation is not complete (e.g. minimum length). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.
api/v1/clusterextension_types.go:419:2:kubeapilinter:optionalorrequired: field PreflightConfig.CRDUpgradeSafety must be marked as optional or required
api/v1/clusterextension_types.go:435:2:kubeapilinter:requiredfields: field CRDUpgradeSafetyPreflightConfig.Enforcement should have the omitempty tag.
api/v1/clusterextension_types.go:460:2:kubeapilinter:requiredfields: field BundleMetadata.Name has a valid zero value (""), but the validation is not complete (e.g. minimum length). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.
api/v1/clusterextension_types.go:467:2:kubeapilinter:requiredfields: field BundleMetadata.Version has a valid zero value (""), but the validation is not complete (e.g. minimum length). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.
api/v1/clusterextension_types.go:473:2:kubeapilinter:optionalorrequired: field RevisionStatus.Name must be marked as optional or required
api/v1/clusterextension_types.go:482:2:kubeapilinter:conditions: Conditions field in RevisionStatus is missing the following markers: patchStrategy=merge, patchMergeKey=type
api/v1/clusterextension_types.go:513:2:kubeapilinter:conditions: Conditions field in ClusterExtensionStatus is missing the following markers: patchStrategy=merge, patchMergeKey=type
api/v1/clusterextension_types.go:526:2:kubeapilinter:arrayofstruct: ClusterExtensionStatus.ActiveRevisions is an array of structs, but the struct has no required fields. At least one field should be marked as required to prevent ambiguous YAML configurations
api/v1/clusterextension_types.go:537:2:kubeapilinter:requiredfields: field ClusterExtensionInstallStatus.Bundle has a valid zero value ({"name": "", "version": ""}) and should be a pointer.
api/v1/clusterextension_types.go:562:2:kubeapilinter:nonpointerstructs: field ClusterExtension.Spec is a non-pointer struct with required fields. It must be marked as required.
api/v1/clusterextension_types.go:566:2:kubeapilinter:optionalfields: field ClusterExtension.Status has a valid zero value ({}), but the validation is not complete (e.g. min properties/adding required fields). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.
api/v1/clusterextensionrevision_types.go:71:2:kubeapilinter:requiredfields: field ClusterExtensionRevisionSpec.Revision should have the omitempty tag.
api/v1/clusterextensionrevision_types.go:96:2:kubeapilinter:nophase: naming convention "nophase": field ClusterExtensionRevisionSpec.Phases: phase fields are deprecated and conditions should be preferred, avoid phase like enum fields
api/v1/clusterextensionrevision_types.go:245:2:kubeapilinter:requiredfields: field ClusterExtensionRevisionPhase.Name should have the omitempty tag.
api/v1/clusterextensionrevision_types.go:252:2:kubeapilinter:arrayofstruct: ClusterExtensionRevisionPhase.Objects is an array of structs, but the struct has no required fields. At least one field should be marked as required to prevent ambiguous YAML configurations
api/v1/clusterextensionrevision_types.go:277:2:kubeapilinter:optionalorrequired: field ClusterExtensionRevisionObject.Object must be marked as optional or required
api/v1/clusterextensionrevision_types.go:345:2:kubeapilinter:conditions: Conditions field in ClusterExtensionRevisionStatus is missing the following markers: patchStrategy=merge, patchMergeKey=type
api/v1/clusterextensionrevision_types.go:373:2:kubeapilinter:nonpointerstructs: field ClusterExtensionRevision.Spec is a non-pointer struct with required fields. It must be marked as required.
api/v1/clusterextensionrevision_types.go:377:2:kubeapilinter:optionalfields: field ClusterExtensionRevision.Status has a valid zero value ({}), but the validation is not complete (e.g. min properties/adding required fields). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer.

FAILED: 28 new issue(s) introduced


// collisionProtection specifies the default collision protection strategy for all objects
// in this revision. Individual phases or objects can override this value.
//
Expand All @@ -120,6 +124,95 @@ type ClusterExtensionRevisionSpec struct {
CollisionProtection CollisionProtection `json:"collisionProtection,omitempty"`
}

type ProgressionProbe struct {
// +required
Selector ProbeSelector `json:"selector,omitempty"`

// +required
// +kubebuilder:validation:MaxItems=20
Assertions []ProbeAssertion `json:"assertions,omitempty"`
}

// +union
// +kubebuilder:validation:XValidation:rule="self.type == 'GroupKind' ?has(self.groupKind) : !has(self.groupKind)",message="groupKind is required when type is GroupKind, and forbidden otherwise"
// +kubebuilder:validation:XValidation:rule="self.type == 'Label' ?has(self.label) : !has(self.label)",message="label is required when type is Label, and forbidden otherwise"
type ProbeSelector struct {
// +unionDiscriminator
// +kubebuilder:validation:Enum=GroupKind;Label
// +required
SelectorType SelectorType `json:"type,omitempty"`

// +optional
// +unionMember
GroupKind metav1.GroupKind `json:"groupKind,omitempty"`

// +optional
// +unionMember
Label metav1.LabelSelector `json:"label,omitempty"`
Comment on lines +147 to +151
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

ProbeSelector uses non-pointer struct fields (GroupKind metav1.GroupKind, Label metav1.LabelSelector) with omitempty. In Go JSON/YAML marshaling, omitempty does not omit zero-value structs, so Go clients will always send groupKind: {} and label: {} even when not intended. That will violate the CRD XValidation rules that forbid the non-selected union member, making it impossible to create/update progressionProbes programmatically. Consider switching these union members to pointers (e.g., *metav1.GroupKind, *metav1.LabelSelector) so they can truly be omitted, and update deepcopy generation accordingly.

Suggested change
GroupKind metav1.GroupKind `json:"groupKind,omitempty"`
// +optional
// +unionMember
Label metav1.LabelSelector `json:"label,omitempty"`
GroupKind *metav1.GroupKind `json:"groupKind,omitempty"`
// +optional
// +unionMember
Label *metav1.LabelSelector `json:"label,omitempty"`

Copilot uses AI. Check for mistakes.
}

type SelectorType string

const (
SelectorTypeGroupKind SelectorType = "GroupKind"
SelectorTypeLabel SelectorType = "Label"
)

type ProbeType string

const (
ProbeTypeFieldCondition ProbeType = "Condition"
ProbeTypeFieldEqual ProbeType = "FieldsEqual"
ProbeTypeFieldValue ProbeType = "FieldValue"
)

// +union
// +kubebuilder:validation:XValidation:rule="self.type == 'Condition' ?has(self.condition) : !has(self.condition)",message="condition is required when type is Condition, and forbidden otherwise"
// +kubebuilder:validation:XValidation:rule="self.type == 'FieldsEqual' ?has(self.fieldsEqual) : !has(self.fieldsEqual)",message="fieldsEqual is required when type is FieldsEqual, and forbidden otherwise"
// +kubebuilder:validation:XValidation:rule="self.type == 'FieldValue' ?has(self.fieldValue) : !has(self.fieldValue)",message="fieldValue is required when type is FieldValue, and forbidden otherwise"
type ProbeAssertion struct {
// +unionDiscriminator
// +kubebuilder:validation:Enum=Condition;FieldsEqual;FieldValue
// +required
ProbeType ProbeType `json:"type,omitempty"`

// +unionMember
// +optional
Condition ConditionProbe `json:"condition,omitempty"`

// +unionMember
// +optional
FieldsEqual FieldsEqualProbe `json:"fieldsEqual,omitempty"`

// +unionMember
// +optional
FieldValue FieldValueProbe `json:"fieldValue,omitempty"`
Comment on lines +181 to +189
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

ProbeAssertion has the same union/omitempty issue as ProbeSelector: Condition, FieldsEqual, and FieldValue are non-pointer structs, so they will serialize as {} even when not set, which can break the CRD XValidation rules that require exactly one union member. Consider making these union members pointers (e.g., *ConditionProbe, *FieldsEqualProbe, *FieldValueProbe) so they can be omitted cleanly by Go clients / server-side apply.

Suggested change
Condition ConditionProbe `json:"condition,omitempty"`
// +unionMember
// +optional
FieldsEqual FieldsEqualProbe `json:"fieldsEqual,omitempty"`
// +unionMember
// +optional
FieldValue FieldValueProbe `json:"fieldValue,omitempty"`
Condition *ConditionProbe `json:"condition,omitempty"`
// +unionMember
// +optional
FieldsEqual *FieldsEqualProbe `json:"fieldsEqual,omitempty"`
// +unionMember
// +optional
FieldValue *FieldValueProbe `json:"fieldValue,omitempty"`

Copilot uses AI. Check for mistakes.
}

type ConditionProbe struct {
// +required
Type string `json:"type,omitempty"`

// +required
Status string `json:"status,omitempty"`
}

type FieldsEqualProbe struct {
// +required
FieldA string `json:"fieldA,omitempty"`

// +required
FieldB string `json:"fieldB,omitempty"`
}

type FieldValueProbe struct {
// +required
FieldPath string `json:"fieldPath,omitempty"`

// +required
Value string `json:"value,omitempty"`
}

// ClusterExtensionRevisionLifecycleState specifies the lifecycle state of the ClusterExtensionRevision.
type ClusterExtensionRevisionLifecycleState string

Expand Down
108 changes: 108 additions & 0 deletions api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 15 additions & 1 deletion applyconfigurations/api/v1/clusterextensionrevisionspec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 47 additions & 0 deletions applyconfigurations/api/v1/conditionprobe.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 47 additions & 0 deletions applyconfigurations/api/v1/fieldsequalprobe.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading