Compare commits

...

8 Commits

Author SHA1 Message Date
Michael B. Gale
4feb56bc8d Use named return parameters 2023-10-06 11:44:55 +01:00
Michael B. Gale
6729718d23 Allow version suffixes
We allow them, but don't do anything with them yet.
2023-10-06 11:44:54 +01:00
Michael B. Gale
fbbbac017e Fix toolchain regex 2023-10-06 11:44:54 +01:00
Michael B. Gale
19104ff45b Go: Update newer-go-version-needed test
- Use a version that is accepted by Go tooling
- Run is no longer successful with Go 1.21
2023-10-06 11:44:54 +01:00
Michael B. Gale
ed1b1a29de Do not call EmitNewerGoVersionNeeded for v1.21+ 2023-10-06 11:44:54 +01:00
Michael B. Gale
88d5d4cee3 Go: Run go version with GOTOOLCHAIN=local 2023-10-06 11:44:54 +01:00
Michael B. Gale
0ffbd232b5 Go: Find toolchain version in go.mod files 2023-10-06 11:44:51 +01:00
Michael B. Gale
98edaf8ae1 Go: Add GoVersionInfo type
Refactors `tryReadGoDirective` to return this instead of a pair.
This will make it easier to return multiple versions.
2023-10-06 11:44:13 +01:00
4 changed files with 46 additions and 26 deletions

View File

@@ -61,11 +61,19 @@ var goVersion = ""
// Returns the current Go version as returned by 'go version', e.g. go1.14.4
func getEnvGoVersion() string {
if goVersion == "" {
gover, err := exec.Command("go", "version").CombinedOutput()
// Since Go 1.21, running 'go version' in a directory with a 'go.mod' file will attempt to
// download the version of Go specified in there. That may either fail or result in us just
// being told what's already in 'go.mod'. Setting 'GOTOOLCHAIN' to 'local' will force it
// to use the local Go toolchain instead.
cmd := exec.Command("go", "version")
cmd.Env = append(os.Environ(), "GOTOOLCHAIN=local")
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatalf("Unable to run the go command, is it installed?\nError: %s", err.Error())
}
goVersion = parseGoVersion(string(gover))
goVersion = parseGoVersion(string(out))
}
return goVersion
}
@@ -367,23 +375,46 @@ func getDepMode(emitDiagnostics bool) (DependencyInstallerMode, string) {
return GoGetNoModules, "."
}
type GoVersionInfo struct {
// The version string, if any
Version string
// A value indicating whether a version string was found
Found bool
}
// Tries to open `go.mod` and read a go directive, returning the version and whether it was found.
func tryReadGoDirective(buildInfo BuildInfo) (string, bool) {
func tryReadGoDirective(buildInfo BuildInfo) (compilerVersion GoVersionInfo, toolchainVersion GoVersionInfo) {
if buildInfo.DepMode == GoGetWithModules {
versionRe := regexp.MustCompile(`(?m)^go[ \t\r]+([0-9]+\.[0-9]+(\.[0-9]+)?)$`)
versionRe := regexp.MustCompile(`(?m)^go[ \t\r]+([0-9]+\.[0-9]+(\.[0-9]+)?)`)
toolchainRe := regexp.MustCompile(`(?m)^toolchain[ \t\r]+go([0-9]+\.[0-9]+(\.[0-9]+)?)`)
goMod, err := os.ReadFile(filepath.Join(buildInfo.BaseDir, "go.mod"))
if err != nil {
log.Println("Failed to read go.mod to check for missing Go version")
} else {
matches := versionRe.FindSubmatch(goMod)
toolchainMatches := toolchainRe.FindSubmatch(goMod)
if matches != nil {
if len(matches) > 1 {
return string(matches[1]), true
compilerVersion = GoVersionInfo{string(matches[1]), true}
}
}
if toolchainMatches != nil {
if len(toolchainMatches) > 1 {
toolchainVersion = GoVersionInfo{string(toolchainMatches[1]), true}
}
}
}
}
return "", false
// If no `toolchain` directive is specified, Go assumes that its value is the same as that
// specified in a `go` directive
if !toolchainVersion.Found && compilerVersion.Found {
toolchainVersion = compilerVersion
}
return compilerVersion, toolchainVersion
}
// Returns the appropriate ModMode for the current project
@@ -771,13 +802,15 @@ func installDependenciesAndBuild() {
os.Setenv("GO111MODULE", "auto")
}
goModVersion, goModVersionFound := tryReadGoDirective(buildInfo)
goVersionInfo, _ := tryReadGoDirective(buildInfo)
if goModVersionFound && semver.Compare("v"+goModVersion, getEnvGoSemVer()) > 0 {
// This diagnostic is not required if the system Go version is 1.21 or greater, since the
// Go tooling should install required Go versions as needed.
if semver.Compare(getEnvGoSemVer(), "v1.21.0") < 0 && goVersionInfo.Found && semver.Compare("v"+goVersionInfo.Version, getEnvGoSemVer()) > 0 {
diagnostics.EmitNewerGoVersionNeeded()
}
fixGoVendorIssues(&buildInfo, goModVersionFound)
fixGoVendorIssues(&buildInfo, goVersionInfo.Found)
tryUpdateGoModAndGoSum(buildInfo)
@@ -1092,7 +1125,8 @@ func isGoInstalled() bool {
func identifyEnvironment() {
var v versionInfo
buildInfo := getBuildInfo(false)
v.goModVersion, v.goModVersionFound = tryReadGoDirective(buildInfo)
goVersionInfo, _ := tryReadGoDirective(buildInfo)
v.goModVersion, v.goModVersionFound = goVersionInfo.Version, goVersionInfo.Found
v.goEnvVersionFound = isGoInstalled()
if v.goEnvVersionFound {

View File

@@ -12,17 +12,3 @@
"telemetry": true
}
}
{
"markdownMessage": "The detected version of Go is lower than the version specified in `go.mod`. [Install a newer version](https://github.com/actions/setup-go#basic).",
"severity": "error",
"source": {
"extractorName": "go",
"id": "go/autobuilder/newer-go-version-needed",
"name": "Newer Go version needed"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": true,
"telemetry": true
}
}

View File

@@ -4,6 +4,6 @@ from create_database_utils import *
from diagnostics_test_utils import *
os.environ['LGTM_INDEX_IMPORT_PATH'] = "test"
run_codeql_database_create([], lang="go", source="work", db=None)
run_codeql_database_create([], lang="go", source="work", db=None, runFunction=runUnsuccessfully)
check_diagnostics()

View File

@@ -1,3 +1,3 @@
go 999.0
go 1.999.0
module test