Repository navigation
Handle Go module pseudo-versions in dependency constraint checking - #5855
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes dependency constraint checking for Go module pseudo-versions so k6 avoids unnecessary binary provisioning and compares dependency constraints against the same effective version string that k6 version displays.
Changes:
- Centralize runtime k6 version resolution via Go build info (including pseudo-versions) and reuse it for both
versionoutput and dependency checks. - Replace the boolean โcustom build requiredโ check with an error-returning dependency validator that can handle pseudo-version SHA matching.
- Add/expand tests covering pseudo-version and build-metadata SHA matching behavior.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/cmd/version.go | Adds build-info-based runtime version reader and aligns versionDetails() output with it. |
| internal/cmd/test_load.go | Switches auto-extension resolution to validate against runtimeK6Version() via the new dependency checker. |
| internal/cmd/deps.go | Uses the new dependency checker (and runtime version) to determine customBuildRequired. |
| internal/cmd/launcher.go | Implements SHA-aware pseudo-version satisfaction and converts dependency checking to return descriptive errors. |
| internal/cmd/launcher_test.go | Updates/expands unit tests for the new dependency checking and pseudo-version SHA logic. |
๐ก Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| func checkConstraintBySHA(vSHA string, constraint *semver.Constraints) (bool, bool) { | ||
| cs := constraint.String() | ||
| if strings.ContainsAny(cs, " ,") { | ||
| return false, false | ||
| } | ||
| cv, err := semver.NewVersion(constraintVersionStr(cs)) | ||
| if err != nil { | ||
| return false, false | ||
| } | ||
| cSHA, ok := versionSHA(cv) | ||
| if !ok { | ||
| return false, false | ||
| } | ||
| return strings.HasPrefix(vSHA, cSHA) || strings.HasPrefix(cSHA, vSHA), true |
There was a problem hiding this comment.
checkConstraintBySHA() currently treats any single-token constraint (e.g. ">=v0.0.0+", "!=v...", "<v...") as eligible for SHA-based matching. This can produce incorrect results by marking range constraints as satisfied solely because the embedded SHAs match, even when the semver comparison should fail (e.g. ">v0.0.0+sha" vs "v0.0.0+sha"). Restrict SHA-based matching to exact-version constraints only (operator "=" or no operator), and fall back to normal semver checking for all other operators.
There was a problem hiding this comment.
0c2072d makes this even more tight. I opted to disallow more stuff that do not seem reasonable than to allow more.
| // readK6VersionInfo reads Go build info once and returns everything needed by | ||
| // both the version display and the dependency constraint check. This is the | ||
| // single source of truth so that what k6 prints and what it compares against | ||
| // are always the same string. | ||
| func readK6VersionInfo() k6VersionInfo { |
There was a problem hiding this comment.
readK6VersionInfo()'s comment says it "reads Go build info once", but the function calls debug.ReadBuildInfo() each time it's invoked (e.g., via both versionDetails() and runtimeK6Version()). Either cache the result (e.g., with sync.Once) or adjust the comment so it doesn't imply one-time reading/caching.
There was a problem hiding this comment.
I kind of think this is good enough . And definitely won't be adding sync.Once for thi.s This is usually called once eitehr way.
When a script manifest specifies a dependency as a pseudo-version (v0.0.0+somesha or v0.0.0-20241015123456-abcdef123456), the previous code always triggered binary provisioning because it could not match pseudo-version strings against constraints. Two root causes were fixed. First, the dependency checker now compares commit SHAs directly when both the built-in version and the constraint embed one. This handles the case where the semver library silently ignores build metadata (v0.0.0+abc == v0.0.0+xyz under the semver spec), and the case where a Go pseudo-version pre-release (v0.0.0-timestamp-sha) fails a normal semver range check even when the constraint names the exact same commit. SHA comparison is attempted as a fallback in both situations. Short SHAs are matched as prefixes so that 7-char and 12-char forms interoperate. Second, k6's own version is now read from Go build info at runtime via runtimeK6Version() rather than the static build.Version constant. When k6 is installed from a specific commit (go install go.k6.io/k6@sha), the binary carries a pseudo-version in its build info; previously, the static constant was always compared against constraints instead, masking the true version. runtimeK6Version() is guaranteed to return the same string that the version command prints, so the compared version and the displayed version are always in sync. This runtime version lookup is currently only applied to k6 itself. Extension versions are already sourced from build info by the extension registry (ext.extractModuleInfo), but a similar approach could be applied to verify their versions more robustly in the future. Additional changes: - isCustomBuildRequired renamed to checkBuiltinDependencies and changed to return an error describing the first unsatisfied dependency instead of a bool, making failures easier to diagnose via debug logging - readK6VersionInfo() consolidates the build-info reading that was previously duplicated between the version display path and the new dependency checking path Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two correctness fixes to checkConstraintBySHA: First, SHA-based matching is now restricted to exact-version constraints (operator "=" or no operator). Previously, any single-token constraint was eligible, so ">v0.0.0+sha" or "!=v0.0.0+sha" with a matching SHA would be incorrectly reported as satisfied. The operator is extracted as the prefix before the first "v" in the constraint string and checked before any SHA comparison is attempted. Second, compound constraints (containing spaces or commas) now return a definitive failure (false, true) instead of falling through to semver (false, false). For pseudo-versions, semver's handling of compound constraints is unreliable: build metadata is silently stripped, and pre-release versions are excluded from non-pre-release constraints regardless of the base version. Refusing early avoids these pitfalls and produces consistent, predictable behaviour. Also expands the test suite with cases that document: - non-exact operators (>, !=) with matching SHAs - pseudo-versions against non-pre-release range constraints, contrasted with the >=vX.Y.Z-0 form that correctly admits pre-release versions - compound constraints combining an exact SHA with an upper limit - the asymmetry between go pseudo-versions (pre-release form) and build-metadata pseudo-versions (+sha) under range constraints Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
0c2072d to
afdff06
Compare
What?
When a script manifest specifies a dependency as a Go module pseudo-version (
v0.0.0+someshaorv0.0.0-20241015123456-abcdef123456), k6 was always triggering binary provisioning even when the running binary already satisfied the constraint. This PR fixes two root causes and ensures the version k6 compares against constraints matches what it displays inversionoutput.Why?
Build metadata is invisible to semver comparison. The semver spec ignores build metadata, so
v0.0.0+abcandv0.0.0+xyzare treated as equal โ a mismatched SHA would silently pass, and a matching SHA would also pass, but for the wrong reason.Pre-release pseudo-versions always fail range checks.
v0.0.0-timestamp-shais less thanv0.0.0in semver ordering, so any range constraint fails even when the constraint names the exact same commit.The compared version didn't match the displayed version.
checkBuiltinDependencieswas comparing against the staticbuild.Versionconstant, while theversioncommand was printing the actual build-info version, which may be a pseudo-version when k6 is installed viago install go.k6.io/k6@<sha>.Checklist
make check) and all pass.Checklist: Documentation (only for k6 maintainers and if relevant)
Please do not merge this PR until the following items are filled out.
Related PR(s)/Issue(s)
๐ค Generated with Claude Code