internal/proxydatasource: support incompatible modules in GetLatestMajorVersion
Currently, GetLatestMajorVersion uses v2 as a base when searching for
latest major versions. This fails to find major versions for
incompatible modules that jump directly from mod/path to mod/path/vN
where N > 2.
To avoid that, update GetLatestMajorVersion to use module's current
version as a base instead.
Add a test case with an incompatible module.
Fixes golang/go#42922
Change-Id: I660d76c3cddf420b85c25b8e7c9f425ba712824c
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/277472
Reviewed-by: Julie Qiu <julie@golang.org>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
diff --git a/internal/proxydatasource/datasource.go b/internal/proxydatasource/datasource.go
index 167517a..17b2dcc 100644
--- a/internal/proxydatasource/datasource.go
+++ b/internal/proxydatasource/datasource.go
@@ -12,6 +12,7 @@
"fmt"
"path"
"sort"
+ "strconv"
"strings"
"sync"
"time"
@@ -182,13 +183,27 @@
func (ds *DataSource) GetLatestMajorVersion(ctx context.Context, fullPath, modulePath string) (_ string, _ string, err error) {
// We are checking if the full path is valid so that we can forward the error if not.
seriesPath := internal.SeriesPathForModule(modulePath)
- _, err = ds.proxyClient.GetInfo(ctx, seriesPath, internal.LatestVersion)
+ info, err := ds.proxyClient.GetInfo(ctx, seriesPath, internal.LatestVersion)
if err != nil {
return "", "", err
}
- const startVersion = 2
- // We start checking versions from "/v2", since v1 and v0 versions don't
- // have a major version at the end of the modulepath.
+
+ // Converting version numbers to integers may cause an overflow, as version
+ // numbers need not fit into machine integers.
+ // While using Atoi is wrong, for it to fail, the version number must reach a
+ // value higher than at least 2^31, which is unlikely.
+ startVersion, err := strconv.Atoi(strings.TrimPrefix(semver.Major(info.Version), "v"))
+ if err != nil {
+ return "", "", err
+ }
+ startVersion++
+
+ // We start checking versions from "/v2" or higher, since v1 and v0 versions
+ // don't have a major version at the end of the modulepath.
+ if startVersion < 2 {
+ startVersion = 2
+ }
+
for v := startVersion; ; v++ {
query := fmt.Sprintf("%s/v%d", seriesPath, v)
diff --git a/internal/proxydatasource/datasource_test.go b/internal/proxydatasource/datasource_test.go
index 6306bc1..5fee0d8 100644
--- a/internal/proxydatasource/datasource_test.go
+++ b/internal/proxydatasource/datasource_test.go
@@ -212,6 +212,13 @@
{
ModulePath: "bar.com/foo",
},
+ {
+ ModulePath: "incompatible.com/bar",
+ Version: "v2.1.1+incompatible",
+ },
+ {
+ ModulePath: "incompatible.com/bar/v3",
+ },
}
client, teardownProxy := proxy.SetupTestClient(t, testModules)
defer teardownProxy()
@@ -249,6 +256,12 @@
wantModulePath: "foo.com/bar/v3",
wantPackagePath: "foo.com/bar/v3",
},
+ {
+ fullPath: "incompatible.com/bar",
+ modulePath: "incompatible.com/bar",
+ wantModulePath: "incompatible.com/bar/v3",
+ wantPackagePath: "incompatible.com/bar/v3",
+ },
} {
gotVersion, gotPath, err := ds.GetLatestMajorVersion(ctx, test.fullPath, test.modulePath)
if err != nil {