You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
You will need to create a `.custom-gcl.yml` file to describe the custom linters you want to run. The following is an example of a `.custom-gcl.yml` file:
34
34
35
35
```yaml
36
-
version: v1.64.8
37
-
name: golangci-kube-api-linter
36
+
version: v2.5.0
37
+
name: golangci-lint-kube-api-linter
38
38
destination: ./bin
39
39
plugins:
40
40
- module: 'sigs.k8s.io/kube-api-linter'
41
-
version: 'v0.0.0'# Replace with the latest version
41
+
version: 'v0.0.0-20251029102002-9992248f8813'
42
42
```
43
43
44
-
Once you have created the custom configuration file, you can run the following command to build the custom `golangci-kal` binary:
44
+
**Important - Version Format**: Since this repository does not have releases yet, you must use a [pseudo-version](https://go.dev/ref/mod#pseudo-versions) in the format `v0.0.0-YYYYMMDDHHMMSS-commithash`.
45
+
46
+
To find the latest version listed, check [pkg.go.dev/sigs.k8s.io/kube-api-linter?tab=versions](https://pkg.go.dev/sigs.k8s.io/kube-api-linter?tab=versions)
47
+
48
+
Once you have created the custom configuration file, you can run the following command to build the custom binary:
45
49
46
50
```shell
47
51
golangci-lint custom
48
52
```
49
53
50
-
The output binary will be a combination of the initial `golangci-lint` binary and the Kube API linter plugin.
51
-
This means that you can use any of the standard `golangci-lint` configuration or flags to run the binary, but may also include the Kube API Linter rules.
54
+
The output binary will be created at the location specified by the `destination` field in `.custom-gcl.yml` and will be a combination of the `golangci-lint` binary with the Kube API Linter included as a module.
55
+
56
+
This means you can use any of the standard `golangci-lint` configuration or flags to run the binary, with the addition of the Kube API Linter rules.
52
57
53
58
If you wish to only use the Kube API Linter rules, you can configure your `.golangci.yml` file to only run the Kube API Linter:
54
59
55
60
```yaml
61
+
version: "2"
56
62
linters-settings:
57
63
custom:
58
64
kubeapilinter:
59
65
type: "module"
60
-
description: Kube API LInter lints Kube like APIs based on API conventions and best practices.
66
+
description: Kube API Linter lints Kube like APIs based on API conventions and best practices.
61
67
settings:
62
68
linters: {}
63
69
lintersConfig: {}
70
+
64
71
linters:
65
72
disable-all: true
66
73
enable:
@@ -77,6 +84,7 @@ issues:
77
84
If you wish to only run selected linters you can do so by specifying the linters you want to enable in the `linters` section:
78
85
79
86
```yaml
87
+
version: "2"
80
88
linters-settings:
81
89
custom:
82
90
kubeapilinter:
@@ -89,6 +97,9 @@ linters-settings:
89
97
- requiredfields
90
98
- statusoptional
91
99
- statussubresource
100
+
linters:
101
+
enable:
102
+
- kubeapilinter
92
103
```
93
104
94
105
The settings for Kube API Linter are based on the [GolangCIConfig][golangci-config-struct] struct and allow for finer control over the linter rules.
@@ -98,10 +109,10 @@ To provide further configuration, add the `custom.kubeapilinter` section to your
To build the plugin, use the `-buildmode=plugin` flag:
128
+
116
129
```shell
117
130
go build -buildmode=plugin -o bin/kube-api-linter.so sigs.k8s.io/kube-api-linter/pkg/plugin
118
131
```
119
132
120
-
This will create a `kube-api-linter.so` file in the `bin` directory.
133
+
**Note**: If you're building the plugin from within another project that vendors kube-api-linter, use the vendor path:
121
134
122
-
The `golangci-lint` configuration is similar to the module configuration, however, you will need to specify the plugin path instead.
135
+
```shell
136
+
go build -mod=vendor -buildmode=plugin -o bin/kube-api-linter.so ./vendor/sigs.k8s.io/kube-api-linter/pkg/plugin
137
+
```
138
+
139
+
This will create a `kube-api-linter.so` plugin file in the specified directory.
140
+
141
+
The `golangci-lint` configuration is similar to the module configuration, however, you will need to specify the plugin path instead in your `.golangci.yml`:
123
142
124
143
```yaml
144
+
version: "2"
125
145
linters-settings:
126
146
custom:
127
147
kubeapilinter:
128
148
path: "bin/kube-api-linter.so"
129
-
description: Kube API LInter lints Kube like APIs based on API conventions and best practices.
149
+
description: Kube API Linter lints Kube like APIs based on API conventions and best practices.
130
150
original-url: sigs.k8s.io/kube-api-linter
131
151
settings:
132
152
linters: {}
133
153
lintersConfig: {}
154
+
linters:
155
+
enable:
156
+
- kubeapilinter
134
157
```
135
158
136
159
The rest of the configuration is the same as the module configuration, except the standard `golangci-lint` binary is invoked, rather than a custom binary.
137
160
138
161
#### VSCode integration
139
162
140
-
Since VSCode already integrates with `golangci-lint` via the [Go][vscode-go] extension, you can use the `golangci-kal` binary as a linter in VSCode.
163
+
Since VSCode already integrates with `golangci-lint` via the [Go][vscode-go] extension, you can use the custom `golangci-lint-kube-api-linter` binary as a linter in VSCode.
164
+
141
165
If your project authors are already using VSCode and have the configuration to lint their code when saving, this can be a seamless integration.
142
166
143
-
Ensure that your project setup includes building the `golangci-kube-api-linter` binary, and then configure the `go.lintTool` and `go.alternateTools` settings in your project `.vscode/settings.json` file.
167
+
Ensure that your project setup includes building the `golangci-lint-kube-api-linter` binary, then configure the `go.lintTool` and `go.alternateTools` settings in your project `.vscode/settings.json` file:
Alternatively, you can also replace the binary with a script that runs the `golangci-kube-api-linter` binary,
157
-
allowing for customisation or automatic copmilation of the project should it not already exist.
180
+
Alternatively, you can also replace the binary with a script that runs the `golangci-lint-kube-api-linter` binary, allowing for customization or automatic compilation of the project should it not already exist:
-[StatusOptional](#statusoptional) - Ensures status fields are marked as optional
@@ -570,6 +571,105 @@ The `optionalorrequired` linter can automatically fix fields that are using the
570
571
571
572
It will also remove the secondary marker where both the preferred and secondary marker are present on a field.
572
573
574
+
## PreferredMarkers
575
+
576
+
The `preferredmarkers` linter ensures that types and fields use preferred markers instead of equivalent but different marker identifiers.
577
+
578
+
By default, `preferredmarkers` is not enabled.
579
+
580
+
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:
581
+
- `+optional`
582
+
- `+k8s:optional`
583
+
- `+kubebuilder:validation:Optional`
584
+
585
+
The linter can be configured to enforce using one preferred marker identifier and report any equivalent markers that should be replaced.
586
+
587
+
### Configuration
588
+
589
+
The linter requires a configuration that specifies preferred markers and their equivalent identifiers.
590
+
591
+
**Scenario:** Enforce using `+k8s:optional` instead of `+kubebuilder:validation:Optional`
592
+
593
+
```yaml
594
+
linterConfig:
595
+
preferredmarkers:
596
+
markers:
597
+
- preferredIdentifier: "k8s:optional"
598
+
equivalentIdentifiers:
599
+
- identifier: "kubebuilder:validation:Optional"
600
+
```
601
+
602
+
**Scenario:** Enforce using a custom marker instead of multiple equivalent markers
603
+
604
+
```yaml
605
+
linterConfig:
606
+
preferredmarkers:
607
+
markers:
608
+
- preferredIdentifier: "custom:preferred"
609
+
equivalentIdentifiers:
610
+
- identifier: "custom:old:marker"
611
+
- identifier: "custom:deprecated:marker"
612
+
- identifier: "custom:legacy:marker"
613
+
```
614
+
615
+
**Scenario:** Multiple preferred markers with different equivalents
616
+
617
+
```yaml
618
+
linterConfig:
619
+
preferredmarkers:
620
+
markers:
621
+
- preferredIdentifier: "k8s:optional"
622
+
equivalentIdentifiers:
623
+
- identifier: "kubebuilder:validation:Optional"
624
+
- preferredIdentifier: "k8s:required"
625
+
equivalentIdentifiers:
626
+
- identifier: "kubebuilder:validation:Required"
627
+
```
628
+
629
+
The linter checks both type-level and field-level markers, including markers inherited from type aliases.
630
+
631
+
### Fixes
632
+
633
+
When one or more equivalent markers are found, the linter will:
634
+
635
+
1. Report a diagnostic message indicating which marker(s) should be preferred
636
+
2. Suggest a fix that:
637
+
- 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`)
638
+
- If the preferred marker already exists: removes all equivalent markers to avoid duplicates
639
+
- Removes any additional equivalent markers
640
+
641
+
**Example 1:** If both `+kubebuilder:validation:Optional` and `+custom:optional` are configured as equivalents to `+k8s:optional`, the following code:
642
+
643
+
```go
644
+
// +kubebuilder:validation:Optional
645
+
// +custom:optional
646
+
type MyType string
647
+
```
648
+
649
+
will be automatically fixed to:
650
+
651
+
```go
652
+
// +k8s:optional
653
+
type MyType string
654
+
```
655
+
656
+
**Example 2:** If the preferred marker already exists alongside equivalent markers:
657
+
658
+
```go
659
+
// +k8s:optional
660
+
// +kubebuilder:validation:Optional
661
+
type MyType string
662
+
```
663
+
664
+
will be automatically fixed to:
665
+
666
+
```go
667
+
// +k8s:optional
668
+
type MyType string
669
+
```
670
+
671
+
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.
672
+
573
673
## RequiredFields
574
674
575
675
The `requiredfields` linter checks that all fields marked as required adhere to having `omitempty` or `omitzero` values in their `json` tags.
message:=fmt.Sprintf("%s 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", prefix)
message:=fmt.Sprintf("%s 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", qualifiedFieldName)
0 commit comments