Skip to content

Commit 817afe8

Browse files
author
Bryan C. Mills
committed
cmd/go: adjust heuristics for skipping +incompatible versions
We know of at least one module (github.com/stripe/stripe-go) that has a run of +incompatible versions, followed by a run of versions with go.mod files, followed by another run of +incompatible versions. We want the heuristics for showing +incompatible versions to reflect the authors' current intent, and it seems clear that the current intent of the authors of that module is for users of the unversioned import path to still be on +incompatible versions. To respect that intent, we need to keep checking for +incompatible versions even after we have seen a lower major version with an explicit go.mod file. However, we still don't want to download every single version of the module to check it. A given major version should have a consistent, canonical import path, so the path (as inferred by the presence or absence of a go.mod file) should be the same for every release across that major version. To avoid unnecessary overhead — and to allow module authors to correct accidental changes to a major version's import path — we check only the most recent release of each major version. If a release accidentally changes the import path in either direction (by deleting or adding a go.mod file), it can be corrected by issuing a single subsequent release of that major version to restore the correct path. I manually verified that, with this change, github.com/stripe/stripe-go@latest reverts to v68.7.0+incompatible as it was in Go 1.13. The other regression tests for #34165 continue to pass. Updates #34165 Change-Id: I5daff3cd2123f94c7c49519babf4eecd509f169e Reviewed-on: https://go-review.googlesource.com/c/go/+/212317 Reviewed-by: Jay Conrod <[email protected]>
1 parent 2248fc6 commit 817afe8

File tree

1 file changed

+30
-37
lines changed

1 file changed

+30
-37
lines changed

src/cmd/go/internal/modfetch/coderepo.go

Lines changed: 30 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -191,22 +191,6 @@ func (r *codeRepo) appendIncompatibleVersions(list, incompatible []string) ([]st
191191
return list, nil
192192
}
193193

194-
// We assume that if the latest release of any major version has a go.mod
195-
// file, all subsequent major versions will also have go.mod files (and thus
196-
// be ineligible for use as +incompatible versions).
197-
// If we're wrong about a major version, users will still be able to 'go get'
198-
// specific higher versions explicitly — they just won't affect 'latest' or
199-
// appear in 'go list'.
200-
//
201-
// Conversely, we assume that if the latest release of any major version lacks
202-
// a go.mod file, all versions also lack go.mod files. If we're wrong, we may
203-
// include a +incompatible version that isn't really valid, but most
204-
// operations won't try to use that version anyway.
205-
//
206-
// These optimizations bring
207-
// 'go list -versions -m github.com/openshift/origin' down from 1m58s to 0m37s.
208-
// That's still not great, but a substantial improvement.
209-
210194
versionHasGoMod := func(v string) (bool, error) {
211195
_, err := r.code.ReadFile(v, "go.mod", codehost.MaxGoMod)
212196
if err == nil {
@@ -241,32 +225,41 @@ func (r *codeRepo) appendIncompatibleVersions(list, incompatible []string) ([]st
241225
}
242226
}
243227

244-
var lastMajor string
228+
var (
229+
lastMajor string
230+
lastMajorHasGoMod bool
231+
)
245232
for i, v := range incompatible {
246233
major := semver.Major(v)
247-
if major == lastMajor {
248-
list = append(list, v+"+incompatible")
249-
continue
250-
}
251-
252-
rem := incompatible[i:]
253-
j := sort.Search(len(rem), func(j int) bool {
254-
return semver.Major(rem[j]) != major
255-
})
256-
latestAtMajor := rem[j-1]
257234

258-
ok, err := versionHasGoMod(latestAtMajor)
259-
if err != nil {
260-
return nil, err
261-
}
262-
if ok {
263-
// This major version has a go.mod file, so it is not allowed as
264-
// +incompatible. Subsequent major versions are likely to also have
265-
// go.mod files, so stop here.
266-
break
235+
if major != lastMajor {
236+
rem := incompatible[i:]
237+
j := sort.Search(len(rem), func(j int) bool {
238+
return semver.Major(rem[j]) != major
239+
})
240+
latestAtMajor := rem[j-1]
241+
242+
var err error
243+
lastMajor = major
244+
lastMajorHasGoMod, err = versionHasGoMod(latestAtMajor)
245+
if err != nil {
246+
return nil, err
247+
}
267248
}
268249

269-
lastMajor = major
250+
if lastMajorHasGoMod {
251+
// The latest release of this major version has a go.mod file, so it is
252+
// not allowed as +incompatible. It would be confusing to include some
253+
// minor versions of this major version as +incompatible but require
254+
// semantic import versioning for others, so drop all +incompatible
255+
// versions for this major version.
256+
//
257+
// If we're wrong about a minor version in the middle, users will still be
258+
// able to 'go get' specific tags for that version explicitly — they just
259+
// won't appear in 'go list' or as the results for queries with inequality
260+
// bounds.
261+
continue
262+
}
270263
list = append(list, v+"+incompatible")
271264
}
272265

0 commit comments

Comments
 (0)