Skip to content

golangci-lint v2 #131477

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 3, 2025
Merged

golangci-lint v2 #131477

merged 4 commits into from
May 3, 2025

Conversation

pohly
Copy link
Contributor

@pohly pohly commented Apr 25, 2025

What type of PR is this?

/kind cleanup

What this PR does / why we need it:

This updates Kubernetes to use the new and revised golangci-lint v2. On this occasion, the check suppressions got revisited, revealing that in some cases existing code really is broken (fix included in this PR, see individual commits).

Special notes for your reviewer:

This is a continuation of #131113. See last commit for the differences.

Does this PR introduce a user-facing change?

NONE

/cc @mmorel-35 @ldez

@k8s-ci-robot
Copy link
Contributor

@pohly: GitHub didn't allow me to request PR reviews from the following users: mmorel-35, ldez.

Note that only kubernetes members and repo collaborators can review this PR, and authors cannot review their own PRs.

In response to this:

What type of PR is this?

/kind cleanup

What this PR does / why we need it:

This updates Kubernetes to use the new and revised golangci-lint v2. On this occasion, the check suppressions got revisited, revealing that in some cases existing code really is broken (fix included in this PR, see individual commits).

Special notes for your reviewer:

This is a continuation of #131113. See last commit for the differences.

Does this PR introduce a user-facing change?

NONE

/cc @mmorel-35 @ldez

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@k8s-ci-robot k8s-ci-robot added release-note-none Denotes a PR that doesn't merit a release note. kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. do-not-merge/needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. needs-priority Indicates a PR lacks a `priority/foo` label and requires one. area/code-generation area/dependency Issues or PRs related to dependency changes area/kube-proxy area/kubelet area/test kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. sig/apps Categorizes an issue or PR as relevant to SIG Apps. sig/auth Categorizes an issue or PR as relevant to SIG Auth. sig/network Categorizes an issue or PR as relevant to SIG Network. and removed do-not-merge/needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. labels Apr 25, 2025
@k8s-ci-robot k8s-ci-robot added sig/node Categorizes an issue or PR as relevant to SIG Node. sig/storage Categorizes an issue or PR as relevant to SIG Storage. labels Apr 25, 2025
@github-project-automation github-project-automation bot moved this to Needs Triage in SIG Auth Apr 25, 2025
@github-project-automation github-project-automation bot moved this to Needs Triage in SIG Apps Apr 25, 2025
@k8s-ci-robot k8s-ci-robot added the sig/testing Categorizes an issue or PR as relevant to SIG Testing. label Apr 25, 2025
@pohly pohly changed the title Golangci lint@v2 golangci-lint v2 Apr 25, 2025
@k8s-ci-robot k8s-ci-robot removed the needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. label Apr 29, 2025
@@ -65,7 +65,7 @@ func Convert_v1_JSON_To_apiextensions_JSON(in *JSON, out *apiextensions.JSON, s
}
*out = i
} else {
out = nil
*out = nil
Copy link
Member

Choose a reason for hiding this comment

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

this is a really subtle one, we'll need to tag in API reviewers

Copy link
Contributor Author

Choose a reason for hiding this comment

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

/assign @liggitt

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Without this:

ERROR: staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1/conversion.go:68:3: ineffectual assignment to out (ineffassign)
ERROR: 		out = nil
ERROR: 		^

Copy link
Member

@liggitt liggitt Apr 30, 2025

Choose a reason for hiding this comment

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

  1. This change is correct, the linter was correct to flag the old code.

  2. This change is also safe. out must be a non-nil pointer for conversion to work, and in all call sites, a non-nil out pointer is passed.

  3. This change is also ultimately a no-op for existing callers because in all call sites, a nil in parameter is never passed.

@@ -7,69 +7,77 @@ godebug default=go1.24
require (
github.com/aojea/sloppy-netparser v0.0.0-20210819225411-1b3bd8b3b975
github.com/cespare/prettybench v0.0.0-20150116022406-03b8cfe5406c
github.com/golangci/golangci-lint v1.64.5
github.com/golangci/golangci-lint/v2 v2.1.5
Copy link
Member

Choose a reason for hiding this comment

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

starting to think about moving tools into seperate modules, so they behave closer to if you just go installed them and don't conflate dep versions, there are some tradeoffs (sharing deps improves build caching for them marginally), it's hard to tell if any of these impact other tools

Copy link

Choose a reason for hiding this comment

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

if you want to do that, I recommend reading the section go tool of the golangci-lint doc https://golangci-lint.run/welcome/install/#install-from-sources

Copy link
Member

Choose a reason for hiding this comment

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

Right, currently we have this issue from the other tools:

When using the "tools pattern" or tool command/directives, the dependencies of a tool can modify the dependencies of another tool or your project. The resulting binary was not tested and is not guaranteed to work.

Tracking it in a shared tools module has risks, I think we should split it out.
Then the only question is if we use a specific module or avoid a module entirely.
Using a module means we get GOSHASUM and other visibility, at the risk of breaking replace statements.

Copy link
Member

Choose a reason for hiding this comment

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

We prefer not to take opaque binary dependencies generally, and it's also more complex to do portably across OS-es. It is somewhat less opaque to track this way, and I see shasums breaking as a feature that indicates some unknown change was made that hasn't been looked at. The GOSHASUMS enable TOFU in a way that is much simpler and re-usable than binaries.

Copy link

@ldez ldez Apr 29, 2025

Choose a reason for hiding this comment

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

I suggested that you read the section "go tool usage recommendations" inside the "install from sources" section.
You have to click on the triangle.

Screenshot 2025-04-30 at 00-07-27 Install golangci-lint

Copy link
Member

Choose a reason for hiding this comment

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

Ahh! it wasn't obvious that this expanded, and the lines above at the linked heading talk about go tool

Might be worth tweaking the styling / layout.

Copy link

Choose a reason for hiding this comment

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

It is intentionally not a heading because we strongly don't recommend that.
But I prefer to provide the right way to do it instead of letting users in the dark.
So this is a compromise.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Installing golangci-lint through a separate module seems worthwhile. I've added one more commit doing that:

golangci-lint: move into hack/tools/golangci-lint

The advantage is that it separates the dependencies of the different tools
better. golangci-lint in particular has many dependencies and is sometimes
sensitive to the exact version being used. This way, "go get" bumps up
dependencies exactly as defined by the upstream golangci-lint module.

It's not quite self-contained because logcheck as a Go plugin for golangci-lint
must be built from the same dependencies. But it only adds one and does not
change any of the others.

While at it, the Go 1.24 "tools" directive gets used instead of the traditional
tools.go approach.

Copy link
Member

@BenTheElder BenTheElder left a comment

Choose a reason for hiding this comment

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

/approve
for hack/
Need more eyes on the other changes to confirm.

@@ -644,7 +646,7 @@ func (dc *DisruptionController) processNextWorkItem(ctx context.Context) bool {
return true
}

utilruntime.HandleError(fmt.Errorf("Error syncing PodDisruptionBudget %v, requeuing: %w", dKey, err)) //nolint:stylecheck
utilruntime.HandleErrorWithContext(ctx, err, "Error syncing PodDisruptionBudget", "key", dKey)
Copy link
Member

Choose a reason for hiding this comment

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

This is a curious change to pair with the lint v2 bump ... was the existing //nolint:stylecheck comment suppressing an "errors start with lowercase letter" check? If so, this changed to context logging (which is a functional change that looks unrelated to the linting), but is still passing the initial uppercase message the stylecheck complained about?

At the very least, we should avoid dropping the "requeuing" bit from the message, so "Error syncing PodDisruptionBudget, requeuing"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

was the existing //nolint:stylecheck comment suppressing an "errors start with lowercase letter" check?

That check is not enforced. Perhaps //nolint was added in https://github.com/kubernetes/kubernetes/blame/03a3c0c89161935bc2338f5754ebb1104f779af1/pkg/controller/disruption/disruption.go#L647 to silence the hint. That was unnecessary and in this case, I would have preferred fixing the code.

We should have a linter which complains about //nolint:something without an additional comment after it (//nolint: // " Not relevant because ...)...

If so, this changed to context logging (which is a functional change that looks unrelated to the linting),

We can:

  • Leave this line as it is (including the //nolint:stylecheck, which is useless now because the linter is no longer active).
  • Remove just the //nolint:stylecheck.
  • Update the line to use current best practices (= use HandleErrorWithContext).

I prefer the last option.

but is still passing the initial uppercase message the stylecheck complained about?

HandleError was a logging function in disguise with additional tooling that normal error logging doesn't have. Using fmt.Errorf was (mis)used to produce a log message.

HandleErrorWithContext explicitly accepts a log message and additional key/value pairs, in addition to the error (if there is one - it's not required, i.e. no need to fabricate a new one if there isn't one already). For log messages, the recommendation is to start with a capital letter. I'm not exactly sure why, that recommendation pre-dates my involvement.

TLDR: `Error syncing" is fine here.

At the very least, we should avoid dropping the "requeuing" bit from the message, so "Error syncing PodDisruptionBudget, requeuing"

Ack, changed.

Copy link
Contributor

Choose a reason for hiding this comment

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

We should have a linter which complains about //nolint:something without an additional comment after it (//nolint: // " Not relevant because ...)...

You might want to take a look at whyNoLint rule from go-critic

Copy link

Choose a reason for hiding this comment

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

or just nolintlint https://golangci-lint.run/usage/linters/#nolintlint

nolintlint is the official linter to handle nolint directives.

Copy link
Contributor

Choose a reason for hiding this comment

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

I suggested whyNoLint because go-critic is already enabled in this project and also nolintlint has been deactivated on some projects for generating conflicts with other linters see this open issue golangci/golangci-lint#3228

Copy link

@ldez ldez May 2, 2025

Choose a reason for hiding this comment

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

This problem is not a specific issue related to nolintlint and not related to comments, this is explained inside the issue.

@@ -65,7 +65,7 @@ func Convert_v1_JSON_To_apiextensions_JSON(in *JSON, out *apiextensions.JSON, s
}
*out = i
} else {
out = nil
*out = nil
Copy link
Member

@liggitt liggitt Apr 30, 2025

Choose a reason for hiding this comment

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

  1. This change is correct, the linter was correct to flag the old code.

  2. This change is also safe. out must be a non-nil pointer for conversion to work, and in all call sites, a non-nil out pointer is passed.

  3. This change is also ultimately a no-op for existing callers because in all call sites, a nil in parameter is never passed.

@@ -153,9 +155,8 @@ if [ "${golangci_config}" ]; then
# don't to do it when not required.
if grep -q 'path: ../_output/local/bin/' "${golangci_config}" &&
Copy link
Member

Choose a reason for hiding this comment

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

should the .. be dropped from the grep if we're dropping it from the sed here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, thanks for catching this.

echo "installing golangci-lint and logcheck plugin from hack/tools into ${GOBIN}"
GOTOOLCHAIN="$(kube::golang::hack_tools_gotoolchain)" go -C "${KUBE_ROOT}/hack/tools" install github.com/golangci/golangci-lint/v2/cmd/golangci-lint
GOWORK=off GOTOOLCHAIN="$(kube::golang::hack_tools_gotoolchain)" go -C "${KUBE_ROOT}/hack/tools/golangci-lint" install github.com/golangci/golangci-lint/v2/cmd/golangci-lint
Copy link
Member

Choose a reason for hiding this comment

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

we already have a dummy go.work checked in for hack/tools/go.work that meant we didn't need to do GOWORK=off before ... I'm not 100% sure why we needed to do that ... is there any other reason to add a peer hack/tools/golangci-lint/go.work? I think it would let us drop this disable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That also works. Changed.

checks:
- "all"
{{- if .Base }}
- "-QF1001" # Apply De Morgan’s law
Copy link
Member

Choose a reason for hiding this comment

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

are all these exclusions for checks that are new in v2, or did we start running entire linters we weren't running before? I'm surprised we have to exclude so many individual new checks

Copy link
Contributor

@mmorel-35 mmorel-35 Apr 30, 2025

Choose a reason for hiding this comment

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

To my understanding gosimple and stylecheck have been merged into staticcheck and staticcheck is the only one left available in golangci-lint.

# The default is relative to the configuration, which is confusing because
# then all paths start with ../ to move out of the "hack" directory.
# `gomod` mirrors the current behavior of `golangci-lint.sh` changing into
# the root.
Copy link
Member

Choose a reason for hiding this comment

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

... changing into the root

the root of k8s.io/kubernetes or of the module being evaluated (when we evaluate stuff under staging/src/k8s.io/*?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed:

# `gomod` mirrors the current behavior of `golangci-lint.sh` changing into
# the root of the repository. Because we are operating in a workspace,
# the module picked by `gomod` is the main one.

Copy link
Member

Choose a reason for hiding this comment

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

It's tricky to understand how stuff in the old config translated to the new one. Was the v2 config auto-generated with https://golangci-lint.run/product/migration-guide/ or done by hand?

Is there a way to see which changes were mechanical v1 → v2 translations and which were intentional changes from how we configured v1 to behave?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think @mmorel-35 started by converting automatically because the initial commit in #131113 also included some re-ordering.

But some things are necessarily manual. I think we tried to stick as closely as possible to the original configuration, except for a few points where some cleanup was possible because something was obsolete (for example, a suppression because of a bug in the Ginkgo linter which had been fixed already long ago).

The important part is that the current code passes the base configuration. Not much had to be changed in the code to achieve that. If we find that the new configuration is too strong (whether its the base configuration or for hints), then we can always refine it in the future.

Copy link

Choose a reason for hiding this comment

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

The re-ordering is not related to automatic conversion, because the order is not the order produced by the automatic conversion.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not anymore, because at some point I asked @mmorel-35 to restore the original order.

@mmorel-35: did you initially convert automatically?

Copy link
Contributor

Choose a reason for hiding this comment

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

I started with golangci-lint migrate and then align with existing config to ease review (restore comments, quoting, spacing...)

@haircommander
Copy link
Contributor

/cc

@haircommander haircommander moved this from Triage to PRs - Needs Reviewer in SIG Node CI/Test Board Apr 30, 2025
- float-compare
- formatter
- len
- useless-assert
Copy link
Contributor

Choose a reason for hiding this comment

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

Those rules are new or updated to discover more cases in testifylint and needs to be disabled so the base is still passing

mmorel-35 and others added 2 commits May 2, 2025 12:51
Passing a constant value to gomega.Consistently means that it will not re-check
while running.

Found by linter after removing the suppression rule for the check. It was
disabled earlier because of a bug in the linter.
@pohly pohly force-pushed the golangci-lint@v2 branch from 9b6a16a to 2e3e9f4 Compare May 2, 2025 10:51
@pohly
Copy link
Contributor Author

pohly commented May 2, 2025

/test pull-kubernetes-integration

TestVolumeBindingRescheduling timeout

pohly added 2 commits May 2, 2025 14:38
This finishes the work started in
kubernetes#131113.

Changes:
- Remove TODOs for things that we don't have plans to fix.
- Add issue for older TODO.
- Reorganize and remove suppression rules so that the base check
  has no unused rules.
- Document warn-unused, but don't enable it.
- Remove disabling of statistics (they are useful) and ensure that
  they don't get the ERROR prefix.
- Avoid ../ prefix in paths via `run.relative-path-mode: gomod`.
The advantage is that it separates the dependencies of the different tools
better. golangci-lint in particular has many dependencies and is sometimes
sensitive to the exact version being used. This way, "go get" bumps up
dependencies exactly as defined by the upstream golangci-lint module.

It's not quite self-contained because logcheck as a Go plugin for golangci-lint
must be built from the same dependencies. But it only adds one and does not
change any of the others.

While at it, the Go 1.24 "tools" directive gets used instead of the traditional
tools.go approach.
@pohly pohly force-pushed the golangci-lint@v2 branch from 2e3e9f4 to 0faeb5a Compare May 2, 2025 12:38
@liggitt
Copy link
Member

liggitt commented May 3, 2025

cc @kubernetes/sig-api-machinery-bugs
unit test flake:

k8s.io/apiserver/pkg/admission/plugin/policy/validating
{Failed  === RUN   TestParamRef/ParamRefWithNameWithNamespaceAllowNotFound

/retest
/lgtm
/approve

@k8s-ci-robot k8s-ci-robot added kind/bug Categorizes issue or PR as related to a bug. lgtm "Looks good to me", indicates that a PR is ready to be merged. labels May 3, 2025
@k8s-ci-robot
Copy link
Contributor

LGTM label has been added.

Git tree hash: 6c2f07f71e15663eb30eb985328b09a0756aec61

@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: BenTheElder, liggitt, pohly

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label May 3, 2025
@k8s-ci-robot k8s-ci-robot merged commit 0b81338 into kubernetes:master May 3, 2025
16 checks passed
@k8s-ci-robot k8s-ci-robot added this to the v1.34 milestone May 3, 2025
@github-project-automation github-project-automation bot moved this from PRs - Needs Reviewer to Done in SIG Node CI/Test Board May 3, 2025
@github-project-automation github-project-automation bot moved this from Needs Triage to Done in SIG Apps May 3, 2025
@github-project-automation github-project-automation bot moved this from Needs Triage to Closed / Done in SIG Auth May 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. area/code-generation area/dependency Issues or PRs related to dependency changes area/kube-proxy area/kubelet area/test cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API kind/bug Categorizes issue or PR as related to a bug. kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. lgtm "Looks good to me", indicates that a PR is ready to be merged. needs-priority Indicates a PR lacks a `priority/foo` label and requires one. release-note-none Denotes a PR that doesn't merit a release note. sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. sig/apps Categorizes an issue or PR as relevant to SIG Apps. sig/auth Categorizes an issue or PR as relevant to SIG Auth. sig/network Categorizes an issue or PR as relevant to SIG Network. sig/node Categorizes an issue or PR as relevant to SIG Node. sig/storage Categorizes an issue or PR as relevant to SIG Storage. sig/testing Categorizes an issue or PR as relevant to SIG Testing. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. triage/accepted Indicates an issue or PR is ready to be actively worked on.
Projects
Status: Done
Status: Closed / Done
Development

Successfully merging this pull request may close these issues.

8 participants