diff --git a/go.mod b/go.mod index 018f0128c..d2df89d07 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ toolchain go1.22.3 require ( github.com/charmbracelet/bubbles v0.19.0 github.com/charmbracelet/bubbletea v0.27.1 - github.com/coreos/go-semver v0.3.0 + github.com/coreos/go-semver v0.3.1 github.com/dukex/mixpanel v1.0.1 github.com/getsentry/sentry-go v0.29.0 github.com/go-git/go-git/v5 v5.11.0 @@ -22,7 +22,7 @@ require ( github.com/onflow/flixkit-go/v2 v2.0.0 github.com/onflow/flow-core-contracts/lib/go/templates v1.3.1 github.com/onflow/flow-emulator v1.0.0 - github.com/onflow/flow-evm-gateway v0.35.0 + github.com/onflow/flow-evm-gateway v0.36.4 github.com/onflow/flow-go v0.37.10 github.com/onflow/flow-go-sdk v1.0.0-preview.56 github.com/onflow/flowkit/v2 v2.0.0 @@ -39,12 +39,12 @@ require ( github.com/spf13/viper v1.16.0 github.com/stretchr/testify v1.9.0 golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 - google.golang.org/grpc v1.66.2 + google.golang.org/grpc v1.67.0 ) require ( cloud.google.com/go v0.112.1 // indirect - cloud.google.com/go/compute/metadata v0.3.0 // indirect + cloud.google.com/go/compute/metadata v0.5.0 // indirect cloud.google.com/go/iam v1.1.6 // indirect cloud.google.com/go/kms v1.15.7 // indirect cloud.google.com/go/storage v1.38.0 // indirect @@ -121,7 +121,7 @@ require ( github.com/goccy/go-json v0.10.2 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.2.1 // indirect + github.com/golang/glog v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect @@ -274,8 +274,8 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/crypto v0.26.0 // indirect - golang.org/x/net v0.26.0 // indirect - golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/oauth2 v0.22.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.24.0 // indirect golang.org/x/term v0.23.0 // indirect @@ -286,9 +286,9 @@ require ( google.golang.org/api v0.169.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect - google.golang.org/protobuf v1.34.1 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 519c99e04..a9ea56892 100644 --- a/go.sum +++ b/go.sum @@ -261,8 +261,8 @@ cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZ cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= @@ -1215,8 +1215,8 @@ github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkE github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= +github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -1531,8 +1531,8 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= -github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= -github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= +github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -2178,8 +2178,8 @@ github.com/onflow/flow-core-contracts/lib/go/templates v1.3.1 h1:FfhMBAb78p6VAWk github.com/onflow/flow-core-contracts/lib/go/templates v1.3.1/go.mod h1:NgbMOYnMh0GN48VsNKZuiwK7uyk38Wyo8jN9+C9QE30= github.com/onflow/flow-emulator v1.0.0 h1:CCE9mFUYidb4YPQWFSBHzcBGggs5bXVqIh02wF2wRr0= github.com/onflow/flow-emulator v1.0.0/go.mod h1:sHbe9e1RG7Y6LA/dFyLEoBnKyjJ4iHeOdkXIobMjjrE= -github.com/onflow/flow-evm-gateway v0.35.0 h1:SYAlAfQTF7LhowbeCAoEuQ1CoABkrI9F46dJW7jFya4= -github.com/onflow/flow-evm-gateway v0.35.0/go.mod h1:zJP03G1buu1QavxBKnprUhe77JPF+DDfgz27pjOOgmg= +github.com/onflow/flow-evm-gateway v0.36.4 h1:AvPahikqfSN8SCMHn16ZkPz5Vvg60F1HkMHsFsQzkus= +github.com/onflow/flow-evm-gateway v0.36.4/go.mod h1:LWeu5hyXWU9mWPlKgeJOGcHRO67/hMtiyxtMFxRTZY4= github.com/onflow/flow-ft/lib/go/contracts v1.0.0 h1:mToacZ5NWqtlWwk/7RgIl/jeKB/Sy/tIXdw90yKHcV0= github.com/onflow/flow-ft/lib/go/contracts v1.0.0/go.mod h1:PwsL8fC81cjnUnTfmyL/HOIyHnyaw/JA474Wfj2tl6A= github.com/onflow/flow-ft/lib/go/templates v1.0.0 h1:6cMS/lUJJ17HjKBfMO/eh0GGvnpElPgBXx7h5aoWJhs= @@ -2835,8 +2835,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20170207211851-4464e7848382/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2871,8 +2871,8 @@ golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/perf v0.0.0-20230113213139-801c7ef9e5c5/go.mod h1:UBKtEnL8aqnd+0JHqZ+2qoMDwtuy6cYhhKNoHLBiTQc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -3448,8 +3448,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13/go. google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0= google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:SUBoKXbI1Efip18FClrQVGjWcyd0QZd8KkvdP34t7ww= google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= -google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU= -google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230807174057-1744710a1577/go.mod h1:NjCQG/D8JandXxM57PZbAJL1DCNL6EypA0vPPwfsc7c= google.golang.org/genproto/googleapis/bytestream v0.0.0-20231030173426-d783a09b4405/go.mod h1:GRUCuLdzVqZte8+Dl/D4N25yLzcGqqWaYkeVOwulFqw= @@ -3471,8 +3471,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v0.0.0-20170208002647-2a6bf6142e96/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -3529,8 +3529,8 @@ google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= -google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= +google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -3550,8 +3550,8 @@ google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/dependencymanager/add.go b/internal/dependencymanager/add.go index b08810a06..736a3b4c7 100644 --- a/internal/dependencymanager/add.go +++ b/internal/dependencymanager/add.go @@ -20,15 +20,19 @@ package dependencymanager import ( "fmt" + "strings" - "github.com/onflow/flow-cli/internal/util" + "github.com/onflow/flow-go/fvm/systemcontracts" "github.com/spf13/cobra" "github.com/onflow/flowkit/v2" "github.com/onflow/flowkit/v2/output" + flowGo "github.com/onflow/flow-go/model/flow" + "github.com/onflow/flow-cli/internal/command" + "github.com/onflow/flow-cli/internal/util" ) type addFlagsCollection struct { @@ -42,10 +46,11 @@ var addFlags = addFlagsCollection{ var addCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "add ", - Short: "Add a single contract and its dependencies.", - Example: "flow dependencies add testnet://0afe396ebc8eee65.FlowToken", - Args: cobra.ExactArgs(1), + Use: "add ", + Short: "Add a single contract and its dependencies.", + Example: `flow dependencies add testnet://0afe396ebc8eee65.FlowToken +flow dependencies add FlowToken`, + Args: cobra.ExactArgs(1), }, RunS: add, Flags: &struct{}{}, @@ -75,6 +80,17 @@ func add( return nil, err } + // First check if the dependency is a core contract. + coreContractName := findCoreContractCaseInsensitive(dep) + if coreContractName != "" { + if err := installer.AddByCoreContractName(coreContractName, addFlags.name); err != nil { + logger.Error(fmt.Sprintf("Error: %v", err)) + return nil, err + } + return nil, nil + } + + // Otherwise, add the dependency by source string. if err := installer.AddBySourceString(dep, addFlags.name); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err @@ -82,3 +98,12 @@ func add( return nil, nil } + +func findCoreContractCaseInsensitive(name string) string { + for _, contract := range systemcontracts.SystemContractsForChain(flowGo.Mainnet).All() { + if strings.EqualFold(contract.Name, name) { + return contract.Name + } + } + return "" +} diff --git a/internal/dependencymanager/dependencies.go b/internal/dependencymanager/dependencies.go index 2c97be4db..197e01f3e 100644 --- a/internal/dependencymanager/dependencies.go +++ b/internal/dependencymanager/dependencies.go @@ -33,4 +33,5 @@ var Cmd = &cobra.Command{ func init() { addCommand.AddToParent(Cmd) installCommand.AddToParent(Cmd) + discoverCommand.AddToParent(Cmd) } diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go index d6c3b63ac..f902b1d87 100644 --- a/internal/dependencymanager/dependencyinstaller.go +++ b/internal/dependencymanager/dependencyinstaller.go @@ -203,19 +203,40 @@ func (di *DependencyInstaller) AddBySourceString(depSource, customName string) e }, } - if err := di.processDependency(dep); err != nil { - return fmt.Errorf("error processing dependency: %w", err) + return di.Add(dep) +} + +func (di *DependencyInstaller) AddByCoreContractName(coreContractName, customName string) error { + var depNetwork, depAddress, depContractName string + sc := systemcontracts.SystemContractsForChain(flowGo.Mainnet) + for _, coreContract := range sc.All() { + if coreContract.Name == coreContractName { + depAddress = coreContract.Address.String() + depNetwork = config.MainnetNetwork.Name + depContractName = coreContractName + break + } } - di.checkForConflictingContracts() + if depAddress == "" { + return fmt.Errorf("contract %s not found in core contracts", coreContractName) + } - if err := di.saveState(); err != nil { - return err + name := depContractName + if customName != "" { + name = customName } - di.logs.LogAll(di.Logger) + dep := config.Dependency{ + Name: name, + Source: config.Source{ + NetworkName: depNetwork, + Address: flowsdk.HexToAddress(depAddress), + ContractName: depContractName, + }, + } - return nil + return di.Add(dep) } // Add processes a single dependency and installs it and any dependencies it has, as well as adding it to the state @@ -224,6 +245,8 @@ func (di *DependencyInstaller) Add(dep config.Dependency) error { return fmt.Errorf("error processing dependency: %w", err) } + di.checkForConflictingContracts() + if err := di.saveState(); err != nil { return err } diff --git a/internal/dependencymanager/dependencyinstaller_test.go b/internal/dependencymanager/dependencyinstaller_test.go index 6850f2d7d..2957d3ef7 100644 --- a/internal/dependencymanager/dependencyinstaller_test.go +++ b/internal/dependencymanager/dependencyinstaller_test.go @@ -185,6 +185,45 @@ func TestDependencyInstallerAdd(t *testing.T) { assert.NoError(t, err, "Failed to read generated file") assert.NotNil(t, fileContent) }) + + t.Run("Add by core contract name", func(t *testing.T) { + gw := mocks.DefaultMockGateway() + + gw.GetAccount.Run(func(args mock.Arguments) { + addr := args.Get(1).(flow.Address) + assert.Equal(t, addr.String(), "1654653399040a61") + acc := tests.NewAccountWithAddress(addr.String()) + acc.Contracts = map[string][]byte{ + "FlowToken": []byte("access(all) contract FlowToken {}"), + } + + gw.GetAccount.Return(acc, nil) + }) + + di := &DependencyInstaller{ + Gateways: map[string]gateway.Gateway{ + config.EmulatorNetwork.Name: gw.Mock, + config.TestnetNetwork.Name: gw.Mock, + config.MainnetNetwork.Name: gw.Mock, + }, + Logger: logger, + State: state, + SaveState: true, + TargetDir: "", + SkipDeployments: true, + SkipAlias: true, + dependencies: make(map[string]config.Dependency), + } + + err := di.AddByCoreContractName("FlowToken", "") + assert.NoError(t, err, "Failed to install dependencies") + + filePath := fmt.Sprintf("imports/%s/%s.cdc", "1654653399040a61", "FlowToken") + fileContent, err := state.ReaderWriter().ReadFile(filePath) + assert.NoError(t, err, "Failed to read generated file") + assert.NotNil(t, fileContent) + assert.Contains(t, string(fileContent), "contract FlowToken") + }) } func TestDependencyInstallerAddMany(t *testing.T) { diff --git a/internal/dependencymanager/discover.go b/internal/dependencymanager/discover.go new file mode 100644 index 000000000..4763f696e --- /dev/null +++ b/internal/dependencymanager/discover.go @@ -0,0 +1,131 @@ +/* + * Flow CLI + * + * Copyright Flow Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dependencymanager + +import ( + "fmt" + "slices" + + flowsdk "github.com/onflow/flow-go-sdk" + "github.com/onflow/flow-go/fvm/systemcontracts" + + "github.com/spf13/cobra" + + "github.com/onflow/flowkit/v2" + "github.com/onflow/flowkit/v2/output" + + flowGo "github.com/onflow/flow-go/model/flow" + flowkitConfig "github.com/onflow/flowkit/v2/config" + + "github.com/onflow/flow-cli/internal/command" + "github.com/onflow/flow-cli/internal/prompt" + "github.com/onflow/flow-cli/internal/util" +) + +type DiscoverResult struct { + Contracts []string `json:"contracts"` +} + +var discoverCommand = &command.Command{ + Cmd: &cobra.Command{ + Use: "discover", + Short: "Discover available contracts to add to your project.", + Example: "flow dependencies discover", + Args: cobra.NoArgs, + }, + RunS: discover, + Flags: &struct{}{}, +} + +func discover( + _ []string, + globalFlags command.GlobalFlags, + logger output.Logger, + flow flowkit.Services, + state *flowkit.State, +) (command.Result, error) { + installedDeps := state.Dependencies() + if installedDeps == nil { + installedDeps = new(flowkitConfig.Dependencies) + } + + installedContracts := make([]string, 0) + for _, dep := range *installedDeps { + installedContracts = append(installedContracts, dep.Name) + } + + err := PromptInstallCoreContracts(logger, state, "", installedContracts) + if err != nil { + return nil, err + } + + err = state.SaveDefault() + return nil, err +} + +func PromptInstallCoreContracts(logger output.Logger, state *flowkit.State, targetDir string, excludeContracts []string) error { + // Prompt to ask which core contracts should be installed + sc := systemcontracts.SystemContractsForChain(flowGo.Mainnet) + promptMessage := "Select any core contracts you would like to install or skip to continue." + + contractNames := make([]string, 0) + + for _, contract := range sc.All() { + if slices.Contains(excludeContracts, contract.Name) { + continue + } + contractNames = append(contractNames, contract.Name) + } + + selectedContractNames, err := prompt.RunSelectOptions(contractNames, promptMessage) + if err != nil { + return fmt.Errorf("error running dependency selection: %v\n", err) + } + + var dependencies []flowkitConfig.Dependency + + // Loop standard contracts and add them to the dependencies if selected + for _, contract := range sc.All() { + if slices.Contains(selectedContractNames, contract.Name) { + dependencies = append(dependencies, flowkitConfig.Dependency{ + Name: contract.Name, + Source: flowkitConfig.Source{ + NetworkName: flowkitConfig.MainnetNetwork.Name, + Address: flowsdk.HexToAddress(contract.Address.String()), + ContractName: contract.Name, + }, + }) + } + } + + logger.Info("") + logger.Info(util.MessageWithEmojiPrefix("🔄", "Installing selected core contracts and dependencies...")) + + // Add the selected core contracts as dependencies + installer, err := NewDependencyInstaller(logger, state, false, targetDir, Flags{}) + if err != nil { + return err + } + + if err := installer.AddMany(dependencies); err != nil { + return err + } + + return nil +} diff --git a/internal/super/generate.go b/internal/super/generate.go index 24cd0e2d3..9a3d2e9e0 100644 --- a/internal/super/generate.go +++ b/internal/super/generate.go @@ -19,16 +19,14 @@ package super import ( - "github.com/onflow/flow-cli/internal/super/generator" - "github.com/onflow/flow-cli/internal/util" - "github.com/onflow/flowkit/v2" - "github.com/onflow/flowkit/v2/output" - "github.com/onflow/flow-cli/internal/command" - "github.com/spf13/cobra" + + "github.com/onflow/flow-cli/internal/command" + "github.com/onflow/flow-cli/internal/super/generator" + "github.com/onflow/flow-cli/internal/util" ) type generateFlagsDef struct { @@ -78,19 +76,24 @@ var GenerateScriptCommand = &command.Command{ RunS: generateScript, } +var GenerateTestCommand = &command.Command{ + Cmd: &cobra.Command{ + Use: "test ", + Short: "Generate a Cadence test template", + Example: "flow generate test SomeTest", + Args: cobra.ExactArgs(1), + }, + Flags: &generateFlags, + RunS: generateTest, +} + func init() { GenerateContractCommand.AddToParent(GenerateCommand) GenerateTransactionCommand.AddToParent(GenerateCommand) GenerateScriptCommand.AddToParent(GenerateCommand) + GenerateTestCommand.AddToParent(GenerateCommand) } -const ( - DefaultCadenceDirectory = "cadence" - ContractType = "contract" - TransactionType = "transaction" - ScriptType = "script" -) - func generateContract( args []string, _ command.GlobalFlags, @@ -100,15 +103,7 @@ func generateContract( ) (result command.Result, err error) { g := generator.NewGenerator("", state, logger, false, true) name := util.StripCDCExtension(args[0]) - - templates := []generator.TemplateItem{ - generator.ContractTemplate{Name: name, SkipTests: generateFlags.SkipTests, SaveState: true}, - } - if !generateFlags.SkipTests { - templates = append(templates, generator.TestTemplate{Name: name + "_test", Data: map[string]interface{}{"ContractName": "Counter"}}) - } - - err = g.Create() + err = g.Create(generator.ContractTemplate{Name: name, SkipTests: generateFlags.SkipTests, SaveState: true}) return nil, err } @@ -137,3 +132,16 @@ func generateScript( err = g.Create(generator.ScriptTemplate{Name: name}) return nil, err } + +func generateTest( + args []string, + _ command.GlobalFlags, + logger output.Logger, + _ flowkit.Services, + state *flowkit.State, +) (result command.Result, err error) { + g := generator.NewGenerator("", state, logger, false, true) + name := util.StripCDCExtension(args[0]) + err = g.Create(generator.TestTemplate{Name: name}) + return nil, err +} diff --git a/internal/super/generator/contract_template.go b/internal/super/generator/contract_template.go index 783e9952a..f8bbb5dd9 100644 --- a/internal/super/generator/contract_template.go +++ b/internal/super/generator/contract_template.go @@ -1,13 +1,37 @@ +/* + * Flow CLI + * + * Copyright Flow Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package generator import ( "fmt" "path/filepath" - "github.com/onflow/flow-cli/internal/util" flowsdk "github.com/onflow/flow-go-sdk" "github.com/onflow/flowkit/v2" "github.com/onflow/flowkit/v2/config" + + "github.com/onflow/flow-cli/internal/util" +) + +const ( + DefaultContractDirectory = "contracts" + DefaultTestAddress = "0x0000000000000007" ) // Contract contains properties for contracts @@ -21,8 +45,13 @@ type ContractTemplate struct { } var _ TemplateItem = ContractTemplate{} +var _ TemplateItemWithStateUpdate = ContractTemplate{} +var _ TemplateItemWithChildren = ContractTemplate{} + +func (c ContractTemplate) GetType() string { + return "contract" +} -// GetTemplate returns the template of the contract func (c ContractTemplate) GetTemplatePath() string { if c.TemplatePath == "" { return "contract_init.cdc.tmpl" @@ -31,7 +60,6 @@ func (c ContractTemplate) GetTemplatePath() string { return c.TemplatePath } -// GetData returns the data of the contract func (c ContractTemplate) GetData() map[string]interface{} { data := map[string]interface{}{ "Name": c.Name, @@ -44,7 +72,7 @@ func (c ContractTemplate) GetData() map[string]interface{} { } func (c ContractTemplate) GetTargetPath() string { - return filepath.Join(DefaultCadenceDirectory, "contracts", c.Account, util.AddCDCExtension(c.Name)) + return filepath.Join(DefaultCadenceDirectory, DefaultContractDirectory, c.Account, util.AddCDCExtension(c.Name)) } func (c ContractTemplate) UpdateState(state *flowkit.State) error { @@ -53,7 +81,7 @@ func (c ContractTemplate) UpdateState(state *flowkit.State) error { if c.SkipTests != true { aliases = config.Aliases{{ Network: config.TestingNetwork.Name, - Address: flowsdk.HexToAddress("0x0000000000000007"), + Address: flowsdk.HexToAddress(DefaultTestAddress), }} } @@ -74,3 +102,19 @@ func (c ContractTemplate) UpdateState(state *flowkit.State) error { return nil } + +func (c ContractTemplate) GetChildren() []TemplateItem { + if c.SkipTests { + return []TemplateItem{} + } + + return []TemplateItem{ + TestTemplate{ + Name: fmt.Sprintf("%s_test", c.Name), + TemplatePath: "contract_init_test.cdc.tmpl", + Data: map[string]interface{}{ + "ContractName": c.Name, + }, + }, + } +} diff --git a/internal/super/generator/generator.go b/internal/super/generator/generator.go index 9d71367d2..aa05216f4 100644 --- a/internal/super/generator/generator.go +++ b/internal/super/generator/generator.go @@ -39,19 +39,25 @@ var templatesFS embed.FS // TemplateItem is an interface for different template types type TemplateItem interface { + GetType() string GetTemplatePath() string GetData() map[string]interface{} GetTargetPath() string +} + +// TemplateItemWithStateUpdate is an interface for template items that need to update the Flowkit state/flow.json +type TemplateItemWithStateUpdate interface { + TemplateItem UpdateState(state *flowkit.State) error } -//go:generate mockery --name Generator --case underscore -type Generator interface { - // Create generates files from the provided template items - Create(items ...TemplateItem) error +// TemplateItemWithChildren is an interface for template items that have children +type TemplateItemWithChildren interface { + TemplateItem + GetChildren() []TemplateItem } -type GeneratorImpl struct { +type Generator struct { directory string state *flowkit.State logger output.Logger @@ -65,8 +71,8 @@ func NewGenerator( logger output.Logger, disableLogs, saveState bool, -) *GeneratorImpl { - return &GeneratorImpl{ +) *Generator { + return &Generator{ directory: directory, state: state, logger: logger, @@ -75,18 +81,25 @@ func NewGenerator( } } -func (g *GeneratorImpl) Create(items ...TemplateItem) error { +func (g *Generator) Create(items ...TemplateItem) error { for _, item := range items { err := g.generate(item) if err != nil { return err } + + if itemWithChildren, ok := item.(TemplateItemWithChildren); ok { + err = g.Create(itemWithChildren.GetChildren()...) + if err != nil { + return err + } + } } return nil } -func (g *GeneratorImpl) generate(item TemplateItem) error { +func (g *Generator) generate(item TemplateItem) error { rootDir := g.directory targetRelativeToRoot := item.GetTargetPath() @@ -100,8 +113,7 @@ func (g *GeneratorImpl) generate(item TemplateItem) error { outputContent, err := g.processTemplate(templatePath, fileData) if err != nil { - // TODO, better error based on template type - return fmt.Errorf("error generating template: %w", err) + return fmt.Errorf("error generating %s template: %w", item.GetType(), err) } targetPath := filepath.Join(rootDir, targetRelativeToRoot) @@ -124,14 +136,15 @@ func (g *GeneratorImpl) generate(item TemplateItem) error { } if !g.disableLogs { - // TODO: Add more detailed logging - g.logger.Info(fmt.Sprintf("Generated %s", targetPath)) + g.logger.Info(fmt.Sprintf("Generated new %s: %s", item.GetType(), targetPath)) } // Call template state update function if it exists - err = item.UpdateState(g.state) - if err != nil { - return err + if itemWithStateUpdate, ok := item.(TemplateItemWithStateUpdate); ok { + err = itemWithStateUpdate.UpdateState(g.state) + if err != nil { + return err + } } return nil @@ -139,8 +152,9 @@ func (g *GeneratorImpl) generate(item TemplateItem) error { // processTemplate reads a template file from the embedded filesystem and processes it with the provided data // If you don't need to provide data, pass nil -func (g *GeneratorImpl) processTemplate(templatePath string, data map[string]interface{}) (string, error) { - templateData, err := templatesFS.ReadFile(filepath.Join("templates", templatePath)) +func (g *Generator) processTemplate(templatePath string, data map[string]interface{}) (string, error) { + resolvedPath := filepath.Join("templates", templatePath) + templateData, err := templatesFS.ReadFile(filepath.ToSlash(resolvedPath)) if err != nil { return "", fmt.Errorf("failed to read template file: %w", err) } diff --git a/internal/super/generator/generator_test.go b/internal/super/generator/generator_test.go index 6c0309019..f4fca000c 100644 --- a/internal/super/generator/generator_test.go +++ b/internal/super/generator/generator_test.go @@ -23,12 +23,11 @@ import ( "path/filepath" "testing" - "github.com/onflow/flow-cli/internal/util" - "github.com/spf13/afero" - "github.com/stretchr/testify/assert" "github.com/onflow/flowkit/v2/output" + + "github.com/onflow/flow-cli/internal/util" ) func TestGenerateNewContract(t *testing.T) { @@ -83,7 +82,7 @@ func TestGenerateNewContractSkipTests(t *testing.T) { g := NewGenerator("", state, logger, false, true) // Test contract generation - err := g.Create(ContractTemplate{Name: "TestContract", Account: "", skipTests: true}) + err := g.Create(ContractTemplate{Name: "TestContract", Account: "", SkipTests: true}) assert.NoError(t, err, "Failed to generate contract") fileContent, err := state.ReaderWriter().ReadFile(filepath.FromSlash("cadence/contracts/TestContract.cdc")) @@ -193,52 +192,32 @@ func TestGenerateTestTemplate(t *testing.T) { logger := output.NewStdoutLogger(output.NoneLog) _, state, _ := util.TestMocks(t) - // Create a mock template file - tmplFs := afero.Afero{Fs: afero.NewMemMapFs()} - err := tmplFs.WriteFile("file.tmpl", []byte("{{.content}}"), 0644) - assert.NoError(t, err, "Failed to create template file") - g := NewGenerator("", state, logger, false, true) - err = g.Create(TestTemplate{ - Name: "FooBar_test", - TemplatePath: "file.tmpl", + err := g.Create(TestTemplate{ + Name: "Foobar_test", + TemplatePath: "contract_init_test.cdc.tmpl", Data: map[string]interface{}{ - "content": "test template", + "ContractName": "Foobar", }}, ) assert.NoError(t, err, "Failed to generate file") - content, err := state.ReaderWriter().ReadFile(filepath.FromSlash("cadence/tests/FooBar_test.cdc")) + content, err := state.ReaderWriter().ReadFile(filepath.FromSlash("cadence/tests/Foobar_test.cdc")) assert.NoError(t, err, "Failed to read generated file") assert.NotNil(t, content) - expectedContent := `test template` - assert.Equal(t, expectedContent, util.NormalizeLineEndings(string(content))) -} + expectedContent := `import Test -func TestGenerateFileTemplate(t *testing.T) { - logger := output.NewStdoutLogger(output.NoneLog) - _, state, _ := util.TestMocks(t) +access(all) let account = Test.createAccount() - // Create a mock template file - tmplFs := afero.Afero{Fs: afero.NewMemMapFs()} - err := tmplFs.WriteFile("file.tmpl", []byte("{{.content}}"), 0644) - assert.NoError(t, err, "Failed to create template file") +access(all) fun testContract() { + let err = Test.deployContract( + name: "Foobar", + path: "../contracts/Foobar.cdc", + arguments: [], + ) - g := NewGenerator("", state, logger, false, true) - err = g.Create(FileTemplate{ - TargetPath: "TestFile", - TemplatePath: "file.tmpl", - Data: map[string]interface{}{ - "content": "test template", - }}, - ) - assert.NoError(t, err, "Failed to generate file") - - content, err := state.ReaderWriter().ReadFile(filepath.FromSlash("TestFile")) - assert.NoError(t, err, "Failed to read generated file") - assert.NotNil(t, content) - - expectedContent := `test template` + Test.expect(err, Test.beNil()) +}` assert.Equal(t, expectedContent, util.NormalizeLineEndings(string(content))) } diff --git a/internal/super/generator/script_template.go b/internal/super/generator/script_template.go index 7f13b55aa..ffde60371 100644 --- a/internal/super/generator/script_template.go +++ b/internal/super/generator/script_template.go @@ -1,13 +1,33 @@ +/* + * Flow CLI + * + * Copyright Flow Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package generator import ( "path/filepath" "github.com/onflow/flow-cli/internal/util" - "github.com/onflow/flowkit/v2" ) -// ScriptTemplate contains only a name property for scripts and transactions +const ( + DefaultScriptDirectory = "scripts" +) + type ScriptTemplate struct { Name string TemplatePath string @@ -16,12 +36,10 @@ type ScriptTemplate struct { var _ TemplateItem = ScriptTemplate{} -// GetName returns the name of the script or transaction -func (o ScriptTemplate) GetName() string { - return o.Name +func (o ScriptTemplate) GetType() string { + return "script" } -// GetTemplate returns an empty string for scripts and transactions func (o ScriptTemplate) GetTemplatePath() string { if o.TemplatePath == "" { return "script_init.cdc.tmpl" @@ -30,15 +48,10 @@ func (o ScriptTemplate) GetTemplatePath() string { return o.TemplatePath } -// GetData returns the data of the script or transaction func (o ScriptTemplate) GetData() map[string]interface{} { return o.Data } func (o ScriptTemplate) GetTargetPath() string { - return filepath.Join(DefaultCadenceDirectory, "scripts", util.AddCDCExtension(o.Name)) -} - -func (o ScriptTemplate) UpdateState(state *flowkit.State) error { - return nil + return filepath.Join(DefaultCadenceDirectory, DefaultScriptDirectory, util.AddCDCExtension(o.Name)) } diff --git a/internal/super/generator/templates/empty_test.cdc.tmpl b/internal/super/generator/templates/empty_test.cdc.tmpl new file mode 100644 index 000000000..98ea2508a --- /dev/null +++ b/internal/super/generator/templates/empty_test.cdc.tmpl @@ -0,0 +1,8 @@ +import Test + +access(all) let account = Test.createAccount() + +access(all) fun testExample() { + // Test something + Test.expect(true, true) +} \ No newline at end of file diff --git a/internal/super/generator/test_template.go b/internal/super/generator/test_template.go index a3e32a5c3..49e13e718 100644 --- a/internal/super/generator/test_template.go +++ b/internal/super/generator/test_template.go @@ -1,10 +1,31 @@ +/* + * Flow CLI + * + * Copyright Flow Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package generator import ( "path/filepath" "github.com/onflow/flow-cli/internal/util" - "github.com/onflow/flowkit/v2" +) + +const ( + DefaultTestDirectory = "tests" ) type TestTemplate struct { @@ -15,6 +36,10 @@ type TestTemplate struct { var _ TemplateItem = TestTemplate{} +func (o TestTemplate) GetType() string { + return "test" +} + // GetName returns the name of the script or transaction func (o TestTemplate) GetName() string { return o.Name @@ -23,7 +48,7 @@ func (o TestTemplate) GetName() string { // GetTemplate returns an empty string for scripts and transactions func (o TestTemplate) GetTemplatePath() string { if o.TemplatePath == "" { - return "contract_init_test.cdc.tmpl" + return "empty_test.cdc.tmpl" } return o.TemplatePath @@ -35,9 +60,5 @@ func (o TestTemplate) GetData() map[string]interface{} { } func (o TestTemplate) GetTargetPath() string { - return filepath.Join(DefaultCadenceDirectory, "tests", util.AddCDCExtension(o.Name)) -} - -func (o TestTemplate) UpdateState(state *flowkit.State) error { - return nil + return filepath.Join(DefaultCadenceDirectory, DefaultTestDirectory, util.AddCDCExtension(o.Name)) } diff --git a/internal/super/generator/transaction_template.go b/internal/super/generator/transaction_template.go index d90ba3cce..4accc1cdc 100644 --- a/internal/super/generator/transaction_template.go +++ b/internal/super/generator/transaction_template.go @@ -1,10 +1,31 @@ +/* + * Flow CLI + * + * Copyright Flow Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package generator import ( "path/filepath" "github.com/onflow/flow-cli/internal/util" - "github.com/onflow/flowkit/v2" +) + +const ( + DefaultTransactionDirectory = "transactions" ) // TransactionTemplate contains only a name property for scripts and transactions @@ -17,8 +38,8 @@ type TransactionTemplate struct { var _ TemplateItem = TransactionTemplate{} // GetName returns the name of the script or transaction -func (o TransactionTemplate) GetName() string { - return o.Name +func (o TransactionTemplate) GetType() string { + return "transaction" } // GetTemplate returns an empty string for scripts and transactions @@ -36,9 +57,5 @@ func (o TransactionTemplate) GetData() map[string]interface{} { } func (o TransactionTemplate) GetTargetPath() string { - return filepath.Join(DefaultCadenceDirectory, "transactions", util.AddCDCExtension(o.Name)) -} - -func (o TransactionTemplate) UpdateState(state *flowkit.State) error { - return nil + return filepath.Join(DefaultCadenceDirectory, DefaultTransactionDirectory, util.AddCDCExtension(o.Name)) } diff --git a/internal/super/setup.go b/internal/super/setup.go index 44283f7f0..2fc439d48 100644 --- a/internal/super/setup.go +++ b/internal/super/setup.go @@ -25,12 +25,6 @@ import ( "os" "path/filepath" - flowsdk "github.com/onflow/flow-go-sdk" - "github.com/onflow/flow-go/fvm/systemcontracts" - flowGo "github.com/onflow/flow-go/model/flow" - flowkitConfig "github.com/onflow/flowkit/v2/config" - "golang.org/x/exp/slices" - "github.com/onflow/flow-cli/internal/dependencymanager" "github.com/onflow/flow-cli/internal/super/generator" "github.com/onflow/flow-cli/internal/util" @@ -44,9 +38,11 @@ import ( "github.com/onflow/flowkit/v2" "github.com/onflow/flowkit/v2/output" - "github.com/onflow/flow-cli/internal/config" - "github.com/onflow/flow-cli/internal/command" + "github.com/onflow/flow-cli/internal/config" + "github.com/onflow/flow-cli/internal/dependencymanager" + "github.com/onflow/flow-cli/internal/super/generator" + "github.com/onflow/flow-cli/internal/util" ) type flagsSetup struct { @@ -234,13 +230,13 @@ func startInteractiveSetup( Name: "Counter_test", Data: map[string]interface{}{"ContractName": "Counter"}, }, - /*generator.FileTemplate{ + generator.FileTemplate{ TemplatePath: "README.md.tmpl", TargetPath: "README.md", Data: map[string]interface{}{ "ProjectName": filepath.Base(targetDir), }, - },*/ + }, } g := generator.NewGenerator(tempDir, state, logger, true, false) @@ -251,7 +247,7 @@ func startInteractiveSetup( msg := "Would you like to install any core contracts and their dependencies?" if prompt.GenericBoolPrompt(msg) { - err := installCoreContracts(logger, state, tempDir) + err := dependencymanager.PromptInstallCoreContracts(logger, state, tempDir, nil) if err != nil { return "", err } @@ -276,54 +272,6 @@ func startInteractiveSetup( return targetDir, nil } -func installCoreContracts(logger output.Logger, state *flowkit.State, tempDir string) error { - // Prompt to ask which core contracts should be installed - sc := systemcontracts.SystemContractsForChain(flowGo.Mainnet) - promptMessage := "Select any core contracts you would like to install or skip to continue." - - contractNames := make([]string, 0) - - for _, contract := range sc.All() { - contractNames = append(contractNames, contract.Name) - } - - selectedContractNames, err := prompt.RunSelectOptions(contractNames, promptMessage) - if err != nil { - return fmt.Errorf("error running dependency selection: %v\n", err) - } - - var dependencies []flowkitConfig.Dependency - - // Loop standard contracts and add them to the dependencies if selected - for _, contract := range sc.All() { - if slices.Contains(selectedContractNames, contract.Name) { - dependencies = append(dependencies, flowkitConfig.Dependency{ - Name: contract.Name, - Source: flowkitConfig.Source{ - NetworkName: flowkitConfig.MainnetNetwork.Name, - Address: flowsdk.HexToAddress(contract.Address.String()), - ContractName: contract.Name, - }, - }) - } - } - - logger.Info("") - logger.Info(util.MessageWithEmojiPrefix("🔄", "Installing selected core contracts and dependencies...")) - - // Add the selected core contracts as dependencies - installer, err := dependencymanager.NewDependencyInstaller(logger, state, false, tempDir, dependencymanager.Flags{}) - if err != nil { - return err - } - - if err := installer.AddMany(dependencies); err != nil { - return err - } - - return nil -} - // getTargetDirectory checks if the specified directory path is suitable for use. // It verifies that the path points to an existing, empty directory. // If the directory does not exist, the function returns the path without error, diff --git a/internal/transactions/transactions.go b/internal/transactions/transactions.go index 64dc90ab2..fb195fb2b 100644 --- a/internal/transactions/transactions.go +++ b/internal/transactions/transactions.go @@ -32,6 +32,8 @@ import ( "github.com/onflow/flow-cli/internal/command" "github.com/onflow/flow-cli/internal/events" "github.com/onflow/flow-cli/internal/util" + + jsoncdc "github.com/onflow/cadence/encoding/json" ) var Cmd = &cobra.Command{ @@ -82,7 +84,7 @@ func (r *transactionResult) JSON() any { "index": event.EventIndex, "type": event.Type, "values": json.RawMessage( - event.Payload, + jsoncdc.MustEncode(event.Value), ), }) } diff --git a/internal/transactions/transactions_test.go b/internal/transactions/transactions_test.go index a7637efcc..fd7d635c4 100644 --- a/internal/transactions/transactions_test.go +++ b/internal/transactions/transactions_test.go @@ -323,7 +323,6 @@ func Test_Result(t *testing.T) { []cadence.Field{{Type: cadence.StringType, Identifier: "bar"}}, []cadence.Value{cadence.NewInt(1)}, ) - event.Payload = []byte("mock_payload") withdrawFlowEvent := tests.NewEvent( 1, @@ -446,7 +445,7 @@ Fee Events (hidden, use --include fee-events)`, output.OkEmoji()), "\n") map[string]any{ "index": 0, "type": "A.foo", - "values": json.RawMessage{0x6d, 0x6f, 0x63, 0x6b, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64}, + "values": json.RawMessage{0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x41, 0x2e, 0x66, 0x6f, 0x6f, 0x22, 0x2c, 0x22, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x22, 0x31, 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x49, 0x6e, 0x74, 0x22, 0x7d, 0x2c, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x22, 0x62, 0x61, 0x72, 0x22, 0x7d, 0x5d, 0x7d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x7d, 0xa}, }, }, "id": "e913d1f3e431c7df49c99845bea9ebff9db11bbf25d507b9ad0fad45652d515f", diff --git a/scaffolds.json b/scaffolds.json index 2f48af14c..6dc2b2f27 100644 --- a/scaffolds.json +++ b/scaffolds.json @@ -5,5 +5,17 @@ "description": "Simple TypeScript web application using next.js, FCL, and Cadence.", "commit": "3a5d4f87eef72cebf45f1c48c51c2b786b28f7b6", "type": "web" + }, + { + "name": "Simple Cadence Project", + "repo": "https://github.com/sideninja/flow-basic-scaffold.git", + "description": "Scaffold contains required folder structure as well as some example Cadence code.", + "commit": "8065287e55bc298d776665bef98a577ceb4a226c" + }, + { + "name": "Cadence NFT Project", + "repo": "https://github.com/nvdtf/flow-nft-scaffold.git", + "description": "Scaffold contains the ExampleNFT sample NFT contract.", + "commit": "ef9437c05549e3f581cf619dec9d59d8c7f6e3ec" } ]