mirror of
https://github.com/github/codeql.git
synced 2026-05-05 21:55:19 +02:00
Fix behaviour for single non-root go.mod
Also add telemetry so we can prioritise future work on the autobuilder.
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/mod/semver"
|
||||
@@ -240,28 +241,109 @@ func getSourceDir() string {
|
||||
return srcdir
|
||||
}
|
||||
|
||||
func getDirs(paths []string) []string {
|
||||
dirs := make([]string, len(paths))
|
||||
for i, path := range paths {
|
||||
dirs[i] = filepath.Dir(path)
|
||||
}
|
||||
return dirs
|
||||
}
|
||||
|
||||
// Note this has the side effect of sorting `dirs`
|
||||
func checkDirsNested(dirs []string) bool {
|
||||
// the paths were generated by a depth-first search so I think they might
|
||||
// be sorted, but we sort them just in case
|
||||
sort.Strings(dirs)
|
||||
for _, dir := range dirs {
|
||||
if !strings.HasPrefix(dir, dirs[0]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func findGoModFiles(emitDiagnostics bool) (string, bool) {
|
||||
goModPaths := util.FindAllFilesWithName(".", "go.mod", "vendor")
|
||||
if len(goModPaths) == 0 {
|
||||
// preserve current behaviour
|
||||
return ".", false
|
||||
}
|
||||
goModDirs := getDirs(goModPaths)
|
||||
if util.AnyGoFilesOutsideDirs(".", goModDirs...) {
|
||||
if emitDiagnostics {
|
||||
diagnostics.EmitGoFilesOutsideGoModules(goModPaths)
|
||||
}
|
||||
// preserve current behaviour
|
||||
return ".", true
|
||||
}
|
||||
if len(goModPaths) > 1 {
|
||||
// currently not supported
|
||||
if emitDiagnostics {
|
||||
if checkDirsNested(goModDirs) {
|
||||
diagnostics.EmitMultipleGoModFoundNested(goModPaths)
|
||||
} else {
|
||||
diagnostics.EmitMultipleGoModFoundNotNested(goModPaths)
|
||||
}
|
||||
}
|
||||
// preserve current behaviour
|
||||
return ".", true
|
||||
}
|
||||
if emitDiagnostics {
|
||||
if goModDirs[0] == "." {
|
||||
diagnostics.EmitSingleRootGoModFound(goModPaths[0])
|
||||
} else {
|
||||
diagnostics.EmitSingleNonRootGoModFound(goModPaths[0])
|
||||
}
|
||||
}
|
||||
return goModDirs[0], true
|
||||
}
|
||||
|
||||
// Returns the appropriate DependencyInstallerMode for the current project
|
||||
func getDepMode() DependencyInstallerMode {
|
||||
if util.FileExists("go.mod") {
|
||||
func getDepMode(emitDiagnostics bool) (DependencyInstallerMode, string) {
|
||||
if util.FileExists("BUILD") {
|
||||
// currently not supported
|
||||
if emitDiagnostics {
|
||||
diagnostics.EmitBazelBuildFileFound()
|
||||
}
|
||||
}
|
||||
|
||||
goWorkPaths := util.FindAllFilesWithName(".", "go.work", "vendor")
|
||||
if len(goWorkPaths) > 0 {
|
||||
// currently not supported
|
||||
if emitDiagnostics {
|
||||
diagnostics.EmitGoWorkFound(goWorkPaths)
|
||||
}
|
||||
}
|
||||
|
||||
baseDir, goModFound := findGoModFiles(emitDiagnostics)
|
||||
if goModFound {
|
||||
log.Println("Found go.mod, enabling go modules")
|
||||
return GoGetWithModules
|
||||
return GoGetWithModules, baseDir
|
||||
}
|
||||
|
||||
if util.FileExists("Gopkg.toml") {
|
||||
if emitDiagnostics {
|
||||
diagnostics.EmitGopkgTomlFound()
|
||||
}
|
||||
log.Println("Found Gopkg.toml, using dep instead of go get")
|
||||
return Dep
|
||||
return Dep, "."
|
||||
}
|
||||
|
||||
if util.FileExists("glide.yaml") {
|
||||
if emitDiagnostics {
|
||||
diagnostics.EmitGlideYamlFound()
|
||||
}
|
||||
log.Println("Found glide.yaml, using Glide instead of go get")
|
||||
return Glide
|
||||
return Glide, "."
|
||||
}
|
||||
return GoGetNoModules
|
||||
return GoGetNoModules, "."
|
||||
}
|
||||
|
||||
// Tries to open `go.mod` and read a go directive, returning the version and whether it was found.
|
||||
func tryReadGoDirective(depMode DependencyInstallerMode) (string, bool) {
|
||||
func tryReadGoDirective(depMode DependencyInstallerMode, baseDir string) (string, bool) {
|
||||
if depMode == GoGetWithModules {
|
||||
versionRe := regexp.MustCompile(`(?m)^go[ \t\r]+([0-9]+\.[0-9]+)$`)
|
||||
goMod, err := os.ReadFile("go.mod")
|
||||
goMod, err := os.ReadFile(filepath.Join(baseDir, "go.mod"))
|
||||
if err != nil {
|
||||
log.Println("Failed to read go.mod to check for missing Go version")
|
||||
} else {
|
||||
@@ -277,13 +359,13 @@ func tryReadGoDirective(depMode DependencyInstallerMode) (string, bool) {
|
||||
}
|
||||
|
||||
// Returns the appropriate ModMode for the current project
|
||||
func getModMode(depMode DependencyInstallerMode) ModMode {
|
||||
func getModMode(depMode DependencyInstallerMode, baseDir string) ModMode {
|
||||
if depMode == GoGetWithModules {
|
||||
// if a vendor/modules.txt file exists, we assume that there are vendored Go dependencies, and
|
||||
// skip the dependency installation step and run the extractor with `-mod=vendor`
|
||||
if util.FileExists("vendor/modules.txt") {
|
||||
if util.FileExists(baseDir + "/vendor/modules.txt") {
|
||||
return ModVendor
|
||||
} else if util.DirExists("vendor") {
|
||||
} else if util.DirExists(baseDir + "/vendor") {
|
||||
return ModMod
|
||||
}
|
||||
}
|
||||
@@ -344,25 +426,29 @@ func getNeedGopath(depMode DependencyInstallerMode, importpath string) bool {
|
||||
}
|
||||
|
||||
// Try to update `go.mod` and `go.sum` if the go version is >= 1.16.
|
||||
func tryUpdateGoModAndGoSum(modMode ModMode, depMode DependencyInstallerMode) {
|
||||
func tryUpdateGoModAndGoSum(modMode ModMode, depMode DependencyInstallerMode, baseDir string) {
|
||||
// Go 1.16 and later won't automatically attempt to update go.mod / go.sum during package loading, so try to update them here:
|
||||
if modMode != ModVendor && depMode == GoGetWithModules && semver.Compare(getEnvGoSemVer(), "v1.16") >= 0 {
|
||||
// stat go.mod and go.sum
|
||||
beforeGoModFileInfo, beforeGoModErr := os.Stat("go.mod")
|
||||
goModPath := filepath.Join(baseDir, "go.mod")
|
||||
beforeGoModFileInfo, beforeGoModErr := os.Stat(goModPath)
|
||||
if beforeGoModErr != nil {
|
||||
log.Println("Failed to stat go.mod before running `go mod tidy -e`")
|
||||
}
|
||||
|
||||
beforeGoSumFileInfo, beforeGoSumErr := os.Stat("go.sum")
|
||||
goSumPath := filepath.Join(baseDir, "go.sum")
|
||||
beforeGoSumFileInfo, beforeGoSumErr := os.Stat(goSumPath)
|
||||
|
||||
// run `go mod tidy -e`
|
||||
res := util.RunCmd(exec.Command("go", "mod", "tidy", "-e"))
|
||||
cmd := exec.Command("go", "mod", "tidy", "-e")
|
||||
cmd.Dir = baseDir
|
||||
res := util.RunCmd(cmd)
|
||||
|
||||
if !res {
|
||||
log.Println("Failed to run `go mod tidy -e`")
|
||||
} else {
|
||||
if beforeGoModFileInfo != nil {
|
||||
afterGoModFileInfo, afterGoModErr := os.Stat("go.mod")
|
||||
afterGoModFileInfo, afterGoModErr := os.Stat(goModPath)
|
||||
if afterGoModErr != nil {
|
||||
log.Println("Failed to stat go.mod after running `go mod tidy -e`")
|
||||
} else if afterGoModFileInfo.ModTime().After(beforeGoModFileInfo.ModTime()) {
|
||||
@@ -371,7 +457,7 @@ func tryUpdateGoModAndGoSum(modMode ModMode, depMode DependencyInstallerMode) {
|
||||
}
|
||||
}
|
||||
|
||||
afterGoSumFileInfo, afterGoSumErr := os.Stat("go.sum")
|
||||
afterGoSumFileInfo, afterGoSumErr := os.Stat(goSumPath)
|
||||
if afterGoSumErr != nil {
|
||||
log.Println("Failed to stat go.sum after running `go mod tidy -e`")
|
||||
} else {
|
||||
@@ -560,7 +646,7 @@ func buildWithCustomCommands(inst string) {
|
||||
}
|
||||
|
||||
// Install dependencies using the given dependency installer mode.
|
||||
func installDependencies(depMode DependencyInstallerMode) {
|
||||
func installDependencies(depMode DependencyInstallerMode, baseDir string) {
|
||||
// automatically determine command to install dependencies
|
||||
var install *exec.Cmd
|
||||
if depMode == Dep {
|
||||
@@ -606,31 +692,28 @@ func installDependencies(depMode DependencyInstallerMode) {
|
||||
|
||||
// get dependencies
|
||||
install = exec.Command("go", "get", "-v", "./...")
|
||||
log.Println("Installing dependencies using `go get -v ./...`.")
|
||||
install.Dir = baseDir
|
||||
log.Printf("Installing dependencies using `go get -v ./...` in `%s`.\n", baseDir)
|
||||
}
|
||||
util.RunCmd(install)
|
||||
}
|
||||
|
||||
// Run the extractor.
|
||||
func extract(depMode DependencyInstallerMode, modMode ModMode) {
|
||||
func extract(depMode DependencyInstallerMode, modMode ModMode, baseDir string) {
|
||||
extractor, err := util.GetExtractorPath()
|
||||
if err != nil {
|
||||
log.Fatalf("Could not determine path of extractor: %v.\n", err)
|
||||
}
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to determine current directory: %s\n", err.Error())
|
||||
}
|
||||
|
||||
extractorArgs := []string{}
|
||||
if depMode == GoGetWithModules {
|
||||
extractorArgs = append(extractorArgs, modMode.argsForGoVersion(getEnvGoSemVer())...)
|
||||
}
|
||||
extractorArgs = append(extractorArgs, "./...")
|
||||
|
||||
log.Printf("Running extractor command '%s %v' from directory '%s'.\n", extractor, extractorArgs, cwd)
|
||||
log.Printf("Running extractor command '%s %v' from directory '%s'.\n", extractor, extractorArgs, baseDir)
|
||||
cmd := exec.Command(extractor, extractorArgs...)
|
||||
cmd.Dir = baseDir
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err = cmd.Run()
|
||||
@@ -650,21 +733,21 @@ func installDependenciesAndBuild() {
|
||||
|
||||
// determine how to install dependencies and whether a GOPATH needs to be set up before
|
||||
// extraction
|
||||
depMode := getDepMode()
|
||||
depMode, baseDir := getDepMode(true)
|
||||
if _, present := os.LookupEnv("GO111MODULE"); !present {
|
||||
os.Setenv("GO111MODULE", "auto")
|
||||
}
|
||||
|
||||
goModVersion, goModVersionFound := tryReadGoDirective(depMode)
|
||||
goModVersion, goModVersionFound := tryReadGoDirective(depMode, baseDir)
|
||||
|
||||
if semver.Compare("v"+goModVersion, getEnvGoSemVer()) >= 0 {
|
||||
diagnostics.EmitNewerGoVersionNeeded()
|
||||
}
|
||||
|
||||
modMode := getModMode(depMode)
|
||||
modMode := getModMode(depMode, baseDir)
|
||||
modMode = fixGoVendorIssues(modMode, depMode, goModVersionFound)
|
||||
|
||||
tryUpdateGoModAndGoSum(modMode, depMode)
|
||||
tryUpdateGoModAndGoSum(modMode, depMode, baseDir)
|
||||
|
||||
importpath := getImportPath()
|
||||
needGopath := getNeedGopath(depMode, importpath)
|
||||
@@ -707,11 +790,11 @@ func installDependenciesAndBuild() {
|
||||
if modMode == ModVendor {
|
||||
log.Printf("Skipping dependency installation because a Go vendor directory was found.")
|
||||
} else {
|
||||
installDependencies(depMode)
|
||||
installDependencies(depMode, baseDir)
|
||||
}
|
||||
}
|
||||
|
||||
extract(depMode, modMode)
|
||||
extract(depMode, modMode, baseDir)
|
||||
}
|
||||
|
||||
const minGoVersion = "1.11"
|
||||
@@ -976,8 +1059,8 @@ func isGoInstalled() bool {
|
||||
// Get the version of Go to install and output it to stdout as json.
|
||||
func identifyEnvironment() {
|
||||
var v versionInfo
|
||||
depMode := getDepMode()
|
||||
v.goModVersion, v.goModVersionFound = tryReadGoDirective(depMode)
|
||||
depMode, baseDir := getDepMode(false)
|
||||
v.goModVersion, v.goModVersionFound = tryReadGoDirective(depMode, baseDir)
|
||||
|
||||
v.goEnvVersionFound = isGoInstalled()
|
||||
if v.goEnvVersionFound {
|
||||
|
||||
Reference in New Issue
Block a user