|
20 | 20 | - [Notimestamp](#notimestamp) - Prevents usage of 'TimeStamp' fields |
21 | 21 | - [OptionalFields](#optionalfields) - Validates optional field conventions |
22 | 22 | - [OptionalOrRequired](#optionalorrequired) - Ensures fields are explicitly marked as optional or required |
| 23 | +- [PreferredMarkers](#preferredmarkers) - Ensures preferred markers are used instead of equivalent markers |
23 | 24 | - [RequiredFields](#requiredfields) - Validates required field conventions |
24 | 25 | - [SSATags](#ssatags) - Ensures proper Server-Side Apply (SSA) tags on array fields |
25 | 26 | - [StatusOptional](#statusoptional) - Ensures status fields are marked as optional |
@@ -569,6 +570,105 @@ The `optionalorrequired` linter can automatically fix fields that are using the |
569 | 570 |
|
570 | 571 | It will also remove the secondary marker where both the preferred and secondary marker are present on a field. |
571 | 572 |
|
| 573 | +## PreferredMarkers |
| 574 | + |
| 575 | +The `preferredmarkers` linter ensures that types and fields use preferred markers instead of equivalent but different marker identifiers. |
| 576 | + |
| 577 | +By default, `preferredmarkers` is not enabled. |
| 578 | + |
| 579 | +This linter is useful for projects that want to enforce consistent marker usage across their codebase, especially when multiple equivalent markers exist. For example, Kubernetes has multiple ways to mark fields as optional: |
| 580 | +- `+optional` |
| 581 | +- `+k8s:optional` |
| 582 | +- `+kubebuilder:validation:Optional` |
| 583 | + |
| 584 | +The linter can be configured to enforce using one preferred marker identifier and report any equivalent markers that should be replaced. |
| 585 | + |
| 586 | +### Configuration |
| 587 | + |
| 588 | +The linter requires a configuration that specifies preferred markers and their equivalent identifiers. |
| 589 | + |
| 590 | +**Scenario:** Enforce using `+k8s:optional` instead of `+kubebuilder:validation:Optional` |
| 591 | + |
| 592 | +```yaml |
| 593 | +linterConfig: |
| 594 | + preferredmarkers: |
| 595 | + markers: |
| 596 | + - preferredIdentifier: "k8s:optional" |
| 597 | + equivalentIdentifiers: |
| 598 | + - identifier: "kubebuilder:validation:Optional" |
| 599 | +``` |
| 600 | + |
| 601 | +**Scenario:** Enforce using a custom marker instead of multiple equivalent markers |
| 602 | + |
| 603 | +```yaml |
| 604 | +linterConfig: |
| 605 | + preferredmarkers: |
| 606 | + markers: |
| 607 | + - preferredIdentifier: "custom:preferred" |
| 608 | + equivalentIdentifiers: |
| 609 | + - identifier: "custom:old:marker" |
| 610 | + - identifier: "custom:deprecated:marker" |
| 611 | + - identifier: "custom:legacy:marker" |
| 612 | +``` |
| 613 | + |
| 614 | +**Scenario:** Multiple preferred markers with different equivalents |
| 615 | + |
| 616 | +```yaml |
| 617 | +linterConfig: |
| 618 | + preferredmarkers: |
| 619 | + markers: |
| 620 | + - preferredIdentifier: "k8s:optional" |
| 621 | + equivalentIdentifiers: |
| 622 | + - identifier: "kubebuilder:validation:Optional" |
| 623 | + - preferredIdentifier: "k8s:required" |
| 624 | + equivalentIdentifiers: |
| 625 | + - identifier: "kubebuilder:validation:Required" |
| 626 | +``` |
| 627 | + |
| 628 | +The linter checks both type-level and field-level markers, including markers inherited from type aliases. |
| 629 | + |
| 630 | +### Fixes |
| 631 | + |
| 632 | +When one or more equivalent markers are found, the linter will: |
| 633 | + |
| 634 | +1. Report a diagnostic message indicating which marker(s) should be preferred |
| 635 | +2. Suggest a fix that: |
| 636 | + - If the preferred marker does not already exist: replaces the first equivalent marker with the preferred identifier and preserves any marker expressions (e.g., `=value` or `:key=value`) |
| 637 | + - If the preferred marker already exists: removes all equivalent markers to avoid duplicates |
| 638 | + - Removes any additional equivalent markers |
| 639 | + |
| 640 | +**Example 1:** If both `+kubebuilder:validation:Optional` and `+custom:optional` are configured as equivalents to `+k8s:optional`, the following code: |
| 641 | + |
| 642 | +```go |
| 643 | +// +kubebuilder:validation:Optional |
| 644 | +// +custom:optional |
| 645 | +type MyType string |
| 646 | +``` |
| 647 | + |
| 648 | +will be automatically fixed to: |
| 649 | + |
| 650 | +```go |
| 651 | +// +k8s:optional |
| 652 | +type MyType string |
| 653 | +``` |
| 654 | + |
| 655 | +**Example 2:** If the preferred marker already exists alongside equivalent markers: |
| 656 | + |
| 657 | +```go |
| 658 | +// +k8s:optional |
| 659 | +// +kubebuilder:validation:Optional |
| 660 | +type MyType string |
| 661 | +``` |
| 662 | + |
| 663 | +will be automatically fixed to: |
| 664 | + |
| 665 | +```go |
| 666 | +// +k8s:optional |
| 667 | +type MyType string |
| 668 | +``` |
| 669 | + |
| 670 | +Marker expressions are preserved during replacement. For example, `+kubebuilder:validation:Optional:=someValue` becomes `+k8s:optional=someValue`. Note that unnamed expressions (`:=value`) are normalized to use `=value` syntax for universal compatibility across different marker systems. |
| 671 | + |
572 | 672 | ## RequiredFields |
573 | 673 |
|
574 | 674 | The `requiredfields` linter checks that all fields marked as required adhere to having `omitempty` or `omitzero` values in their `json` tags. |
|
0 commit comments