diff options
author | Pontus Leitzler <leitzler@gmail.com> | 2019-04-26 20:38:49 +0000 |
---|---|---|
committer | Jay Conrod <jayconrod@google.com> | 2019-05-01 16:33:17 +0000 |
commit | cbe2b14d5072dde739e5bfda7e5b4405412464ec (patch) | |
tree | 3d2587729171996528d8609a8a0459221b341d28 /src/cmd/go/internal/modfetch/codehost/git.go | |
parent | e56c73f17b49793f9c57c0706344afafbec726d1 (diff) | |
download | go-cbe2b14d5072dde739e5bfda7e5b4405412464ec.tar.gz go-cbe2b14d5072dde739e5bfda7e5b4405412464ec.zip |
cmd/go/internal/modfetch/codehost: fix pseudoversions for non-semver tags and tags on other branches
Pseudoversion determination depends in part on the results from gitRepo.RecentTag, which currently invokes:
git describe --first-parent --always --abbrev=0 --match <prefix>v[0-9]*.[0-9]*.[0-9]* --tags <rev>
The comment at https://github.com/golang/go/issues/27171#issuecomment-470134255 describes some problems with the current approach.
One problem is Docker and other repos can have tags that are not valid semver tags but that still match a glob pattern of v[0-9]*.[0-9]*.[0-9]* which are found by 'git describe' but then rejected by cmd/go, and hence those repos currently can end up with v0.0.0 pseudoversions instead of finding a proper semver tag to use as input to building a pseudoversion (when then causes problems when the v0.0.0 pseudoversion is fed into MVS). An example problematic tag is a date-based tag such as 'v18.06.16', which matches the glob pattern, but is not a valid semver tag (due to the leading 0 in '06').
Issues #31673, #31287, and #27171 also describe problems where the '--first-parent' argument to 'git describe' cause the current approach to miss relevant semver tags that were created on a separate branch and then subsequently merged to master.
In #27171, Bryan described the base tag that is supposed to be used for pseudoversions as:
"It is intended to be the semantically-latest tag that appears on any commit that is a (transitive) parent of the commit with the given hash, regardless of branches. (The pseudo-version is supposed to sort after every version — tagged or otherwise — that came before it, but before the next tag that a human might plausibly want to apply to the branch.)"
This CL solves the glob problem and tags-on-other-branches problem more directly than the current approach: this CL gets the full list of tags that have been merged into the specific revision of interest, and then sorts and filters the results in cmd/go to select the semantically-latest valid semver tag.
Fixes #31673
Fixes #31287
Updates #27171
Change-Id: I7c3e6b46b2b21dd60562cf2893b6bd2afaae61d5
Reviewed-on: https://go-review.googlesource.com/c/go/+/174061
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
Diffstat (limited to 'src/cmd/go/internal/modfetch/codehost/git.go')
-rw-r--r-- | src/cmd/go/internal/modfetch/codehost/git.go | 33 |
1 files changed, 29 insertions, 4 deletions
diff --git a/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go index 5273e633b5..55627cb72a 100644 --- a/src/cmd/go/internal/modfetch/codehost/git.go +++ b/src/cmd/go/internal/modfetch/codehost/git.go @@ -19,6 +19,7 @@ import ( "cmd/go/internal/lockedfile" "cmd/go/internal/par" + "cmd/go/internal/semver" ) // GitRepo returns the code repository at the given Git remote reference. @@ -652,16 +653,40 @@ func (r *gitRepo) RecentTag(rev, prefix string) (tag string, err error) { } rev = info.Name // expand hash prefixes - // describe sets tag and err using 'git describe' and reports whether the + // describe sets tag and err using 'git for-each-ref' and reports whether the // result is definitive. describe := func() (definitive bool) { var out []byte - out, err = Run(r.dir, "git", "describe", "--first-parent", "--always", "--abbrev=0", "--match", prefix+"v[0-9]*.[0-9]*.[0-9]*", "--tags", rev) + out, err = Run(r.dir, "git", "for-each-ref", "--format", "%(refname)", "refs/tags", "--merged", rev) if err != nil { - return true // Because we use "--always", describe should never fail. + return true + } + + // prefixed tags aren't valid semver tags so compare without prefix, but only tags with correct prefix + var highest string + for _, line := range strings.Split(string(out), "\n") { + line = strings.TrimSpace(line) + // git do support lstrip in for-each-ref format, but it was added in v2.13.0. Stripping here + // instead gives support for git v2.7.0. + if !strings.HasPrefix(line, "refs/tags/") { + continue + } + line = line[len("refs/tags/"):] + + if !strings.HasPrefix(line, prefix) { + continue + } + + semtag := line[len(prefix):] + if semver.IsValid(semtag) { + highest = semver.Max(highest, semtag) + } + } + + if highest != "" { + tag = prefix + highest } - tag = string(bytes.TrimSpace(out)) return tag != "" && !AllHex(tag) } |