golangci-lint/pkg/goutil/version.go
2024-08-27 22:50:05 +02:00

76 lines
1.7 KiB
Go

package goutil
import (
"fmt"
"go/version"
"regexp"
"runtime"
"strings"
hcversion "github.com/hashicorp/go-version"
)
func CheckGoVersion(goVersion string) error {
rv, err := CleanRuntimeVersion()
if err != nil {
return fmt.Errorf("clean runtime version: %w", err)
}
langVersion := version.Lang(rv)
runtimeVersion, err := hcversion.NewVersion(strings.TrimPrefix(langVersion, "go"))
if err != nil {
return err
}
targetedVersion, err := hcversion.NewVersion(TrimGoVersion(goVersion))
if err != nil {
return err
}
if runtimeVersion.LessThan(targetedVersion) {
return fmt.Errorf("the Go language version (%s) used to build golangci-lint is lower than the targeted Go version (%s)",
langVersion, goVersion)
}
return nil
}
// TrimGoVersion Trims the Go version to keep only M.m.
// Since Go 1.21 the version inside the go.mod can be a patched version (ex: 1.21.0).
// The version can also include information which we want to remove (ex: 1.21alpha1)
// https://go.dev/doc/toolchain#versions
// This a problem with staticcheck and gocritic.
func TrimGoVersion(v string) string {
if v == "" {
return ""
}
exp := regexp.MustCompile(`(\d\.\d+)(?:\.\d+|[a-z]+\d)`)
if exp.MatchString(v) {
return exp.FindStringSubmatch(v)[1]
}
return v
}
func CleanRuntimeVersion() (string, error) {
return cleanRuntimeVersion(runtime.Version())
}
func cleanRuntimeVersion(rv string) (string, error) {
parts := strings.Fields(rv)
for _, part := range parts {
// Allow to handle:
// - GOEXPERIMENT -> "go1.23.0 X:boringcrypto"
// - devel -> "devel go1.24-e705a2d Wed Aug 7 01:16:42 2024 +0000 linux/amd64"
if strings.HasPrefix(part, "go1.") {
return part, nil
}
}
return "", fmt.Errorf("invalid Go runtime version: %s", rv)
}