Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Go: Use toolchain directives for version selection if available, and add tests (v2) #16703

Merged
merged 5 commits into from
Jun 10, 2024
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions go/extractor/project/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ type GoModule struct {
Module *modfile.File // The parsed contents of the `go.mod` file
}

// Tries to find the Go toolchain version required for this module.
func (module *GoModule) RequiredGoVersion() util.SemVer {
if module.Module != nil && module.Module.Toolchain != nil {
return util.NewSemVer(module.Module.Toolchain.Name)
}
if module.Module != nil && module.Module.Go != nil {
return util.NewSemVer(module.Module.Go.Version)
} else {
return tryReadGoDirective(module.Path)
}
}

// Represents information about a Go project workspace: this may either be a folder containing
// a `go.work` file or a collection of `go.mod` files.
type GoWorkspace struct {
Expand All @@ -54,24 +66,23 @@ type GoVersionInfo = util.SemVer
// 1. The Go version specified in the `go.work` file, if any.
// 2. The greatest Go version specified in any `go.mod` file, if any.
func (workspace *GoWorkspace) RequiredGoVersion() util.SemVer {
if workspace.WorkspaceFile != nil && workspace.WorkspaceFile.Go != nil {
// If we have parsed a `go.work` file, return the version number from it.
// If we have parsed a `go.work` file, we prioritise versions from it over those in individual `go.mod`
// files. We are interested in toolchain versions, so if there is an explicit toolchain declaration in
// a `go.work` file, we use that. Otherwise, we fall back to the language version in the `go.work` file
// and use that as toolchain version. If we didn't parse a `go.work` file, then we try to find the
// greatest version contained in `go.mod` files.
if workspace.WorkspaceFile != nil && workspace.WorkspaceFile.Toolchain != nil {
return util.NewSemVer(workspace.WorkspaceFile.Toolchain.Name)
} else if workspace.WorkspaceFile != nil && workspace.WorkspaceFile.Go != nil {
return util.NewSemVer(workspace.WorkspaceFile.Go.Version)
} else if workspace.Modules != nil && len(workspace.Modules) > 0 {
// Otherwise, if we have `go.work` files, find the greatest Go version in those.
var greatestVersion util.SemVer = nil
for _, module := range workspace.Modules {
if module.Module != nil && module.Module.Go != nil {
// If we have parsed the file, retrieve the version number we have already obtained.
modVersion := util.NewSemVer(module.Module.Go.Version)
if greatestVersion == nil || modVersion.IsNewerThan(greatestVersion) {
greatestVersion = modVersion
}
} else {
modVersion := tryReadGoDirective(module.Path)
if modVersion != nil && (greatestVersion == nil || modVersion.IsNewerThan(greatestVersion)) {
greatestVersion = modVersion
}
modVersion := module.RequiredGoVersion()

if modVersion != nil && (greatestVersion == nil || modVersion.IsNewerThan(greatestVersion)) {
greatestVersion = modVersion
}
}

Expand Down