From d584d2b3dda9ab88a51a3e9cffe8ecd140479cef Mon Sep 17 00:00:00 2001 From: Sam Thanawalla Date: Mon, 31 Mar 2025 19:06:43 +0000 Subject: [PATCH] cmd/go: fix version stamping for v2 modules and subdirectories We were not passing the module path to newCodeRepo which caused it to incorrectly parse the major version. This allowed v0 and v1 modules to work because an empty major version is allowed in that case. Additionally we need to pass the root module path to derive the correct tag for subdirectories. Fixes: #72877 Fixes: #71738 Change-Id: Id792923f426858513972e713623270edbc76c545 Reviewed-on: https://go-review.googlesource.com/c/go/+/661875 LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Matloob --- src/cmd/go/internal/load/pkg.go | 11 ++- src/cmd/go/internal/modfetch/repo.go | 12 ++- .../script/build_version_stamping_git.txt | 82 +++++++++++++++++-- .../testdata/script/version_buildvcs_bzr.txt | 8 +- .../testdata/script/version_buildvcs_hg.txt | 14 ++-- 5 files changed, 110 insertions(+), 17 deletions(-) diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 4a28a2a2cb..f11c2d9bed 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -2577,7 +2577,16 @@ func (p *Package) setBuildInfo(ctx context.Context, autoVCS bool) { } appendSetting("vcs.modified", strconv.FormatBool(st.Uncommitted)) // Determine the correct version of this module at the current revision and update the build metadata accordingly. - repo := modfetch.LookupLocal(ctx, repoDir) + rootModPath := goModPath(repoDir) + // If no root module is found, skip embedding VCS data since we cannot determine the module path of the root. + if rootModPath == "" { + goto omitVCS + } + codeRoot, _, ok := module.SplitPathVersion(rootModPath) + if !ok { + goto omitVCS + } + repo := modfetch.LookupLocal(ctx, codeRoot, p.Module.Path, repoDir) revInfo, err := repo.Stat(ctx, st.Revision) if err != nil { goto omitVCS diff --git a/src/cmd/go/internal/modfetch/repo.go b/src/cmd/go/internal/modfetch/repo.go index 782d1dade7..b07fda0fb5 100644 --- a/src/cmd/go/internal/modfetch/repo.go +++ b/src/cmd/go/internal/modfetch/repo.go @@ -222,15 +222,19 @@ func Lookup(ctx context.Context, proxy, path string) Repo { var lookupLocalCache par.Cache[string, Repo] // path, Repo -// LookupLocal will only use local VCS information to fetch the Repo. -func LookupLocal(ctx context.Context, path string) Repo { +// LookupLocal returns a Repo that accesses local VCS information. +// +// codeRoot is the module path of the root module in the repository. +// path is the module path of the module being looked up. +// dir is the file system path of the repository containing the module. +func LookupLocal(ctx context.Context, codeRoot string, path string, dir string) Repo { if traceRepo { defer logCall("LookupLocal(%q)", path)() } return lookupLocalCache.Do(path, func() Repo { return newCachingRepo(ctx, path, func(ctx context.Context) (Repo, error) { - repoDir, vcsCmd, err := vcs.FromDir(path, "", true) + repoDir, vcsCmd, err := vcs.FromDir(dir, "", true) if err != nil { return nil, err } @@ -238,7 +242,7 @@ func LookupLocal(ctx context.Context, path string) Repo { if err != nil { return nil, err } - r, err := newCodeRepo(code, repoDir, path) + r, err := newCodeRepo(code, codeRoot, path) if err == nil && traceRepo { r = newLoggingRepo(r) } diff --git a/src/cmd/go/testdata/script/build_version_stamping_git.txt b/src/cmd/go/testdata/script/build_version_stamping_git.txt index e9aa824474..f9dbb370b6 100644 --- a/src/cmd/go/testdata/script/build_version_stamping_git.txt +++ b/src/cmd/go/testdata/script/build_version_stamping_git.txt @@ -34,14 +34,14 @@ exec git branch -m main # Use a 0.0.0 pseudo-version when no tags are present. go build go version -m example$GOEXE -stdout '\s+mod\s+example\s+v0.0.0-20220719150700-b52f952448d2\s+' +stdout '\s+mod\s+example\s+v0.0.0-20220719150700-e7537ba8fd6d\s+' rm example$GOEXE # Use a 0.0.0 pseudo-version if the current tag is not a valid semantic version. exec git tag 1.0.1 go build go version -m example$GOEXE -stdout '\s+mod\s+example\s+v0.0.0-20220719150700-b52f952448d2\s+' +stdout '\s+mod\s+example\s+v0.0.0-20220719150700-e7537ba8fd6d\s+' rm example$GOEXE # Use the current tag which has a valid semantic version to stamp the version. @@ -79,14 +79,14 @@ exec git commit -m 'commit 3' # Use a pseudo-version when current commit doesn't match a tagged version. go build go version -m example$GOEXE -stdout '\s+mod\s+example\s+v1.0.3-0.20220719150702-deaeab06f7fe\s+' +stdout '\s+mod\s+example\s+v1.0.3-0.20220719150702-b0226f18a7ae\s+' rm example$GOEXE # Use pseudo+dirty when uncommitted changes are present. mv README2 README3 go build go version -m example$GOEXE -stdout '\s+mod\s+example\s+v1.0.3-0.20220719150702-deaeab06f7fe\+dirty\s+' +stdout '\s+mod\s+example\s+v1.0.3-0.20220719150702-b0226f18a7ae\+dirty\s+' rm example$GOEXE # Make sure we always use the previously tagged version to generate the pseudo-version at a untagged revision. @@ -105,7 +105,7 @@ exec git tag v1.0.4 exec git checkout ':/commit 4' go build go version -m example$GOEXE -stdout '\s+mod\s+example\s+v1.0.3-0.20220719150703-2e239bf29c13\s+' +stdout '\s+mod\s+example\s+v1.0.3-0.20220719150703-2ebc76937b49\s+' rm example$GOEXE # Create +incompatible module @@ -121,6 +121,67 @@ go version -m example$GOEXE stdout '\s+mod\s+example\s+v2.0.0\+incompatible.dirty\s+' rm example$GOEXE +# Make sure v2 works as expected. +exec git checkout v1.0.4 +go mod edit -module example/v2 +exec git add . +exec git commit -m 'commit 7' +exec git tag v2.1.1 +go build +go version -m example$GOEXE +stdout '\s+mod\s+example/v2\s+v2.1.1\s+' +rm example$GOEXE + +# v2+dirty +mv README5 README6 +go build +go version -m example$GOEXE +stdout '\s+mod\s+example/v2\s+v2.1.1\+dirty\s+' +rm example$GOEXE + +# v2+pseudo +exec git add . +exec git commit -m 'commit 8' +go build +go version -m example$GOEXE +stdout '\s+mod\s+example/v2\s+v2.1.2-0.20220719150704-0ebeb94ecde2\s+' +rm example$GOEXE + +# v2+pseudo+dirty +mv README6 README7 +go build +go version -m example$GOEXE +stdout '\s+mod\s+example/v2\s+v2.1.2-0.20220719150704-0ebeb94ecde2\+dirty\s+' +rm example$GOEXE + +# modules in subdirectories should be stamped with the correct tag +exec git add . +cd subdir +exec git commit -m 'commit 9' +go build +go version -m subdir$GOEXE +# missing tag creates a pseudo version with v2.0.0 +stdout '\s+mod\s+example/subdir/v2\s+v2.0.0-20220719150704-fbef6799938f\s+' +rm subdir$GOEXE +# tag with subdir +exec git tag subdir/v2.1.0 +go build +go version -m subdir$GOEXE +stdout '\s+mod\s+example/subdir/v2\s+v2.1.0\s+' +# v2+dirty +mv ../README7 README8 +go build +go version -m subdir$GOEXE +stdout '\s+mod\s+example/subdir/v2\s+v2.1.0\+dirty\s+' +rm subdir$GOEXE + +# modules in a subdirectory without a go.mod in the root should result in (devel) +rm ../go.mod +go build +go version -m subdir$GOEXE +stdout '\s+mod\s+example/subdir/v2\s+\(devel\)\s+' +rm subdir$GOEXE + -- $WORK/repo/go.mod -- module example @@ -133,6 +194,17 @@ func main() { -- $WORK/copy/README -- hello +-- $WORK/repo/subdir/go.mod -- +module example/subdir/v2 + +go 1.18 + +-- $WORK/repo/subdir/main.go -- +package main + +func main() { +} + -- $WORK/home/gopher/.gitconfig -- [user] name = Go Gopher diff --git a/src/cmd/go/testdata/script/version_buildvcs_bzr.txt b/src/cmd/go/testdata/script/version_buildvcs_bzr.txt index 59796d1ffa..fd0b80c40a 100644 --- a/src/cmd/go/testdata/script/version_buildvcs_bzr.txt +++ b/src/cmd/go/testdata/script/version_buildvcs_bzr.txt @@ -44,7 +44,7 @@ stdout '^\tbuild\tvcs.modified=true$' cd .. # Revision and commit time are tagged for repositories with commits. -exec bzr add a README +exec bzr add a README go.mod exec bzr commit -m 'initial commit' cd a go install @@ -61,7 +61,7 @@ cd .. cp README README2 exec bzr add a README2 exec bzr commit -m 'second commit' -exec bzr tag v1.2.3 +exec bzr tag a/v1.2.3 cd a go install go version -m $GOBIN/a$GOEXE @@ -114,6 +114,10 @@ exit 1 -- repo/README -- Far out in the uncharted backwaters of the unfashionable end of the western spiral arm of the Galaxy lies a small, unregarded yellow sun. +-- repo/go.mod -- +module example.com + +go 1.18 -- repo/a/go.mod -- module example.com/a diff --git a/src/cmd/go/testdata/script/version_buildvcs_hg.txt b/src/cmd/go/testdata/script/version_buildvcs_hg.txt index 4f9fa7f2f4..81dee5a9df 100644 --- a/src/cmd/go/testdata/script/version_buildvcs_hg.txt +++ b/src/cmd/go/testdata/script/version_buildvcs_hg.txt @@ -41,20 +41,20 @@ go version -m $GOBIN/a$GOEXE stdout '^\tbuild\tvcs.revision=0000000000000000000000000000000000000000$' stdout '^\tbuild\tvcs.time=1970-01-01T00:00:00Z$' stdout '^\tbuild\tvcs.modified=true$' -stdout '\s+mod\s+example.com/a\s+v0.0.0-19700101000000-000000000000\+dirty' +stdout '\s+mod\s+example.com/a\s\(devel\)\s+' cd .. # Revision and commit time are tagged for repositories with commits. -exec hg add a README +exec hg add a README go.mod exec hg commit -m 'initial commit' --user test-user --date '2024-07-31T01:21:27+00:00' -exec hg tag v1.2.3 +exec hg tag a/v1.2.3 # Switch back to the tagged branch. # Tagging a commit causes a new commit to be created. (See https://repo.mercurial-scm.org/hg/help/revsets) exec hg update '.~1' cd a go install go version -m $GOBIN/a$GOEXE -stdout '^\tbuild\tvcs.revision=71eaed52daeaafea83cb604f75b0a0336ef2c345$' +stdout '^\tbuild\tvcs.revision=eae91df98b5dd3c4451accf64c683ddc3edff6a9$' stdout '^\tbuild\tvcs.time=2024-07-31T01:21:27Z$' stdout '^\tbuild\tvcs.modified=false$' stdout '\s+mod\s+example.com/a\s+v1.2.3\s+' @@ -73,7 +73,7 @@ exec hg status stdout '^.+' go install go version -m $GOBIN/a$GOEXE -stdout '^\tbuild\tvcs.revision=71eaed52daeaafea83cb604f75b0a0336ef2c345$' +stdout '^\tbuild\tvcs.revision=eae91df98b5dd3c4451accf64c683ddc3edff6a9$' stdout '^\tbuild\tvcs.time=2024-07-31T01:21:27Z$' stdout '^\tbuild\tvcs.modified=false$' stdout '\s+mod\s+example.com/a\s+v1.2.3\s+' @@ -112,6 +112,10 @@ exit 1 -- repo/README -- Far out in the uncharted backwaters of the unfashionable end of the western spiral arm of the Galaxy lies a small, unregarded yellow sun. +-- repo/go.mod -- +module example.com + +go 1.18 -- repo/a/go.mod -- module example.com/a