Commit aad2336c authored by Bryan C. Mills's avatar Bryan C. Mills

cmd/go: convert semver tags with metadata to pseudoversions

Some repositories include tags like 'v1.0.0-rc.1+oryOS.9'.

If we were to allow such tags, they could become ambiguous: semantic
versioning defines versions that differ only in metadata to have equal
precedence, so if someone added a tag 'v1.0.0-rc.1+other' at a
different commit, then the version 'v1.0.0-rc.1' would become
ambiguous.

However, we should still allow those tags to be used to resolve
versions, and since we can even parse the underlying semantic version,
we can at least use that as the basis for a unique (and well-ordered)
pseudo-version.

Fixes #31713

Change-Id: I5035f76d74ead6e786c04a368595cb5e42d36f91
Reviewed-on: https://go-review.googlesource.com/c/go/+/176905
Run-TryBot: Bryan C. Mills <bcmills@google.com>
Reviewed-by: default avatarJay Conrod <jayconrod@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 9892cd63
......@@ -31,7 +31,7 @@ import (
// - <v1.2.3, <=v1.2.3, >v1.2.3, >=v1.2.3,
// denoting the version closest to the target and satisfying the given operator,
// with non-prereleases preferred over prereleases.
// - a repository commit identifier, denoting that commit.
// - a repository commit identifier or tag, denoting that commit.
//
// If the allowed function is non-nil, Query excludes any versions for which allowed returns false.
//
......@@ -106,18 +106,24 @@ func Query(path, query string, allowed func(module.Version) bool) (*modfetch.Rev
}
prefix = query + "."
case semver.IsValid(query):
vers := module.CanonicalVersion(query)
if !allowed(module.Version{Path: path, Version: vers}) {
return nil, fmt.Errorf("%s@%s excluded", path, vers)
}
return modfetch.Stat(path, vers)
default:
// Direct lookup of semantic version or commit identifier.
//
// If the identifier is not a canonical semver tag — including if it's a
// semver tag with a +metadata suffix — then modfetch.Stat will populate
// info.Version with a suitable pseudo-version.
info, err := modfetch.Stat(path, query)
if err != nil {
return nil, err
queryErr := err
// The full query doesn't correspond to a tag. If it is a semantic version
// with a +metadata suffix, see if there is a tag without that suffix:
// semantic versioning defines them to be equivalent.
if vers := module.CanonicalVersion(query); vers != "" && vers != query {
info, err = modfetch.Stat(path, vers)
}
if err != nil {
return nil, queryErr
}
}
if !allowed(module.Version{Path: path, Version: info.Version}) {
return nil, fmt.Errorf("%s@%s excluded", path, info.Version)
......
......@@ -62,7 +62,7 @@ var queryTests = []struct {
git add go.mod
git commit -m v1 go.mod
git tag start
for i in v0.0.0-pre1 v0.0.0 v0.0.1 v0.0.2 v0.0.3 v0.1.0 v0.1.1 v0.1.2 v0.3.0 v1.0.0 v1.1.0 v1.9.0 v1.9.9 v1.9.10-pre1; do
for i in v0.0.0-pre1 v0.0.0 v0.0.1 v0.0.2 v0.0.3 v0.1.0 v0.1.1 v0.1.2 v0.3.0 v1.0.0 v1.1.0 v1.9.0 v1.9.9 v1.9.10-pre1 v1.9.10-pre2+metadata; do
echo before $i >status
git add status
git commit -m "before $i" status
......@@ -104,6 +104,9 @@ var queryTests = []struct {
{path: queryRepo, query: "v0.1", vers: "v0.1.2"},
{path: queryRepo, query: "v0.2", err: `no matching versions for query "v0.2"`},
{path: queryRepo, query: "v0.0", vers: "v0.0.3"},
{path: queryRepo, query: "v1.9.10-pre2+metadata", vers: "v1.9.10-pre2.0.20190513201126-42abcb6df8ee"},
{path: queryRepo, query: "v1.9.10-pre2+wrongmetadata", err: `unknown revision v1.9.10-pre2+wrongmetadata`},
{path: queryRepo, query: "v1.9.10-pre2", err: `unknown revision v1.9.10-pre2`},
{path: queryRepo, query: "latest", vers: "v1.9.9"},
{path: queryRepo, query: "latest", allow: "NOMATCH", err: `no matching versions for query "latest"`},
{path: queryRepo, query: ">v1.9.9", vers: "v1.9.10-pre1"},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment