-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Go: Add go-autobuilder --identify-environment
#12957
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: Add go-autobuilder --identify-environment
#12957
Conversation
44396a8
to
c02edb0
Compare
c02edb0
to
0c6efb8
Compare
`%s is a wrapper script that installs dependencies and calls the extractor, or if '--identify-environment' | ||
is passed then it produces a file 'environment.json' which specifies what go version is needed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would probably be nice to format this across multiple lines, something like:
%s is a wrapper script that installs dependencies and calls the extractor
Options:
--identify-environment If this flag is specified, then ...
content = `{ "include": [ { "go": { "version": "` + version + `" } } ] }` | ||
} | ||
|
||
targetFile, err := os.Create("environment.json") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we have talked about, this should probably be a value from an environment variable (with this as a fallback).
|
||
func EmitUnsupportedVersionGoMod(msg string) { | ||
emitDiagnostic( | ||
"go/identify-environment/unsupported-version-in-go-mod", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this should still be go/autobuilder/..
for these diagnostics, since that part of the identifier refers to the tool rather than a particular sub-command.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed it so that go/autobuilder/env-
is a common prefix to all the these new diagnostics.
func EmitVersionGoModNotHigherVersionEnvironment(msg string) { | ||
emitDiagnostic( | ||
"go/identify-environment/version-go-mod-not-higher-than-go-env", | ||
"The Go version in `go.mod` file is not higher than the Go version in environment", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"not higher" is strange wording. Should this be "lower"? Or "not equal to or greater than"?
if v.goDirectiveFound && outsideSupportedRange(v.goModVersion) { | ||
msg = "The version of Go found in the `go.mod` file (" + v.goModVersion + | ||
") is outside of the supported range (" + minGoVersion + "-" + maxGoVersion + ")." | ||
version = "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be better to return nil
instead of an empty string if these functions cannot determine which go version to install? And have msg
as an error
rather than a string
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the nil
idea but strings can't be nil
in go. I have effectively given the empty string a special meaning, and I've been careful to always assign a value to version
even when I could leave it as the default value so that it's easier to spot any places where it hasn't been considered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think msg
should be an error
because then people will assume that it's only non-nil
if something has gone wrong, whereas it's actually non-nil
on every path through the code.
func getVersionToInstall(v versionInfo) (msg, version string) { | ||
msg, version = checkForUnsupportedVersions(v) | ||
if msg != "" { | ||
return msg, version | ||
} | ||
|
||
msg, version = checkForVersionsNotFound(v) | ||
if msg != "" { | ||
return msg, version | ||
} | ||
|
||
msg, version = compareVersions(v) | ||
return msg, version | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic implemented in these functions is relatively complicated and tricky to follow / it is easy to miss corner cases. Once tests are added, those will increase confidence, but it would also be good to add documentation and more explicitly document assumptions/invariants throughout these functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add docstrings to the functions. (With a lot of help from Copilot 😄 .)
func checkForVersionsNotFound(v versionInfo) (msg, version string) { | ||
if !v.goInstallationFound && !v.goDirectiveFound { | ||
msg = "No version of Go installed and no `go.mod` file found. Writing an " + | ||
"`environment.json` file specifying the maximum supported version of Go (" + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For all the occurrences of environment.json
here, you can probably use a generic name here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me for now
Step 1 of https://github.com/github/codeql-go-team/issues/329.
Integration tests look tricky. I will instead use unit tests in
ql/go/extractor/cli/go-autobuilder/go-autobuilder_test.go
and some manual end-to-end testing. Once other languages have also implemented this flag we can set up everything up to make integration testing possible.