From b32bbcc4d69ce7281b15f63937e9524999805ff9 Mon Sep 17 00:00:00 2001 From: Austin Pond Date: Thu, 9 Apr 2026 11:03:12 -0400 Subject: [PATCH] fix(lint): resolve golangci-lint v2.11.4 errors Fixes deprecatedComment, gosec, prealloc, revive (use-slices-sort), and staticcheck issues introduced by the upgrade from golangci-lint v2.5.0 to v2.11.4. Updates linter version in Makefile and CI workflow. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/pr.yml | 2 +- Makefile | 2 +- app/manifest.go | 3 +++ app/runner.go | 2 +- cmd/grafana-app-sdk/manifest.go | 6 +++--- cmd/grafana-app-sdk/project.go | 8 ++++---- codegen/jennies/gotypes.go | 5 +++-- codegen/jennies/manifest.go | 9 ++++----- codegen/jennies/typescript.go | 5 +++-- codegen/jennies/util.go | 3 ++- codegen/kind.go | 1 + codegen/templates/templates.go | 5 +++-- examples/resource/store/store.go | 2 +- health/observer.go | 2 +- k8s/apiserver/connector.go | 2 +- k8s/apiserver/installer.go | 15 +++++++-------- k8s/apiserver/options.go | 2 +- k8s/apiserver/strategy.go | 2 +- k8s/manager.go | 6 +++--- k8s/negotiator.go | 2 +- operator/informer_concurrent.go | 1 + operator/retry_processor.go | 2 +- resource/schema.go | 3 +++ resource/simplestore.go | 2 ++ simple/app.go | 4 ++-- simple/operator.go | 2 ++ 26 files changed, 56 insertions(+), 42 deletions(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index b4c400ada..56ee54f15 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -58,7 +58,7 @@ jobs: - name: Lint uses: golangci/golangci-lint-action@b002b6ecfcabe6ac0e2c6cba1bcc779eb34ac51f # v9 with: - version: v2.5.0 + version: v2.11.4 only-new-issues: true args: --timeout 5m $(go list -f '{{.Dir}}/...' -m | tr '\n' ' ') test: diff --git a/Makefile b/Makefile index dc9ce36c0..6b28e23b8 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ check-go-version: exit 1; \ fi -LINTER_VERSION := 2.5.0 +LINTER_VERSION := 2.11.4 LINTER_BINARY := $(BIN_DIR)/golangci-lint-$(LINTER_VERSION) .PHONY: lint diff --git a/app/manifest.go b/app/manifest.go index fa4d389ee..8ede26db7 100644 --- a/app/manifest.go +++ b/app/manifest.go @@ -213,6 +213,7 @@ func (m *ManifestData) Validate() error { } // Kinds returns a list of ManifestKinds parsed from Versions, for compatibility with kind-centric usage +// // Deprecated: this exists to support current workflows, and should not be used for new ones. func (m *ManifestData) Kinds() []ManifestKind { kinds := make(map[string]ManifestKind) @@ -244,6 +245,7 @@ func (m *ManifestData) Kinds() []ManifestKind { // ManifestKind is the manifest for a particular kind, including its Kind, Scope, and Versions. // The values for Kind, Plural, Scope, and Conversion are hoisted up from their namesakes in Versions entries +// // Deprecated: this is used only for the deprecated method ManifestData.Kinds() type ManifestKind struct { // Kind is the name of the kind @@ -259,6 +261,7 @@ type ManifestKind struct { } // ManifestKindVersion is an extension on ManifestVersionKind that adds the version name +// // Deprecated: this type if used only as part of the deprecated method ManifestData.Kinds() type ManifestKindVersion struct { ManifestVersionKind `json:",inline" yaml:",inline"` diff --git a/app/runner.go b/app/runner.go index ebcb32f03..7a45091dd 100644 --- a/app/runner.go +++ b/app/runner.go @@ -403,7 +403,7 @@ func (d *DynamicMultiRunner) HealthChecks() []health.Check { } func (d *DynamicMultiRunner) runTuple(tpl *dynamicMultiRunnerTuple) { d.wg.Add(1) - ctx, cancel := context.WithCancel(d.runCtx) + ctx, cancel := context.WithCancel(d.runCtx) //nolint:gosec tpl.cancelFunc = cancel go func() { err := tpl.runner.Run(ctx) diff --git a/cmd/grafana-app-sdk/manifest.go b/cmd/grafana-app-sdk/manifest.go index 975ab0e30..74d284808 100644 --- a/cmd/grafana-app-sdk/manifest.go +++ b/cmd/grafana-app-sdk/manifest.go @@ -6,7 +6,7 @@ import ( "io" "os" "regexp" - "sort" + "slices" "cuelang.org/go/cue" "cuelang.org/go/cue/cuecontext" @@ -49,8 +49,8 @@ func getManifestLatestVersion(manifestDir string) (string, error) { if len(versions) == 0 { return "", errNoVersions } - sort.Slice(versions, func(i, j int) bool { - return k8sversion.CompareKubeAwareVersionStrings(versions[i], versions[j]) > 0 + slices.SortFunc(versions, func(a, b string) int { + return -k8sversion.CompareKubeAwareVersionStrings(a, b) }) return versions[0], nil } diff --git a/cmd/grafana-app-sdk/project.go b/cmd/grafana-app-sdk/project.go index e36b8842d..7b69b1b33 100644 --- a/cmd/grafana-app-sdk/project.go +++ b/cmd/grafana-app-sdk/project.go @@ -468,7 +468,7 @@ func projectAddKindCUE(srcPath, manifestFileName, fieldName, kindName, version, if err != nil { return nil, err } - files := make(codejen.Files, 2) + files := make(codejen.Files, 2) //nolint:prealloc files[0] = codejen.File{ RelativePath: fmt.Sprintf("%s.cue", strings.ToLower(kindName)), Data: buf.Bytes(), @@ -856,19 +856,19 @@ func moveFiles(srcDir, destDir string) error { if err != nil { return err } - if err = os.Remove(path); err != nil { + if err = os.Remove(path); err != nil { //nolint:gosec return err } return fs.SkipDir } - err = os.Rename(path, filepath.Join(destDir, d.Name())) + err = os.Rename(path, filepath.Join(destDir, d.Name())) //nolint:gosec if err != nil { return err } return fs.SkipDir } - return os.Rename(path, filepath.Join(destDir, d.Name())) + return os.Rename(path, filepath.Join(destDir, d.Name())) //nolint:gosec }) } diff --git a/codegen/jennies/gotypes.go b/codegen/jennies/gotypes.go index 7c06f8d1a..8cb6605a3 100644 --- a/codegen/jennies/gotypes.go +++ b/codegen/jennies/gotypes.go @@ -159,8 +159,9 @@ type goTypesGenerateFilesConfig struct { //nolint:goconst func (g *GoTypes) generateFilesAtDepth(v cue.Value, schemaPath cue.Path, currDepth int, cfg goTypesGenerateFilesConfig) (codejen.Files, error) { if currDepth == g.Depth { - fieldName := make([]string, 0) - for _, s := range TrimPathPrefix(v.Path(), schemaPath).Selectors() { + selectors := TrimPathPrefix(v.Path(), schemaPath).Selectors() + fieldName := make([]string, 0, len(selectors)) + for _, s := range selectors { fieldName = append(fieldName, s.String()) } exclude := false diff --git a/codegen/jennies/manifest.go b/codegen/jennies/manifest.go index fb2b215a8..b708a591a 100644 --- a/codegen/jennies/manifest.go +++ b/codegen/jennies/manifest.go @@ -10,7 +10,6 @@ import ( "maps" "path/filepath" "slices" - "sort" "strings" "cuelang.org/go/cue" @@ -90,7 +89,7 @@ func (m *ManifestGenerator) Generate(appManifest codegen.AppManifest) (codejen.F } output["spec"] = manifestSpec - files := make(codejen.Files, 0) + files := make(codejen.Files, 0, 1) out, err := m.Encoder(output) if err != nil { return nil, err @@ -160,7 +159,7 @@ func (g *ManifestGoGenerator) Generate(appManifest codegen.AppManifest) (codejen } } - files := make(codejen.Files, 0) + files := make(codejen.Files, 0, 1) files = append(files, codejen.File{ Data: formatted, RelativePath: filepath.Join(g.DestinationPath, fmt.Sprintf("%s_manifest.go", appManifest.Properties().Group)), @@ -415,7 +414,7 @@ func buildDefaultManifestRolesAndBindings(m codegen.AppManifest) (map[string]cod for k := range kindListMap { kindList = append(kindList, k) } - sort.Strings(kindList) + slices.Sort(kindList) allKindsDesc := joinKindNames(kindList) roles := map[string]codegen.AppManifestPropertiesRole{ readerKey: { @@ -766,7 +765,7 @@ func cueSchemaToParameters(v cue.Value) ([]*spec3.Parameter, error) { for name := range schemaProps.Properties { paramNames = append(paramNames, name) } - sort.Strings(paramNames) + slices.Sort(paramNames) parameters := make([]*spec3.Parameter, 0, len(paramNames)) // Iterate through sorted names diff --git a/codegen/jennies/typescript.go b/codegen/jennies/typescript.go index 2af55c870..7253b9e3e 100644 --- a/codegen/jennies/typescript.go +++ b/codegen/jennies/typescript.go @@ -167,8 +167,9 @@ func (j TypeScriptTypes) generateFiles(version string, kind *codegen.VersionedKi func (j TypeScriptTypes) generateFilesAtDepth(v cue.Value, version string, vk *codegen.VersionedKind, currDepth int, pathPrefix string, prefix string) (codejen.Files, error) { if currDepth == j.Depth { - fieldName := make([]string, 0) - for _, s := range TrimPathPrefix(v.Path(), vk.Schema.Path()).Selectors() { + selectors := TrimPathPrefix(v.Path(), vk.Schema.Path()).Selectors() + fieldName := make([]string, 0, len(selectors)) + for _, s := range selectors { fieldName = append(fieldName, s.String()) } tsBytes, err := generateTypescriptBytes(v, ToPackageName(version), exportField(strings.Join(fieldName, "")), cog.TypescriptConfig{ diff --git a/codegen/jennies/util.go b/codegen/jennies/util.go index 5311c6e31..66c32294b 100644 --- a/codegen/jennies/util.go +++ b/codegen/jennies/util.go @@ -17,9 +17,10 @@ func ToPackageName(input string) string { // generated code should be grouped by kind or by GroupVersion. // When groupByKind is true, the path will be /. // When groupByKind is false, the path will be /. +// // Deprecated: Use GetGeneratedGoTypePath instead. // -//nolint:revive +//nolint:revive,staticcheck func GetGeneratedPath(groupByKind bool, kind codegen.Kind, version string) string { if groupByKind { return filepath.Join(ToPackageName(kind.Properties().MachineName), ToPackageName(version)) diff --git a/codegen/kind.go b/codegen/kind.go index 006b521d3..1d2d27ab7 100644 --- a/codegen/kind.go +++ b/codegen/kind.go @@ -7,6 +7,7 @@ import ( // Kind is a common interface declaration for code generation. // Any type parser should be able to parse a kind into this definition to supply // to various common Jennies in the codegen package. +// // Deprecated: use AppManifest instead type Kind interface { Name() string diff --git a/codegen/templates/templates.go b/codegen/templates/templates.go index 87f2f4898..96967d58a 100644 --- a/codegen/templates/templates.go +++ b/codegen/templates/templates.go @@ -159,11 +159,12 @@ type SchemaMetadataSelectableField struct { } func (SchemaMetadata) ToObjectPath(s string) string { - parts := make([]string, 0) if len(s) > 0 && s[0] == '.' { s = s[1:] } - for i, part := range strings.Split(s, ".") { + split := strings.Split(s, ".") + parts := make([]string, 0, len(split)) + for i, part := range split { if i == 0 && part == "metadata" { part = "ObjectMeta" } diff --git a/examples/resource/store/store.go b/examples/resource/store/store.go index 65f1159bb..5cf625e61 100644 --- a/examples/resource/store/store.go +++ b/examples/resource/store/store.go @@ -177,7 +177,7 @@ func useStore(generator resource.ClientGenerator) { // The trade-off is that the SimpleStore can only be tied to one specific Schema. func useSimpleStore(generator resource.ClientGenerator) { // SimpleStore can only manipulate one Custom Resource type, but allows for direct manipulation of the Spec object - simpleStore, _ := resource.NewSimpleStore[Obj2Spec](obj2Kind, generator) + simpleStore, _ := resource.NewSimpleStore[Obj2Spec](obj2Kind, generator) //nolint:staticcheck added, err := simpleStore.Add(context.TODO(), resource.Identifier{ Namespace: "default", Name: "example-2", diff --git a/health/observer.go b/health/observer.go index a5ca19d4c..6b9897c5a 100644 --- a/health/observer.go +++ b/health/observer.go @@ -32,7 +32,7 @@ func (c CheckStatus) String() string { b := strings.Builder{} for _, result := range c.Results { - b.WriteString(fmt.Sprintf("%s\n", result.String())) //nolint:revive + fmt.Fprintf(&b, "%s\n", result.String()) //nolint:revive } return b.String() } diff --git a/k8s/apiserver/connector.go b/k8s/apiserver/connector.go index e83457c71..c02318be1 100644 --- a/k8s/apiserver/connector.go +++ b/k8s/apiserver/connector.go @@ -81,7 +81,7 @@ func (*SubresourceConnector) Destroy() { } func (r *SubresourceConnector) ConnectMethods() []string { - methods := make([]string, 0) + methods := make([]string, 0, len(r.Methods)) for method := range r.Methods { methods = append(methods, method) } diff --git a/k8s/apiserver/installer.go b/k8s/apiserver/installer.go index 60b2d84aa..d6b24aeda 100644 --- a/k8s/apiserver/installer.go +++ b/k8s/apiserver/installer.go @@ -13,7 +13,6 @@ import ( "reflect" "regexp" "slices" - "sort" "strings" "sync" @@ -305,14 +304,14 @@ func (r *defaultInstaller) AddToScheme(scheme *runtime.Scheme) error { } } - sort.Slice(groupVersions, func(i, j int) bool { - if groupVersions[i].Version == r.appConfig.ManifestData.PreferredVersion { - return true + slices.SortFunc(groupVersions, func(a, b schema.GroupVersion) int { + if a.Version == r.appConfig.ManifestData.PreferredVersion { + return -1 } - if groupVersions[j].Version == r.appConfig.ManifestData.PreferredVersion { - return false + if b.Version == r.appConfig.ManifestData.PreferredVersion { + return 1 } - return version.CompareKubeAwareVersionStrings(groupVersions[i].Version, groupVersions[j].Version) > 0 + return -version.CompareKubeAwareVersionStrings(a.Version, b.Version) }) if len(groupVersions) > 0 { if err = scheme.SetVersionPriority(groupVersions...); err != nil { @@ -798,7 +797,7 @@ func (r *defaultInstaller) App() (app.App, error) { } func (r *defaultInstaller) GroupVersions() []schema.GroupVersion { - groupVersions := make([]schema.GroupVersion, 0) + groupVersions := make([]schema.GroupVersion, 0, len(r.appConfig.ManifestData.Versions)) for _, gv := range r.appConfig.ManifestData.Versions { groupVersions = append(groupVersions, schema.GroupVersion{Group: r.appConfig.ManifestData.Group, Version: gv.Name}) } diff --git a/k8s/apiserver/options.go b/k8s/apiserver/options.go index 6c4af1331..9bb69d670 100644 --- a/k8s/apiserver/options.go +++ b/k8s/apiserver/options.go @@ -47,7 +47,7 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) { } func (o *Options) Validate() error { - errs := []error{} + errs := []error{} //nolint:prealloc errs = append(errs, o.RecommendedOptions.Validate()...) return utilerrors.NewAggregate(errs) } diff --git a/k8s/apiserver/strategy.go b/k8s/apiserver/strategy.go index 56f4b24b4..09c7ad53c 100644 --- a/k8s/apiserver/strategy.go +++ b/k8s/apiserver/strategy.go @@ -223,7 +223,7 @@ func (g *genericSubresourceStrategy) NamespaceScoped() bool { } func (g *genericSubresourceStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { - paths := make([]fieldpath.Path, 0) + paths := make([]fieldpath.Path, 0, len(g.resetFields)) for _, path := range g.resetFields { paths = append(paths, fieldpath.MakePathOrDie(path)) } diff --git a/k8s/manager.go b/k8s/manager.go index f1dd1efeb..a03c8cd6b 100644 --- a/k8s/manager.go +++ b/k8s/manager.go @@ -7,7 +7,7 @@ import ( "fmt" "net/http" "reflect" - "sort" + "slices" "strings" "time" @@ -109,8 +109,8 @@ func (m *ResourceManager) RegisterSchema(ctx context.Context, schema resource.Sc existing.Spec.Versions = append(existing.Spec.Versions, toVersion(schema)) } // Make sure the latest is the one with storage = true - sort.Slice(existing.Spec.Versions, func(i, j int) bool { - return existing.Spec.Versions[i].Name > existing.Spec.Versions[j].Name + slices.SortFunc(existing.Spec.Versions, func(a, b CustomResourceDefinitionSpecVersion) int { + return strings.Compare(b.Name, a.Name) }) for i := 0; i < len(existing.Spec.Versions); i++ { existing.Spec.Versions[i].Storage = false diff --git a/k8s/negotiator.go b/k8s/negotiator.go index 5ade4b9ed..429b1dcd6 100644 --- a/k8s/negotiator.go +++ b/k8s/negotiator.go @@ -144,7 +144,7 @@ type KindNegotiatedSerializer struct { // SupportedMediaTypes returns the JSON supported media type with a GenericJSONDecoder and kubernetes JSON Framer. func (k *KindNegotiatedSerializer) SupportedMediaTypes() []runtime.SerializerInfo { - supported := make([]runtime.SerializerInfo, 0) + supported := make([]runtime.SerializerInfo, 0, len(k.Kind.Codecs)) for encoding, codec := range k.Kind.Codecs { serializer := &CodecDecoder{ SampleObject: k.Kind.ZeroValue(), diff --git a/operator/informer_concurrent.go b/operator/informer_concurrent.go index 72ddf8221..795d762b7 100644 --- a/operator/informer_concurrent.go +++ b/operator/informer_concurrent.go @@ -39,6 +39,7 @@ type ConcurrentInformerOptions struct { } // NewConcurrentInformer creates a new ConcurrentInformer wrapping the provided Informer. +// // Deprecated: Use NewConcurrentInformerFromOptions instead, which accepts InformerOptions. func NewConcurrentInformer(inf Informer, opts ConcurrentInformerOptions) ( *ConcurrentInformer, error) { diff --git a/operator/retry_processor.go b/operator/retry_processor.go index f3c78047e..bf6b990b5 100644 --- a/operator/retry_processor.go +++ b/operator/retry_processor.go @@ -76,7 +76,7 @@ func NewRetryProcessor(cfg RetryProcessorConfig, retryPolicyFn func() RetryPolic return &defaultRetryProcessor{ workers: workers, - workerCount: uint64(cfg.WorkerPoolSize), + workerCount: uint64(cfg.WorkerPoolSize), //nolint:gosec retryPolicyFn: retryPolicyFn, } } diff --git a/resource/schema.go b/resource/schema.go index 2c732f42d..2734bb7ac 100644 --- a/resource/schema.go +++ b/resource/schema.go @@ -49,6 +49,7 @@ type SelectableField struct { // SchemaGroup represents a group of Schemas. The interface does not require commonality between Schemas, // but an implementation may require a relationship. +// // Deprecated: Kinds are now favored over Schemas for usage. type SchemaGroup interface { Schemas() []Schema @@ -112,6 +113,7 @@ func (s *SimpleSchema) SelectableFields() []SelectableField { } // SimpleSchemaGroup collects schemas with the same group and version +// // Deprecated: Kinds are now favored over Schemas for usage. Use KindGroup instead. type SimpleSchemaGroup struct { group string @@ -193,6 +195,7 @@ func NewSimpleSchema(group, version string, zeroVal Object, zeroList ListObject, } // NewSimpleSchemaGroup returns a new SimpleSchemaGroup +// // Deprecated: Kinds are now favored over Schemas for usage. Use KindGroup instead. func NewSimpleSchemaGroup(group, version string) *SimpleSchemaGroup { return &SimpleSchemaGroup{ diff --git a/resource/simplestore.go b/resource/simplestore.go index cdd737c3b..f195b1ed1 100644 --- a/resource/simplestore.go +++ b/resource/simplestore.go @@ -52,6 +52,7 @@ func WithResourceVersion(resourceVersion string) ObjectMetadataOption { // allowing the user to work with the actual type in the Schema Object's spec, // without casting in and out of the Object interface. // It should be instantiated with NewSimpleStore. +// // Deprecated: prefer using TypedStore instead type SimpleStore[SpecType any] struct { client Client @@ -61,6 +62,7 @@ type SimpleStore[SpecType any] struct { // It will error if the type of the Schema.ZeroValue().SpecObject() does not match the provided SpecType. // It will also error if a client cannot be created from the generator, as unlike Store, the client is generated once // and reused for all subsequent calls. +// // Deprecated: prefer using TypedStore instead func NewSimpleStore[SpecType any](kind Kind, generator ClientGenerator) (*SimpleStore[SpecType], error) { if reflect.TypeOf(kind.Schema.ZeroValue().GetSpec()) != reflect.TypeOf(new(SpecType)).Elem() { diff --git a/simple/app.go b/simple/app.go index e4322d96d..07f98f9d1 100644 --- a/simple/app.go +++ b/simple/app.go @@ -407,7 +407,7 @@ func (a *App) ValidateManifest(manifest app.ManifestData) error { // ManagedKinds returns a slice of all Kinds managed by this App func (a *App) ManagedKinds() []resource.Kind { - kinds := make([]resource.Kind, 0) + kinds := make([]resource.Kind, 0, len(a.kinds)) for _, k := range a.kinds { kinds = append(kinds, k.Kind) } @@ -548,7 +548,7 @@ func (a *App) PrometheusCollectors() []prometheus.Collector { } func (a *App) HealthChecks() []health.Check { - checks := make([]health.Check, 0) + checks := make([]health.Check, 0) //nolint:prealloc checks = append(checks, a.runner.HealthChecks()...) checks = append(checks, a.informerController.HealthChecks()...) diff --git a/simple/operator.go b/simple/operator.go index 4560d3f56..37886f908 100644 --- a/simple/operator.go +++ b/simple/operator.go @@ -76,6 +76,7 @@ type TracingConfig struct { } // NewOperator creates a new Operator +// // Deprecated: please use simple.NewApp and operator.NewRunner to create a simple operator app. func NewOperator(cfg OperatorConfig) (*Operator, error) { cg := k8s.NewClientRegistry(cfg.KubeConfig, k8s.ClientConfig{}) @@ -165,6 +166,7 @@ func NewOperator(cfg OperatorConfig) (*Operator, error) { // use WatchKind to add a watcher for a specific kind (schema) and configuration (such as namespace, label filters), // ReconcileKind to add a reconciler for a specific kind (schema) and configuration (such as namespace, label filers), // and ValidateKind or MutateKind to add admission control for a kind (schema). +// // Deprecated: use simple.App in conjunction with operator.Runner instead. type Operator struct { Name string