diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index b17c66d8e5a..d52ed5c0ba6 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -73,3 +73,22 @@ jobs: - run: go run ./gnovm/cmd/gno lint --verbose ./examples/gno.land/r/gnoland - run: go run ./gnovm/cmd/gno lint --verbose ./examples/gno.land/r/system # TODO: track coverage + mod-tidy: + strategy: + fail-fast: false + matrix: + go-version: [ "1.21.x" ] + # unittests: TODO: matrix with contracts + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/setup-go@v4 + with: + go-version: ${{ matrix.go-version }} + - uses: actions/checkout@v3 + - run: | + GNO_CMD="$(pwd)/gnovm/cmd/gno" + # Find all directories containing gno.mod file + find ./examples -name "gno.mod" -execdir go run "$GNO_CMD" mod tidy \; + # Check if there are changes after running gno mod tidy + git diff --exit-code || (echo "Some gno.mod files are not tidy, please run 'make tidy'." && exit 1) diff --git a/examples/Makefile b/examples/Makefile index f20072d9df2..9b628e01ce5 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -37,3 +37,7 @@ clean: GOFMT_FLAGS ?= -w fmt: go run -modfile ../misc/devdeps/go.mod mvdan.cc/gofumpt $(GOFMT_FLAGS) `find . -name "*.gno"` + +.PHONY: tidy +tidy: + find . -name "gno.mod" -execdir go run github.com/gnolang/gno/gnovm/cmd/gno mod tidy \; diff --git a/examples/gno.land/p/demo/acl/gno.mod b/examples/gno.land/p/demo/acl/gno.mod index 2aabe3a5645..176cde637bd 100644 --- a/examples/gno.land/p/demo/acl/gno.mod +++ b/examples/gno.land/p/demo/acl/gno.mod @@ -1,6 +1,6 @@ module gno.land/p/demo/acl require ( - "gno.land/p/demo/avl" v0.0.0-latest - "gno.land/p/demo/testutils" v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/testutils v0.0.0-latest ) diff --git a/examples/gno.land/p/demo/blog/gno.mod b/examples/gno.land/p/demo/blog/gno.mod index c8437af1732..65f58e7a0f6 100644 --- a/examples/gno.land/p/demo/blog/gno.mod +++ b/examples/gno.land/p/demo/blog/gno.mod @@ -1,7 +1,7 @@ module gno.land/p/demo/blog require ( - "gno.land/p/demo/avl" v0.0.0-latest - "gno.land/p/demo/ufmt" v0.0.0-latest - "gno.land/p/demo/mux" v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/mux v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest ) diff --git a/examples/gno.land/p/demo/dom/gno.mod b/examples/gno.land/p/demo/dom/gno.mod index e7d0e5a9e75..83ca827cf66 100644 --- a/examples/gno.land/p/demo/dom/gno.mod +++ b/examples/gno.land/p/demo/dom/gno.mod @@ -1,5 +1,3 @@ module gno.land/p/demo/dom -require ( - "gno.land/p/demo/avl" v0.0.0-latest -) +require gno.land/p/demo/avl v0.0.0-latest diff --git a/examples/gno.land/p/demo/flow/gno.mod b/examples/gno.land/p/demo/flow/gno.mod index 4a4d4fb4d82..5adddbfe021 100644 --- a/examples/gno.land/p/demo/flow/gno.mod +++ b/examples/gno.land/p/demo/flow/gno.mod @@ -1 +1 @@ -module "gno.land/p/demo/flow" +module gno.land/p/demo/flow diff --git a/examples/gno.land/p/demo/gnode/gno.mod b/examples/gno.land/p/demo/gnode/gno.mod index e922821f7fd..a93c2051830 100644 --- a/examples/gno.land/p/demo/gnode/gno.mod +++ b/examples/gno.land/p/demo/gnode/gno.mod @@ -1 +1 @@ -module "gno.land/p/demo/gnode" +module gno.land/p/demo/gnode diff --git a/examples/gno.land/p/demo/grc/exts/vault/gno.mod b/examples/gno.land/p/demo/grc/exts/vault/gno.mod index 8b4d4524366..2720bf09d95 100644 --- a/examples/gno.land/p/demo/grc/exts/vault/gno.mod +++ b/examples/gno.land/p/demo/grc/exts/vault/gno.mod @@ -1,6 +1,6 @@ module gno.land/p/demo/grc/exts/vault require ( - "gno.land/p/demo/avl" v0.0.0-latest - "gno.land/p/demo/grc/grc20" v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/grc/grc20 v0.0.0-latest ) diff --git a/examples/gno.land/p/demo/grc/grc1155/gno.mod b/examples/gno.land/p/demo/grc/grc1155/gno.mod index 33a8e55be71..0b2b85d8e86 100644 --- a/examples/gno.land/p/demo/grc/grc1155/gno.mod +++ b/examples/gno.land/p/demo/grc/grc1155/gno.mod @@ -1,7 +1,7 @@ module gno.land/p/demo/grc/grc1155 require ( - "gno.land/p/demo/avl" v0.0.0-latest - "gno.land/r/demo/users" v0.0.0-latest - "gno.land/p/demo/ufmt" v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest + gno.land/r/demo/users v0.0.0-latest ) diff --git a/examples/gno.land/p/demo/grc/grc20/gno.mod b/examples/gno.land/p/demo/grc/grc20/gno.mod index 5e6e13f834c..fd80766a956 100644 --- a/examples/gno.land/p/demo/grc/grc20/gno.mod +++ b/examples/gno.land/p/demo/grc/grc20/gno.mod @@ -1,7 +1,7 @@ module gno.land/p/demo/grc/grc20 require ( - "gno.land/p/demo/avl" v0.0.0-latest - "gno.land/p/demo/ufmt" v0.0.0-latest - "gno.land/p/demo/grc/exts" v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/grc/exts v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest ) diff --git a/examples/gno.land/p/demo/grc/grc721/gno.mod b/examples/gno.land/p/demo/grc/grc721/gno.mod index 229fc3f739c..ea8c9c9e52e 100644 --- a/examples/gno.land/p/demo/grc/grc721/gno.mod +++ b/examples/gno.land/p/demo/grc/grc721/gno.mod @@ -1,7 +1,7 @@ module gno.land/p/demo/grc/grc721 require ( - "gno.land/p/demo/avl" v0.0.0-latest - "gno.land/r/demo/users" v0.0.0-latest - "gno.land/p/demo/ufmt" v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest + gno.land/r/demo/users v0.0.0-latest ) diff --git a/examples/gno.land/p/demo/grc/grc777/gno.mod b/examples/gno.land/p/demo/grc/grc777/gno.mod index 2fddce3f8f8..9fbf2f2b7cd 100644 --- a/examples/gno.land/p/demo/grc/grc777/gno.mod +++ b/examples/gno.land/p/demo/grc/grc777/gno.mod @@ -1,5 +1,3 @@ module gno.land/p/demo/grc/grc777 -require ( - "gno.land/p/demo/grc/exts" v0.0.0-latest -) +require gno.land/p/demo/grc/exts v0.0.0-latest diff --git a/examples/gno.land/p/demo/groups/gno.mod b/examples/gno.land/p/demo/groups/gno.mod index b52ad8b05b1..0e9f7cf2a7c 100644 --- a/examples/gno.land/p/demo/groups/gno.mod +++ b/examples/gno.land/p/demo/groups/gno.mod @@ -1,7 +1,6 @@ module gno.land/p/demo/groups require ( - "gno.land/r/demo/boards" v0.0.0-latest - "gno.land/p/demo/maths" v0.0.0-latest - "gno.land/p/demo/testutils" v0.0.0-latest + gno.land/p/demo/maths v0.0.0-latest + gno.land/r/demo/boards v0.0.0-latest ) diff --git a/examples/gno.land/p/demo/math_eval/int32/gno.mod b/examples/gno.land/p/demo/math_eval/int32/gno.mod index 9a1e634447c..de57497a699 100644 --- a/examples/gno.land/p/demo/math_eval/int32/gno.mod +++ b/examples/gno.land/p/demo/math_eval/int32/gno.mod @@ -1,5 +1,3 @@ module gno.land/p/demo/math_eval/int32 -require ( - "gno.land/p/demo/ufmt" v0.0.0-latest -) +require gno.land/p/demo/ufmt v0.0.0-latest diff --git a/examples/gno.land/p/demo/microblog/gno.mod b/examples/gno.land/p/demo/microblog/gno.mod index fe19b89f777..5964679efa6 100644 --- a/examples/gno.land/p/demo/microblog/gno.mod +++ b/examples/gno.land/p/demo/microblog/gno.mod @@ -1,7 +1,8 @@ module gno.land/p/demo/microblog require ( - "gno.land/p/demo/avl" v0.0.0-latest - "gno.land/p/demo/ufmt" v0.0.0-latest - "gno.land/r/demo/users" v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/testutils v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest + gno.land/r/demo/users v0.0.0-latest ) diff --git a/examples/gno.land/p/demo/mux/gno.mod b/examples/gno.land/p/demo/mux/gno.mod index 13e4736bea8..972a531e14c 100644 --- a/examples/gno.land/p/demo/mux/gno.mod +++ b/examples/gno.land/p/demo/mux/gno.mod @@ -1 +1 @@ -module "gno.land/p/demo/mux" +module gno.land/p/demo/mux diff --git a/examples/gno.land/p/demo/rand/gno.mod b/examples/gno.land/p/demo/rand/gno.mod index 66082ea873e..098af152648 100644 --- a/examples/gno.land/p/demo/rand/gno.mod +++ b/examples/gno.land/p/demo/rand/gno.mod @@ -1,3 +1,3 @@ // Draft -module gno.land/p/demo/rand +module gno.land/p/demo/rand diff --git a/examples/gno.land/p/demo/svg/gno.mod b/examples/gno.land/p/demo/svg/gno.mod index adb2acf1350..0af7ba0636d 100644 --- a/examples/gno.land/p/demo/svg/gno.mod +++ b/examples/gno.land/p/demo/svg/gno.mod @@ -1,5 +1,3 @@ module gno.land/p/demo/svg -require ( - "gno.land/p/demo/ufmt" v0.0.0-latest -) +require gno.land/p/demo/ufmt v0.0.0-latest diff --git a/examples/gno.land/p/demo/tests/gno.mod b/examples/gno.land/p/demo/tests/gno.mod index 229c2f62d9c..5d80e106567 100644 --- a/examples/gno.land/p/demo/tests/gno.mod +++ b/examples/gno.land/p/demo/tests/gno.mod @@ -1,6 +1,6 @@ module gno.land/p/demo/tests require ( - "gno.land/p/demo/tests/subtests" v0.0.0-latest - "gno.land/r/demo/tests" v0.0.0-latest + gno.land/p/demo/tests/subtests v0.0.0-latest + gno.land/r/demo/tests v0.0.0-latest ) diff --git a/examples/gno.land/p/demo/tests/subtests/gno.mod b/examples/gno.land/p/demo/tests/subtests/gno.mod index 26ec7c4879a..c8333722809 100644 --- a/examples/gno.land/p/demo/tests/subtests/gno.mod +++ b/examples/gno.land/p/demo/tests/subtests/gno.mod @@ -1,4 +1,4 @@ module gno.land/p/demo/tests/subtests -// TODO: this file should not exist. +// TODO: this file should not exist. // This is a temporary workaround. Until https://github.com/gnolang/gno/issues/852 diff --git a/examples/gno.land/p/demo/ui/gno.mod b/examples/gno.land/p/demo/ui/gno.mod index e71ee2d1ab1..41f5cb78d83 100644 --- a/examples/gno.land/p/demo/ui/gno.mod +++ b/examples/gno.land/p/demo/ui/gno.mod @@ -1 +1 @@ -module "gno.land/p/demo/ui" +module gno.land/p/demo/ui diff --git a/examples/gno.land/r/demo/art/gnoface/gno.mod b/examples/gno.land/r/demo/art/gnoface/gno.mod index 33d644206d6..bc17ee9df3b 100644 --- a/examples/gno.land/r/demo/art/gnoface/gno.mod +++ b/examples/gno.land/r/demo/art/gnoface/gno.mod @@ -1,6 +1,6 @@ module gno.land/r/demo/art/gnoface require ( - "gno.land/p/demo/rand" v0.0.0-latest - "gno.land/p/demo/ufmt" v0.0.0-latest + gno.land/p/demo/rand v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest ) diff --git a/examples/gno.land/r/demo/art/millipede/gno.mod b/examples/gno.land/r/demo/art/millipede/gno.mod index 10e3d2f1474..346e3a1673c 100644 --- a/examples/gno.land/r/demo/art/millipede/gno.mod +++ b/examples/gno.land/r/demo/art/millipede/gno.mod @@ -1,5 +1,3 @@ module gno.land/r/demo/art/millipede -require ( - "gno.land/p/demo/ufmt" v0.0.0-latest -) +require gno.land/p/demo/ufmt v0.0.0-latest diff --git a/examples/gno.land/r/demo/boards/gno.mod b/examples/gno.land/r/demo/boards/gno.mod index 882d97fec83..434ad019883 100644 --- a/examples/gno.land/r/demo/boards/gno.mod +++ b/examples/gno.land/r/demo/boards/gno.mod @@ -1,6 +1,6 @@ module gno.land/r/demo/boards require ( - "gno.land/p/demo/avl" v0.0.0-latest - "gno.land/r/demo/users" v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest + gno.land/r/demo/users v0.0.0-latest ) diff --git a/examples/gno.land/r/demo/foo1155/gno.mod b/examples/gno.land/r/demo/foo1155/gno.mod index 07c05ff5ef3..6fdf18a1658 100644 --- a/examples/gno.land/r/demo/foo1155/gno.mod +++ b/examples/gno.land/r/demo/foo1155/gno.mod @@ -1,7 +1,7 @@ module gno.land/r/demo/foo1155 require ( - "gno.land/p/demo/ufmt" v0.0.0-latest - "gno.land/p/demo/grc/grc1155" v0.0.0-latest - "gno.land/r/demo/users" v0.0.0-latest + gno.land/p/demo/grc/grc1155 v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest + gno.land/r/demo/users v0.0.0-latest ) diff --git a/examples/gno.land/r/demo/foo20/gno.mod b/examples/gno.land/r/demo/foo20/gno.mod index 1dbe9e01e4f..516690ee66c 100644 --- a/examples/gno.land/r/demo/foo20/gno.mod +++ b/examples/gno.land/r/demo/foo20/gno.mod @@ -1,7 +1,7 @@ module gno.land/r/demo/foo20 require ( - "gno.land/p/demo/ufmt" v0.0.0-latest - "gno.land/p/demo/grc/grc20" v0.0.0-latest - "gno.land/r/demo/users" v0.0.0-latest + gno.land/p/demo/grc/grc20 v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest + gno.land/r/demo/users v0.0.0-latest ) diff --git a/examples/gno.land/r/demo/foo721/gno.mod b/examples/gno.land/r/demo/foo721/gno.mod index b34ffd2b3fe..46c19e6ae55 100644 --- a/examples/gno.land/r/demo/foo721/gno.mod +++ b/examples/gno.land/r/demo/foo721/gno.mod @@ -1,7 +1,7 @@ module gno.land/r/demo/foo721 require ( - "gno.land/p/demo/ufmt" v0.0.0-latest - "gno.land/p/demo/grc/grc721" v0.0.0-latest - "gno.land/r/demo/users" v0.0.0-latest + gno.land/p/demo/grc/grc721 v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest + gno.land/r/demo/users v0.0.0-latest ) diff --git a/examples/gno.land/r/demo/groups/gno.mod b/examples/gno.land/r/demo/groups/gno.mod index d97acbecc7a..fc6756e13e2 100644 --- a/examples/gno.land/r/demo/groups/gno.mod +++ b/examples/gno.land/r/demo/groups/gno.mod @@ -1,6 +1,6 @@ module gno.land/r/demo/groups require ( - "gno.land/p/demo/avl" v0.0.0-latest - "gno.land/r/demo/users" v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest + gno.land/r/demo/users v0.0.0-latest ) diff --git a/examples/gno.land/r/demo/keystore/gno.mod b/examples/gno.land/r/demo/keystore/gno.mod index 88d59c9ccd6..af0b907c259 100644 --- a/examples/gno.land/r/demo/keystore/gno.mod +++ b/examples/gno.land/r/demo/keystore/gno.mod @@ -1,6 +1,7 @@ module gno.land/r/demo/keystore require ( - "gno.land/p/demo/ufmt" v0.0.0-latest - "gno.land/p/demo/avl" v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/testutils v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest ) diff --git a/examples/gno.land/r/demo/math_eval/gno.mod b/examples/gno.land/r/demo/math_eval/gno.mod index 69d4e8c459b..0e3fcfe6e9b 100644 --- a/examples/gno.land/r/demo/math_eval/gno.mod +++ b/examples/gno.land/r/demo/math_eval/gno.mod @@ -1,6 +1,6 @@ module gno.land/r/demo/math_eval require ( - "gno.land/p/demo/ufmt" v0.0.0-latest - "gno.land/p/demo/math_eval/int32" v0.0.0-latest + gno.land/p/demo/math_eval/int32 v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest ) diff --git a/examples/gno.land/r/demo/microblog/gno.mod b/examples/gno.land/r/demo/microblog/gno.mod index 3d79a38d5fd..f496b1008ce 100644 --- a/examples/gno.land/r/demo/microblog/gno.mod +++ b/examples/gno.land/r/demo/microblog/gno.mod @@ -1,6 +1,6 @@ module gno.land/r/demo/microblog require ( - "gno.land/p/demo/microblog" v0.0.0-latest - "gno.land/r/demo/users" v0.0.0-latest + gno.land/p/demo/microblog v0.0.0-latest + gno.land/r/demo/users v0.0.0-latest ) diff --git a/examples/gno.land/r/demo/nft/gno.mod b/examples/gno.land/r/demo/nft/gno.mod index 2fefdbd1907..89e0055be51 100644 --- a/examples/gno.land/r/demo/nft/gno.mod +++ b/examples/gno.land/r/demo/nft/gno.mod @@ -1,6 +1,6 @@ module gno.land/r/demo/nft require ( - "gno.land/p/demo/avl" v0.0.0-latest - "gno.land/p/demo/grc/grc721" v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/grc/grc721 v0.0.0-latest ) diff --git a/examples/gno.land/r/demo/releases_example/gno.mod b/examples/gno.land/r/demo/releases_example/gno.mod index 85bcd07f232..22f640fe797 100644 --- a/examples/gno.land/r/demo/releases_example/gno.mod +++ b/examples/gno.land/r/demo/releases_example/gno.mod @@ -1,5 +1,3 @@ module gno.land/r/demo/releases_example -require ( - "gno.land/p/demo/releases" v0.0.0-latest -) +require gno.land/p/demo/releases v0.0.0-latest diff --git a/examples/gno.land/r/demo/tests/gno.mod b/examples/gno.land/r/demo/tests/gno.mod index 23dd3760157..9c5162f848e 100644 --- a/examples/gno.land/r/demo/tests/gno.mod +++ b/examples/gno.land/r/demo/tests/gno.mod @@ -1,6 +1,6 @@ module gno.land/r/demo/tests require ( - "gno.land/p/demo/testutils" v0.0.0-latest - "gno.land/r/demo/tests/subtests" v0.0.0-latest + gno.land/p/demo/testutils v0.0.0-latest + gno.land/r/demo/tests/subtests v0.0.0-latest ) diff --git a/examples/gno.land/r/demo/tests/subtests/gno.mod b/examples/gno.land/r/demo/tests/subtests/gno.mod index 80db73b4c15..9f466ff77b9 100644 --- a/examples/gno.land/r/demo/tests/subtests/gno.mod +++ b/examples/gno.land/r/demo/tests/subtests/gno.mod @@ -1,4 +1,4 @@ module gno.land/r/demo/tests/subtests -// TODO: this file should not exist. +// TODO: this file should not exist. // This is a temporary workaround. Until https://github.com/gnolang/gno/issues/852 diff --git a/examples/gno.land/r/demo/tests_foo/gno.mod b/examples/gno.land/r/demo/tests_foo/gno.mod index b19d8a21de1..226271ae4b0 100644 --- a/examples/gno.land/r/demo/tests_foo/gno.mod +++ b/examples/gno.land/r/demo/tests_foo/gno.mod @@ -1,5 +1,3 @@ module gno.land/r/demo/tests_foo -require ( - "gno.land/r/demo/tests" v0.0.0-latest -) +require gno.land/r/demo/tests v0.0.0-latest diff --git a/examples/gno.land/r/demo/types/gno.mod b/examples/gno.land/r/demo/types/gno.mod index 5709668ef2a..0e86e5d5676 100644 --- a/examples/gno.land/r/demo/types/gno.mod +++ b/examples/gno.land/r/demo/types/gno.mod @@ -1,5 +1,3 @@ module gno.land/r/demo/types -require ( - "gno.land/p/demo/avl" v0.0.0-latest -) +require gno.land/p/demo/avl v0.0.0-latest diff --git a/examples/gno.land/r/demo/ui/gno.mod b/examples/gno.land/r/demo/ui/gno.mod index 597c0f388a4..42be8cec3f0 100644 --- a/examples/gno.land/r/demo/ui/gno.mod +++ b/examples/gno.land/r/demo/ui/gno.mod @@ -1,5 +1,3 @@ module gno.land/r/demo/ui -require ( - "gno.land/p/demo/ui" v0.0.0-latest -) +require gno.land/p/demo/ui v0.0.0-latest diff --git a/examples/gno.land/r/demo/users/gno.mod b/examples/gno.land/r/demo/users/gno.mod index 055b5816871..edd20eb2721 100644 --- a/examples/gno.land/r/demo/users/gno.mod +++ b/examples/gno.land/r/demo/users/gno.mod @@ -1,6 +1,3 @@ module gno.land/r/demo/users -require ( - "gno.land/p/demo/avl" v0.0.0-latest - "gno.land/p/demo/testutils" v0.0.0-latest -) +require gno.land/p/demo/avl v0.0.0-latest diff --git a/examples/gno.land/r/gnoland/blog/gno.mod b/examples/gno.land/r/gnoland/blog/gno.mod index a8b4f3ceaa9..1d64238cdc8 100644 --- a/examples/gno.land/r/gnoland/blog/gno.mod +++ b/examples/gno.land/r/gnoland/blog/gno.mod @@ -1,6 +1,6 @@ module gno.land/r/gnoland/blog require ( - "gno.land/p/demo/avl" v0.0.0-latest - "gno.land/p/demo/blog" v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/blog v0.0.0-latest ) diff --git a/examples/gno.land/r/gnoland/faucet/gno.mod b/examples/gno.land/r/gnoland/faucet/gno.mod index 75e85df326b..693b0e795cf 100644 --- a/examples/gno.land/r/gnoland/faucet/gno.mod +++ b/examples/gno.land/r/gnoland/faucet/gno.mod @@ -1,7 +1,7 @@ module gno.land/r/gnoland/faucet require ( - "gno.land/p/demo/avl" v0.0.0-latest - "gno.land/p/demo/testutils" v0.0.0-latest - "gno.land/p/demo/ufmt" v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/testutils v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest ) diff --git a/examples/gno.land/r/gnoland/pages/gno.mod b/examples/gno.land/r/gnoland/pages/gno.mod index 0f5c4076509..31e9ad2c85b 100644 --- a/examples/gno.land/r/gnoland/pages/gno.mod +++ b/examples/gno.land/r/gnoland/pages/gno.mod @@ -1,6 +1,6 @@ module gno.land/r/gnoland/pages require ( - "gno.land/p/demo/avl" v0.0.0-latest - "gno.land/p/demo/blog" v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/blog v0.0.0-latest ) diff --git a/examples/gno.land/r/system/names/gno.mod b/examples/gno.land/r/system/names/gno.mod index 31c456f90e0..cd4fd0aae4a 100644 --- a/examples/gno.land/r/system/names/gno.mod +++ b/examples/gno.land/r/system/names/gno.mod @@ -1,5 +1,3 @@ module gno.land/r/system/names -require ( - "gno.land/p/demo/avl" v0.0.0-latest -) +require gno.land/p/demo/avl v0.0.0-latest diff --git a/examples/gno.land/r/x/manfred_outfmt/gno.mod b/examples/gno.land/r/x/manfred_outfmt/gno.mod index eef8ec5956e..e6f705c46b9 100644 --- a/examples/gno.land/r/x/manfred_outfmt/gno.mod +++ b/examples/gno.land/r/x/manfred_outfmt/gno.mod @@ -1,6 +1,6 @@ module gno.land/r/x/manfred_outfmt require ( - "gno.land/p/demo/rand" v0.0.0-latest - "gno.land/p/demo/ufmt" v0.0.0-latest + gno.land/p/demo/rand v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest ) diff --git a/gnovm/cmd/gno/mod.go b/gnovm/cmd/gno/mod.go index 267b7d99237..9fb5dd704ce 100644 --- a/gnovm/cmd/gno/mod.go +++ b/gnovm/cmd/gno/mod.go @@ -4,8 +4,12 @@ import ( "context" "flag" "fmt" + "go/parser" + "go/token" "os" "path/filepath" + "sort" + "strings" "github.com/gnolang/gno/gnovm/pkg/gnomod" "github.com/gnolang/gno/tm2/pkg/commands" @@ -31,6 +35,7 @@ func newModCmd(io *commands.IO) *commands.Command { cmd.AddSubCommands( newModDownloadCmd(io), newModInitCmd(), + newModTidy(io), ) return cmd @@ -66,6 +71,20 @@ func newModInitCmd() *commands.Command { ) } +func newModTidy(io *commands.IO) *commands.Command { + return commands.NewCommand( + commands.Metadata{ + Name: "tidy", + ShortUsage: "tidy", + ShortHelp: "Add missing and remove unused modules", + }, + commands.NewEmptyConfig(), + func(_ context.Context, args []string) error { + return execModTidy(args, io) + }, + ) +} + func (c *modDownloadCfg) RegisterFlags(fs *flag.FlagSet) { fs.StringVar( &c.remote, @@ -152,3 +171,89 @@ func execModInit(args []string) error { return nil } + +func execModTidy(args []string, io *commands.IO) error { + if len(args) > 0 { + return flag.ErrHelp + } + + wd, err := os.Getwd() + if err != nil { + return err + } + fname := filepath.Join(wd, "gno.mod") + gm, err := gnomod.ParseGnoMod(fname) + if err != nil { + return err + } + + // Drop all existing requires + for _, r := range gm.Require { + gm.DropRequire(r.Mod.Path) + } + + imports, err := getGnoImports(wd) + if err != nil { + return err + } + for _, im := range imports { + // skip if importpath is modulepath + if im == gm.Module.Mod.Path { + continue + } + gm.AddRequire(im, "v0.0.0-latest") + } + + gm.Write(fname) + return nil +} + +// getGnoImports returns the list of gno imports from a given path. +// Note: It ignores subdirs. Since right now we are still deciding on +// how to handle subdirs. +// See: +// - https://github.com/gnolang/gno/issues/1024 +// - https://github.com/gnolang/gno/issues/852 +// +// TODO: move this to better location. +func getGnoImports(path string) ([]string, error) { + entries, err := os.ReadDir(path) + if err != nil { + return nil, err + } + + allImports := make([]string, 0) + seen := make(map[string]struct{}) + for _, e := range entries { + filename := e.Name() + if ext := filepath.Ext(filename); ext != ".gno" { + continue + } + if strings.HasSuffix(filename, "_filetest.gno") { + continue + } + data, err := os.ReadFile(filepath.Join(path, filename)) + if err != nil { + return nil, err + } + fs := token.NewFileSet() + f, err := parser.ParseFile(fs, filename, data, parser.ImportsOnly) + if err != nil { + return nil, err + } + for _, imp := range f.Imports { + importPath := strings.TrimPrefix(strings.TrimSuffix(imp.Path.Value, `"`), `"`) + if !strings.HasPrefix(importPath, "gno.land/") { + continue + } + if _, ok := seen[importPath]; ok { + continue + } + allImports = append(allImports, importPath) + seen[importPath] = struct{}{} + } + } + sort.Strings(allImports) + + return allImports, nil +} diff --git a/gnovm/cmd/gno/mod_test.go b/gnovm/cmd/gno/mod_test.go index fdae3d12c7a..bbf106c8960 100644 --- a/gnovm/cmd/gno/mod_test.go +++ b/gnovm/cmd/gno/mod_test.go @@ -1,6 +1,13 @@ package main -import "testing" +import ( + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) func TestModApp(t *testing.T) { tc := []testMainCase{ @@ -9,7 +16,7 @@ func TestModApp(t *testing.T) { errShouldBe: "flag: help requested", }, - // test gno.mod download + // test `gno mod download` { args: []string{"mod", "download"}, testDir: "../../tests/integ/empty-dir", @@ -73,7 +80,7 @@ func TestModApp(t *testing.T) { errShouldContain: "fetch: writepackage: querychain", }, - // test gno.mod init with no module name + // test `gno mod init` with no module name { args: []string{"mod", "init"}, testDir: "../../tests/integ/valid1", @@ -110,7 +117,7 @@ func TestModApp(t *testing.T) { errShouldBe: "create gno.mod file: gno.mod file already exists", }, - // test gno.mod init with module name + // test `gno mod init` with module name { args: []string{"mod", "init", "gno.land/p/demo/foo"}, testDir: "../../tests/integ/empty-dir", @@ -137,6 +144,164 @@ func TestModApp(t *testing.T) { simulateExternalRepo: true, errShouldBe: "create gno.mod file: gno.mod file already exists", }, + + // test `gno mod tidy` with module name + { + args: []string{"mod", "tidy", "arg1"}, + testDir: "../../tests/integ/minimalist-gnomod", + simulateExternalRepo: true, + errShouldContain: "flag: help requested", + }, + { + args: []string{"mod", "tidy"}, + testDir: "../../tests/integ/empty-dir", + simulateExternalRepo: true, + errShouldContain: "could not read gno.mod file", + }, + { + args: []string{"mod", "tidy"}, + testDir: "../../tests/integ/invalid-module-version1", + simulateExternalRepo: true, + errShouldContain: "error parsing gno.mod file at", + }, + { + args: []string{"mod", "tidy"}, + testDir: "../../tests/integ/minimalist-gnomod", + simulateExternalRepo: true, + }, + { + args: []string{"mod", "tidy"}, + testDir: "../../tests/integ/require-remote-module", + simulateExternalRepo: true, + }, + { + args: []string{"mod", "tidy"}, + testDir: "../../tests/integ/valid2", + simulateExternalRepo: true, + }, + { + args: []string{"mod", "tidy"}, + testDir: "../../tests/integ/invalid-gno-file", + simulateExternalRepo: true, + errShouldContain: "expected 'package', found packag", + }, } testMainCaseRun(t, tc) } + +func TestGetGnoImports(t *testing.T) { + workingDir, err := os.Getwd() + require.NoError(t, err) + + // create external dir + tmpDir, cleanUpFn := createTmpDir(t) + defer cleanUpFn() + + // cd to tmp directory + os.Chdir(tmpDir) + defer os.Chdir(workingDir) + + files := []struct { + name, data string + }{ + { + name: "file1.gno", + data: ` + package tmp + + import ( + "std" + + "gno.land/p/demo/pkg1" + ) + `, + }, + { + name: "file2.gno", + data: ` + package tmp + + import ( + "gno.land/p/demo/pkg1" + "gno.land/p/demo/pkg2" + ) + `, + }, + { + name: "file1_test.gno", + data: ` + package tmp + + import ( + "testing" + + "gno.land/p/demo/testpkg" + ) + `, + }, + { + name: "z_0_filetest.gno", + data: ` + package main + + import ( + "gno.land/p/demo/filetestpkg" + ) + `, + }, + + // subpkg files + { + name: filepath.Join("subtmp", "file1.gno"), + data: ` + package subtmp + + import ( + "std" + + "gno.land/p/demo/subpkg1" + ) + `, + }, + { + name: filepath.Join("subtmp", "file2.gno"), + data: ` + package subtmp + + import ( + "gno.land/p/demo/subpkg1" + "gno.land/p/demo/subpkg2" + ) + `, + }, + } + + // Expected list of imports + // - ignore subdirs + // - ignore duplicate + // - ignore *_filetest.gno + // - should be sorted + expected := []string{ + "gno.land/p/demo/pkg1", + "gno.land/p/demo/pkg2", + "gno.land/p/demo/testpkg", + } + + // Create subpkg dir + err = os.Mkdir("subtmp", 0o700) + require.NoError(t, err) + + // Create files + for _, f := range files { + err = os.WriteFile(f.name, []byte(f.data), 0o644) + require.NoError(t, err) + } + + imports, err := getGnoImports(tmpDir) + require.NoError(t, err) + + require.Equal(t, len(expected), len(imports)) + for i := range imports { + assert.Equal(t, expected[i], imports[i]) + } +} diff --git a/gnovm/pkg/doc/dirs.go b/gnovm/pkg/doc/dirs.go index 21216828ce4..19d312f6826 100644 --- a/gnovm/pkg/doc/dirs.go +++ b/gnovm/pkg/doc/dirs.go @@ -5,7 +5,6 @@ package doc import ( - "fmt" "log" "os" "path" @@ -52,7 +51,7 @@ func newDirs(dirs []string, modDirs []string) *bfsDirs { } for _, mdir := range modDirs { - gm, err := parseGnoMod(filepath.Join(mdir, "gno.mod")) + gm, err := gnomod.ParseGnoMod(filepath.Join(mdir, "gno.mod")) if err != nil { log.Printf("%v", err) continue @@ -68,34 +67,6 @@ func newDirs(dirs []string, modDirs []string) *bfsDirs { return d } -// tries to parse gno mod file given the filename, using Parse and Validate from -// the gnomod package -// -// TODO(tb): replace by `gnomod.ParseAt` ? The key difference is the latter -// looks for gno.mod in parent directories, while this function doesn't. -func parseGnoMod(fname string) (*gnomod.File, error) { - file, err := os.Stat(fname) - if err != nil { - return nil, fmt.Errorf("could not read gno.mod file: %w", err) - } - if file.IsDir() { - return nil, fmt.Errorf("invalid gno.mod at %q: is a directory", fname) - } - - b, err := os.ReadFile(fname) - if err != nil { - return nil, fmt.Errorf("could not read gno.mod file: %w", err) - } - gm, err := gnomod.Parse(fname, b) - if err != nil { - return nil, fmt.Errorf("error parsing gno.mod file at %q: %w", fname, err) - } - if err := gm.Validate(); err != nil { - return nil, fmt.Errorf("error validating gno.mod file at %q: %w", fname, err) - } - return gm, nil -} - func getGnoModDirs(gm *gnomod.File) []bfsDir { // cmd/go makes use of the go list command, we don't have that here. diff --git a/gnovm/pkg/gnomod/parse.go b/gnovm/pkg/gnomod/parse.go index 5bda3c31f70..a6314d5729f 100644 --- a/gnovm/pkg/gnomod/parse.go +++ b/gnovm/pkg/gnomod/parse.go @@ -42,6 +42,34 @@ func ParseAt(dir string) (*File, error) { return gm, nil } +// tries to parse gno mod file given the filename, using Parse and Validate from +// the gnomod package +// +// TODO(tb): replace by `gnomod.ParseAt` ? The key difference is the latter +// looks for gno.mod in parent directories, while this function doesn't. +func ParseGnoMod(fname string) (*File, error) { + file, err := os.Stat(fname) + if err != nil { + return nil, fmt.Errorf("could not read gno.mod file: %w", err) + } + if file.IsDir() { + return nil, fmt.Errorf("invalid gno.mod at %q: is a directory", fname) + } + + b, err := os.ReadFile(fname) + if err != nil { + return nil, fmt.Errorf("could not read gno.mod file: %w", err) + } + gm, err := Parse(fname, b) + if err != nil { + return nil, fmt.Errorf("error parsing gno.mod file at %q: %w", fname, err) + } + if err := gm.Validate(); err != nil { + return nil, fmt.Errorf("error validating gno.mod file at %q: %w", fname, err) + } + return gm, nil +} + // Parse parses and returns a gno.mod file. // // - file is the name of the file, used in positions and errors. diff --git a/gnovm/pkg/gnomod/parse_test.go b/gnovm/pkg/gnomod/parse_test.go index 934531e69c7..61aaa83482b 100644 --- a/gnovm/pkg/gnomod/parse_test.go +++ b/gnovm/pkg/gnomod/parse_test.go @@ -1,9 +1,12 @@ package gnomod import ( + "path/filepath" "testing" + "github.com/gnolang/gno/tm2/pkg/testutils" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestModuleDeprecated(t *testing.T) { @@ -167,3 +170,57 @@ func TestParseDraft(t *testing.T) { }) } } + +func TestParseGnoMod(t *testing.T) { + pkgDir := "bar" + for _, tc := range []struct { + desc, modData, modPath, errShouldContain string + }{ + { + desc: "file not exists", + modData: `module foo`, + modPath: filepath.Join(pkgDir, "mod.gno"), + errShouldContain: "could not read gno.mod file:", + }, + { + desc: "file path is dir", + modData: `module foo`, + modPath: pkgDir, + errShouldContain: "is a directory", + }, + { + desc: "valid gno.mod file", + modData: `module foo`, + modPath: filepath.Join(pkgDir, "gno.mod"), + }, + { + desc: "error parsing gno.mod", + modData: `module foo v0.0.0`, + modPath: filepath.Join(pkgDir, "gno.mod"), + errShouldContain: "error parsing gno.mod file at", + }, + { + desc: "error validating gno.mod", + modData: `require bar v0.0.0`, + modPath: filepath.Join(pkgDir, "gno.mod"), + errShouldContain: "error validating gno.mod file at", + }, + } { + t.Run(tc.desc, func(t *testing.T) { + // Create test dir + tempDir, cleanUpFn := testutils.NewTestCaseDir(t) + require.NotNil(t, tempDir) + defer cleanUpFn() + + // Create gno package + createGnoModPkg(t, tempDir, pkgDir, tc.modData) + + _, err := ParseGnoMod(filepath.Join(tempDir, tc.modPath)) + if tc.errShouldContain != "" { + assert.ErrorContains(t, err, tc.errShouldContain) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/gnovm/tests/integ/invalid-gno-file/gno.mod b/gnovm/tests/integ/invalid-gno-file/gno.mod new file mode 100644 index 00000000000..060e28b9dc4 --- /dev/null +++ b/gnovm/tests/integ/invalid-gno-file/gno.mod @@ -0,0 +1 @@ +module test diff --git a/gnovm/tests/integ/invalid-gno-file/invalid.gno b/gnovm/tests/integ/invalid-gno-file/invalid.gno new file mode 100644 index 00000000000..1e4ff406ada --- /dev/null +++ b/gnovm/tests/integ/invalid-gno-file/invalid.gno @@ -0,0 +1 @@ +packag invalid diff --git a/gnovm/tests/integ/valid2/gno.mod b/gnovm/tests/integ/valid2/gno.mod new file mode 100644 index 00000000000..98a5a0dacc1 --- /dev/null +++ b/gnovm/tests/integ/valid2/gno.mod @@ -0,0 +1,3 @@ +module gno.land/p/integ/valid + +require gno.land/p/demo/avl v0.0.0-latest diff --git a/gnovm/tests/integ/valid2/valid.gno b/gnovm/tests/integ/valid2/valid.gno new file mode 100644 index 00000000000..4de283f5d87 --- /dev/null +++ b/gnovm/tests/integ/valid2/valid.gno @@ -0,0 +1,11 @@ +package valid + +import ( + "gno.land/p/demo/avl" +) + +const Foo = "foo" + +func DoNothing(t *avl.Tree) { + // noop +} diff --git a/gnovm/tests/integ/valid2/valid_test.gno b/gnovm/tests/integ/valid2/valid_test.gno new file mode 100644 index 00000000000..2394da5c5ae --- /dev/null +++ b/gnovm/tests/integ/valid2/valid_test.gno @@ -0,0 +1,11 @@ +package valid + +import ( + "testing" + + "gno.land/p/integ/valid" +) + +func TestAlwaysValid(t *testing.T) { + _ = valid.Foo +} diff --git a/gnovm/tests/integ/valid2/z_0_filetest.gno b/gnovm/tests/integ/valid2/z_0_filetest.gno new file mode 100644 index 00000000000..06ab7d0f9a3 --- /dev/null +++ b/gnovm/tests/integ/valid2/z_0_filetest.gno @@ -0,0 +1 @@ +package main