Skip to content

Commit e02743c

Browse files
committed
Add initializer package to reduce per linter boilerplate
1 parent ab9f31e commit e02743c

File tree

21 files changed

+358
-454
lines changed

21 files changed

+358
-454
lines changed

pkg/analysis/commentstart/initializer.go

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,34 +17,21 @@ package commentstart
1717

1818
import (
1919
"golang.org/x/tools/go/analysis"
20+
"sigs.k8s.io/kube-api-linter/pkg/analysis/initializer"
2021
"sigs.k8s.io/kube-api-linter/pkg/config"
2122
)
2223

2324
// Initializer returns the AnalyzerInitializer for this
2425
// Analyzer so that it can be added to the registry.
25-
func Initializer() initializer {
26-
return initializer{}
27-
}
28-
29-
// intializer implements the AnalyzerInitializer interface.
30-
type initializer struct{}
31-
32-
// Name returns the name of the Analyzer.
33-
func (initializer) Name() string {
34-
return name
26+
func Initializer() initializer.AnalyzerInitializer {
27+
return initializer.NewInitializer(
28+
name,
29+
initAnalyzer,
30+
true,
31+
)
3532
}
3633

3734
// Init returns the intialized Analyzer.
38-
func (initializer) Init(cfg config.LintersConfig) (*analysis.Analyzer, error) {
35+
func initAnalyzer(cfg config.LintersConfig) (*analysis.Analyzer, error) {
3936
return Analyzer, nil
4037
}
41-
42-
// IsConfigurable determines whether or not the Analyzer provides configuration options.
43-
func (initializer) IsConfigurable() bool {
44-
return false
45-
}
46-
47-
// Default determines whether this Analyzer is on by default, or not.
48-
func (initializer) Default() bool {
49-
return true
50-
}

pkg/analysis/conditions/initializer.go

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,38 +20,30 @@ import (
2020

2121
"golang.org/x/tools/go/analysis"
2222
"k8s.io/apimachinery/pkg/util/validation/field"
23+
"sigs.k8s.io/kube-api-linter/pkg/analysis/initializer"
2324
"sigs.k8s.io/kube-api-linter/pkg/config"
2425
)
2526

2627
// Initializer returns the AnalyzerInitializer for this
2728
// Analyzer so that it can be added to the registry.
28-
func Initializer() initializer {
29-
return initializer{}
29+
func Initializer() initializer.AnalyzerInitializer {
30+
return initializer.NewConfigurableInitializer(
31+
name,
32+
initAnalyzer,
33+
true,
34+
validateConfig,
35+
)
3036
}
3137

32-
// intializer implements the AnalyzerInitializer interface.
33-
type initializer struct{}
34-
35-
// Name returns the name of the Analyzer.
36-
func (initializer) Name() string {
37-
return name
38-
}
39-
40-
// Init returns the intialized Analyzer.
41-
func (initializer) Init(cfg config.LintersConfig) (*analysis.Analyzer, error) {
38+
func initAnalyzer(cfg config.LintersConfig) (*analysis.Analyzer, error) {
4239
return newAnalyzer(cfg.Conditions), nil
4340
}
4441

45-
// IsConfigurable determines whether or not the Analyzer provides configuration options.
46-
func (initializer) IsConfigurable() bool {
47-
return true
48-
}
49-
50-
// ValidateConfig implements validation of the conditions linter config.
51-
func (initializer) ValidateConfig(cfg any, fldPath *field.Path) field.ErrorList {
42+
// validateConfig implements validation of the conditions linter config.
43+
func validateConfig(cfg any, fldPath *field.Path) field.ErrorList {
5244
cc, ok := cfg.(config.ConditionsConfig)
5345
if !ok {
54-
return field.ErrorList{field.InternalError(fldPath, fmt.Errorf("incorrect type for passed configuration: %T", cfg))}
46+
return field.ErrorList{field.InternalError(fldPath, initializer.NewIncorrectTypeError(cfg))}
5547
}
5648

5749
fieldErrors := field.ErrorList{}
@@ -76,8 +68,3 @@ func (initializer) ValidateConfig(cfg any, fldPath *field.Path) field.ErrorList
7668

7769
return fieldErrors
7870
}
79-
80-
// Default determines whether this Analyzer is on by default, or not.
81-
func (initializer) Default() bool {
82-
return true
83-
}

pkg/analysis/duplicatemarkers/initializer.go

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,36 +17,21 @@ package duplicatemarkers
1717

1818
import (
1919
"golang.org/x/tools/go/analysis"
20+
"sigs.k8s.io/kube-api-linter/pkg/analysis/initializer"
2021
"sigs.k8s.io/kube-api-linter/pkg/config"
2122
)
2223

2324
// Initializer returns the AnalyzerInitializer for this
2425
// Analyzer so that it can be added to the registry.
25-
func Initializer() initializer {
26-
return initializer{}
26+
func Initializer() initializer.AnalyzerInitializer {
27+
return initializer.NewInitializer(
28+
name,
29+
initAnalyzer,
30+
true,
31+
)
2732
}
2833

29-
// intializer implements the AnalyzerInitializer interface.
30-
type initializer struct{}
31-
32-
// Name returns the name of the Analyzer.
33-
func (initializer) Name() string {
34-
return name
35-
}
36-
37-
// Init returns the intialized Analyzer.
38-
func (initializer) Init(cfg config.LintersConfig) (*analysis.Analyzer, error) {
34+
// initAnalyzer returns the intialized Analyzer.
35+
func initAnalyzer(cfg config.LintersConfig) (*analysis.Analyzer, error) {
3936
return Analyzer, nil
4037
}
41-
42-
// IsConfigurable determines whether or not the Analyzer provides configuration options.
43-
func (initializer) IsConfigurable() bool {
44-
return false
45-
}
46-
47-
// Default determines whether this Analyzer is on by default, or not.
48-
func (initializer) Default() bool {
49-
// Duplicated markers are a sign of bad code, and should be avoided.
50-
// This is a good rule to have on by default.
51-
return true
52-
}

pkg/analysis/initializer/errors.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package initializer
17+
18+
import (
19+
"errors"
20+
"fmt"
21+
)
22+
23+
var (
24+
errIncorrectType = errors.New("incorrect type for passed configuration")
25+
)
26+
27+
// NewIncorrectTypeError returns a new error indicating that the provided configuration
28+
// is of the incorrect type.
29+
func NewIncorrectTypeError(cfg any) error {
30+
return fmt.Errorf("%w: %T", errIncorrectType, cfg)
31+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package initializer
17+
18+
import (
19+
"golang.org/x/tools/go/analysis"
20+
"k8s.io/apimachinery/pkg/util/validation/field"
21+
"sigs.k8s.io/kube-api-linter/pkg/config"
22+
)
23+
24+
// InitializerFunc is a function that initializes an Analyzer.
25+
type InitializerFunc func(config.LintersConfig) (*analysis.Analyzer, error)
26+
27+
// ValidateFunc is a function that validates the configuration for an Analyzer.
28+
type ValidateFunc func(any, *field.Path) field.ErrorList
29+
30+
// AnalyzerInitializer is used to initialize analyzers.
31+
type AnalyzerInitializer interface {
32+
// Name returns the name of the analyzer initialized by this initializer.
33+
Name() string
34+
35+
// Init returns the newly initialized analyzer.
36+
// It will be passed the complete LintersConfig and is expected to rely only on its own configuration.
37+
Init(config.LintersConfig) (*analysis.Analyzer, error)
38+
39+
// IsConfigurable determines whether or not the initializer expects to be provided a config.
40+
// When true, the initializer should also match the ConfigurableAnalyzerInitializer interface.
41+
IsConfigurable() bool
42+
43+
// Default determines whether the inializer intializes an analyzer that should be
44+
// on by default, or not.
45+
Default() bool
46+
}
47+
48+
// ConfigurableAnalyzerInitializer is an analyzer initializer that also has a configuration.
49+
// This means it can validate its config.
50+
type ConfigurableAnalyzerInitializer interface {
51+
AnalyzerInitializer
52+
53+
// ValidateConfig will be called during the config validation phase and is used to validate
54+
// the provided config for the linter.
55+
ValidateConfig(any, *field.Path) field.ErrorList
56+
}
57+
58+
// NewInitializer construct a new initializer for initializing an Analyzer.
59+
func NewInitializer(name string, initFunc InitializerFunc, isDefault bool) AnalyzerInitializer {
60+
return initializer{
61+
name: name,
62+
initFunc: initFunc,
63+
isDefault: isDefault,
64+
}
65+
}
66+
67+
// NewConfigurableInitializer constructs a new initializer for intializing a
68+
// configurable Analyzer.
69+
func NewConfigurableInitializer(name string, initFunc InitializerFunc, isDefault bool, validateFunc ValidateFunc) ConfigurableAnalyzerInitializer {
70+
return configurableInitializer{
71+
initializer: initializer{
72+
name: name,
73+
initFunc: initFunc,
74+
isDefault: isDefault,
75+
},
76+
validateFunc: validateFunc,
77+
}
78+
}
79+
80+
type initializer struct {
81+
name string
82+
initFunc InitializerFunc
83+
isDefault bool
84+
}
85+
86+
// Name returns the name of the initializer.
87+
func (i initializer) Name() string {
88+
return i.name
89+
}
90+
91+
// Init returns a newly initializr analyzer.
92+
func (i initializer) Init(cfg config.LintersConfig) (*analysis.Analyzer, error) {
93+
return i.initFunc(cfg)
94+
}
95+
96+
// IsConfigurable determines whether or not to expect this initializer to
97+
// be able to be configured with custom configuration.
98+
func (i initializer) IsConfigurable() bool {
99+
return false
100+
}
101+
102+
// Default determines whether this initializer should be enabled by default or not.
103+
func (i initializer) Default() bool {
104+
return i.isDefault
105+
}
106+
107+
type configurableInitializer struct {
108+
initializer
109+
110+
validateFunc ValidateFunc
111+
}
112+
113+
// IsConfigurable determines whether or not to expect this initializer to
114+
// be able to be configured with custom configuration.
115+
func (i configurableInitializer) IsConfigurable() bool {
116+
return true
117+
}
118+
119+
// ValidateConfig validates the configuration for the initializer.
120+
func (i configurableInitializer) ValidateConfig(cfg any, fld *field.Path) field.ErrorList {
121+
return i.validateFunc(cfg, fld)
122+
}

pkg/analysis/integers/initializer.go

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,34 +17,20 @@ package integers
1717

1818
import (
1919
"golang.org/x/tools/go/analysis"
20+
"sigs.k8s.io/kube-api-linter/pkg/analysis/initializer"
2021
"sigs.k8s.io/kube-api-linter/pkg/config"
2122
)
2223

2324
// Initializer returns the AnalyzerInitializer for this
2425
// Analyzer so that it can be added to the registry.
25-
func Initializer() initializer {
26-
return initializer{}
26+
func Initializer() initializer.AnalyzerInitializer {
27+
return initializer.NewInitializer(
28+
name,
29+
initAnalyzer,
30+
true,
31+
)
2732
}
2833

29-
// intializer implements the AnalyzerInitializer interface.
30-
type initializer struct{}
31-
32-
// Name returns the name of the Analyzer.
33-
func (initializer) Name() string {
34-
return name
35-
}
36-
37-
// Init returns the intialized Analyzer.
38-
func (initializer) Init(cfg config.LintersConfig) (*analysis.Analyzer, error) {
34+
func initAnalyzer(cfg config.LintersConfig) (*analysis.Analyzer, error) {
3935
return Analyzer, nil
4036
}
41-
42-
// IsConfigurable determines whether or not the Analyzer provides configuration options.
43-
func (initializer) IsConfigurable() bool {
44-
return false
45-
}
46-
47-
// Default determines whether this Analyzer is on by default, or not.
48-
func (initializer) Default() bool {
49-
return true
50-
}

0 commit comments

Comments
 (0)