| # This file demonstrates the go.mod changes needed to ensure reproducibility |
| # when running 'go test' on a sequence of packages for which each package in the |
| # sequence is a test-only dependency of the previous package, as a user might do |
| # if they encounter a test failure while fixing a bug found in one of their |
| # dependencies. |
| |
| cp go.mod go.mod.old |
| cp lazy.go lazy.go.old |
| go mod tidy |
| cmp go.mod go.mod.old |
| |
| # Before adding a new import, the go.mod file should |
| # enumerate modules for all packages already imported. |
| go list -m all |
| stdout '^example.com/d v0.1.0' # not v0.2.0 as would be resolved by 'latest' |
| cp stdout list.old |
| cmp go.mod go.mod.old |
| |
| # Following the chain of dependencies by listing test dependencies |
| # or running tests should not change the go.mod file. |
| go list -test -deps example.com/a |
| stdout '^example.com/a' |
| stdout '^example.com/b' |
| ! stdout '^example.com/c' |
| [!short] go test -c example.com/a |
| cmp go.mod go.mod.old |
| |
| go list -test -deps example.com/b |
| stdout '^example.com/b' |
| stdout '^example.com/c' |
| ! stdout '^example.com/d' |
| [!short] go test -c example.com/b |
| cmp go.mod go.mod.old |
| |
| go list -test -deps example.com/c |
| stdout '^example.com/c' |
| stdout '^example.com/d' |
| [!short] go test -c example.com/c |
| cmp go.mod go.mod.old |
| |
| # When we add a new import of a package already imported by a test of a test of |
| # a dependency, and that dependency is already tidy, its transitive dependencies |
| # should already be present. |
| cp lazy.go.new lazy.go |
| go list all |
| go list -m all |
| cmp stdout list.old |
| cmp go.mod go.mod.new # Indirect dependency promoted to direct. |
| |
| # TODO(#36460): |
| |
| cp lazy.go.old lazy.go |
| cp go.mod.old go.mod |
| go mod edit -go=1.16 |
| |
| # If we reach d by running successive tests, we should end up with exactly the |
| # version required by c, with an update to the go.mod file as soon as we load a |
| # dependency not found in the deepening scan. |
| |
| # However, if we skip directly to adding a new import of d, the dependency is |
| # too far away for a deepening scan to find, which is fine because the package |
| # whose test imported it wasn't even in "all". It should resolve from the latest |
| # version of its module. |
| |
| -- go.mod -- |
| module example.com/lazy |
| |
| go 1.14 |
| |
| require example.com/a v0.1.0 |
| |
| replace ( |
| example.com/a v0.1.0 => ./a |
| example.com/b v0.1.0 => ./b |
| example.com/c v0.1.0 => ./c |
| example.com/d v0.1.0 => ./d1 |
| example.com/d v0.2.0 => ./d2 |
| ) |
| -- go.mod.new -- |
| module example.com/lazy |
| |
| go 1.14 |
| |
| require ( |
| example.com/a v0.1.0 |
| example.com/d v0.1.0 |
| ) |
| |
| replace ( |
| example.com/a v0.1.0 => ./a |
| example.com/b v0.1.0 => ./b |
| example.com/c v0.1.0 => ./c |
| example.com/d v0.1.0 => ./d1 |
| example.com/d v0.2.0 => ./d2 |
| ) |
| -- lazy.go -- |
| package lazy |
| |
| import ( |
| _ "example.com/a" |
| ) |
| |
| func main() {} |
| -- lazy.go.new -- |
| package lazy |
| |
| import ( |
| _ "example.com/a" |
| "example.com/d" |
| ) |
| |
| func main() { |
| println(d.Version) |
| } |
| -- a/go.mod -- |
| module example.com/a |
| |
| go 1.14 |
| |
| require example.com/b v0.1.0 |
| -- a/a.go -- |
| package a |
| import _ "example.com/b" |
| -- b/go.mod -- |
| module example.com/b |
| |
| go 1.16 |
| |
| require example.com/c v0.1.0 |
| -- b/b.go -- |
| package b |
| -- b/b_test.go -- |
| package b |
| import _ "example.com/c" |
| -- c/go.mod -- |
| module example.com/c |
| |
| go 1.16 |
| |
| require example.com/d v0.1.0 |
| -- c/c.go -- |
| package c |
| -- c/c_test.go -- |
| package c |
| import _ "example.com/d" |
| -- d1/go.mod -- |
| module example.com/d |
| |
| go 1.16 |
| -- d1/d.go -- |
| package d |
| const Version = "v0.1.0" |
| -- d2/go.mod -- |
| module example.com/d |
| |
| go 1.16 |
| -- d2/d.go -- |
| package d |
| const Version = "v0.2.0" |