feat(gvm): add auto-detect Go version from .go-version / go.mod - #16
Conversation
Implement `gvm use` and `gvm install` without an explicit version argument by resolving the required Go version from the nearest project files, closing #10 / moovweb/gvm#523. Key changes: - Add `scripts/function/resolve_project_version` with helpers: - `__gvm_find_file_upwards`: cwd-safe upward directory walker (no longer mutates caller's working directory) - `__gvm_parse_go_mod_version`: reads `toolchain` / `go` directive from `go.mod` - `__gvm_read_dot_go_version_file`: reads `.go-version` pin - `__gvm_map_version_hint_to_tag`: maps language versions like `1.22` to the latest installed or available patch tag - `__gvm_resolve_project_go_version`: orchestrates precedence (`.go-version` → `go.mod`) - Update `scripts/env/use` to call `__gvm_resolve_project_go_version` when no version argument is given - Refactor `scripts/env/applymod` to reuse the same shared helpers - Fix `scripts/function/find_path_upwards` to avoid `cd` side-effects and external `dirname` calls - Document empty-string contract for `_bash_pseudo_hash` (no distinct nil values) - Add CI smoke test for `go.mod` auto-detection from a subdirectory - Bump version to 1.3.0 and update `ChangeLog` / `README.md` feat(install): add auto-detection of Go version from project files When no version is specified, `gvm install` now resolves the required Go version from the nearest `.go-version` or `go.mod` file using `__gvm_resolve_project_go_version`. Language-level versions (e.g. `go 1.22`) are mapped to the latest available patch release for that minor version. This removes the hard failure on missing version argument and replaces it with a smarter fallback, making it easier to install the correct Go version when working inside a project directory without having to look up or type the version manually.
|
Warning Review limit reached
Next review available in: 41 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughChangesProject version resolution
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant ProjectDirectory
participant GvmUse
participant Resolver
participant GoMod
participant GoInstallation
ProjectDirectory->>GvmUse: Invoke without an explicit version
GvmUse->>Resolver: Resolve installed project version
Resolver->>GoMod: Search and parse go.mod
GoMod-->>Resolver: Return go directive or toolchain hint
Resolver-->>GvmUse: Return latest matching stable tag
GvmUse->>GoInstallation: Activate selected Go version
Possibly related issues
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
scripts/function/resolve_project_version (1)
1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate upward-file-search implementation across two files.
__gvm_find_file_upwards(resolve_project_version) and__gvmp_find_path_for_target(find_path_upwards) implement the same cwd-safe traversal algorithm almost line-for-line; the latter is now only a fallback path when the former isn't loaded, so it's dead weight that can silently drift from the primary implementation (e.g. its-f || -dcheck vs. the primary's-echeck).
scripts/function/resolve_project_version#L15-55: keep as the single canonical implementation of the upward walker.scripts/function/find_path_upwards#L44-88: remove__gvmp_find_path_for_target's duplicated traversal body and have it delegate unconditionally to__gvm_find_file_upwards(sourcingresolve_project_versionif not already loaded), rather than keeping a parallel copy as a fallback.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/function/resolve_project_version` at line 1, Remove the duplicated traversal implementation from __gvmp_find_path_for_target in find_path_upwards, and make it unconditionally source or reuse resolve_project_version so it delegates to the canonical __gvm_find_file_upwards implementation. Preserve the existing target lookup behavior while eliminating the parallel fallback algorithm and its differing file-existence checks.tests/gvm_use_gomod_comment_test.sh (1)
1-13: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winHarden the test script per static-analysis findings.
Three related issues flagged by static analysis: (1) unquoted
$GVM_ROOT/scripts/gvmat Line 1 (SC2086); (2)cdat Line 9 with no failure handling (SC2164) — if it fails, subsequent commands includingrm -rfat Line 13 run against the wrong directory; (3) predictable PID-based temp dir names at Lines 4/7 (CWE-377) instead ofmktemp -d.🛡️ Proposed fix
-source $GVM_ROOT/scripts/gvm +source "$GVM_ROOT/scripts/gvm" -## Requires go1.22.12 from 00gvm_install_comment_test.sh -mkdir -p /tmp/gvm2-mod-detect-$$/subdir -echo 'module example.com/t - -go 1.22 -' > /tmp/gvm2-mod-detect-$$/go.mod -cd /tmp/gvm2-mod-detect-$$/subdir +## Requires go1.22.12 from 00gvm_install_comment_test.sh +tmpdir="$(mktemp -d /tmp/gvm2-mod-detect.XXXXXX)" +mkdir -p "$tmpdir/subdir" +echo 'module example.com/t + +go 1.22 +' > "$tmpdir/go.mod" +cd "$tmpdir/subdir" || exit 1 gvm use # status=0; match=/Now using version go1\.22\./ go version # status=0; match=/go1\.22\./ -cd / -rm -rf /tmp/gvm2-mod-detect-$$ +cd / || exit 1 +rm -rf "$tmpdir"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/gvm_use_gomod_comment_test.sh` around lines 1 - 13, Harden tests/gvm_use_gomod_comment_test.sh by quoting the GVM_ROOT-based source path, creating the temporary module directory with mktemp -d instead of a predictable PID-based path, and making the subdirectory change fail safely before running subsequent commands. Reuse the resulting temporary-directory variable consistently for file creation, cd, and cleanup, ensuring cleanup cannot target an unintended directory.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/function/resolve_project_version`:
- Around line 229-244: Add a bounded timeout to the git ls-remote invocation
inside __gvm_list_available_go_tags, using the repository’s established timeout
mechanism or a suitable platform-compatible option. Preserve the existing tag
parsing, empty-output handling, and nonzero return behavior while ensuring
unreachable remotes fail promptly.
- Around line 317-352: Update __gvm_resolve_project_go_version so that once
.go-version yields a non-empty hint, it remains authoritative even when
__gvm_map_version_hint_to_tag returns no mapped version. For scope=available,
preserve returning the exact hint; for other scopes, return failure immediately
instead of checking go.mod. Only consult go.mod when no usable .go-version hint
was found.
- Around line 116-146: The __gvm_read_dot_go_version_file function only accepts
version lines prefixed with “go”, so ecosystem-style plain versions are ignored.
Update its matching logic to accept both go-prefixed values and plain Go version
strings such as 1.22.12, normalizing plain matches to the canonical goX.Y.Z form
before assigning version and returning it; preserve comment, whitespace, and
empty-line handling.
---
Nitpick comments:
In `@scripts/function/resolve_project_version`:
- Line 1: Remove the duplicated traversal implementation from
__gvmp_find_path_for_target in find_path_upwards, and make it unconditionally
source or reuse resolve_project_version so it delegates to the canonical
__gvm_find_file_upwards implementation. Preserve the existing target lookup
behavior while eliminating the parallel fallback algorithm and its differing
file-existence checks.
In `@tests/gvm_use_gomod_comment_test.sh`:
- Around line 1-13: Harden tests/gvm_use_gomod_comment_test.sh by quoting the
GVM_ROOT-based source path, creating the temporary module directory with mktemp
-d instead of a predictable PID-based path, and making the subdirectory change
fail safely before running subsequent commands. Reuse the resulting
temporary-directory variable consistently for file creation, cd, and cleanup,
ensuring cleanup cannot target an unintended directory.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 45c7786b-d51d-4e9f-917c-d90a3f7e1d50
⛔ Files ignored due to path filters (1)
.DS_Storeis excluded by!**/.DS_Store
📒 Files selected for processing (11)
ChangeLogREADME.mdVERSIONscripts/ci-smoke.shscripts/env/applymodscripts/env/usescripts/function/_bash_pseudo_hashscripts/function/find_path_upwardsscripts/function/resolve_project_versionscripts/installtests/gvm_use_gomod_comment_test.sh
tf executes each line as its own command, so a multi-line echo left an unclosed quote and wedged the suite after the alias cleanup noise.
Bound remote tag listing with git HTTP low-speed abort, keep .go-version authoritative, accept plain 1.x.y pins, dedupe path walking, and harden the go.mod comment test tempdir handling.
Implement
gvm useandgvm installwithout an explicit version argument by resolving the required Go version from the nearest project files, closing #10 / moovweb/gvm#523.Key changes:
scripts/function/resolve_project_versionwith helpers:__gvm_find_file_upwards: cwd-safe upward directory walker (no longer mutates caller's working directory)__gvm_parse_go_mod_version: readstoolchain/godirective fromgo.mod__gvm_read_dot_go_version_file: reads.go-versionpin__gvm_map_version_hint_to_tag: maps language versions like1.22to the latest installed or available patch tag__gvm_resolve_project_go_version: orchestrates precedence (.go-version→go.mod)scripts/env/useto call__gvm_resolve_project_go_versionwhen no version argument is givenscripts/env/applymodto reuse the same shared helpersscripts/function/find_path_upwardsto avoidcdside-effects and externaldirnamecalls_bash_pseudo_hash(no distinct nil values)go.modauto-detection from a subdirectoryChangeLog/README.mdfeat(install): add auto-detection of Go version from project files
When no version is specified,
gvm installnow resolves the required Go version from the nearest.go-versionorgo.modfile using__gvm_resolve_project_go_version. Language-level versions (e.g.go 1.22) are mapped to the latest available patch release for that minor version.This removes the hard failure on missing version argument and replaces it with a smarter fallback, making it easier to install the correct Go version when working inside a project directory without having to look up or type the version manually.
Summary by CodeRabbit
gvm useandgvm installcan automatically detect Go versions from.go-versionorgo.mod.1.22are mapped to the latest matching patch release.gvm applymodnow follows the same project-version detection behavior.