From 76781e5d754bdfeee12b098b6e6f69cdefa8e4bd Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 8 Sep 2023 13:55:35 +0100 Subject: [PATCH 1/4] Go: Add `GoVersionInfo` type Refactors `tryReadGoDirective` to return this instead of a pair. This will make it easier to return multiple versions. --- .../cli/go-autobuilder/go-autobuilder.go | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/go/extractor/cli/go-autobuilder/go-autobuilder.go b/go/extractor/cli/go-autobuilder/go-autobuilder.go index fc309a3d44c..10eda5e5dab 100644 --- a/go/extractor/cli/go-autobuilder/go-autobuilder.go +++ b/go/extractor/cli/go-autobuilder/go-autobuilder.go @@ -367,8 +367,15 @@ 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) GoVersionInfo { if buildInfo.DepMode == GoGetWithModules { versionRe := regexp.MustCompile(`(?m)^go[ \t\r]+([0-9]+\.[0-9]+(\.[0-9]+)?)$`) goMod, err := os.ReadFile(filepath.Join(buildInfo.BaseDir, "go.mod")) @@ -378,12 +385,12 @@ func tryReadGoDirective(buildInfo BuildInfo) (string, bool) { matches := versionRe.FindSubmatch(goMod) if matches != nil { if len(matches) > 1 { - return string(matches[1]), true + return GoVersionInfo{string(matches[1]), true} } } } } - return "", false + return GoVersionInfo{"", false} } // Returns the appropriate ModMode for the current project @@ -771,13 +778,13 @@ func installDependenciesAndBuild() { os.Setenv("GO111MODULE", "auto") } - goModVersion, goModVersionFound := tryReadGoDirective(buildInfo) + goVersionInfo := tryReadGoDirective(buildInfo) - if goModVersionFound && semver.Compare("v"+goModVersion, getEnvGoSemVer()) > 0 { + if goVersionInfo.Found && semver.Compare("v"+goVersionInfo.Version, getEnvGoSemVer()) > 0 { diagnostics.EmitNewerGoVersionNeeded() } - fixGoVendorIssues(&buildInfo, goModVersionFound) + fixGoVendorIssues(&buildInfo, goVersionInfo.Found) tryUpdateGoModAndGoSum(buildInfo) @@ -1092,7 +1099,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 { From c63f6807c41599e0d95860501ead780cfc0a32ac Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Tue, 12 Sep 2023 20:02:35 +0100 Subject: [PATCH 2/4] Go: Run `go version` with `GOTOOLCHAIN=local` --- go/extractor/cli/go-autobuilder/go-autobuilder.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/go/extractor/cli/go-autobuilder/go-autobuilder.go b/go/extractor/cli/go-autobuilder/go-autobuilder.go index 10eda5e5dab..65469432da5 100644 --- a/go/extractor/cli/go-autobuilder/go-autobuilder.go +++ b/go/extractor/cli/go-autobuilder/go-autobuilder.go @@ -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 } From 01a1d814f436f82c0422138bf557db6c3953b6ef Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Tue, 12 Sep 2023 20:13:40 +0100 Subject: [PATCH 3/4] Do not call `EmitNewerGoVersionNeeded` for v1.21+ --- go/extractor/cli/go-autobuilder/go-autobuilder.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/go/extractor/cli/go-autobuilder/go-autobuilder.go b/go/extractor/cli/go-autobuilder/go-autobuilder.go index 65469432da5..1523cdec8f2 100644 --- a/go/extractor/cli/go-autobuilder/go-autobuilder.go +++ b/go/extractor/cli/go-autobuilder/go-autobuilder.go @@ -788,7 +788,9 @@ func installDependenciesAndBuild() { goVersionInfo := tryReadGoDirective(buildInfo) - if goVersionInfo.Found && semver.Compare("v"+goVersionInfo.Version, 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() } From 0b13da35ebfd299df0b51afff1bc6c7c5f5beb34 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Tue, 12 Sep 2023 20:20:55 +0100 Subject: [PATCH 4/4] 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 --- .../newer-go-version-needed/diagnostics.expected | 14 -------------- .../go/diagnostics/newer-go-version-needed/test.py | 2 +- .../newer-go-version-needed/work/go.mod | 2 +- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/go/ql/integration-tests/all-platforms/go/diagnostics/newer-go-version-needed/diagnostics.expected b/go/ql/integration-tests/all-platforms/go/diagnostics/newer-go-version-needed/diagnostics.expected index 1db1354f164..56d774b7037 100644 --- a/go/ql/integration-tests/all-platforms/go/diagnostics/newer-go-version-needed/diagnostics.expected +++ b/go/ql/integration-tests/all-platforms/go/diagnostics/newer-go-version-needed/diagnostics.expected @@ -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 - } -} diff --git a/go/ql/integration-tests/all-platforms/go/diagnostics/newer-go-version-needed/test.py b/go/ql/integration-tests/all-platforms/go/diagnostics/newer-go-version-needed/test.py index 9f34f431b93..2f43492da41 100644 --- a/go/ql/integration-tests/all-platforms/go/diagnostics/newer-go-version-needed/test.py +++ b/go/ql/integration-tests/all-platforms/go/diagnostics/newer-go-version-needed/test.py @@ -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() diff --git a/go/ql/integration-tests/all-platforms/go/diagnostics/newer-go-version-needed/work/go.mod b/go/ql/integration-tests/all-platforms/go/diagnostics/newer-go-version-needed/work/go.mod index 14415aab0a7..b3be9331165 100644 --- a/go/ql/integration-tests/all-platforms/go/diagnostics/newer-go-version-needed/work/go.mod +++ b/go/ql/integration-tests/all-platforms/go/diagnostics/newer-go-version-needed/work/go.mod @@ -1,3 +1,3 @@ -go 999.0 +go 1.999.0 module test