Skip to content

Commit 4b95fc1

Browse files
Bryan C. Millsmknyszek
Bryan C. Mills
authored andcommitted
[release-branch.go1.20] cmd/go: save checksums for go.mod files needed for go version lines
When we load a package from a module, we need the go version line from that module's go.mod file to know what language semantics to use for the package. We need to save a checksum for the go.mod file even if the module's requirements are pruned out of the module graph. Previously, we were missing checksums for test dependencies of packages in 'all' and packages passed to 'go get -t'. This change preserves the existing bug for 'go mod tidy', but fixes it for 'go get -t' and flags the missing checksum with a clearer error in other cases. Fixes #60001. Updates #56222. Change-Id: Icd6acce348907621ae0b02dbeac04fb180353dcf (cherry picked from CL 489075 and CL 492741) Reviewed-on: https://go-review.googlesource.com/c/go/+/493015 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Michael Matloob <[email protected]> Run-TryBot: Bryan Mills <[email protected]>
1 parent 31a1e19 commit 4b95fc1

16 files changed

+143
-28
lines changed

src/cmd/go/internal/list/list.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
646646
} else {
647647
pmain, ptest, pxtest, err = load.TestPackagesFor(ctx, pkgOpts, p, nil)
648648
if err != nil {
649-
base.Errorf("can't load test package: %s", err)
649+
base.Errorf("go: can't load test package: %s", err)
650650
}
651651
}
652652
if pmain != nil {

src/cmd/go/internal/modload/import.go

+19-1
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,13 @@ func (e *invalidImportError) Unwrap() error {
256256
// If the package is present in exactly one module, importFromModules will
257257
// return the module, its root directory, and a list of other modules that
258258
// lexically could have provided the package but did not.
259-
func importFromModules(ctx context.Context, path string, rs *Requirements, mg *ModuleGraph) (m module.Version, modroot, dir string, altMods []module.Version, err error) {
259+
//
260+
// If skipModFile is true, the go.mod file for the package is not loaded. This
261+
// allows 'go mod tidy' to preserve a minor checksum-preservation bug
262+
// (https://go.dev/issue/56222) for modules with 'go' versions between 1.17 and
263+
// 1.20, preventing unnecessary go.sum churn and network access in those
264+
// modules.
265+
func importFromModules(ctx context.Context, path string, rs *Requirements, mg *ModuleGraph, skipModFile bool) (m module.Version, modroot, dir string, altMods []module.Version, err error) {
260266
invalidf := func(format string, args ...interface{}) (module.Version, string, string, []module.Version, error) {
261267
return module.Version{}, "", "", nil, &invalidImportError{
262268
importPath: path,
@@ -435,6 +441,18 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
435441
}
436442

437443
if len(mods) == 1 {
444+
// We've found the unique module containing the package.
445+
// However, in order to actually compile it we need to know what
446+
// Go language version to use, which requires its go.mod file.
447+
//
448+
// If the module graph is pruned and this is a test-only dependency
449+
// of a package in "all", we didn't necessarily load that file
450+
// when we read the module graph, so do it now to be sure.
451+
if !skipModFile && cfg.BuildMod != "vendor" && mods[0].Path != "" && !MainModules.Contains(mods[0].Path) {
452+
if _, err := goModSummary(mods[0]); err != nil {
453+
return module.Version{}, "", "", nil, err
454+
}
455+
}
438456
return mods[0], roots[0], dirs[0], altMods, nil
439457
}
440458

src/cmd/go/internal/modload/init.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -1583,7 +1583,8 @@ func commitRequirements(ctx context.Context) (err error) {
15831583
// keepSums returns the set of modules (and go.mod file entries) for which
15841584
// checksums would be needed in order to reload the same set of packages
15851585
// loaded by the most recent call to LoadPackages or ImportFromFiles,
1586-
// including any go.mod files needed to reconstruct the MVS result,
1586+
// including any go.mod files needed to reconstruct the MVS result
1587+
// or identify go versions,
15871588
// in addition to the checksums for every module in keepMods.
15881589
func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums) map[module.Version]bool {
15891590
// Every module in the full module graph contributes its requirements,
@@ -1605,6 +1606,16 @@ func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums
16051606
continue
16061607
}
16071608

1609+
// We need the checksum for the go.mod file for pkg.mod
1610+
// so that we know what Go version to use to compile pkg.
1611+
// However, we didn't do so before Go 1.21, and the bug is relatively
1612+
// minor, so we maintain the previous (buggy) behavior in 'go mod tidy' to
1613+
// avoid introducing unnecessary churn.
1614+
if !ld.Tidy || semver.Compare("v"+ld.GoVersion, tidyGoModSumVersionV) >= 0 {
1615+
r := resolveReplacement(pkg.mod)
1616+
keep[modkey(r)] = true
1617+
}
1618+
16081619
if rs.pruning == pruned && pkg.mod.Path != "" {
16091620
if v, ok := rs.rootSelected(pkg.mod.Path); ok && v == pkg.mod.Version {
16101621
// pkg was loaded from a root module, and because the main module has
@@ -1660,6 +1671,7 @@ func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums
16601671
if which == addBuildListZipSums {
16611672
for _, m := range mg.BuildList() {
16621673
r := resolveReplacement(m)
1674+
keep[modkey(r)] = true // we need the go version from the go.mod file to do anything useful with the zipfile
16631675
keep[r] = true
16641676
}
16651677
}

src/cmd/go/internal/modload/load.go

+12-4
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,10 @@ type loader struct {
823823
// transitively *imported by* the packages and tests in the main module.)
824824
allClosesOverTests bool
825825

826+
// skipImportModFiles indicates whether we may skip loading go.mod files
827+
// for imported packages (as in 'go mod tidy' in Go 1.17–1.20).
828+
skipImportModFiles bool
829+
826830
work *par.Queue
827831

828832
// reset on each iteration
@@ -1003,6 +1007,10 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
10031007
// version higher than the go.mod version adds nothing.
10041008
ld.TidyCompatibleVersion = ld.GoVersion
10051009
}
1010+
1011+
if semver.Compare("v"+ld.GoVersion, tidyGoModSumVersionV) < 0 {
1012+
ld.skipImportModFiles = true
1013+
}
10061014
}
10071015

10081016
if semver.Compare("v"+ld.GoVersion, narrowAllVersionV) < 0 && !ld.UseVendorAll {
@@ -1398,7 +1406,7 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
13981406
//
13991407
// In some sense, we can think of this as ‘upgraded the module providing
14001408
// pkg.path from "none" to a version higher than "none"’.
1401-
if _, _, _, _, err = importFromModules(ctx, pkg.path, rs, nil); err == nil {
1409+
if _, _, _, _, err = importFromModules(ctx, pkg.path, rs, nil, ld.skipImportModFiles); err == nil {
14021410
changed = true
14031411
break
14041412
}
@@ -1609,7 +1617,7 @@ func (ld *loader) preloadRootModules(ctx context.Context, rootPkgs []string) (ch
16091617
// If the main module is tidy and the package is in "all" — or if we're
16101618
// lucky — we can identify all of its imports without actually loading the
16111619
// full module graph.
1612-
m, _, _, _, err := importFromModules(ctx, path, ld.requirements, nil)
1620+
m, _, _, _, err := importFromModules(ctx, path, ld.requirements, nil, ld.skipImportModFiles)
16131621
if err != nil {
16141622
var missing *ImportMissingError
16151623
if errors.As(err, &missing) && ld.ResolveMissingImports {
@@ -1697,7 +1705,7 @@ func (ld *loader) load(ctx context.Context, pkg *loadPkg) {
16971705
}
16981706

16991707
var modroot string
1700-
pkg.mod, modroot, pkg.dir, pkg.altMods, pkg.err = importFromModules(ctx, pkg.path, ld.requirements, mg)
1708+
pkg.mod, modroot, pkg.dir, pkg.altMods, pkg.err = importFromModules(ctx, pkg.path, ld.requirements, mg, ld.skipImportModFiles)
17011709
if pkg.dir == "" {
17021710
return
17031711
}
@@ -1956,7 +1964,7 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements)
19561964

19571965
pkg := pkg
19581966
ld.work.Add(func() {
1959-
mod, _, _, _, err := importFromModules(ctx, pkg.path, rs, mg)
1967+
mod, _, _, _, err := importFromModules(ctx, pkg.path, rs, mg, ld.skipImportModFiles)
19601968
if mod != pkg.mod {
19611969
mismatches := <-mismatchMu
19621970
mismatches[pkg] = mismatch{mod: mod, err: err}

src/cmd/go/internal/modload/modfile.go

+11-4
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ const (
4545
// "// indirect" dependencies are added in a block separate from the direct
4646
// ones. See https://golang.org/issue/45965.
4747
separateIndirectVersionV = "v1.17"
48+
49+
// tidyGoModSumVersionV is the Go version (plus leading "v") at which
50+
// 'go mod tidy' preserves go.mod checksums needed to build test dependencies
51+
// of packages in "all", so that 'go test all' can be run without checksum
52+
// errors.
53+
// See https://go.dev/issue/56222.
54+
tidyGoModSumVersionV = "v1.21"
4855
)
4956

5057
// ReadModFile reads and parses the mod file at gomod. ReadModFile properly applies the
@@ -566,6 +573,8 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
566573
summary := &modFileSummary{
567574
module: module.Version{Path: m.Path},
568575
}
576+
577+
readVendorList(MainModules.mustGetSingleMainModule())
569578
if vendorVersion[m.Path] != m.Version {
570579
// This module is not vendored, so packages cannot be loaded from it and
571580
// it cannot be relevant to the build.
@@ -574,19 +583,17 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
574583

575584
// For every module other than the target,
576585
// return the full list of modules from modules.txt.
577-
readVendorList(MainModules.mustGetSingleMainModule())
578-
579586
// We don't know what versions the vendored module actually relies on,
580587
// so assume that it requires everything.
581588
summary.require = vendorList
582589
return summary, nil
583590
}
584591

585592
actual := resolveReplacement(m)
586-
if HasModRoot() && cfg.BuildMod == "readonly" && !inWorkspaceMode() && actual.Version != "" {
593+
if mustHaveSums() && actual.Version != "" {
587594
key := module.Version{Path: actual.Path, Version: actual.Version + "/go.mod"}
588595
if !modfetch.HaveSum(key) {
589-
suggestion := fmt.Sprintf("; to add it:\n\tgo mod download %s", m.Path)
596+
suggestion := fmt.Sprintf(" for go.mod file; to add it:\n\tgo mod download %s", m.Path)
590597
return nil, module.VersionError(actual, &sumMissingError{suggestion: suggestion})
591598
}
592599
}

src/cmd/go/testdata/script/list_parse_err.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ stderr '^p[/\\]b.go:2:2: expected ''package'', found ''EOF''$'
44
! go list -f '{{range .Imports}}{{.}} {{end}}' ./p
55
stderr '^p[/\\]b.go:2:2: expected ''package'', found ''EOF''$'
66
! go list -test ./t
7-
stderr '^can''t load test package: t[/\\]t_test.go:8:1: expected declaration, found ʕ'
7+
stderr '^go: can''t load test package: t[/\\]t_test.go:8:1: expected declaration, found ʕ'
88
! go list -test -f '{{range .Imports}}{{.}} {{end}}' ./t
9-
stderr '^can''t load test package: t[/\\]t_test.go:8:1: expected declaration, found ʕ'
9+
stderr '^go: can''t load test package: t[/\\]t_test.go:8:1: expected declaration, found ʕ'
1010

1111
# 'go list -e' should report imports, even if some files have parse errors
1212
# before the import block.

src/cmd/go/testdata/script/mod_install_pkg_version.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ env GO111MODULE=auto
1616
cd m
1717
cp go.mod go.mod.orig
1818
! go list -m all
19-
stderr '^go: example.com/[email protected]: missing go.sum entry; to add it:\n\tgo mod download example.com/cmd$'
19+
stderr '^go: example.com/[email protected]: reading http.*/mod/example.com/cmd/@v/v1.1.0-doesnotexist.info: 404 Not Found\n\tserver response: 404 page not found$'
20+
stderr '^go: example.com/[email protected]: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/cmd$'
2021
go install example.com/cmd/a@latest
2122
cmp go.mod go.mod.orig
2223
exists $GOPATH/bin/a$GOEXE

src/cmd/go/testdata/script/mod_list_sums.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ stderr '^go: updates to go.sum needed, disabled by -mod=readonly$'
2929
#
3030
# TODO(#41297): This should not be an error either.
3131
! go list -m -mod=readonly -versions rsc.io/sampler
32-
stderr '^go: rsc\.io/quote@v1\.5\.1: missing go\.sum entry; to add it:\n\tgo mod download rsc\.io/quote$'
32+
stderr '^go: rsc\.io/quote@v1\.5\.1: missing go\.sum entry for go.mod file; to add it:\n\tgo mod download rsc\.io/quote$'

src/cmd/go/testdata/script/mod_run_pkg_version.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ env GO111MODULE=on
2121
cd m
2222
cp go.mod go.mod.orig
2323
! go list -m all
24-
stderr '^go: example.com/[email protected]: missing go.sum entry; to add it:\n\tgo mod download example.com/cmd$'
24+
stderr '^go: example.com/[email protected]: reading http.*/mod/example\.com/cmd/@v/v1.1.0-doesnotexist.info: 404 Not Found\n\tserver response: 404 page not found$'
25+
stderr '^go: example.com/[email protected]: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/cmd$'
2526
go run example.com/cmd/[email protected]
2627
2728
cmp go.mod go.mod.orig
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Regression test for #56222: 'go get -t' and 'go mod tidy'
2+
# should save enough checksums to run 'go test' on the named
3+
# packages or any package in "all" respectively.
4+
5+
6+
# At go 1.20 or earlier, 'go mod tidy' should preserve the historical go.sum
7+
# contents, but 'go test' should flag the missing checksums (instead of trying
8+
# to build the test dependency with the wrong language version).
9+
10+
cd m1
11+
go mod tidy
12+
! go test -o $devnull -c example.com/m2/q
13+
stderr '^# example.com/m2/q\n'..${/}m2${/}q${/}'q_test.go:3:8: example.com/[email protected]: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/generics$'
14+
15+
go mod download -json example.com/generics
16+
go list -f '{{if eq .ImportPath "example.com/generics"}}{{.Module.GoVersion}}{{end}}' -deps -test example.com/m2/q
17+
stdout 1.18
18+
19+
20+
# Even at go 1.20 or earlier, 'go mod tidy' shouldn't need go.mod files or
21+
# checksums that it won't record.
22+
23+
go mod tidy -go=1.20
24+
go clean -modcache # Remove checksums from the module cache, so that only go.sum is used.
25+
26+
env OLDSUMDB=$GOSUMDB
27+
env GOSUMDB=bad
28+
go mod tidy
29+
30+
env GOSUMDB=$OLDSUMDB
31+
32+
33+
# Regardless of the go version in go.mod, 'go get -t' should fetch
34+
# enough checksums to run 'go test' on the named package.
35+
36+
rm p
37+
go mod tidy -go=1.20
38+
go list -m all
39+
! stdout example.com/generics
40+
go get -t example.com/m2/[email protected]
41+
go list -f '{{if eq .ImportPath "example.com/generics"}}{{.Module.GoVersion}}{{end}}' -deps -test example.com/m2/q
42+
stdout 1.18
43+
[!short] go test -o $devnull -c example.com/m2/q
44+
45+
46+
-- m1/go.mod --
47+
module example.com/m1
48+
49+
go 1.20
50+
51+
require example.com/m2 v1.0.0
52+
replace example.com/m2 => ../m2
53+
-- m1/p/p.go --
54+
package p
55+
56+
import _ "example.com/m2/q"
57+
-- m2/go.mod --
58+
module example.com/m2
59+
60+
go 1.20
61+
62+
require example.com/generics v1.0.0
63+
-- m2/q/q.go --
64+
package q
65+
-- m2/q/q_test.go --
66+
package q
67+
68+
import _ "example.com/generics"

src/cmd/go/testdata/script/mod_sum_readonly.txt

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ env GO111MODULE=on
44
# When a sum is needed to load the build list, we get an error for the
55
# specific module. The .mod file is not downloaded, and go.sum is not written.
66
! go list -m all
7-
stderr '^go: rsc.io/[email protected]: missing go.sum entry; to add it:\n\tgo mod download rsc.io/quote$'
7+
stderr '^go: rsc.io/[email protected]: missing go.sum entry for go.mod file; to add it:\n\tgo mod download rsc.io/quote$'
88
! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod
99
! exists go.sum
1010

1111
# If go.sum exists but contains hashes from an algorithm we don't know about,
1212
# we should see the same error.
1313
cp go.sum.h2only go.sum
1414
! go list -m all
15-
stderr '^go: rsc.io/[email protected]: missing go.sum entry; to add it:\n\tgo mod download rsc.io/quote$'
15+
stderr '^go: rsc.io/[email protected]: missing go.sum entry for go.mod file; to add it:\n\tgo mod download rsc.io/quote$'
1616
! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod
1717
cmp go.sum go.sum.h2only
1818
rm go.sum
@@ -21,7 +21,7 @@ rm go.sum
2121
cp go.mod go.mod.orig
2222
go mod edit -replace rsc.io/[email protected]=rsc.io/[email protected]
2323
! go list -m all
24-
stderr '^go: rsc.io/[email protected] \(replaced by rsc.io/[email protected]\): missing go.sum entry; to add it:\n\tgo mod download rsc.io/quote$'
24+
stderr '^go: rsc.io/[email protected] \(replaced by rsc.io/[email protected]\): missing go.sum entry for go.mod file; to add it:\n\tgo mod download rsc.io/quote$'
2525
! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.1.mod
2626
! exists go.sum
2727
cp go.mod.orig go.mod

src/cmd/go/testdata/script/mod_tidy_compat.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ cmp stdout m_all.txt
5050

5151
go mod edit -go=1.16
5252
! go list -m all
53-
stderr '^go: example.net/[email protected] requires\n\texample.com/[email protected]: missing go.sum entry; to add it:\n\tgo mod download example.com/version$'
53+
stderr '^go: example.net/[email protected] requires\n\texample.com/[email protected]: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/version$'
5454

5555

5656
-- go.mod --

src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ cmp stdout all-m.txt
6262

6363
go mod edit -go=1.16
6464
! go list -m all
65-
stderr '^go: example\.net/indirect@v0\.1\.0 requires\n\texample\.net/ambiguous@v0\.1\.0: missing go\.sum entry; to add it:\n\tgo mod download example\.net/ambiguous\n'
65+
stderr '^go: example\.net/indirect@v0\.1\.0 requires\n\texample\.net/ambiguous@v0\.1\.0: missing go\.sum entry for go\.mod file; to add it:\n\tgo mod download example\.net/ambiguous\n'
6666

6767

6868
-- go.mod --

src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt

+5-5
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,14 @@ go mod tidy -compat=1.17
4545
! stderr .
4646
cmp go.mod go.mod.orig
4747

48-
go list -deps -test -f $MODFMT all
49-
stdout '^example\.com/retract/incompatible v1\.0\.0$'
48+
go list -deps -test -f $MODFMT ./...
49+
stdout '^example.net/lazy v0.1.0$'
5050

5151
go mod edit -go=1.16
52-
! go list -deps -test -f $MODFMT all
52+
! go list -deps -test -f $MODFMT ./...
5353

5454
# TODO(#46160): -count=1 instead of -count=2.
55-
stderr -count=2 '^go: example\.net/lazy@v0\.1\.0 requires\n\texample\.com/retract/incompatible@v1\.0\.0: missing go\.sum entry; to add it:\n\tgo mod download example\.com/retract/incompatible$'
55+
stderr -count=2 '^go: example\.net/lazy@v0\.1\.0 requires\n\texample\.com/retract/incompatible@v1\.0\.0: missing go\.sum entry for go\.mod file; to add it:\n\tgo mod download example\.com/retract/incompatible$'
5656

5757

5858
# If we combine a Go 1.16 go.sum file...
@@ -63,7 +63,7 @@ cp go.mod.orig go.mod
6363

6464
# ...then Go 1.17 no longer works. 😞
6565
! go list -deps -test -f $MODFMT all
66-
stderr -count=1 '^can''t load test package: lazy[/\\]lazy_test.go:3:8: missing go\.sum entry for module providing package example\.com/retract/incompatible \(imported by example\.net/lazy\); to add:\n\tgo get -t example.net/lazy@v0\.1\.0$'
66+
stderr -count=1 '^go: can''t load test package: lazy[/\\]lazy_test.go:3:8: missing go\.sum entry for module providing package example\.com/retract/incompatible \(imported by example\.net/lazy\); to add:\n\tgo get -t example.net/lazy@v0\.1\.0$'
6767

6868

6969
# However, if we take the union of the go.sum files...

src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ cmp go.mod go.mod.orig
4949
go mod edit -go=1.16
5050
! go list -f $MODFMT -deps ./...
5151
# TODO(#46160): -count=1 instead of -count=2.
52-
stderr -count=2 '^go: example\.net/lazy@v0\.1\.0 requires\n\texample\.net/requireincompatible@v0\.1\.0 requires\n\texample\.com/retract/incompatible@v2\.0\.0\+incompatible: missing go.sum entry; to add it:\n\tgo mod download example.com/retract/incompatible$'
52+
stderr -count=2 '^go: example\.net/lazy@v0\.1\.0 requires\n\texample\.net/requireincompatible@v0\.1\.0 requires\n\texample\.com/retract/incompatible@v2\.0\.0\+incompatible: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/retract/incompatible$'
5353

5454

5555
# There are two ways for the module author to bring the two into alignment.

src/cmd/go/testdata/script/mod_tidy_compat_irrelevant.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ cmp stdout out-117.txt
4848
go mod edit -go=1.16
4949
! go list -deps -test -f $MODFMT all
5050
# TODO(#46160): -count=1 instead of -count=2.
51-
stderr -count=2 '^go: example.net/[email protected] requires\n\texample.com/retract/[email protected]: missing go.sum entry; to add it:\n\tgo mod download example.com/retract/incompatible$'
51+
stderr -count=2 '^go: example.net/[email protected] requires\n\texample.com/retract/[email protected]: missing go.sum entry for go.mod file; to add it:\n\tgo mod download example.com/retract/incompatible$'
5252

5353

5454
-- go.mod --

0 commit comments

Comments
 (0)