Skip to content

Commit

Permalink
cmd/go/internal/modfetch/codehost: add new git tags before statLocal …
Browse files Browse the repository at this point in the history
…instead of after

gitRepo.statLocal reports tag and version information.
If we are statting a hash that corresponds to a tag, we need to add that tag
before calling statLocal so that it can be included in that information.

Fixes #53955.
Updates #56881.

Change-Id: I69a71428e6ed9096d4cb8ed1bb79531415ff06c1
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest,gotip-windows-amd64-longtest
Reviewed-on: https://go-review.googlesource.com/c/go/+/547155
Auto-Submit: Bryan Mills <bcmills@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Matloob <matloob@golang.org>
  • Loading branch information
Bryan C. Mills authored and gopherbot committed Dec 6, 2023
1 parent 3f2bf70 commit 7b5a373
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 9 deletions.
24 changes: 15 additions & 9 deletions src/cmd/go/internal/modfetch/codehost/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"os/exec"
"path/filepath"
"runtime"
"slices"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -154,7 +155,7 @@ type gitRepo struct {
refsErr error

localTagsOnce sync.Once
localTags map[string]bool
localTags sync.Map // map[string]bool
}

const (
Expand All @@ -166,7 +167,6 @@ const (

// loadLocalTags loads tag references from the local git cache
// into the map r.localTags.
// Should only be called as r.localTagsOnce.Do(r.loadLocalTags).
func (r *gitRepo) loadLocalTags(ctx context.Context) {
// The git protocol sends all known refs and ls-remote filters them on the client side,
// so we might as well record both heads and tags in one shot.
Expand All @@ -176,10 +176,9 @@ func (r *gitRepo) loadLocalTags(ctx context.Context) {
return
}

r.localTags = make(map[string]bool)
for _, line := range strings.Split(string(out), "\n") {
if line != "" {
r.localTags[line] = true
r.localTags.Store(line, true)
}
}
}
Expand Down Expand Up @@ -430,7 +429,7 @@ func (r *gitRepo) stat(ctx context.Context, rev string) (info *RevInfo, err erro
// Maybe rev is a tag we already have locally.
// (Note that we're excluding branches, which can be stale.)
r.localTagsOnce.Do(func() { r.loadLocalTags(ctx) })
if r.localTags[rev] {
if _, ok := r.localTags.Load(rev); ok {
return r.statLocal(ctx, rev, "refs/tags/"+rev)
}

Expand Down Expand Up @@ -506,11 +505,18 @@ func (r *gitRepo) stat(ctx context.Context, rev string) (info *RevInfo, err erro
// Either way, try a local stat before falling back to network I/O.
if !didStatLocal {
if info, err := r.statLocal(ctx, rev, hash); err == nil {
if after, found := strings.CutPrefix(ref, "refs/tags/"); found {
// Make sure tag exists, so it will be in localTags next time the go command is run.
Run(ctx, r.dir, "git", "tag", after, hash)
tag, fromTag := strings.CutPrefix(ref, "refs/tags/")
if fromTag && !slices.Contains(info.Tags, tag) {
// The local repo includes the commit hash we want, but it is missing
// the corresponding tag. Add that tag and try again.
_, err := Run(ctx, r.dir, "git", "tag", tag, hash)
if err != nil {
return nil, err
}
r.localTags.Store(tag, true)
return r.statLocal(ctx, rev, ref)
}
return info, nil
return info, err
}
}

Expand Down
67 changes: 67 additions & 0 deletions src/cmd/go/testdata/script/get_issue53955.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Regression test for https://go.dev/issue/53955.
# New remote tags were erroneously added to the local clone of a repo
# only *after* extracting version information for a locally-cached commit,
# causing the version information to have incomplete Tags and Version fields.

[short] skip 'constructs a local git repo'
[!git] skip
[!net:github.com] skip 'does not actually use github.com because of insteadOf, but silence network check just in case'

env GIT_CONFIG_GLOBAL=$WORK/.gitconfig
env GIT_ALLOW_PROTOCOL=file
env GOPRIVATE=github.com/golang/issue53955

[!GOOS:windows] exec git config --global 'url.file://'$WORK'/repo.insteadOf' 'https://github.com/golang/issue53955'
[GOOS:windows] exec git config --global 'url.file:///'$WORK'/repo.insteadOf' 'https://github.com/golang/issue53955'

cd $WORK/repo

env GIT_AUTHOR_NAME='Go Gopher'
env GIT_AUTHOR_EMAIL='gopher@golang.org'
env GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME
env GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL

exec git init

env GIT_COMMITTER_DATE=2022-07-19T11:07:00-04:00
env GIT_AUTHOR_DATE=2022-07-19T11:07:00-04:00
exec git add go.mod issue53955.go
exec git commit -m 'initial commit'
exec git branch -m main
exec git tag v1.0.9

env GIT_COMMITTER_DATE=2022-07-19T11:07:01-04:00
env GIT_AUTHOR_DATE=2022-07-19T11:07:01-04:00
exec git add extra.go
exec git commit -m 'next commit'
exec git show-ref --tags --heads
cmp stdout $WORK/.git-refs-1

cd $WORK/m
go get -x github.com/golang/issue53955@2cb3d49f
stderr '^go: added github.com/golang/issue53955 v1.0.10-0.20220719150701-2cb3d49f8874$'

cd $WORK/repo
exec git tag v1.0.10

cd $WORK/m
go get -x github.com/golang/issue53955@v1.0.10
! stderr 'v1\.0\.10 is not a tag'
stderr '^go: upgraded github.com/golang/issue53955 v.* => v1\.0\.10$'

-- $WORK/repo/go.mod --
module github.com/golang/issue53955

go 1.18
-- $WORK/repo/issue53955.go --
package issue53955
-- $WORK/repo/extra.go --
package issue53955
-- $WORK/.git-refs-1 --
2cb3d49f8874b9362ed0ddd2a6512e4108bbf6b1 refs/heads/main
050526ebf5883191e990529eb3cc9345abaf838c refs/tags/v1.0.9
-- $WORK/m/go.mod --
module m

go 1.18
-- $WORK/.gitconfig --

0 comments on commit 7b5a373

Please sign in to comment.