Repository: golangci/golangci-lint (Go)

Issue:
Can't run against "rc" versions of Go
### Welcome

- [X] Yes, I'm using a binary release within 2 latest major releases. Only such installations are supported.
- [X] Yes, I've searched similar issues on GitHub and didn't find any.
- [X] Yes, I've read the typecheck section of the FAQ (https://golangci-lint.run/usage/faq/#why-do-you-have-typecheck-errors).
- [X] Yes, I've tried with the standalone linter if available (e.g., gocritic, go vet, etc.). (https://golangci-lint.run/usage/linters/)

### Description of the problem

I am trying to convert kubernetes to use go workspaces. To do that I need Go 1.22rc.  Go puts that string in all my go.mod files.  golangci-lint barfs on it.

```
ERRO [runner] Panic: gocritic: package "main" (isInitialPkg: true, needAnalyzeSource: true): invalid minor version part: 22rc1: strconv.Atoi: parsing "22rc1": invalid syntax: goroutine 93540 [running]:
runtime/debug.Stack()
	/home/thockin/sdk/gotip/src/runtime/debug/stack.go:24 +0x5e
github.com/golangci/golangci-lint/pkg/golinters/goanalysis.(*action).analyzeSafe.func1()
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/golinters/goanalysis/runner_action.go:109 +0x277
panic({0x1694260?, 0xc02a325a40?})
	/home/thockin/sdk/gotip/src/runtime/panic.go:770 +0x132
github.com/go-critic/go-critic/linter.(*Context).SetGoVersion(...)
	/home/thockin/go/pkg/mod/github.com/go-critic/go-critic@v0.9.0/linter/linter.go:258
github.com/golangci/golangci-lint/pkg/golinters.(*goCriticWrapper).run(0xc000b19dd0, 0xc01a22f930)
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/golinters/gocritic.go:116 +0x469
github.com/golangci/golangci-lint/pkg/golinters.NewGoCritic.func1(0x16758c0?)
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/golinters/gocritic.go:46 +0x33
github.com/golangci/golangci-lint/pkg/golinters/goanalysis.(*action).analyze(0xc00fa7d8e0)
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/golinters/goanalysis/runner_action.go:195 +0x99a
github.com/golangci/golangci-lint/pkg/golinters/goanalysis.(*action).analyzeSafe.func2()
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/golinters/goanalysis/runner_action.go:113 +0x17
github.com/golangci/golangci-lint/pkg/timeutils.(*Stopwatch).TrackStage(0xc0053ddef0, {0x17f566a, 0x8}, 0xc00bd5cf48)
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/timeutils/stopwatch.go:111 +0x44
github.com/golangci/golangci-lint/pkg/golinters/goanalysis.(*action).analyzeSafe(0xc004011b00?)
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/golinters/goanalysis/runner_action.go:112 +0x7a
github.com/golangci/golangci-lint/pkg/golinters/goanalysis.(*loadingPackage).analyze.func2(0xc00fa7d8e0)
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/golinters/goanalysis/runner_loadingpackage.go:80 +0xa8
created by github.com/golangci/golangci-lint/pkg/golinters/goanalysis.(*loadingPackage).analyze in goroutine 29404
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/golinters/goanalysis/runner_loadingpackage.go:75 +0x205
WARN [runner] Can't run linter goanalysis_metalinter: goanalysis_metalinter: gocritic: package "main" (isInitialPkg: true, needAnalyzeSource: true): invalid minor version part: 22rc1: strconv.Atoi: parsing "22rc1": invalid syntax
ERRO Running error: 1 error occurred:
	* can't run linter goanalysis_metalinter: goanalysis_metalinter: gocritic: package "main" (isInitialPkg: true, needAnalyzeSource: true): invalid minor version part: 22rc1: strconv.Atoi: parsing "22rc1": invalid syntax

```

It looks like it assumes an int, but that isn't a correct assumption.  Running gocritic standalone does not have this problem.


### Version of golangci-lint

<details>

```console
$ golangci-lint --version
golangci-lint has version v1.55.2 built with devel go1.22-46ea4ab5cb Sat Dec 9 21:48:06 2023 +0000 from (unknown, mod sum: "h1:yllEIsSJ7MtlDBwDJ9IMBkyEUz2fYE0b5B8IUgO1oP8=") on (unknown)
```

</details>

### Configuration

<details>

```yaml
linters:
  disable-all: true
  enable:
    - gocritic           
```

</details>

### Go environment

<details>

```console
$ go version && go env
GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/thockin/.cache/go-build'
GOENV='/home/thockin/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/thockin/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/thockin/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go-1.21.3'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go-1.21.3/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.21.3'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/home/thockin/src/k/enhancements/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1927164996=/tmp/go-build -gno-record-gcc-switches'
```

</details>

### Verbose output of running

<details>

```console
$ golangci-lint cache clean
$ golangci-lint run -v --config=./tmpconfig.yaml ./gengo-v2/...  | xclip
INFO [config_reader] Used config file tmpconfig.yaml 
INFO [lintersdb] Active 1 linters: [gocritic]     
INFO [loader] Go packages loading at mode 575 (deps|exports_file|name|types_sizes|compiled_files|imports|files) took 268.23407ms 
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 2.014388ms 
INFO [linters_context/goanalysis] analyzers took 32.059µs with top 10 stages: typecheck: 32.059µs 
ERRO [runner] Panic: gocritic: package "types" (isInitialPkg: true, needAnalyzeSource: true): invalid minor version part: 22rc1: strconv.Atoi: parsing "22rc1": invalid syntax: goroutine 1618 [running]:
runtime/debug.Stack()
	/home/thockin/sdk/gotip/src/runtime/debug/stack.go:24 +0x5e
github.com/golangci/golangci-lint/pkg/golinters/goanalysis.(*action).analyzeSafe.func1()
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/golinters/goanalysis/runner_action.go:109 +0x277
panic({0x1694260?, 0xc0010e5d20?})
	/home/thockin/sdk/gotip/src/runtime/panic.go:770 +0x132
github.com/go-critic/go-critic/linter.(*Context).SetGoVersion(...)
	/home/thockin/go/pkg/mod/github.com/go-critic/go-critic@v0.9.0/linter/linter.go:258
github.com/golangci/golangci-lint/pkg/golinters.(*goCriticWrapper).run(0xc000d4b740, 0xc000ee0a90)
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/golinters/gocritic.go:116 +0x469
github.com/golangci/golangci-lint/pkg/golinters.NewGoCritic.func1(0x16758c0?)
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/golinters/gocritic.go:46 +0x33
github.com/golangci/golangci-lint/pkg/golinters/goanalysis.(*action).analyze(0xc0001a2a88)
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/golinters/goanalysis/runner_action.go:195 +0x99a
github.com/golangci/golangci-lint/pkg/golinters/goanalysis.(*action).analyzeSafe.func2()
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/golinters/goanalysis/runner_action.go:113 +0x17
github.com/golangci/golangci-lint/pkg/timeutils.(*Stopwatch).TrackStage(0xc0004774f0, {0x17f566a, 0x8}, 0xc001f89f48)
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/timeutils/stopwatch.go:111 +0x44
github.com/golangci/golangci-lint/pkg/golinters/goanalysis.(*action).analyzeSafe(0xc001604d80?)
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/golinters/goanalysis/runner_action.go:112 +0x7a
github.com/golangci/golangci-lint/pkg/golinters/goanalysis.(*loadingPackage).analyze.func2(0xc0001a2a88)
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/golinters/goanalysis/runner_loadingpackage.go:80 +0xa8
created by github.com/golangci/golangci-lint/pkg/golinters/goanalysis.(*loadingPackage).analyze in goroutine 645
	/home/thockin/go/pkg/mod/github.com/golangci/golangci-lint@v1.55.2/pkg/golinters/goanalysis/runner_loadingpackage.go:75 +0x205 
WARN [runner] Can't run linter goanalysis_metalinter: goanalysis_metalinter: gocritic: package "types" (isInitialPkg: true, needAnalyzeSource: true): invalid minor version part: 22rc1: strconv.Atoi: parsing "22rc1": invalid syntax 
INFO [runner] processing took 2.866µs with stages: max_same_issues: 418ns, skip_dirs: 372ns, nolint: 302ns, max_from_linter: 226ns, identifier_marker: 169ns, cgo: 135ns, autogenerated_exclude: 133ns, path_prettifier: 132ns, filename_unadjuster: 131ns, path_prefixer: 130ns, exclude-rules: 128ns, source_code: 122ns, skip_files: 119ns, diff: 52ns, fixer: 51ns, exclude: 47ns, path_shortener: 45ns, sort_results: 43ns, severity-rules: 40ns, max_per_file_from_linter: 36ns, uniq_by_line: 35ns 
INFO [runner] linters took 369.512143ms with stages: goanalysis_metalinter: 369.471977ms 
ERRO Running error: 1 error occurred:
	* can't run linter goanalysis_metalinter: goanalysis_metalinter: gocritic: package "types" (isInitialPkg: true, needAnalyzeSource: true): invalid minor version part: 22rc1: strconv.Atoi: parsing "22rc1": invalid syntax
 
INFO Memory: 8 samples, avg is 40.4MB, max is 59.0MB 
INFO Execution took 650.196486ms                  

```

</details>

### A minimal reproducible example or link to a public repository

<details>

```go
$ cat gengo-v2/go.mod 
module k8s.io/gengo/v2

go 1.22rc1
```

</details>

### Validation

- [X] Yes, I've included all information above (version, config, etc.).


Discussion:
related to #4273
I think a bug with [`ParseGoVersion`](https://github.com/go-critic/go-critic/blob/028f0fb622a535749e3c57decb866b8b2057c1fd/linter/go_version.go#L31) of `go-critic`:
This function doesn't support `1.22.0` or `1.22rc1` version.

I will improve our `trimVersion` function to support RC and beta.
Thanks! Is there a schedule for tagged releases? 
My current plan is to wait for the release of go1.22, based on the previous Go release, this should happen in a few weeks (beginning of February).
Any way I can beg for a tag before?  This bug is (partially) preventing
kubernetes from adopting the Go release-candidate in master, so we can get
some soak time before release.

On Sun, Jan 14, 2024 at 3:16 PM Ludovic Fernandez ***@***.***>
wrote:

> My current plan is to wait for the release of go1.22, based on the
> previous Go release, this should happen in a few weeks (beginning of
> February).
>
> —
> Reply to this email directly, view it on GitHub
> <https://github.com/golangci/golangci-lint/issues/4318#issuecomment-1891106596>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/ABKWAVHXHXLENUC7FHK7JYTYORRMRAVCNFSM6AAAAABBZWYBWOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQOJRGEYDMNJZGY>
> .
> You are receiving this because you authored the thread.Message ID:
> ***@***.***>
>

Theoretically, this bug is not directly related to Go1.22 but the current use case is only for Go1.22.

Go1.22 (beta, RC, or GA) is currently not officially supported by golangci-lint.

For now, I detected no breaking changes related to the upgrade to go1.22 but that was not the case with the previous versions of Go (changes inside golangci-lint and linters were required).
I would prefer to not send a wrong signal by creating a release related to a non-supported version of Go by golangci-lint.

Otherwise, if we create a release, we will have to create a minor version (because we already merged non-bugfix PRs), I would prefer this next minor be used to add the support of Go1.22.

As a workaround, you can force the Go version inside the configuration:
```yml
run:
  go: 1.22
```

https://golangci-lint.run/usage/configuration/#run-configuration

Kubernetes uses the "tools pattern" to install golangci-lint, another workaround is to use a commit instead of a tag.




Patch:
diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go
index e30d48e4f10c..4a3c1b4d64f4 100644
--- a/pkg/lint/lintersdb/manager.go
+++ b/pkg/lint/lintersdb/manager.go
@@ -991,7 +991,7 @@ func trimGoVersion(v string) string {
 		return ""
 	}
 
-	exp := regexp.MustCompile(`(\d\.\d+)\.\d+`)
+	exp := regexp.MustCompile(`(\d\.\d+)(?:\.\d+|[a-z]+\d)`)
 
 	if exp.MatchString(v) {
 		return exp.FindStringSubmatch(v)[1]


Test patch:
diff --git a/pkg/lint/lintersdb/manager_test.go b/pkg/lint/lintersdb/manager_test.go
new file mode 100644
index 000000000000..0b05c9ec39d7
--- /dev/null
+++ b/pkg/lint/lintersdb/manager_test.go
@@ -0,0 +1,56 @@
+package lintersdb
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func Test_trimGoVersion(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		version  string
+		expected string
+	}{
+		{
+			desc:     "patched version",
+			version:  "1.22.0",
+			expected: "1.22",
+		},
+		{
+			desc:     "minor version",
+			version:  "1.22",
+			expected: "1.22",
+		},
+		{
+			desc:     "RC version",
+			version:  "1.22rc1",
+			expected: "1.22",
+		},
+		{
+			desc:     "alpha version",
+			version:  "1.22alpha1",
+			expected: "1.22",
+		},
+		{
+			desc:     "beta version",
+			version:  "1.22beta1",
+			expected: "1.22",
+		},
+		{
+			desc:     "semver RC version",
+			version:  "1.22.0-rc1",
+			expected: "1.22",
+		},
+	}
+
+	for _, test := range testCases {
+		test := test
+		t.Run(test.desc, func(t *testing.T) {
+			t.Parallel()
+
+			version := trimGoVersion(test.version)
+			assert.Equal(t, test.expected, version)
+		})
+	}
+}