How go-modern-guidelines Detects the Go Version Without Flags or File Paths
When invoked without explicit inputs, the go-modern-guidelines CLI automatically queries the local Go toolchain via go env GOVERSION, normalizes the output to a major.minor format, and uses that value to filter applicable coding guidelines.
The JetBrains/go-modern-guidelines tool analyzes Go source code against modern best practices, but it requires a target Go version to determine which rules apply. When you run the list command without specifying --go-version or --file-path, the CLI implements a sophisticated fallback chain that interrogates your local Go installation directly.
The Auto-Detection Pipeline
The detection mechanism spans three logical layers: the command parser, the resolution engine, and the toolchain interface. This ensures that even in bare invocations, the linter evaluates code against the correct Go version constraints.
Entry Point in the CLI Layer
The process begins in internal/cli/cli.go within the runList function. This handler parses your command-line arguments and immediately delegates version resolution to the goversion package:
targetVersion, err := goversion.Resolve(filePath, goVersion, guidelines.LatestKnownVersion())
If both filePath and goVersion are empty strings—meaning you provided no --file-path or --go-version flags—the Resolve function triggers the automatic detection sequence rather than returning an error.
Resolution Logic in the goversion Package
Located in internal/goversion/goversion.go, the Resolve function implements a priority-based fallback strategy:
- Check for explicit version via
--go-versionflag - Check for module file via
--file-pathargument - Fallback to local Go toolchain execution
When both inputs are empty, the function calls resolveGoToolVersion with a descriptive label and the latest known guideline version as a safety bound:
return resolveGoToolVersion("local Go toolchain", develVersion)
Executing the Toolchain Query
The resolveGoToolVersion function executes an external process call to extract the Go version from your environment:
output, err := exec.Command("go", "env", "GOVERSION").Output()
version, err := normalizeGoVersion(string(output), develVersion)
This spawns go env GOVERSION, which returns the exact version string of the Go binary currently in your PATH (e.g., go1.22.3). The function captures stdout and passes it to the normalization routine to ensure consistent formatting.
Normalizing the Version String
Raw toolchain output varies by installation (some distributions append build metadata or release candidates). The normalizeGoVersion function in internal/goversion/goversion.go sanitizes this using regex matching:
match := goVersionInText.FindStringSubmatch(trimmed)
return fmt.Sprintf("%d.%d", majorMinor.major, majorMinor.minor), nil
This reduces strings like go1.22.3 or 1.22rc1 to the canonical major.minor format (e.g., 1.22) required by the guideline matrix. The CLI then compares this normalized version against its internal database of modern Go recommendations to determine which rules to display or enforce.
Why Runtime Detection Over Build-Time
The go-modern-guidelines binary also defines a detectedVersion() function that reads debug.ReadBuildInfo to determine which Go version compiled the linter itself. However, the list command deliberately ignores this build-time constant.
Runtime detection via go env GOVERSION ensures the linter evaluates your source code against the Go version you use to build that code, not the version used to build the linter. This distinction matters in CI/CD environments where the linter binary might be compiled with Go 1.21 but is analyzing code intended for Go 1.22 deployment.
Practical Usage Examples
Automatic Detection (No Flags)
go-modern-guidelines list
The CLI invokes go env GOVERSION, extracts the local toolchain version (e.g., 1.22), and displays guidelines applicable to that release.
Explicit Version Override
go-modern-guidelines list --go-version 1.20
Bypasses auto-detection entirely; the specified version is normalized and used directly.
Module File Override
go-modern-guidelines list --file-path ./go.mod
The CLI parses the go directive within the specified go.mod file, taking precedence over the local toolchain query.
Summary
- The
runListfunction ininternal/cli/cli.gocallsgoversion.Resolveto determine the target Go version. - When no flags are provided,
Resolvefalls back toresolveGoToolVersion, which executesgo env GOVERSION. - The
normalizeGoVersionfunction converts the raw toolchain output (e.g.,go1.22.3) into a standardizedmajor.minorstring. - Auto-detection uses the runtime Go toolchain rather than the linter's build-time version to ensure accurate guideline matching for the code being analyzed.
Frequently Asked Questions
What happens if the go command is not in my PATH when I run go-modern-guidelines?
If the CLI cannot locate the go binary to execute go env GOVERSION, the resolveGoToolVersion function returns an error and the command fails. You must either add Go to your PATH or use the --go-version flag to specify the version manually.
Can I force the CLI to use a different Go version than the one in my PATH?
Yes. Providing either --go-version or --file-path overrides the automatic detection entirely. The CLI does not execute go env GOVERSION when an explicit version source is provided.
Why does the CLI report a different version than go version shows?
The CLI normalizes full version strings (e.g., go1.22.3) to their major.minor components (e.g., 1.22) using the normalizeGoVersion function. This truncation allows the tool to match against guideline categories that apply to entire minor releases, rather than specific patch levels.
Is there a way to see which version the CLI detected automatically?
While the CLI does not have a dedicated "verbose version detection" flag, running go-modern-guidelines list without arguments and observing which guidelines appear will indicate the detected version, as the output is filtered specifically for that Go release. You can verify the underlying value by running go env GOVERSION directly in your shell.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →