Skip to content

Commit be027e2

Browse files
committed
Go: Emit diagnostic for invalid toolchain versions
1 parent 3649af3 commit be027e2

File tree

3 files changed

+36
-9
lines changed

3 files changed

+36
-9
lines changed

go/extractor/cli/go-autobuilder/go-autobuilder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ func installDependencies(workspace project.GoWorkspace) {
475475
} else {
476476
if workspace.Modules == nil {
477477
project.InitGoModForLegacyProject(workspace.BaseDir)
478-
workspace.Modules = project.LoadGoModules([]string{filepath.Join(workspace.BaseDir, "go.mod")})
478+
workspace.Modules = project.LoadGoModules(true, []string{filepath.Join(workspace.BaseDir, "go.mod")})
479479
}
480480

481481
// get dependencies for all modules

go/extractor/diagnostics/diagnostics.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,3 +508,18 @@ func EmitExtractionFailedForProjects(path []string) {
508508
noLocation,
509509
)
510510
}
511+
512+
func EmitInvalidToolchainVersion(goModPath string, version string) {
513+
emitDiagnostic(
514+
"go/autobuilder/invalid-go-toolchain-version",
515+
fmt.Sprintf("`%s` is not a valid Go toolchain version", version),
516+
strings.Join([]string{
517+
"As of Go 1.21, toolchain versions [must use the 1.N.P syntax](https://tip.golang.org/doc/toolchain#version).",
518+
fmt.Sprintf("`%s` in `%s` does not match this syntax and there is no additional `toolchain` directive, which may cause some `go` commands to fail.", version, goModPath),
519+
},
520+
"\n\n"),
521+
severityWarning,
522+
fullVisibility,
523+
&locationStruct{File: goModPath},
524+
)
525+
}

go/extractor/project/project.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,13 @@ func findGoModFiles(root string) []string {
176176
return util.FindAllFilesWithName(root, "go.mod", "vendor")
177177
}
178178

179+
// A regular expression for the Go toolchain version syntax.
180+
var toolchainVersionRe *regexp.Regexp = regexp.MustCompile(`(?m)^([0-9]+\.[0-9]+\.[0-9]+)$`)
181+
179182
// Given a list of `go.mod` file paths, try to parse them all. The resulting array of `GoModule` objects
180183
// will be the same length as the input array and the objects will contain at least the `go.mod` path.
181184
// If parsing the corresponding file is successful, then the parsed contents will also be available.
182-
func LoadGoModules(goModFilePaths []string) []*GoModule {
185+
func LoadGoModules(emitDiagnostics bool, goModFilePaths []string) []*GoModule {
183186
results := make([]*GoModule, len(goModFilePaths))
184187

185188
for i, goModFilePath := range goModFilePaths {
@@ -201,6 +204,15 @@ func LoadGoModules(goModFilePaths []string) []*GoModule {
201204
}
202205

203206
results[i].Module = modFile
207+
208+
// If this `go.mod` file specifies a Go language version, that version is `1.21` or greater, and
209+
// there is no `toolchain` directive, check that it is a valid Go toolchain version. Otherwise,
210+
// `go` commands which try to download the right version of the Go toolchain will fail. We detect
211+
// this situation and emit a diagnostic.
212+
if modFile.Toolchain == nil && modFile.Go != nil &&
213+
!toolchainVersionRe.Match([]byte(modFile.Go.Version)) && semver.Compare("v"+modFile.Go.Version, "v1.21.0") >= 0 {
214+
diagnostics.EmitInvalidToolchainVersion(goModFilePath, modFile.Go.Version)
215+
}
204216
}
205217

206218
return results
@@ -209,7 +221,7 @@ func LoadGoModules(goModFilePaths []string) []*GoModule {
209221
// Given a path to a `go.work` file, this function attempts to parse the `go.work` file. If unsuccessful,
210222
// we attempt to discover `go.mod` files within subdirectories of the directory containing the `go.work`
211223
// file ourselves.
212-
func discoverWorkspace(workFilePath string) GoWorkspace {
224+
func discoverWorkspace(emitDiagnostics bool, workFilePath string) GoWorkspace {
213225
log.Printf("Loading %s...\n", workFilePath)
214226
baseDir := filepath.Dir(workFilePath)
215227
workFileSrc, err := os.ReadFile(workFilePath)
@@ -223,7 +235,7 @@ func discoverWorkspace(workFilePath string) GoWorkspace {
223235

224236
return GoWorkspace{
225237
BaseDir: baseDir,
226-
Modules: LoadGoModules(goModFilePaths),
238+
Modules: LoadGoModules(emitDiagnostics, goModFilePaths),
227239
DepMode: GoGetWithModules,
228240
ModMode: getModMode(GoGetWithModules, baseDir),
229241
}
@@ -240,7 +252,7 @@ func discoverWorkspace(workFilePath string) GoWorkspace {
240252

241253
return GoWorkspace{
242254
BaseDir: baseDir,
243-
Modules: LoadGoModules(goModFilePaths),
255+
Modules: LoadGoModules(emitDiagnostics, goModFilePaths),
244256
DepMode: GoGetWithModules,
245257
ModMode: getModMode(GoGetWithModules, baseDir),
246258
}
@@ -263,7 +275,7 @@ func discoverWorkspace(workFilePath string) GoWorkspace {
263275
return GoWorkspace{
264276
BaseDir: baseDir,
265277
WorkspaceFile: workFile,
266-
Modules: LoadGoModules(goModFilePaths),
278+
Modules: LoadGoModules(emitDiagnostics, goModFilePaths),
267279
DepMode: GoGetWithModules,
268280
ModMode: ModReadonly, // Workspaces only support "readonly"
269281
}
@@ -286,7 +298,7 @@ func discoverWorkspaces(emitDiagnostics bool) []GoWorkspace {
286298
for i, goModFile := range goModFiles {
287299
results[i] = GoWorkspace{
288300
BaseDir: filepath.Dir(goModFile),
289-
Modules: LoadGoModules([]string{goModFile}),
301+
Modules: LoadGoModules(emitDiagnostics, []string{goModFile}),
290302
DepMode: GoGetWithModules,
291303
ModMode: getModMode(GoGetWithModules, filepath.Dir(goModFile)),
292304
}
@@ -303,7 +315,7 @@ func discoverWorkspaces(emitDiagnostics bool) []GoWorkspace {
303315

304316
results := make([]GoWorkspace, len(goWorkFiles))
305317
for i, workFilePath := range goWorkFiles {
306-
results[i] = discoverWorkspace(workFilePath)
318+
results[i] = discoverWorkspace(emitDiagnostics, workFilePath)
307319
}
308320

309321
// Add all stray `go.mod` files (i.e. those not referenced by `go.work` files)
@@ -335,7 +347,7 @@ func discoverWorkspaces(emitDiagnostics bool) []GoWorkspace {
335347
log.Printf("Module %s is not referenced by any go.work file; adding it separately.\n", goModFile)
336348
results = append(results, GoWorkspace{
337349
BaseDir: filepath.Dir(goModFile),
338-
Modules: LoadGoModules([]string{goModFile}),
350+
Modules: LoadGoModules(emitDiagnostics, []string{goModFile}),
339351
DepMode: GoGetWithModules,
340352
ModMode: getModMode(GoGetWithModules, filepath.Dir(goModFile)),
341353
})

0 commit comments

Comments
 (0)