From 03a1c959838266c6f4a2b216ee3a26e98160f0e5 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 24 Apr 2023 16:08:13 +0200 Subject: [PATCH 1/2] fix(autocli): fix simapp enriching and migrate nft queries to autocli --- api/cosmos/autocli/v1/options.pulsar.go | 4 +- client/cmd.go | 3 +- client/v2/CHANGELOG.md | 37 ++ client/v2/README.md | 7 + client/v2/autocli/app.go | 79 ++-- client/v2/autocli/common.go | 71 +++- client/v2/autocli/flag/address.go | 22 +- client/v2/autocli/flag/builder.go | 9 +- client/v2/autocli/msg.go | 28 +- client/v2/autocli/msg_test.go | 78 ++-- client/v2/autocli/query.go | 18 +- client/v2/autocli/query_test.go | 15 +- client/v2/go.mod | 2 +- docs/docs/building-modules/10-autocli.md | 2 +- docs/docs/building-modules/11-structure.md | 4 +- proto/cosmos/autocli/v1/options.proto | 4 +- server/util.go | 3 +- simapp/go.mod | 3 +- simapp/go.sum | 6 +- simapp/simd/cmd/root.go | 4 - tests/e2e/nft/query.go | 399 --------------------- tests/e2e/nft/test_helper.go | 76 ---- tests/e2e/nft/tx.go | 8 +- tests/go.mod | 2 +- tests/go.sum | 4 +- types/module/module.go | 6 - x/auth/autocli.go | 4 +- x/nft/client/cli/query.go | 270 -------------- x/nft/client/cli/query_test.go | 308 ---------------- x/nft/module/autocli.go | 87 +++++ x/nft/module/module.go | 5 +- 31 files changed, 309 insertions(+), 1259 deletions(-) create mode 100644 client/v2/CHANGELOG.md create mode 100644 client/v2/README.md delete mode 100644 tests/e2e/nft/query.go delete mode 100644 tests/e2e/nft/test_helper.go delete mode 100644 x/nft/client/cli/query.go delete mode 100644 x/nft/client/cli/query_test.go create mode 100644 x/nft/module/autocli.go diff --git a/api/cosmos/autocli/v1/options.pulsar.go b/api/cosmos/autocli/v1/options.pulsar.go index 265c2368769b..a97a51701f77 100644 --- a/api/cosmos/autocli/v1/options.pulsar.go +++ b/api/cosmos/autocli/v1/options.pulsar.go @@ -4268,9 +4268,9 @@ type ModuleOptions struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // tx describes the tx command for the module. + // tx describes the tx commands for the module. Tx *ServiceCommandDescriptor `protobuf:"bytes,1,opt,name=tx,proto3" json:"tx,omitempty"` - // query describes the tx command for the module. + // query describes the queries commands for the module. Query *ServiceCommandDescriptor `protobuf:"bytes,2,opt,name=query,proto3" json:"query,omitempty"` } diff --git a/client/cmd.go b/client/cmd.go index 83b46028960b..1c649ad47031 100644 --- a/client/cmd.go +++ b/client/cmd.go @@ -355,10 +355,11 @@ func GetClientContextFromCmd(cmd *cobra.Command) Context { } // SetCmdClientContext sets a command's Context value to the provided argument. +// If the context has not been set, set the given context as the default. func SetCmdClientContext(cmd *cobra.Command, clientCtx Context) error { v := cmd.Context().Value(ClientContextKey) if v == nil { - return errors.New("client context not set") + v = &clientCtx } clientCtxPtr := v.(*Context) diff --git a/client/v2/CHANGELOG.md b/client/v2/CHANGELOG.md new file mode 100644 index 000000000000..0c3c9d03857f --- /dev/null +++ b/client/v2/CHANGELOG.md @@ -0,0 +1,37 @@ + + +# Changelog + +## [Unreleased] diff --git a/client/v2/README.md b/client/v2/README.md new file mode 100644 index 000000000000..fcb07f0e2ee1 --- /dev/null +++ b/client/v2/README.md @@ -0,0 +1,7 @@ +# AutoCLI + +The `autocli` package is a Go library for generating CLI (command line interface) interfaces for Cosmos SDK-based applications. + +Read more about in in the Cosmos SDK documentation: + +- https://docs.cosmos.network/main/building-modules/autocli \ No newline at end of file diff --git a/client/v2/autocli/app.go b/client/v2/autocli/app.go index 280afce7e979..833332b111fe 100644 --- a/client/v2/autocli/app.go +++ b/client/v2/autocli/app.go @@ -1,9 +1,9 @@ package autocli import ( - "fmt" - autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" + "cosmossdk.io/client/v2/autocli/flag" + "cosmossdk.io/core/address" "cosmossdk.io/core/appmodule" "cosmossdk.io/depinject" @@ -32,23 +32,18 @@ type AppOptions struct { // app to override module options if they are either not provided by a // module or need to be improved. ModuleOptions map[string]*autocliv1.ModuleOptions `optional:"true"` -} -// RootCmd generates a root command for an app based on the AppOptions. This -// command currently only includes query commands but will be enhanced over -// time to cover the full scope of an app CLI. -func (appOptions AppOptions) RootCmd() (*cobra.Command, error) { - rootCmd := &cobra.Command{} - err := appOptions.EnhanceRootCommand(rootCmd) - return rootCmd, err + // AddressCodec is the address codec to use for the app. + // If not provided the default address prefix will be fetched from the reflection client. + AddressCodec address.Codec `optional:"true"` } // EnhanceRootCommand enhances the provided root command with autocli AppOptions, -// only adding missing query commands and doesn't override commands already +// only adding missing commands and doesn't override commands already // in the root command. This allows for the graceful integration of autocli with // existing app CLI commands where autocli simply automatically adds things that -// weren't manually provided. It does take into account custom query commands -// provided by modules with the HasCustomQueryCommand extension interface. +// weren't manually provided. It does take into account custom commands +// provided by modules with the HasCustomQueryCommand or HasCustomTxCommand extension interface. // Example Usage: // // var autoCliOpts autocli.AppOptions @@ -60,6 +55,12 @@ func (appOptions AppOptions) RootCmd() (*cobra.Command, error) { // err = autoCliOpts.EnhanceRootCommand(rootCmd) func (appOptions AppOptions) EnhanceRootCommand(rootCmd *cobra.Command) error { builder := &Builder{ + Builder: flag.Builder{ + AddressCodec: appOptions.AddressCodec, + GetClientConn: func() (grpc.ClientConnInterface, error) { + return client.GetClientQueryContext(rootCmd) + }, + }, GetClientConn: func(cmd *cobra.Command) (grpc.ClientConnInterface, error) { return client.GetClientQueryContext(cmd) }, @@ -71,19 +72,8 @@ func (appOptions AppOptions) EnhanceRootCommand(rootCmd *cobra.Command) error { } func (appOptions AppOptions) EnhanceRootCommandWithBuilder(rootCmd *cobra.Command, builder *Builder) error { - moduleOptions := appOptions.ModuleOptions - if moduleOptions == nil { - moduleOptions = map[string]*autocliv1.ModuleOptions{} - - for name, module := range appOptions.Modules { - if module, ok := module.(HasAutoCLIConfig); ok { - moduleOptions[name] = module.AutoCLIOptions() - } - } - } - - customQueryCmds := map[string]*cobra.Command{} - customMsgCmds := map[string]*cobra.Command{} + // extract any custom commands from modules + customQueryCmds, customMsgCmds := map[string]*cobra.Command{}, map[string]*cobra.Command{} for name, module := range appOptions.Modules { if queryModule, ok := module.(HasCustomQueryCommand); ok { queryCmd := queryModule.GetQueryCmd() @@ -101,27 +91,12 @@ func (appOptions AppOptions) EnhanceRootCommandWithBuilder(rootCmd *cobra.Comman } } - // if we have an existing query command, enhance it or build a custom one - enhanceQuery := func(cmd *cobra.Command, modOpts *autocliv1.ModuleOptions, moduleName string) error { - queryCmdDesc := modOpts.Query - if queryCmdDesc != nil { - subCmd := topLevelCmd(moduleName, fmt.Sprintf("Querying commands for the %s module", moduleName)) - err := builder.AddQueryServiceCommands(cmd, queryCmdDesc) - if err != nil { - return err - } - - cmd.AddCommand(subCmd) - } - return nil - } - if queryCmd := findSubCommand(rootCmd, "query"); queryCmd != nil { - if err := builder.enhanceCommandCommon(queryCmd, moduleOptions, customQueryCmds, enhanceQuery); err != nil { + if err := builder.enhanceCommandCommon(queryCmd, appOptions, customQueryCmds, enhanceQuery); err != nil { return err } } else { - queryCmd, err := builder.BuildQueryCommand(moduleOptions, customQueryCmds) + queryCmd, err := builder.BuildQueryCommand(appOptions, customQueryCmds, enhanceQuery) if err != nil { return err } @@ -129,26 +104,12 @@ func (appOptions AppOptions) EnhanceRootCommandWithBuilder(rootCmd *cobra.Comman rootCmd.AddCommand(queryCmd) } - enhanceMsg := func(cmd *cobra.Command, modOpts *autocliv1.ModuleOptions, moduleName string) error { - txCmdDesc := modOpts.Tx - if txCmdDesc != nil { - subCmd := topLevelCmd(moduleName, fmt.Sprintf("Transactions commands for the %s module", moduleName)) - err := builder.AddQueryServiceCommands(cmd, txCmdDesc) - if err != nil { - return err - } - - cmd.AddCommand(subCmd) - } - return nil - } - if msgCmd := findSubCommand(rootCmd, "tx"); msgCmd != nil { - if err := builder.enhanceCommandCommon(msgCmd, moduleOptions, customQueryCmds, enhanceMsg); err != nil { + if err := builder.enhanceCommandCommon(msgCmd, appOptions, customMsgCmds, enhanceMsg); err != nil { return err } } else { - subCmd, err := builder.BuildMsgCommand(moduleOptions, customQueryCmds) + subCmd, err := builder.BuildMsgCommand(appOptions, customMsgCmds, enhanceMsg) if err != nil { return err } diff --git a/client/v2/autocli/common.go b/client/v2/autocli/common.go index 610d59c9e5e0..301cb43204be 100644 --- a/client/v2/autocli/common.go +++ b/client/v2/autocli/common.go @@ -7,6 +7,7 @@ import ( autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/spf13/cobra" + "golang.org/x/exp/maps" "google.golang.org/protobuf/reflect/protoreflect" "sigs.k8s.io/yaml" @@ -67,22 +68,27 @@ func (b *Builder) buildMethodCommandCommon(descriptor protoreflect.MethodDescrip // options or the provided custom commands for each module. If the provided query command already contains a command // for a module, that command is not over-written by this method. This allows a graceful addition of autocli to // automatically fill in missing commands. -func (b *Builder) enhanceCommandCommon(cmd *cobra.Command, moduleOptions map[string]*autocliv1.ModuleOptions, customCmds map[string]*cobra.Command, buildModuleCommand func(*cobra.Command, *autocliv1.ModuleOptions, string) error) error { - allModuleNames := map[string]bool{} - for moduleName := range moduleOptions { - allModuleNames[moduleName] = true - } - for moduleName := range customCmds { - allModuleNames[moduleName] = true +func (b *Builder) enhanceCommandCommon( + cmd *cobra.Command, + appOptions AppOptions, + customCmds map[string]*cobra.Command, + buildModuleCommand enhanceCommandFunc, +) error { + moduleOptions := appOptions.ModuleOptions + if len(moduleOptions) == 0 { + moduleOptions = map[string]*autocliv1.ModuleOptions{} + for name, module := range appOptions.Modules { + if module, ok := module.(HasAutoCLIConfig); ok { + moduleOptions[name] = module.AutoCLIOptions() + } + } } - for moduleName := range allModuleNames { + modules := append(maps.Keys(appOptions.Modules), maps.Keys(moduleOptions)...) + for _, moduleName := range modules { // if we have an existing command skip adding one here - if cmd.HasSubCommands() { - if _, _, err := cmd.Find([]string{moduleName}); err == nil { - // command already exists, skip - continue - } + if findSubCommand(cmd, moduleName) != nil { + continue } // if we have a custom command use that instead of generating one @@ -98,8 +104,7 @@ func (b *Builder) enhanceCommandCommon(cmd *cobra.Command, moduleOptions map[str continue } - err := buildModuleCommand(cmd, modOpts, moduleName) - if err != nil { + if err := buildModuleCommand(b, moduleName, cmd, modOpts); err != nil { return err } } @@ -107,19 +112,51 @@ func (b *Builder) enhanceCommandCommon(cmd *cobra.Command, moduleOptions map[str return nil } +type enhanceCommandFunc func(builder *Builder, moduleName string, cmd *cobra.Command, modOpts *autocliv1.ModuleOptions) error + +// enhanceQuery enhances the provided query command with the autocli commands for a module. +func enhanceQuery(builder *Builder, moduleName string, cmd *cobra.Command, modOpts *autocliv1.ModuleOptions) error { + queryCmdDesc := modOpts.Query + if queryCmdDesc != nil { + subCmd := topLevelCmd(moduleName, fmt.Sprintf("Querying commands for the %s module", moduleName)) + if err := builder.AddQueryServiceCommands(subCmd, queryCmdDesc); err != nil { + return err + } + + cmd.AddCommand(subCmd) + } + + return nil +} + +// enhanceMsg enhances the provided msg command with the autocli commands for a module. +func enhanceMsg(builder *Builder, moduleName string, cmd *cobra.Command, modOpts *autocliv1.ModuleOptions) error { + txCmdDesc := modOpts.Tx + if txCmdDesc != nil { + subCmd := topLevelCmd(moduleName, fmt.Sprintf("Transactions commands for the %s module", moduleName)) + if err := builder.AddMsgServiceCommands(subCmd, txCmdDesc); err != nil { + return err + } + + cmd.AddCommand(subCmd) + } + + return nil +} + // outOrStdoutFormat formats the output based on the output flag and writes it to the command's output stream. func (b *Builder) outOrStdoutFormat(cmd *cobra.Command, out []byte) error { var err error outputType := cmd.Flag(flags.FlagOutput) // if the output type is text, convert the json to yaml // if output type is json or nil, default to json - if outputType != nil && outputType.Value.String() == "text" { + if outputType != nil && outputType.Value.String() == flags.OutputFormatText { out, err = yaml.JSONToYAML(out) if err != nil { return err } } - _, err = fmt.Fprintln(cmd.OutOrStdout(), string(out)) + _, err = fmt.Fprintln(cmd.OutOrStdout(), string(out)) return err } diff --git a/client/v2/autocli/flag/address.go b/client/v2/autocli/flag/address.go index 16d6ce5759c2..4897a7461ee2 100644 --- a/client/v2/autocli/flag/address.go +++ b/client/v2/autocli/flag/address.go @@ -2,16 +2,19 @@ package flag import ( "context" + "fmt" reflectionv2alpha1 "cosmossdk.io/api/cosmos/base/reflection/v2alpha1" - "github.com/cosmos/cosmos-sdk/types" + "cosmossdk.io/core/address" "google.golang.org/protobuf/reflect/protoreflect" + + addresscodec "github.com/cosmos/cosmos-sdk/codec/address" ) type addressStringType struct{} func (a addressStringType) NewValue(ctx context.Context, b *Builder) Value { - if b.AddressPrefix == "" { + if b.AddressCodec == nil { conn, err := b.GetClientConn() if err != nil { panic(err) @@ -24,9 +27,11 @@ func (a addressStringType) NewValue(ctx context.Context, b *Builder) Value { if resp == nil || resp.Config == nil { panic("bech32 account address prefix is not set") } - b.AddressPrefix = resp.Config.Bech32AccountAddressPrefix + + b.AddressCodec = addresscodec.NewBech32Codec(resp.Config.Bech32AccountAddressPrefix) } - return &addressValue{addressPrefix: b.AddressPrefix} + + return &addressValue{addressCodec: b.AddressCodec} } func (a addressStringType) DefaultValue() string { @@ -34,8 +39,8 @@ func (a addressStringType) DefaultValue() string { } type addressValue struct { - value string - addressPrefix string + value string + addressCodec address.Codec } func (a addressValue) Get(protoreflect.Value) (protoreflect.Value, error) { @@ -48,10 +53,11 @@ func (a addressValue) String() string { // Set implements the flag.Value interface for addressValue it only supports bech32 addresses. func (a *addressValue) Set(s string) error { - _, err := types.GetFromBech32(s, a.addressPrefix) + _, err := a.addressCodec.StringToBytes(s) if err != nil { - return err + return fmt.Errorf("invalid bech32 account address: %w", err) } + a.value = s return nil diff --git a/client/v2/autocli/flag/builder.go b/client/v2/autocli/flag/builder.go index 5b4ae5f7eca6..ad2057ef4633 100644 --- a/client/v2/autocli/flag/builder.go +++ b/client/v2/autocli/flag/builder.go @@ -5,6 +5,8 @@ import ( "google.golang.org/protobuf/reflect/protodesc" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoregistry" + + "cosmossdk.io/core/address" ) // Builder manages options for building pflag flags for protobuf messages. @@ -23,9 +25,10 @@ type Builder struct { messageFlagTypes map[protoreflect.FullName]Type scalarFlagTypes map[string]Type - // AddressPrefix is the prefix for the address flag - AddressPrefix string - // reflectionClient is the reflection client for the address flag + // AddressCodec is the address codec used for the address flag + AddressCodec address.Codec + + // GetClientConn is the reflection client for the address flag GetClientConn func() (grpc.ClientConnInterface, error) } diff --git a/client/v2/autocli/msg.go b/client/v2/autocli/msg.go index c15d750756d4..704d4e3c08b6 100644 --- a/client/v2/autocli/msg.go +++ b/client/v2/autocli/msg.go @@ -14,22 +14,9 @@ import ( // BuildMsgCommand builds the msg commands for all the provided modules. If a custom command is provided for a // module, this is used instead of any automatically generated CLI commands. This allows apps to a fully dynamic client // with a more customized experience if a binary with custom commands is downloaded. -func (b *Builder) BuildMsgCommand(moduleOptions map[string]*autocliv1.ModuleOptions, customCmds map[string]*cobra.Command) (*cobra.Command, error) { +func (b *Builder) BuildMsgCommand(appOptions AppOptions, customCmds map[string]*cobra.Command, buildModuleCommand enhanceCommandFunc) (*cobra.Command, error) { msgCmd := topLevelCmd("tx", "Transaction subcommands") - enhanceMsg := func(cmd *cobra.Command, modOpts *autocliv1.ModuleOptions, moduleName string) error { - txCmdDesc := modOpts.Tx - if txCmdDesc != nil { - subCmd := topLevelCmd(moduleName, fmt.Sprintf("Transactions commands for the %s module", moduleName)) - err := b.AddMsgServiceCommands(subCmd, txCmdDesc) - if err != nil { - return err - } - - cmd.AddCommand(subCmd) - } - return nil - } - if err := b.enhanceCommandCommon(msgCmd, moduleOptions, customCmds, enhanceMsg); err != nil { + if err := b.enhanceCommandCommon(msgCmd, appOptions, customCmds, enhanceMsg); err != nil { return nil, err } @@ -78,8 +65,7 @@ func (b *Builder) AddMsgServiceCommands(cmd *cobra.Command, cmdDescriptor *autoc } - methodsLength := methods.Len() - for i := 0; i < methodsLength; i++ { + for i := 0; i < methods.Len(); i++ { methodDescriptor := methods.Get(i) methodOpts, ok := rpcOptMap[methodDescriptor.Name()] if !ok { @@ -89,10 +75,12 @@ func (b *Builder) AddMsgServiceCommands(cmd *cobra.Command, cmdDescriptor *autoc if methodOpts.Skip { continue } + methodCmd, err := b.BuildMsgMethodCommand(methodDescriptor, methodOpts) if err != nil { return err } + if methodCmd != nil { cmd.AddCommand(methodCmd) } @@ -101,6 +89,7 @@ func (b *Builder) AddMsgServiceCommands(cmd *cobra.Command, cmdDescriptor *autoc return nil } +// BuildMsgMethodCommand returns a command that outputs the JSON representation of the message. func (b *Builder) BuildMsgMethodCommand(descriptor protoreflect.MethodDescriptor, options *autocliv1.RpcCommandOptions) (*cobra.Command, error) { jsonMarshalOptions := protojson.MarshalOptions{ Indent: " ", @@ -116,11 +105,12 @@ func (b *Builder) BuildMsgMethodCommand(descriptor protoreflect.MethodDescriptor return err } - err = b.outOrStdoutFormat(cmd, bz) - return err + return b.outOrStdoutFormat(cmd, bz) }) + if b.AddTxConnFlags != nil { b.AddTxConnFlags(cmd) } + return cmd, err } diff --git a/client/v2/autocli/msg_test.go b/client/v2/autocli/msg_test.go index 1bd0d11bc70a..b58393da8b19 100644 --- a/client/v2/autocli/msg_test.go +++ b/client/v2/autocli/msg_test.go @@ -5,14 +5,12 @@ import ( "strings" "testing" + "github.com/spf13/cobra" "google.golang.org/protobuf/encoding/protojson" - + "gotest.tools/v3/assert" "gotest.tools/v3/golden" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" - "github.com/spf13/cobra" - "gotest.tools/v3/assert" - "cosmossdk.io/client/v2/internal/testpb" ) @@ -225,18 +223,22 @@ func TestHelpMsg(t *testing.T) { golden.Assert(t, conn.out.String(), "help-deprecated-msg.golden") } -func TestBuildCustomMsgCommand(t *testing.T) { +func TestBuildMsgCommand(t *testing.T) { b := &Builder{} customCommandCalled := false - cmd, err := b.BuildMsgCommand(map[string]*autocliv1.ModuleOptions{ - "test": { - Tx: testCmdMsgDesc, + appOptions := AppOptions{ + ModuleOptions: map[string]*autocliv1.ModuleOptions{ + "test": { + Tx: testCmdMsgDesc, + }, }, - }, map[string]*cobra.Command{ + } + + cmd, err := b.BuildMsgCommand(appOptions, map[string]*cobra.Command{ "test": {Use: "test", Run: func(cmd *cobra.Command, args []string) { customCommandCalled = true }}, - }) + }, enhanceMsg) assert.NilError(t, err) cmd.SetArgs([]string{"test", "tx"}) assert.NilError(t, cmd.Execute()) @@ -260,21 +262,20 @@ func TestErrorBuildMsgCommand(t *testing.T) { }, } - opts := map[string]*autocliv1.ModuleOptions{ - "test": { - Tx: commandDescriptor, + appOptions := AppOptions{ + ModuleOptions: map[string]*autocliv1.ModuleOptions{ + "test": { + Tx: commandDescriptor, + }, }, } - _, err := b.BuildMsgCommand(opts, nil) + + _, err := b.BuildMsgCommand(appOptions, nil, enhanceMsg) assert.ErrorContains(t, err, "can't find field un-existent-proto-field") nonExistentService := &autocliv1.ServiceCommandDescriptor{Service: "un-existent-service"} - opts = map[string]*autocliv1.ModuleOptions{ - "test": { - Tx: nonExistentService, - }, - } - _, err = b.BuildMsgCommand(opts, nil) + appOptions.ModuleOptions["test"].Tx = nonExistentService + _, err = b.BuildMsgCommand(appOptions, nil, enhanceMsg) assert.ErrorContains(t, err, "can't find service un-existent-service") } @@ -328,42 +329,35 @@ func TestNotFoundErrorsMsg(t *testing.T) { func TestEnhanceMessageCommand(t *testing.T) { b := &Builder{} - enhanceMsg := func(cmd *cobra.Command, modOpts *autocliv1.ModuleOptions, moduleName string) error { - txCmdDesc := modOpts.Tx - if txCmdDesc != nil { - subCmd := topLevelCmd(moduleName, fmt.Sprintf("Transactions commands for the %s module", moduleName)) - err := b.AddMsgServiceCommands(cmd, txCmdDesc) - if err != nil { - return err - } - - cmd.AddCommand(subCmd) - } - return nil - } - // Test that the command has a subcommand cmd := &cobra.Command{Use: "test"} cmd.AddCommand(&cobra.Command{Use: "test"}) - options := map[string]*autocliv1.ModuleOptions{ - "test": {}, + + appOptions := AppOptions{ + ModuleOptions: map[string]*autocliv1.ModuleOptions{ + "test": {}, + }, } - err := b.enhanceCommandCommon(cmd, options, map[string]*cobra.Command{}, enhanceMsg) + + err := b.enhanceCommandCommon(cmd, appOptions, map[string]*cobra.Command{}, enhanceMsg) assert.NilError(t, err) cmd = &cobra.Command{Use: "test"} - options = map[string]*autocliv1.ModuleOptions{} + + appOptions.ModuleOptions = map[string]*autocliv1.ModuleOptions{} customCommands := map[string]*cobra.Command{ "test2": {Use: "test"}, } - err = b.enhanceCommandCommon(cmd, options, customCommands, enhanceMsg) + err = b.enhanceCommandCommon(cmd, appOptions, customCommands, enhanceMsg) assert.NilError(t, err) cmd = &cobra.Command{Use: "test"} - options = map[string]*autocliv1.ModuleOptions{ - "test": {Tx: nil}, + appOptions = AppOptions{ + ModuleOptions: map[string]*autocliv1.ModuleOptions{ + "test": {Tx: nil}, + }, } customCommands = map[string]*cobra.Command{} - err = b.enhanceCommandCommon(cmd, options, customCommands, enhanceMsg) + err = b.enhanceCommandCommon(cmd, appOptions, customCommands, enhanceMsg) assert.NilError(t, err) } diff --git a/client/v2/autocli/query.go b/client/v2/autocli/query.go index 1f0734da1d77..3fd10ea525dd 100644 --- a/client/v2/autocli/query.go +++ b/client/v2/autocli/query.go @@ -16,24 +16,11 @@ import ( // BuildQueryCommand builds the query commands for all the provided modules. If a custom command is provided for a // module, this is used instead of any automatically generated CLI commands. This allows apps to a fully dynamic client // with a more customized experience if a binary with custom commands is downloaded. -func (b *Builder) BuildQueryCommand(moduleOptions map[string]*autocliv1.ModuleOptions, customCmds map[string]*cobra.Command) (*cobra.Command, error) { +func (b *Builder) BuildQueryCommand(appOptions AppOptions, customCmds map[string]*cobra.Command, enhanceQuery enhanceCommandFunc) (*cobra.Command, error) { queryCmd := topLevelCmd("query", "Querying subcommands") queryCmd.Aliases = []string{"q"} - enhanceMsg := func(cmd *cobra.Command, modOpts *autocliv1.ModuleOptions, moduleName string) error { - txQueryDesc := modOpts.Query - if txQueryDesc != nil { - subCmd := topLevelCmd(moduleName, fmt.Sprintf("Querying commands for the %s module", moduleName)) - err := b.AddQueryServiceCommands(subCmd, txQueryDesc) - if err != nil { - return err - } - - cmd.AddCommand(subCmd) - } - return nil - } - if err := b.enhanceCommandCommon(queryCmd, moduleOptions, customCmds, enhanceMsg); err != nil { + if err := b.enhanceCommandCommon(queryCmd, appOptions, customCmds, enhanceQuery); err != nil { return nil, err } @@ -99,7 +86,6 @@ func (b *Builder) AddQueryServiceCommands(cmd *cobra.Command, cmdDescriptor *aut } cmd.AddCommand(methodCmd) - } return nil diff --git a/client/v2/autocli/query_test.go b/client/v2/autocli/query_test.go index 434543ff9ff5..67b0293131a8 100644 --- a/client/v2/autocli/query_test.go +++ b/client/v2/autocli/query_test.go @@ -336,15 +336,20 @@ func TestDeprecated(t *testing.T) { func TestBuildCustomQueryCommand(t *testing.T) { b := &Builder{} customCommandCalled := false - cmd, err := b.BuildQueryCommand(map[string]*autocliv1.ModuleOptions{ - "test": { - Query: testCmdDesc, + + appOptions := AppOptions{ + ModuleOptions: map[string]*autocliv1.ModuleOptions{ + "test": { + Query: testCmdDesc, + }, }, - }, map[string]*cobra.Command{ + } + + cmd, err := b.BuildQueryCommand(appOptions, map[string]*cobra.Command{ "test": {Use: "test", Run: func(cmd *cobra.Command, args []string) { customCommandCalled = true }}, - }) + }, enhanceQuery) assert.NilError(t, err) cmd.SetArgs([]string{"test", "query"}) assert.NilError(t, cmd.Execute()) diff --git a/client/v2/go.mod b/client/v2/go.mod index b8da5c1ee796..101faada8098 100644 --- a/client/v2/go.mod +++ b/client/v2/go.mod @@ -11,6 +11,7 @@ require ( github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230424095137-b73c17cb9cc8 github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 google.golang.org/grpc v1.54.0 google.golang.org/protobuf v1.30.0 gotest.tools/v3 v3.4.0 @@ -104,7 +105,6 @@ require ( github.com/zondax/hid v0.9.1 // indirect github.com/zondax/ledger-go v0.14.1 // indirect golang.org/x/crypto v0.8.0 // indirect - golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect golang.org/x/net v0.9.0 // indirect golang.org/x/sys v0.7.0 // indirect golang.org/x/term v0.7.0 // indirect diff --git a/docs/docs/building-modules/10-autocli.md b/docs/docs/building-modules/10-autocli.md index 1629e3d65620..10a9bde61701 100644 --- a/docs/docs/building-modules/10-autocli.md +++ b/docs/docs/building-modules/10-autocli.md @@ -24,7 +24,7 @@ The `autocli` package is a [Go library](https://pkg.go.dev/cosmossdk.io/client/v Here are the steps to use the `autocli` package: 1. Define your app's modules that implement the `appmodule.AppModule` interface. -2. (optional) When willing to configure how behave `autocli` command generation, implement the `func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions` method on the module. Learn more [here](#advanced-usage). +2. Configure how behave `autocli` command generation, by implementing the `func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions` method on the module. Learn more [here](#advanced-usage). 3. Use the `autocli.AppOptions` struct to specifies the modules you defined. If you are using the `depinject` package to manage your app's dependencies, it can automatically create an instance of `autocli.AppOptions` based on your app's configuration. 4. Use the `EnhanceRootCommand()` method provided by `autocli` to add the CLI commands for the specified modules to your root command and can also be found in the `client/v2/autocli/app.go` file. Additionally, this method adds the `autocli` functionality to your app's root command. This method is additive only, meaning that it does not create commands if they are already registered for a module. Instead, it adds any missing commands to the root command. diff --git a/docs/docs/building-modules/11-structure.md b/docs/docs/building-modules/11-structure.md index 5e31c31d944b..77c9b3ead2bc 100644 --- a/docs/docs/building-modules/11-structure.md +++ b/docs/docs/building-modules/11-structure.md @@ -53,13 +53,13 @@ x/{module_name} ├── module │   └── module.go │   └── abci.go +│   └── autocli.go ├── simulation │   ├── decoder.go │   ├── genesis.go │   ├── operations.go │   └── params.go ├── {module_name}.pb.go -├── autocli.go ├── codec.go ├── errors.go ├── events.go @@ -80,10 +80,10 @@ x/{module_name} * `keeper/`: The module's `Keeper` and `MsgServer` implementation. * `module/`: The module's `AppModule` and `AppModuleBasic` implementation. * `abci.go`: The module's `BeginBlocker` and `EndBlocker` implementations (this file is only required if `BeginBlocker` and/or `EndBlocker` need to be defined). + * `autocli.go`: The module [autocli](./10-autocli.md) options. * `simulation/`: The module's [simulation](./14-simulator.md) package defines functions used by the blockchain simulator application (`simapp`). * `REAMDE.md`: The module's specification documents outlining important concepts, state storage structure, and message and event type definitions. Learn more how to write module specs in the [spec guidelines](../spec/SPEC-SPEC.md). * The root directory includes type definitions for messages, events, and genesis state, including the type definitions generated by Protocol Buffers. - * `autocli.go`: The module [autocli](./10-autocli.md) options. * `codec.go`: The module's registry methods for interface types. * `errors.go`: The module's sentinel errors. * `events.go`: The module's event types and constructors. diff --git a/proto/cosmos/autocli/v1/options.proto b/proto/cosmos/autocli/v1/options.proto index 4b938db6977f..b023490c9709 100644 --- a/proto/cosmos/autocli/v1/options.proto +++ b/proto/cosmos/autocli/v1/options.proto @@ -6,10 +6,10 @@ option go_package = "cosmossdk.io/api/cosmos/base/cli/v1;cliv1"; // ModuleOptions describes the CLI options for a Cosmos SDK module. message ModuleOptions { - // tx describes the tx command for the module. + // tx describes the tx commands for the module. ServiceCommandDescriptor tx = 1; - // query describes the tx command for the module. + // query describes the queries commands for the module. ServiceCommandDescriptor query = 2; } diff --git a/server/util.go b/server/util.go index e74110105aa4..bd1b80371ffa 100644 --- a/server/util.go +++ b/server/util.go @@ -213,10 +213,11 @@ func GetServerContextFromCmd(cmd *cobra.Command) *Context { } // SetCmdServerContext sets a command's Context value to the provided argument. +// If the context has not been set, set the given context as the default. func SetCmdServerContext(cmd *cobra.Command, serverCtx *Context) error { v := cmd.Context().Value(ServerContextKey) if v == nil { - return errors.New("server context not set") + v = serverCtx } serverCtxPtr := v.(*Context) diff --git a/simapp/go.mod b/simapp/go.mod index c3a66895226d..8a5a4f67337d 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( cosmossdk.io/api v0.4.1 cosmossdk.io/client/v2 v2.0.0-20230309163709-87da587416ba - cosmossdk.io/core v0.6.1 + cosmossdk.io/core v0.6.2-0.20230323161322-ccd8d40119e4 cosmossdk.io/depinject v1.0.0-alpha.3 cosmossdk.io/log v1.0.0 cosmossdk.io/math v1.0.0 @@ -197,6 +197,7 @@ require ( replace ( // TODO tag all extracted modules after SDK refactor cosmossdk.io/api => ../api + cosmossdk.io/client/v2 => ../client/v2 cosmossdk.io/store => ../store cosmossdk.io/tools/confix => ../tools/confix cosmossdk.io/tools/rosetta => ../tools/rosetta diff --git a/simapp/go.sum b/simapp/go.sum index a05adcb99164..623136a5c10e 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -188,12 +188,10 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cosmossdk.io/client/v2 v2.0.0-20230309163709-87da587416ba h1:LuPHCncU2KLMNPItFECs709uo46I9wSu2fAWYVCx+/U= -cosmossdk.io/client/v2 v2.0.0-20230309163709-87da587416ba/go.mod h1:SXdwqO7cN5htalh/lhXWP8V4zKtBrhhcSTU+ytuEtmM= cosmossdk.io/collections v0.1.0 h1:nzJGeiq32KnZroSrhB6rPifw4I85Cgmzw/YAmr4luv8= cosmossdk.io/collections v0.1.0/go.mod h1:xbauc0YsbUF8qKMVeBZl0pFCunxBIhKN/WlxpZ3lBuo= -cosmossdk.io/core v0.6.1 h1:OBy7TI2W+/gyn2z40vVvruK3di+cAluinA6cybFbE7s= -cosmossdk.io/core v0.6.1/go.mod h1:g3MMBCBXtxbDWBURDVnJE7XML4BG5qENhs0gzkcpuFA= +cosmossdk.io/core v0.6.2-0.20230323161322-ccd8d40119e4 h1:l1scDTT2VX18ZuR6P0irvT/bAP0h4297D/Lka5nz2vE= +cosmossdk.io/core v0.6.2-0.20230323161322-ccd8d40119e4/go.mod h1:J8R0E7soOpQFVqFiFd7EKepXCPpINa2n2t2EqbEsXnY= cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= cosmossdk.io/depinject v1.0.0-alpha.3/go.mod h1:eRbcdQ7MRpIPEM5YUJh8k97nxHpYbc3sMUnEtt8HPWU= cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w= diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index 84c798aa1714..2d7734490416 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -239,8 +239,6 @@ func queryCommand() *cobra.Command { authcmd.QueryTxCmd(), ) - simapp.ModuleBasics.AddQueryCommands(cmd) - return cmd } @@ -265,8 +263,6 @@ func txCommand() *cobra.Command { authcmd.GetAuxToFeeCommand(), ) - simapp.ModuleBasics.AddTxCommands(cmd) - return cmd } diff --git a/tests/e2e/nft/query.go b/tests/e2e/nft/query.go deleted file mode 100644 index 6d02a65f8a4f..000000000000 --- a/tests/e2e/nft/query.go +++ /dev/null @@ -1,399 +0,0 @@ -package nft - -import ( - "cosmossdk.io/x/nft" -) - -func (s *E2ETestSuite) TestQueryClass() { - val := s.network.Validators[0] - testCases := []struct { - name string - args struct { - ClassID string - } - expectErr bool - }{ - { - name: "class id does not exist", - args: struct { - ClassID string - }{ - ClassID: "class", - }, - expectErr: true, - }, - { - name: "class id exist", - args: struct { - ClassID string - }{ - ClassID: testClassID, - }, - expectErr: false, - }, - } - for _, tc := range testCases { - s.Run(tc.name, func() { - resp, err := ExecQueryClass(val, tc.args.ClassID) - if tc.expectErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - var result nft.QueryClassResponse - err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &result) - s.Require().NoError(err) - s.Require().EqualValues(ExpClass, *result.Class) - } - }) - } -} - -func (s *E2ETestSuite) TestQueryClasses() { - val := s.network.Validators[0] - testCases := []struct { - name string - expectErr bool - }{ - { - name: "no params", - expectErr: false, - }, - } - for _, tc := range testCases { - s.Run(tc.name, func() { - resp, err := ExecQueryClasses(val) - if tc.expectErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - var result nft.QueryClassesResponse - err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &result) - s.Require().NoError(err) - s.Require().Len(result.Classes, 1) - s.Require().EqualValues(ExpClass, *result.Classes[0]) - } - }) - } -} - -func (s *E2ETestSuite) TestQueryNFT() { - val := s.network.Validators[0] - testCases := []struct { - name string - args struct { - ClassID string - ID string - } - expectErr bool - }{ - { - name: "class id does not exist", - args: struct { - ClassID string - ID string - }{ - ClassID: "class", - ID: testID, - }, - expectErr: true, - }, - { - name: "nft id does not exist", - args: struct { - ClassID string - ID string - }{ - ClassID: testClassID, - ID: "id", - }, - expectErr: true, - }, - { - name: "exist nft", - args: struct { - ClassID string - ID string - }{ - ClassID: testClassID, - ID: testID, - }, - expectErr: false, - }, - } - for _, tc := range testCases { - s.Run(tc.name, func() { - resp, err := ExecQueryNFT(val, tc.args.ClassID, tc.args.ID) - if tc.expectErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - var result nft.QueryNFTResponse - err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &result) - s.Require().NoError(err) - s.Require().EqualValues(ExpNFT, *result.Nft) - } - }) - } -} - -func (s *E2ETestSuite) TestQueryNFTs() { - val := s.network.Validators[0] - testCases := []struct { - name string - args struct { - ClassID string - Owner string - } - expectErr bool - expectResult []*nft.NFT - }{ - { - name: "class id does not exist", - args: struct { - ClassID string - Owner string - }{ - ClassID: "class", - Owner: val.Address.String(), - }, - expectErr: false, - expectResult: []*nft.NFT{}, - }, - { - name: "owner does not exist", - args: struct { - ClassID string - Owner string - }{ - ClassID: testClassID, - Owner: s.owner.String(), - }, - expectErr: false, - expectResult: []*nft.NFT{}, - }, - { - name: "class id and owner both does not exist", - args: struct { - ClassID string - Owner string - }{}, - expectErr: true, - expectResult: []*nft.NFT{}, - }, - { - name: "nft exist", - args: struct { - ClassID string - Owner string - }{ - ClassID: testClassID, - Owner: val.Address.String(), - }, - expectErr: false, - expectResult: []*nft.NFT{&ExpNFT}, - }, - } - for _, tc := range testCases { - s.Run(tc.name, func() { - resp, err := ExecQueryNFTs(val, tc.args.ClassID, tc.args.Owner) - if tc.expectErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - var result nft.QueryNFTsResponse - err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &result) - s.Require().NoError(err) - s.Require().EqualValues(tc.expectResult, result.Nfts) - } - }) - } -} - -func (s *E2ETestSuite) TestQueryOwner() { - val := s.network.Validators[0] - testCases := []struct { - name string - args struct { - ClassID string - ID string - } - expectErr bool - errorMsg string - expectResult string - }{ - { - name: "class id does not exist", - args: struct { - ClassID string - ID string - }{ - ClassID: "class", - ID: testID, - }, - expectErr: false, - expectResult: "", - }, - { - name: "nft id does not exist", - args: struct { - ClassID string - ID string - }{ - ClassID: testClassID, - ID: "nft-id", - }, - expectErr: false, - expectResult: "", - }, - { - name: "nft exist", - args: struct { - ClassID string - ID string - }{ - ClassID: testClassID, - ID: testID, - }, - expectErr: false, - expectResult: val.Address.String(), - }, - } - for _, tc := range testCases { - s.Run(tc.name, func() { - resp, err := ExecQueryOwner(val, tc.args.ClassID, tc.args.ID) - if tc.expectErr { - s.Require().Contains(string(resp.Bytes()), tc.errorMsg) - } else { - s.Require().NoError(err) - var result nft.QueryOwnerResponse - err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &result) - s.Require().NoError(err) - s.Require().EqualValues(tc.expectResult, result.Owner) - } - }) - } -} - -func (s *E2ETestSuite) TestQueryBalance() { - val := s.network.Validators[0] - testCases := []struct { - name string - args struct { - ClassID string - Owner string - } - expectErr bool - errorMsg string - expectResult uint64 - }{ - { - name: "class id does not exist", - args: struct { - ClassID string - Owner string - }{ - ClassID: "class", - Owner: val.Address.String(), - }, - expectErr: false, - expectResult: 0, - }, - { - name: "owner does not exist", - args: struct { - ClassID string - Owner string - }{ - ClassID: testClassID, - Owner: s.owner.String(), - }, - expectErr: false, - expectResult: 0, - }, - { - name: "nft exist", - args: struct { - ClassID string - Owner string - }{ - ClassID: testClassID, - Owner: val.Address.String(), - }, - expectErr: false, - expectResult: 1, - }, - } - for _, tc := range testCases { - s.Run(tc.name, func() { - resp, err := ExecQueryBalance(val, tc.args.ClassID, tc.args.Owner) - if tc.expectErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - var result nft.QueryBalanceResponse - err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &result) - s.Require().NoError(err) - s.Require().EqualValues(tc.expectResult, result.Amount) - } - }) - } -} - -func (s *E2ETestSuite) TestQuerySupply() { - val := s.network.Validators[0] - testCases := []struct { - name string - args struct { - ClassID string - } - expectErr bool - errorMsg string - expectResult uint64 - }{ - { - name: "class id is empty", - args: struct { - ClassID string - }{ - ClassID: "", - }, - expectErr: true, - errorMsg: nft.ErrEmptyClassID.Error(), - expectResult: 0, - }, - { - name: "class id does not exist", - args: struct { - ClassID string - }{ - ClassID: "class", - }, - expectErr: false, - expectResult: 0, - }, - { - name: "class id exist", - args: struct { - ClassID string - }{ - ClassID: testClassID, - }, - expectErr: false, - expectResult: 1, - }, - } - for _, tc := range testCases { - s.Run(tc.name, func() { - resp, err := ExecQuerySupply(val, tc.args.ClassID) - if tc.expectErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - var result nft.QuerySupplyResponse - err = val.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &result) - s.Require().NoError(err) - s.Require().EqualValues(tc.expectResult, result.Amount) - } - }) - } -} diff --git a/tests/e2e/nft/test_helper.go b/tests/e2e/nft/test_helper.go deleted file mode 100644 index ce34da3d6736..000000000000 --- a/tests/e2e/nft/test_helper.go +++ /dev/null @@ -1,76 +0,0 @@ -package nft - -import ( - "fmt" - - "cosmossdk.io/x/nft/client/cli" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec/address" - "github.com/cosmos/cosmos-sdk/testutil" - clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" - "github.com/cosmos/cosmos-sdk/testutil/network" -) - -func ExecSend(val *network.Validator, args []string) (testutil.BufferWriter, error) { - cmd := cli.NewCmdSend() - return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) -} - -func ExecQueryClass(val *network.Validator, classID string) (testutil.BufferWriter, error) { - cmd := cli.GetCmdQueryClass() - var args []string - args = append(args, classID) - args = append(args, fmt.Sprintf("--%s=json", flags.FlagOutput)) - return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) -} - -func ExecQueryClasses(val *network.Validator) (testutil.BufferWriter, error) { - cmd := cli.GetCmdQueryClasses() - var args []string - args = append(args, fmt.Sprintf("--%s=json", flags.FlagOutput)) - return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) -} - -func ExecQueryNFT(val *network.Validator, classID, nftID string) (testutil.BufferWriter, error) { - cmd := cli.GetCmdQueryNFT() - var args []string - args = append(args, classID) - args = append(args, nftID) - args = append(args, fmt.Sprintf("--%s=json", flags.FlagOutput)) - return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) -} - -func ExecQueryNFTs(val *network.Validator, classID, owner string) (testutil.BufferWriter, error) { - cmd := cli.GetCmdQueryNFTs(address.NewBech32Codec("cosmos")) - var args []string - args = append(args, fmt.Sprintf("--%s=%s", cli.FlagClassID, classID)) - args = append(args, fmt.Sprintf("--%s=%s", cli.FlagOwner, owner)) - args = append(args, fmt.Sprintf("--%s=json", flags.FlagOutput)) - return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) -} - -func ExecQueryOwner(val *network.Validator, classID, nftID string) (testutil.BufferWriter, error) { - cmd := cli.GetCmdQueryOwner() - var args []string - args = append(args, classID) - args = append(args, nftID) - args = append(args, fmt.Sprintf("--%s=json", flags.FlagOutput)) - return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) -} - -func ExecQueryBalance(val *network.Validator, classID, owner string) (testutil.BufferWriter, error) { - cmd := cli.GetCmdQueryBalance() - var args []string - args = append(args, owner) - args = append(args, classID) - args = append(args, fmt.Sprintf("--%s=json", flags.FlagOutput)) - return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) -} - -func ExecQuerySupply(val *network.Validator, classID string) (testutil.BufferWriter, error) { - cmd := cli.GetCmdQuerySupply() - var args []string - args = append(args, classID) - args = append(args, fmt.Sprintf("--%s=json", flags.FlagOutput)) - return clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) -} diff --git a/tests/e2e/nft/tx.go b/tests/e2e/nft/tx.go index 2c1423b71a07..ccfbaaa58819 100644 --- a/tests/e2e/nft/tx.go +++ b/tests/e2e/nft/tx.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/suite" "cosmossdk.io/x/nft" + "cosmossdk.io/x/nft/client/cli" "github.com/cosmos/cosmos-sdk/client/flags" clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" "github.com/cosmos/cosmos-sdk/testutil/network" @@ -92,6 +93,7 @@ func (s *E2ETestSuite) TearDownSuite() { } func (s *E2ETestSuite) TestCLITxSend() { + cmd := cli.NewCmdSend() val := s.network.Validators[0] args := []string{ fmt.Sprintf("--%s=%s", flags.FlagFrom, OwnerName), @@ -122,10 +124,8 @@ func (s *E2ETestSuite) TestCLITxSend() { s.Run(tc.name, func() { clientCtx := val.ClientCtx args = append(args, tc.args...) - out, err := ExecSend( - val, - args, - ) + + out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) if tc.expectErr { s.Require().Error(err) } else { diff --git a/tests/go.mod b/tests/go.mod index 6042f34247ec..6cf264055823 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -38,7 +38,7 @@ require ( cloud.google.com/go/storage v1.30.0 // indirect cosmossdk.io/client/v2 v2.0.0-20230309163709-87da587416ba // indirect cosmossdk.io/collections v0.1.0 // indirect - cosmossdk.io/core v0.6.1 // indirect + cosmossdk.io/core v0.6.2-0.20230323161322-ccd8d40119e4 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect diff --git a/tests/go.sum b/tests/go.sum index 6a671c8303ff..711b29a342e6 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -192,8 +192,8 @@ cosmossdk.io/client/v2 v2.0.0-20230309163709-87da587416ba h1:LuPHCncU2KLMNPItFEC cosmossdk.io/client/v2 v2.0.0-20230309163709-87da587416ba/go.mod h1:SXdwqO7cN5htalh/lhXWP8V4zKtBrhhcSTU+ytuEtmM= cosmossdk.io/collections v0.1.0 h1:nzJGeiq32KnZroSrhB6rPifw4I85Cgmzw/YAmr4luv8= cosmossdk.io/collections v0.1.0/go.mod h1:xbauc0YsbUF8qKMVeBZl0pFCunxBIhKN/WlxpZ3lBuo= -cosmossdk.io/core v0.6.1 h1:OBy7TI2W+/gyn2z40vVvruK3di+cAluinA6cybFbE7s= -cosmossdk.io/core v0.6.1/go.mod h1:g3MMBCBXtxbDWBURDVnJE7XML4BG5qENhs0gzkcpuFA= +cosmossdk.io/core v0.6.2-0.20230323161322-ccd8d40119e4 h1:l1scDTT2VX18ZuR6P0irvT/bAP0h4297D/Lka5nz2vE= +cosmossdk.io/core v0.6.2-0.20230323161322-ccd8d40119e4/go.mod h1:J8R0E7soOpQFVqFiFd7EKepXCPpINa2n2t2EqbEsXnY= cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= cosmossdk.io/depinject v1.0.0-alpha.3/go.mod h1:eRbcdQ7MRpIPEM5YUJh8k97nxHpYbc3sMUnEtt8HPWU= cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w= diff --git a/types/module/module.go b/types/module/module.go index 3e52dc8b24d1..492631f5a55c 100644 --- a/types/module/module.go +++ b/types/module/module.go @@ -138,9 +138,6 @@ func (bm BasicManager) RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr * } // AddTxCommands adds all tx commands to the rootTxCmd. -// -// TODO: Remove clientCtx argument. -// REF: https://github.com/cosmos/cosmos-sdk/issues/6571 func (bm BasicManager) AddTxCommands(rootTxCmd *cobra.Command) { for _, b := range bm { if cmd := b.GetTxCmd(); cmd != nil { @@ -150,9 +147,6 @@ func (bm BasicManager) AddTxCommands(rootTxCmd *cobra.Command) { } // AddQueryCommands adds all query commands to the rootQueryCmd. -// -// TODO: Remove clientCtx argument. -// REF: https://github.com/cosmos/cosmos-sdk/issues/6571 func (bm BasicManager) AddQueryCommands(rootQueryCmd *cobra.Command) { for _, b := range bm { if cmd := b.GetQueryCmd(); cmd != nil { diff --git a/x/auth/autocli.go b/x/auth/autocli.go index f114e0c98964..3eaa323cc70a 100644 --- a/x/auth/autocli.go +++ b/x/auth/autocli.go @@ -25,8 +25,6 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, }, }, - Tx: &autocliv1.ServiceCommandDescriptor{ - Service: authv1beta1.Msg_ServiceDesc.ServiceName, - }, + // Tx is purposely left empty, as the only tx is MsgUpdateParams which is gov gated. } } diff --git a/x/nft/client/cli/query.go b/x/nft/client/cli/query.go deleted file mode 100644 index a32489a76e3e..000000000000 --- a/x/nft/client/cli/query.go +++ /dev/null @@ -1,270 +0,0 @@ -package cli - -import ( - "fmt" - "strings" - - "github.com/spf13/cobra" - - "cosmossdk.io/core/address" - "cosmossdk.io/x/nft" - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/version" -) - -// Flag names and values -const ( - FlagOwner = "owner" - FlagClassID = "class-id" -) - -// GetQueryCmd returns the cli query commands for this module -func GetQueryCmd(ac address.Codec) *cobra.Command { - nftQueryCmd := &cobra.Command{ - Use: nft.ModuleName, - Short: "Querying commands for the nft module", - Long: "", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - nftQueryCmd.AddCommand( - GetCmdQueryClass(), - GetCmdQueryClasses(), - GetCmdQueryNFT(), - GetCmdQueryNFTs(ac), - GetCmdQueryOwner(), - GetCmdQueryBalance(), - GetCmdQuerySupply(), - ) - return nftQueryCmd -} - -// GetCmdQueryClass implements the query class command. -func GetCmdQueryClass() *cobra.Command { - cmd := &cobra.Command{ - Use: "class [class-id]", - Args: cobra.ExactArgs(1), - Short: "query an NFT class based on its id", - Example: fmt.Sprintf(`$ %s query %s class `, version.AppName, nft.ModuleName), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientQueryContext(cmd) - if err != nil { - return err - } - queryClient := nft.NewQueryClient(clientCtx) - res, err := queryClient.Class(cmd.Context(), &nft.QueryClassRequest{ - ClassId: args[0], - }) - if err != nil { - return err - } - return clientCtx.PrintProto(res) - }, - } - flags.AddQueryFlagsToCmd(cmd) - return cmd -} - -// GetCmdQueryClasses implements the query classes command. -func GetCmdQueryClasses() *cobra.Command { - cmd := &cobra.Command{ - Use: "classes", - Short: "query all NFT classes", - Example: fmt.Sprintf(`$ %s query %s classes`, version.AppName, nft.ModuleName), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientQueryContext(cmd) - if err != nil { - return err - } - queryClient := nft.NewQueryClient(clientCtx) - pageReq, err := client.ReadPageRequest(cmd.Flags()) - if err != nil { - return err - } - res, err := queryClient.Classes(cmd.Context(), &nft.QueryClassesRequest{ - Pagination: pageReq, - }) - if err != nil { - return err - } - return clientCtx.PrintProto(res) - }, - } - flags.AddQueryFlagsToCmd(cmd) - flags.AddPaginationFlagsToCmd(cmd, "classes") - return cmd -} - -// GetCmdQueryNFT implements the query nft command. -func GetCmdQueryNFT() *cobra.Command { - cmd := &cobra.Command{ - Use: "nft [class-id] [nft-id]", - Args: cobra.ExactArgs(2), - Short: "query an NFT based on its class and id.", - Example: fmt.Sprintf(`$ %s query %s nft`, version.AppName, nft.ModuleName), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientQueryContext(cmd) - if err != nil { - return err - } - queryClient := nft.NewQueryClient(clientCtx) - res, err := queryClient.NFT(cmd.Context(), &nft.QueryNFTRequest{ - ClassId: args[0], - Id: args[1], - }) - if err != nil { - return err - } - return clientCtx.PrintProto(res) - }, - } - flags.AddQueryFlagsToCmd(cmd) - return cmd -} - -// GetCmdQueryNFTs implements the query nft command. -func GetCmdQueryNFTs(ac address.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "nfts", - Short: "query all NFTs of a given class or owner address.", - Long: strings.TrimSpace( - fmt.Sprintf(`Query all NFTs of a given class or owner address. If owner -is set, all nfts that belong to the owner are filtered out. -Examples: -$ %s query %s nfts --owner= -`, - version.AppName, nft.ModuleName), - ), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientQueryContext(cmd) - if err != nil { - return err - } - queryClient := nft.NewQueryClient(clientCtx) - pageReq, err := client.ReadPageRequest(cmd.Flags()) - if err != nil { - return err - } - - owner, err := cmd.Flags().GetString(FlagOwner) - if err != nil { - return err - } - - if len(owner) > 0 { - if _, err := ac.StringToBytes(owner); err != nil { - return err - } - } - - classID, err := cmd.Flags().GetString(FlagClassID) - if err != nil { - return err - } - - if len(owner) == 0 && len(classID) == 0 { - return errors.ErrInvalidRequest.Wrap("must provide at least one of classID or owner") - } - - request := &nft.QueryNFTsRequest{ - ClassId: classID, - Owner: owner, - Pagination: pageReq, - } - res, err := queryClient.NFTs(cmd.Context(), request) - if err != nil { - return err - } - return clientCtx.PrintProto(res) - }, - } - flags.AddQueryFlagsToCmd(cmd) - flags.AddPaginationFlagsToCmd(cmd, "nfts") - cmd.Flags().String(FlagOwner, "", "The owner of the nft") - cmd.Flags().String(FlagClassID, "", "The class-id of the nft") - return cmd -} - -// GetCmdQueryOwner implements the query owner command. -func GetCmdQueryOwner() *cobra.Command { - cmd := &cobra.Command{ - Use: "owner [class-id] [nft-id]", - Args: cobra.ExactArgs(2), - Short: "query the owner of the NFT based on its class and id.", - Example: fmt.Sprintf(`$ %s query %s owner `, version.AppName, nft.ModuleName), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientQueryContext(cmd) - if err != nil { - return err - } - queryClient := nft.NewQueryClient(clientCtx) - res, err := queryClient.Owner(cmd.Context(), &nft.QueryOwnerRequest{ - ClassId: args[0], - Id: args[1], - }) - if err != nil { - return err - } - return clientCtx.PrintProto(res) - }, - } - flags.AddQueryFlagsToCmd(cmd) - return cmd -} - -// GetCmdQueryBalance implements the query balance command. -func GetCmdQueryBalance() *cobra.Command { - cmd := &cobra.Command{ - Use: "balance [owner] [class-id]", - Args: cobra.ExactArgs(2), - Short: "query the number of NFTs of a given class owned by the owner.", - Example: fmt.Sprintf(`$ %s query %s balance `, version.AppName, nft.ModuleName), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientQueryContext(cmd) - if err != nil { - return err - } - queryClient := nft.NewQueryClient(clientCtx) - res, err := queryClient.Balance(cmd.Context(), &nft.QueryBalanceRequest{ - ClassId: args[1], - Owner: args[0], - }) - if err != nil { - return err - } - return clientCtx.PrintProto(res) - }, - } - flags.AddQueryFlagsToCmd(cmd) - return cmd -} - -// GetCmdQuerySupply implements the query supply command. -func GetCmdQuerySupply() *cobra.Command { - cmd := &cobra.Command{ - Use: "supply [class-id]", - Args: cobra.ExactArgs(1), - Short: "query the number of nft based on the class.", - Example: fmt.Sprintf(`$ %s query %s supply `, version.AppName, nft.ModuleName), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientQueryContext(cmd) - if err != nil { - return err - } - queryClient := nft.NewQueryClient(clientCtx) - res, err := queryClient.Supply(cmd.Context(), &nft.QuerySupplyRequest{ - ClassId: args[0], - }) - if err != nil { - return err - } - return clientCtx.PrintProto(res) - }, - } - flags.AddQueryFlagsToCmd(cmd) - return cmd -} diff --git a/x/nft/client/cli/query_test.go b/x/nft/client/cli/query_test.go deleted file mode 100644 index d2e019df2d7a..000000000000 --- a/x/nft/client/cli/query_test.go +++ /dev/null @@ -1,308 +0,0 @@ -package cli_test - -import ( - "context" - "fmt" - "io" - - "cosmossdk.io/x/nft" - "cosmossdk.io/x/nft/client/cli" - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec/address" - svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" - "github.com/cosmos/cosmos-sdk/testutil" - clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" -) - -func (s *CLITestSuite) TestQueryClass() { - testCases := []struct { - name string - args []string - expCmdOutput string - }{ - { - name: "json output", - args: []string{testClassID, fmt.Sprintf("--%s=json", flags.FlagOutput)}, - expCmdOutput: `[kitty --output=json]`, - }, - { - name: "text output", - args: []string{testClassID, fmt.Sprintf("--%s=text", flags.FlagOutput)}, - expCmdOutput: `[kitty --output=text]`, - }, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - cmd := cli.GetCmdQueryClass() - - ctx := svrcmd.CreateExecuteContext(context.Background()) - - cmd.SetOut(io.Discard) - s.Require().NotNil(cmd) - - cmd.SetContext(ctx) - cmd.SetArgs(tc.args) - s.Require().NoError(client.SetCmdClientContextHandler(s.baseCtx, cmd)) - - s.Require().Contains(fmt.Sprint(cmd), "class [class-id] [] [] query an NFT class based on its id") - s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) - - _, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args) - s.Require().NoError(err) - }) - } -} - -func (s *CLITestSuite) TestQueryClasses() { - testCases := []struct { - name string - flagArgs []string - expCmdOutput string - }{ - { - name: "json output", - flagArgs: []string{fmt.Sprintf("--%s=json", flags.FlagOutput)}, - expCmdOutput: `[--output=json]`, - }, - { - name: "text output", - flagArgs: []string{fmt.Sprintf("--%s=text", flags.FlagOutput)}, - expCmdOutput: `[--output=text]`, - }, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - cmd := cli.GetCmdQueryClasses() - ctx := svrcmd.CreateExecuteContext(context.Background()) - - cmd.SetOut(io.Discard) - s.Require().NotNil(cmd) - - cmd.SetContext(ctx) - cmd.SetArgs(tc.flagArgs) - s.Require().NoError(client.SetCmdClientContextHandler(s.baseCtx, cmd)) - - s.Require().Contains(fmt.Sprint(cmd), "classes [] [] query all NFT classes") - s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) - - _, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.flagArgs) - s.Require().NoError(err) - }) - } -} - -func (s *CLITestSuite) TestQueryNFT() { - testCases := []struct { - name string - args []string - expCmdOutput string - }{ - { - name: "json output", - args: []string{testClassID, testID, fmt.Sprintf("--%s=json", flags.FlagOutput)}, - expCmdOutput: `[kitty kitty1 --output=json]`, - }, - { - name: "text output", - args: []string{testClassID, testID, fmt.Sprintf("--%s=text", flags.FlagOutput)}, - expCmdOutput: `[kitty kitty1 --output=text]`, - }, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - cmd := cli.GetCmdQueryNFT() - - ctx := svrcmd.CreateExecuteContext(context.Background()) - - cmd.SetOut(io.Discard) - s.Require().NotNil(cmd) - - cmd.SetContext(ctx) - cmd.SetArgs(tc.args) - s.Require().NoError(client.SetCmdClientContextHandler(s.baseCtx, cmd)) - - s.Require().Contains(fmt.Sprint(cmd), "nft [class-id] [nft-id] [] [] query an NFT based on its class and id") - s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) - - _, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args) - s.Require().NoError(err) - }) - } -} - -func (s *CLITestSuite) TestQueryNFTs() { - accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) - - testCases := []struct { - name string - args struct { - ClassID string - Owner string - } - expectErr bool - expErrMsg string - }{ - { - name: "empty class id and owner", - args: struct { - ClassID string - Owner string - }{}, - expectErr: true, - expErrMsg: "must provide at least one of classID or owner", - }, - { - name: "valid case", - args: struct { - ClassID string - Owner string - }{ - ClassID: testClassID, - Owner: accounts[0].Address.String(), - }, - expectErr: false, - }, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - cmd := cli.GetCmdQueryNFTs(address.NewBech32Codec("cosmos")) - var args []string - args = append(args, fmt.Sprintf("--%s=%s", cli.FlagClassID, tc.args.ClassID)) - args = append(args, fmt.Sprintf("--%s=%s", cli.FlagOwner, tc.args.Owner)) - args = append(args, fmt.Sprintf("--%s=json", flags.FlagOutput)) - - out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, args) - if tc.expectErr { - s.Require().Error(err) - s.Require().Contains(err.Error(), tc.expErrMsg) - } else { - s.Require().NoError(err) - var result nft.QueryNFTsResponse - err = s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), &result) - s.Require().NoError(err) - } - }) - } -} - -func (s *CLITestSuite) TestQueryOwner() { - testCases := []struct { - name string - args []string - expCmdOutput string - }{ - { - name: "json output", - args: []string{testClassID, testID, fmt.Sprintf("--%s=json", flags.FlagOutput)}, - expCmdOutput: `[kitty kitty1 --output=json]`, - }, - { - name: "text output", - args: []string{testClassID, testID, fmt.Sprintf("--%s=text", flags.FlagOutput)}, - expCmdOutput: `[kitty kitty1 --output=text]`, - }, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - cmd := cli.GetCmdQueryOwner() - - ctx := svrcmd.CreateExecuteContext(context.Background()) - - cmd.SetOut(io.Discard) - s.Require().NotNil(cmd) - - cmd.SetContext(ctx) - cmd.SetArgs(tc.args) - s.Require().NoError(client.SetCmdClientContextHandler(s.baseCtx, cmd)) - - s.Require().Contains(fmt.Sprint(cmd), "owner [class-id] [nft-id] [] [] query the owner of the NFT based on its class and id") - s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) - - _, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args) - s.Require().NoError(err) - }) - } -} - -func (s *CLITestSuite) TestQueryBalance() { - accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) - - testCases := []struct { - name string - args []string - expCmdOutput string - }{ - { - name: "json output", - args: []string{accounts[0].Address.String(), testClassID, fmt.Sprintf("--%s=json", flags.FlagOutput)}, - expCmdOutput: fmt.Sprintf("%s kitty --output=json", accounts[0].Address.String()), - }, - { - name: "text output", - args: []string{accounts[0].Address.String(), testClassID, fmt.Sprintf("--%s=text", flags.FlagOutput)}, - expCmdOutput: fmt.Sprintf("%s kitty --output=text", accounts[0].Address.String()), - }, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - cmd := cli.GetCmdQueryBalance() - - ctx := svrcmd.CreateExecuteContext(context.Background()) - - cmd.SetOut(io.Discard) - s.Require().NotNil(cmd) - - cmd.SetContext(ctx) - cmd.SetArgs(tc.args) - s.Require().NoError(client.SetCmdClientContextHandler(s.baseCtx, cmd)) - - s.Require().Contains(fmt.Sprint(cmd), "balance [owner] [class-id] [] [] query the number of NFTs of a given class owned by the owner") - s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) - - _, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args) - s.Require().NoError(err) - }) - } -} - -func (s *CLITestSuite) TestQuerySupply() { - testCases := []struct { - name string - args []string - expCmdOutput string - }{ - { - name: "valid case", - args: []string{testClassID, fmt.Sprintf("--%s=json", flags.FlagOutput)}, - expCmdOutput: `[kitty --output=json]`, - }, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - cmd := cli.GetCmdQuerySupply() - - ctx := svrcmd.CreateExecuteContext(context.Background()) - - cmd.SetOut(io.Discard) - s.Require().NotNil(cmd) - - cmd.SetContext(ctx) - cmd.SetArgs(tc.args) - s.Require().NoError(client.SetCmdClientContextHandler(s.baseCtx, cmd)) - - s.Require().Contains(fmt.Sprint(cmd), "supply [class-id] [] [] query the number of nft based on the class") - s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) - - _, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args) - s.Require().NoError(err) - }) - } -} diff --git a/x/nft/module/autocli.go b/x/nft/module/autocli.go new file mode 100644 index 000000000000..3dec1af45eb5 --- /dev/null +++ b/x/nft/module/autocli.go @@ -0,0 +1,87 @@ +package module + +import ( + "fmt" + + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" + nftv1beta1 "cosmossdk.io/api/cosmos/nft/v1beta1" + "cosmossdk.io/x/nft" + "github.com/cosmos/cosmos-sdk/version" +) + +// AutoCLIOptions implements the autocli.HasAutoCLIConfig interface. +func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { + return &autocliv1.ModuleOptions{ + Query: &autocliv1.ServiceCommandDescriptor{ + Service: nftv1beta1.Query_ServiceDesc.ServiceName, + RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + { + RpcMethod: "Balance", + Use: "balance [owner] [class-id]", + Short: "Query the number of NFTs of a given class owned by the owner.", + Example: fmt.Sprintf(`%s query %s balance `, version.AppName, nft.ModuleName), + PositionalArgs: []*autocliv1.PositionalArgDescriptor{ + {ProtoField: "owner"}, + {ProtoField: "class_id"}, + }, + }, + { + RpcMethod: "Owner", + Use: "owner [class-id] [nft-id]", + Short: "Query the owner of the NFT based on its class and id.", + Example: fmt.Sprintf(`%s query %s owner `, version.AppName, nft.ModuleName), + PositionalArgs: []*autocliv1.PositionalArgDescriptor{ + {ProtoField: "class_id"}, + {ProtoField: "id"}, + }, + }, + { + RpcMethod: "Supply", + Use: "supply [class-id]", + Short: "Query the number of nft based on the class.", + Example: fmt.Sprintf(`%s query %s supply `, version.AppName, nft.ModuleName), + PositionalArgs: []*autocliv1.PositionalArgDescriptor{ + {ProtoField: "class_id"}, + }, + }, + { + RpcMethod: "NFTs", + Use: "nfts [class-id]", + Short: "Query all NFTs of a given class or owner address.", + Example: fmt.Sprintf(`%s query %s nfts --owner=`, version.AppName, nft.ModuleName), + PositionalArgs: []*autocliv1.PositionalArgDescriptor{ + {ProtoField: "class_id"}, + }, + }, + { + RpcMethod: "NFT", + Use: "nft [class-id] [nft-id]", + Short: "Query an NFT based on its class and id.", + Example: fmt.Sprintf(`%s query %s nft `, version.AppName, nft.ModuleName), + PositionalArgs: []*autocliv1.PositionalArgDescriptor{ + {ProtoField: "class_id"}, + {ProtoField: "id"}, + }, + }, + { + RpcMethod: "Class", + Use: "class [class-id]", + Short: "Query an NFT class based on its id", + Example: fmt.Sprintf(`%s query %s class `, version.AppName, nft.ModuleName), + PositionalArgs: []*autocliv1.PositionalArgDescriptor{ + {ProtoField: "class_id"}, + }, + }, + { + RpcMethod: "Classes", + Use: "classes", + Short: "Query all NFT classes.", + Example: fmt.Sprintf(`%s query %s classes`, version.AppName, nft.ModuleName), + }, + }, + }, + Tx: &autocliv1.ServiceCommandDescriptor{ + Service: nftv1beta1.Msg_ServiceDesc.ServiceName, + }, + } +} diff --git a/x/nft/module/module.go b/x/nft/module/module.go index 94db19427c17..ae1c0a53ccfc 100644 --- a/x/nft/module/module.go +++ b/x/nft/module/module.go @@ -86,9 +86,10 @@ func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx sdkclient.Context, mux } } -// GetQueryCmd returns the cli query commands for the nft module +// GetQueryCmd returns a no-op command for the nft module. +// Queries for NFT are registered by autocli. func (ab AppModuleBasic) GetQueryCmd() *cobra.Command { - return cli.GetQueryCmd(ab.ac) + return nil } // GetTxCmd returns the transaction commands for the nft module From 0e377d881b51a0d670b3ef4eca340fc252d179db Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 25 Apr 2023 15:19:47 +0200 Subject: [PATCH 2/2] typo --- client/v2/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/v2/README.md b/client/v2/README.md index fcb07f0e2ee1..6ad3c31e9dde 100644 --- a/client/v2/README.md +++ b/client/v2/README.md @@ -1,7 +1,7 @@ # AutoCLI -The `autocli` package is a Go library for generating CLI (command line interface) interfaces for Cosmos SDK-based applications. +The `autocli` package is a Go library for generating CLIs (command line interfaces) for Cosmos SDK-based applications. -Read more about in in the Cosmos SDK documentation: +Read more about in it the Cosmos SDK documentation: -- https://docs.cosmos.network/main/building-modules/autocli \ No newline at end of file +* https://docs.cosmos.network/main/building-modules/autocli \ No newline at end of file