fix(client/v2): resolve keyring flags properly (#19060)

This commit is contained in:
Julien Robert 2024-01-18 20:26:45 +01:00 committed by GitHub
parent 0698a9fb3f
commit 8f39bfb4e4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 124 additions and 115 deletions

View File

@ -1,6 +1,7 @@
package client
import (
"context"
"crypto/tls"
"fmt"
"strings"
@ -278,7 +279,7 @@ func readTxCommandFlags(clientCtx Context, flagSet *pflag.FlagSet) (Context, err
from, _ := flagSet.GetString(flags.FlagFrom)
fromAddr, fromName, keyType, err := GetFromFields(clientCtx, clientCtx.Keyring, from)
if err != nil {
return clientCtx, err
return clientCtx, fmt.Errorf("failed to convert address field to address: %w", err)
}
clientCtx = clientCtx.WithFrom(from).WithFromAddress(fromAddr).WithFromName(fromName)
@ -358,13 +359,6 @@ 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 {
v = &clientCtx
}
clientCtxPtr := v.(*Context)
*clientCtxPtr = clientCtx
cmd.SetContext(context.WithValue(cmd.Context(), ClientContextKey, &clientCtx))
return nil
}

View File

@ -41,7 +41,16 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Features
* [#18461](https://github.com/cosmos/cosmos-sdk/pull/18461) Support governance proposals.
* [#19039](https://github.com/cosmos/cosmos-sdk/pull/19039) add support for pubkey in autocli.
* [#19039](https://github.com/cosmos/cosmos-sdk/pull/19039) Add support for pubkey in autocli.
### Improvements
* [#19060](https://github.com/cosmos/cosmos-sdk/pull/19060) Use client context from root (or enhanced) command in autocli commands.
* Note, the given command must have a `client.Context` in its context.
### Bug Fixes
* [#19060](https://github.com/cosmos/cosmos-sdk/pull/19060) Simplify key flag parsing logic in flag handler.
### API Breaking Changes

View File

@ -71,7 +71,6 @@ func (appOptions AppOptions) EnhanceRootCommand(rootCmd *cobra.Command) error {
ValidatorAddressCodec: appOptions.ClientCtx.ValidatorAddressCodec,
ConsensusAddressCodec: appOptions.ClientCtx.ConsensusAddressCodec,
},
ClientCtx: appOptions.ClientCtx,
TxConfigOpts: appOptions.TxConfigOpts,
GetClientConn: func(cmd *cobra.Command) (grpc.ClientConnInterface, error) {
return client.GetClientQueryContext(cmd)
@ -112,7 +111,7 @@ func (appOptions AppOptions) EnhanceRootCommandWithBuilder(rootCmd *cobra.Comman
return err
}
} else {
queryCmd, err := builder.BuildQueryCommand(appOptions, customQueryCmds)
queryCmd, err := builder.BuildQueryCommand(rootCmd.Context(), appOptions, customQueryCmds)
if err != nil {
return err
}
@ -125,7 +124,7 @@ func (appOptions AppOptions) EnhanceRootCommandWithBuilder(rootCmd *cobra.Comman
return err
}
} else {
subCmd, err := builder.BuildMsgCommand(appOptions, customMsgCmds)
subCmd, err := builder.BuildMsgCommand(rootCmd.Context(), appOptions, customMsgCmds)
if err != nil {
return err
}

View File

@ -6,8 +6,6 @@ import (
"cosmossdk.io/client/v2/autocli/flag"
authtx "cosmossdk.io/x/auth/tx"
"github.com/cosmos/cosmos-sdk/client"
)
// Builder manages options for building CLI commands.
@ -19,9 +17,6 @@ type Builder struct {
// from a given context.
GetClientConn func(*cobra.Command) (grpc.ClientConnInterface, error)
// ClientCtx contains the necessary information needed to execute the commands.
ClientCtx client.Context
// TxConfigOptions is required to support sign mode textual
TxConfigOpts authtx.ConfigOptions

View File

@ -1,7 +1,6 @@
package autocli
import (
"context"
"fmt"
"strings"
@ -57,7 +56,6 @@ func (b *Builder) buildMethodCommandCommon(descriptor protoreflect.MethodDescrip
Version: options.Version,
}
cmd.SetContext(context.Background())
binder, err := b.AddMessageFlags(cmd.Context(), cmd.Flags(), inputType, options)
if err != nil {
return nil, err
@ -179,7 +177,7 @@ func (b *Builder) enhanceCommandCommon(
// 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 {
if queryCmdDesc := modOpts.Query; queryCmdDesc != nil {
subCmd := topLevelCmd(moduleName, fmt.Sprintf("Querying commands for the %s module", moduleName))
subCmd := topLevelCmd(cmd.Context(), moduleName, fmt.Sprintf("Querying commands for the %s module", moduleName))
if err := builder.AddQueryServiceCommands(subCmd, queryCmdDesc); err != nil {
return err
}
@ -193,7 +191,7 @@ func enhanceQuery(builder *Builder, moduleName string, cmd *cobra.Command, modOp
// 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 {
if txCmdDesc := modOpts.Tx; txCmdDesc != nil {
subCmd := topLevelCmd(moduleName, fmt.Sprintf("Transactions commands for the %s module", moduleName))
subCmd := topLevelCmd(cmd.Context(), moduleName, fmt.Sprintf("Transactions commands for the %s module", moduleName))
if err := builder.AddMsgServiceCommands(subCmd, txCmdDesc); err != nil {
return err
}

View File

@ -28,8 +28,9 @@ import (
)
type fixture struct {
conn *testClientConn
b *Builder
conn *testClientConn
b *Builder
clientCtx client.Context
}
func initFixture(t *testing.T) *fixture {
@ -60,8 +61,7 @@ func initFixture(t *testing.T) *fixture {
interfaceRegistry := encodingConfig.Codec.InterfaceRegistry()
banktypes.RegisterInterfaces(interfaceRegistry)
var initClientCtx client.Context
initClientCtx = initClientCtx.
clientCtx := client.Context{}.
WithAddressCodec(addresscodec.NewBech32Codec("cosmos")).
WithValidatorAddressCodec(addresscodec.NewBech32Codec("cosmosvaloper")).
WithConsensusAddressCodec(addresscodec.NewBech32Codec("cosmosvalcons")).
@ -79,9 +79,9 @@ func initFixture(t *testing.T) *fixture {
Builder: flag.Builder{
TypeResolver: protoregistry.GlobalTypes,
FileResolver: protoregistry.GlobalFiles,
AddressCodec: initClientCtx.AddressCodec,
ValidatorAddressCodec: initClientCtx.ValidatorAddressCodec,
ConsensusAddressCodec: initClientCtx.ConsensusAddressCodec,
AddressCodec: clientCtx.AddressCodec,
ValidatorAddressCodec: clientCtx.ValidatorAddressCodec,
ConsensusAddressCodec: clientCtx.ConsensusAddressCodec,
Keyring: akr,
},
GetClientConn: func(*cobra.Command) (grpc.ClientConnInterface, error) {
@ -89,19 +89,19 @@ func initFixture(t *testing.T) *fixture {
},
AddQueryConnFlags: flags.AddQueryFlagsToCmd,
AddTxConnFlags: flags.AddTxFlagsToCmd,
ClientCtx: initClientCtx,
}
assert.NilError(t, b.ValidateAndComplete())
return &fixture{
conn: conn,
b: b,
conn: conn,
b: b,
clientCtx: clientCtx,
}
}
func runCmd(conn *testClientConn, b *Builder, command func(moduleName string, b *Builder) (*cobra.Command, error), args ...string) (*bytes.Buffer, error) {
func runCmd(fixture *fixture, command func(moduleName string, f *fixture) (*cobra.Command, error), args ...string) (*bytes.Buffer, error) {
out := &bytes.Buffer{}
cmd, err := command("test", b)
cmd, err := command("test", fixture)
if err != nil {
return out, err
}
@ -215,14 +215,13 @@ func TestErrorBuildCommand(t *testing.T) {
Tx: commandDescriptor,
},
},
ClientCtx: b.ClientCtx,
}
_, err := b.BuildMsgCommand(appOptions, nil)
_, err := b.BuildMsgCommand(context.Background(), appOptions, nil)
assert.ErrorContains(t, err, "can't find field un-existent-proto-field")
appOptions.ModuleOptions["test"].Tx = &autocliv1.ServiceCommandDescriptor{Service: "un-existent-service"}
appOptions.ModuleOptions["test"].Query = &autocliv1.ServiceCommandDescriptor{Service: "un-existent-service"}
_, err = b.BuildMsgCommand(appOptions, nil)
_, err = b.BuildMsgCommand(context.Background(), appOptions, nil)
assert.ErrorContains(t, err, "can't find service un-existent-service")
}

View File

@ -62,11 +62,9 @@ func (a *addressValue) Set(s string) error {
return nil
}
_, err = a.addressCodec.StringToBytes(s)
if err != nil {
return fmt.Errorf("invalid account address or key name: %w", err)
}
// failed all validation, just accept the input.
// TODO(@julienrbrt), for final client/v2 2.0.0 revert the logic and
// do a better keyring instantiation.
a.value = s
return nil
@ -129,7 +127,11 @@ func (a *consensusAddressValue) Set(s string) error {
var pk cryptotypes.PubKey
err2 := cdc.UnmarshalInterfaceJSON([]byte(s), &pk)
if err2 != nil {
return fmt.Errorf("input isn't a pubkey %w or is an invalid account address: %w", err, err2)
// failed all validation, just accept the input.
// TODO(@julienrbrt), for final client/v2 2.0.0 revert the logic and
// do a better keyring instantiation.
a.value = s
return nil
}
a.value, err = a.addressCodec.BytesToString(pk.Address())

View File

@ -34,8 +34,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(appOptions AppOptions, customCmds map[string]*cobra.Command) (*cobra.Command, error) {
msgCmd := topLevelCmd("tx", "Transaction subcommands")
func (b *Builder) BuildMsgCommand(ctx context.Context, appOptions AppOptions, customCmds map[string]*cobra.Command) (*cobra.Command, error) {
msgCmd := topLevelCmd(ctx, "tx", "Transaction subcommands")
if err := b.enhanceCommandCommon(msgCmd, msgCmdType, appOptions, customCmds); err != nil {
return nil, err
}
@ -50,7 +51,7 @@ func (b *Builder) AddMsgServiceCommands(cmd *cobra.Command, cmdDescriptor *autoc
for cmdName, subCmdDescriptor := range cmdDescriptor.SubCommands {
subCmd := findSubCommand(cmd, cmdName)
if subCmd == nil {
subCmd = topLevelCmd(cmdName, fmt.Sprintf("Tx commands for the %s service", subCmdDescriptor.Service))
subCmd = topLevelCmd(cmd.Context(), cmdName, fmt.Sprintf("Tx commands for the %s service", subCmdDescriptor.Service))
}
// Add recursive sub-commands if there are any. This is used for nested services.
@ -121,8 +122,6 @@ func (b *Builder) AddMsgServiceCommands(cmd *cobra.Command, cmdDescriptor *autoc
// 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) {
execFunc := func(cmd *cobra.Command, input protoreflect.Message) error {
cmd.SetContext(context.WithValue(context.Background(), client.ClientContextKey, &b.ClientCtx))
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err

View File

@ -1,6 +1,7 @@
package autocli
import (
"context"
"fmt"
"testing"
@ -11,18 +12,22 @@ import (
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1"
"cosmossdk.io/client/v2/internal/testpb"
"github.com/cosmos/cosmos-sdk/client"
)
var buildModuleMsgCommand = func(moduleName string, b *Builder) (*cobra.Command, error) {
cmd := topLevelCmd(moduleName, fmt.Sprintf("Transactions commands for the %s module", moduleName))
err := b.AddMsgServiceCommands(cmd, bankAutoCLI)
var buildModuleMsgCommand = func(moduleName string, f *fixture) (*cobra.Command, error) {
ctx := context.WithValue(context.Background(), client.ClientContextKey, &f.clientCtx)
cmd := topLevelCmd(ctx, moduleName, fmt.Sprintf("Transactions commands for the %s module", moduleName))
err := f.b.AddMsgServiceCommands(cmd, bankAutoCLI)
return cmd, err
}
func buildCustomModuleMsgCommand(cmdDescriptor *autocliv1.ServiceCommandDescriptor) func(moduleName string, b *Builder) (*cobra.Command, error) {
return func(moduleName string, b *Builder) (*cobra.Command, error) {
cmd := topLevelCmd(moduleName, fmt.Sprintf("Transactions commands for the %s module", moduleName))
err := b.AddMsgServiceCommands(cmd, cmdDescriptor)
func buildCustomModuleMsgCommand(cmdDescriptor *autocliv1.ServiceCommandDescriptor) func(moduleName string, f *fixture) (*cobra.Command, error) {
return func(moduleName string, f *fixture) (*cobra.Command, error) {
ctx := context.WithValue(context.Background(), client.ClientContextKey, &f.clientCtx)
cmd := topLevelCmd(ctx, moduleName, fmt.Sprintf("Transactions commands for the %s module", moduleName))
err := f.b.AddMsgServiceCommands(cmd, cmdDescriptor)
return cmd, err
}
}
@ -42,7 +47,7 @@ var bankAutoCLI = &autocliv1.ServiceCommandDescriptor{
func TestMsg(t *testing.T) {
fixture := initFixture(t)
out, err := runCmd(fixture.conn, fixture.b, buildModuleMsgCommand, "send",
out, err := runCmd(fixture, buildModuleMsgCommand, "send",
"cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk", "cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk", "1foo",
"--generate-only",
"--output", "json",
@ -50,7 +55,7 @@ func TestMsg(t *testing.T) {
assert.NilError(t, err)
golden.Assert(t, out.String(), "msg-output.golden")
out, err = runCmd(fixture.conn, fixture.b, buildCustomModuleMsgCommand(&autocliv1.ServiceCommandDescriptor{
out, err = runCmd(fixture, buildCustomModuleMsgCommand(&autocliv1.ServiceCommandDescriptor{
Service: bankv1beta1.Msg_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
@ -71,7 +76,7 @@ func TestMsg(t *testing.T) {
assert.NilError(t, err)
golden.Assert(t, out.String(), "msg-output.golden")
out, err = runCmd(fixture.conn, fixture.b, buildCustomModuleMsgCommand(&autocliv1.ServiceCommandDescriptor{
out, err = runCmd(fixture, buildCustomModuleMsgCommand(&autocliv1.ServiceCommandDescriptor{
Service: bankv1beta1.Msg_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
@ -98,12 +103,12 @@ func TestMsg(t *testing.T) {
func TestMsgOptionsError(t *testing.T) {
fixture := initFixture(t)
_, err := runCmd(fixture.conn, fixture.b, buildModuleMsgCommand,
_, err := runCmd(fixture, buildModuleMsgCommand,
"send", "5",
)
assert.ErrorContains(t, err, "accepts 3 arg(s)")
_, err = runCmd(fixture.conn, fixture.b, buildModuleMsgCommand,
_, err = runCmd(fixture, buildModuleMsgCommand,
"send", "foo", "bar", "invalid",
)
assert.ErrorContains(t, err, "invalid argument")
@ -112,11 +117,11 @@ func TestMsgOptionsError(t *testing.T) {
func TestHelpMsg(t *testing.T) {
fixture := initFixture(t)
out, err := runCmd(fixture.conn, fixture.b, buildModuleMsgCommand, "-h")
out, err := runCmd(fixture, buildModuleMsgCommand, "-h")
assert.NilError(t, err)
golden.Assert(t, out.String(), "help-toplevel-msg.golden")
out, err = runCmd(fixture.conn, fixture.b, buildModuleMsgCommand, "send", "-h")
out, err = runCmd(fixture, buildModuleMsgCommand, "send", "-h")
assert.NilError(t, err)
golden.Assert(t, out.String(), "help-echo-msg.golden")
}
@ -135,7 +140,7 @@ func TestBuildCustomMsgCommand(t *testing.T) {
},
}
cmd, err := b.BuildMsgCommand(appOptions, map[string]*cobra.Command{
cmd, err := b.BuildMsgCommand(context.Background(), appOptions, map[string]*cobra.Command{
"test": {Use: "test", Run: func(cmd *cobra.Command, args []string) {
customCommandCalled = true
}},
@ -153,7 +158,7 @@ func TestNotFoundErrorsMsg(t *testing.T) {
b.AddTxConnFlags = nil
buildModuleMsgCommand := func(moduleName string, cmdDescriptor *autocliv1.ServiceCommandDescriptor) (*cobra.Command, error) {
cmd := topLevelCmd(moduleName, fmt.Sprintf("Transactions commands for the %s module", moduleName))
cmd := topLevelCmd(context.Background(), moduleName, fmt.Sprintf("Transactions commands for the %s module", moduleName))
err := b.AddMsgServiceCommands(cmd, cmdDescriptor)
return cmd, err

View File

@ -9,7 +9,6 @@ import (
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
"cosmossdk.io/x/tx/signing/aminojson"
"github.com/cockroachdb/errors"
"github.com/cosmos/cosmos-sdk/client"
"github.com/spf13/cobra"
"google.golang.org/protobuf/reflect/protoreflect"
@ -20,8 +19,8 @@ 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(appOptions AppOptions, customCmds map[string]*cobra.Command) (*cobra.Command, error) {
queryCmd := topLevelCmd("query", "Querying subcommands")
func (b *Builder) BuildQueryCommand(ctx context.Context, appOptions AppOptions, customCmds map[string]*cobra.Command) (*cobra.Command, error) {
queryCmd := topLevelCmd(ctx, "query", "Querying subcommands")
queryCmd.Aliases = []string{"q"}
if err := b.enhanceCommandCommon(queryCmd, queryCmdType, appOptions, customCmds); err != nil {
@ -38,7 +37,7 @@ func (b *Builder) AddQueryServiceCommands(cmd *cobra.Command, cmdDescriptor *aut
for cmdName, subCmdDesc := range cmdDescriptor.SubCommands {
subCmd := findSubCommand(cmd, cmdName)
if subCmd == nil {
subCmd = topLevelCmd(cmdName, fmt.Sprintf("Querying commands for the %s service", subCmdDesc.Service))
subCmd = topLevelCmd(cmd.Context(), cmdName, fmt.Sprintf("Querying commands for the %s service", subCmdDesc.Service))
}
if err := b.AddQueryServiceCommands(subCmd, subCmdDesc); err != nil {
@ -86,7 +85,7 @@ func (b *Builder) AddQueryServiceCommands(cmd *cobra.Command, cmdDescriptor *aut
continue
}
methodCmd, err := b.BuildQueryMethodCommand(methodDescriptor, methodOpts)
methodCmd, err := b.BuildQueryMethodCommand(cmd.Context(), methodDescriptor, methodOpts)
if err != nil {
return err
}
@ -105,7 +104,7 @@ func (b *Builder) AddQueryServiceCommands(cmd *cobra.Command, cmdDescriptor *aut
// BuildQueryMethodCommand creates a gRPC query command for the given service method. This can be used to auto-generate
// just a single command for a single service rpc method.
func (b *Builder) BuildQueryMethodCommand(descriptor protoreflect.MethodDescriptor, options *autocliv1.RpcCommandOptions) (*cobra.Command, error) {
func (b *Builder) BuildQueryMethodCommand(ctx context.Context, descriptor protoreflect.MethodDescriptor, options *autocliv1.RpcCommandOptions) (*cobra.Command, error) {
getClientConn := b.GetClientConn
serviceDescriptor := descriptor.Parent().(protoreflect.ServiceDescriptor)
methodName := fmt.Sprintf("/%s/%s", serviceDescriptor.FullName(), descriptor.Name())
@ -118,8 +117,6 @@ func (b *Builder) BuildQueryMethodCommand(descriptor protoreflect.MethodDescript
}
cmd, err := b.buildMethodCommandCommon(descriptor, options, func(cmd *cobra.Command, input protoreflect.Message) error {
cmd.SetContext(context.WithValue(context.Background(), client.ClientContextKey, &b.ClientCtx))
clientConn, err := getClientConn(cmd)
if err != nil {
return err

View File

@ -1,6 +1,7 @@
package autocli
import (
"context"
"fmt"
"os"
"strings"
@ -18,26 +19,31 @@ import (
queryv1beta1 "cosmossdk.io/api/cosmos/base/query/v1beta1"
basev1beta1 "cosmossdk.io/api/cosmos/base/v1beta1"
"cosmossdk.io/client/v2/internal/testpb"
"github.com/cosmos/cosmos-sdk/client"
)
var buildModuleQueryCommand = func(moduleName string, b *Builder) (*cobra.Command, error) {
cmd := topLevelCmd(moduleName, fmt.Sprintf("Querying commands for the %s module", moduleName))
var buildModuleQueryCommand = func(moduleName string, f *fixture) (*cobra.Command, error) {
ctx := context.WithValue(context.Background(), client.ClientContextKey, &f.clientCtx)
cmd := topLevelCmd(ctx, moduleName, fmt.Sprintf("Querying commands for the %s module", moduleName))
err := b.AddQueryServiceCommands(cmd, testCmdDesc)
err := f.b.AddQueryServiceCommands(cmd, testCmdDesc)
return cmd, err
}
var buildModuleQueryCommandOptional = func(moduleName string, b *Builder) (*cobra.Command, error) {
cmd := topLevelCmd(moduleName, fmt.Sprintf("Querying commands for the %s module", moduleName))
var buildModuleQueryCommandOptional = func(moduleName string, f *fixture) (*cobra.Command, error) {
ctx := context.WithValue(context.Background(), client.ClientContextKey, &f.clientCtx)
cmd := topLevelCmd(ctx, moduleName, fmt.Sprintf("Querying commands for the %s module", moduleName))
err := b.AddQueryServiceCommands(cmd, testCmdDescOptional)
err := f.b.AddQueryServiceCommands(cmd, testCmdDescOptional)
return cmd, err
}
var buildModuleVargasOptional = func(moduleName string, b *Builder) (*cobra.Command, error) {
cmd := topLevelCmd(moduleName, fmt.Sprintf("Querying commands for the %s module", moduleName))
var buildModuleVargasOptional = func(moduleName string, f *fixture) (*cobra.Command, error) {
ctx := context.WithValue(context.Background(), client.ClientContextKey, &f.clientCtx)
cmd := topLevelCmd(ctx, moduleName, fmt.Sprintf("Querying commands for the %s module", moduleName))
err := b.AddQueryServiceCommands(cmd, testCmdDescInvalidOptAndVargas)
err := f.b.AddQueryServiceCommands(cmd, testCmdDescInvalidOptAndVargas)
return cmd, err
}
@ -190,7 +196,7 @@ var testCmdDescInvalidOptAndVargas = &autocliv1.ServiceCommandDescriptor{
func TestCoin(t *testing.T) {
fixture := initFixture(t)
_, err := runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
_, err := runCmd(fixture, buildModuleQueryCommand,
"echo",
"1",
"abc",
@ -200,7 +206,7 @@ func TestCoin(t *testing.T) {
)
assert.ErrorContains(t, err, "coin flag must be a single coin, specific multiple coins with multiple flags or spaces")
_, err = runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
_, err = runCmd(fixture, buildModuleQueryCommand,
"echo",
"1",
"abc",
@ -241,7 +247,7 @@ func TestCoin(t *testing.T) {
func TestOptional(t *testing.T) {
fixture := initFixture(t)
_, err := runCmd(fixture.conn, fixture.b, buildModuleQueryCommandOptional,
_, err := runCmd(fixture, buildModuleQueryCommandOptional,
"echo",
"1",
"abc",
@ -251,7 +257,7 @@ func TestOptional(t *testing.T) {
assert.Equal(t, request.Positional2, "abc")
assert.DeepEqual(t, fixture.conn.lastRequest, fixture.conn.lastResponse.(*testpb.EchoResponse).Request, protocmp.Transform())
_, err = runCmd(fixture.conn, fixture.b, buildModuleQueryCommandOptional,
_, err = runCmd(fixture, buildModuleQueryCommandOptional,
"echo",
"1",
)
@ -261,7 +267,7 @@ func TestOptional(t *testing.T) {
assert.Equal(t, request.Positional2, "")
assert.DeepEqual(t, fixture.conn.lastRequest, fixture.conn.lastResponse.(*testpb.EchoResponse).Request, protocmp.Transform())
_, err = runCmd(fixture.conn, fixture.b, buildModuleQueryCommandOptional,
_, err = runCmd(fixture, buildModuleQueryCommandOptional,
"echo",
"1",
"abc",
@ -269,7 +275,7 @@ func TestOptional(t *testing.T) {
)
assert.ErrorContains(t, err, "accepts between 1 and 2 arg(s), received 3")
_, err = runCmd(fixture.conn, fixture.b, buildModuleVargasOptional,
_, err = runCmd(fixture, buildModuleVargasOptional,
"echo",
"1",
"abc",
@ -281,7 +287,7 @@ func TestOptional(t *testing.T) {
func TestMap(t *testing.T) {
fixture := initFixture(t)
_, err := runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
_, err := runCmd(fixture, buildModuleQueryCommand,
"echo",
"1",
"abc",
@ -296,7 +302,7 @@ func TestMap(t *testing.T) {
assert.NilError(t, err)
assert.DeepEqual(t, fixture.conn.lastRequest, fixture.conn.lastResponse.(*testpb.EchoResponse).Request, protocmp.Transform())
_, err = runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
_, err = runCmd(fixture, buildModuleQueryCommand,
"echo",
"1",
"abc",
@ -308,7 +314,7 @@ func TestMap(t *testing.T) {
)
assert.ErrorContains(t, err, "invalid argument \"baz,100000foo\" for \"--map-string-coin\" flag: invalid format, expected key=value")
_, err = runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
_, err = runCmd(fixture, buildModuleQueryCommand,
"echo",
"1",
"abc",
@ -320,7 +326,7 @@ func TestMap(t *testing.T) {
)
assert.ErrorContains(t, err, "invalid argument \"bar=not-unint32\" for \"--map-string-uint32\" flag: strconv.ParseUint: parsing \"not-unint32\": invalid syntax")
_, err = runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
_, err = runCmd(fixture, buildModuleQueryCommand,
"echo",
"1",
"abc",
@ -338,7 +344,7 @@ func TestMap(t *testing.T) {
func TestEverything(t *testing.T) {
fixture := initFixture(t)
_, err := runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
_, err := runCmd(fixture, buildModuleQueryCommand,
"echo",
"1",
"abc",
@ -450,7 +456,7 @@ func TestEverything(t *testing.T) {
func TestPubKeyParsingConsensusAddress(t *testing.T) {
fixture := initFixture(t)
_, err := runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
_, err := runCmd(fixture, buildModuleQueryCommand,
"echo",
"1", "abc", "1foo",
"--a-consensus-address", "{\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"j8qdbR+AlH/V6aBTCSWXRvX3JUESF2bV+SEzndBhF0o=\"}",
@ -463,7 +469,7 @@ func TestPubKeyParsingConsensusAddress(t *testing.T) {
func TestJSONParsing(t *testing.T) {
fixture := initFixture(t)
_, err := runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
_, err := runCmd(fixture, buildModuleQueryCommand,
"echo",
"1", "abc", "1foo",
"--some-messages", `{"bar":"baz"}`,
@ -472,7 +478,7 @@ func TestJSONParsing(t *testing.T) {
assert.NilError(t, err)
assert.DeepEqual(t, fixture.conn.lastRequest, fixture.conn.lastResponse.(*testpb.EchoResponse).Request, protocmp.Transform())
_, err = runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
_, err = runCmd(fixture, buildModuleQueryCommand,
"echo",
"1", "abc", "1foo",
"--some-messages", "testdata/some_message.json",
@ -485,7 +491,7 @@ func TestJSONParsing(t *testing.T) {
func TestOptions(t *testing.T) {
fixture := initFixture(t)
_, err := runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
_, err := runCmd(fixture, buildModuleQueryCommand,
"echo",
"1", "abc", "123foo",
"-u", "27", // shorthand
@ -552,7 +558,7 @@ func TestBinaryFlag(t *testing.T) {
fixture := initFixture(t)
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
_, err := runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
_, err := runCmd(fixture, buildModuleQueryCommand,
"echo",
"1", "abc", `100foo`,
"--bz", tc.input,
@ -569,23 +575,25 @@ func TestBinaryFlag(t *testing.T) {
}
func TestAddressValidation(t *testing.T) {
t.Skip() // TODO(@julienrbrt) re-able with better keyring instiantiation
fixture := initFixture(t)
_, err := runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
_, err := runCmd(fixture, buildModuleQueryCommand,
"echo",
"1", "abc", "1foo",
"--an-address", "cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk",
)
assert.NilError(t, err)
_, err = runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
_, err = runCmd(fixture, buildModuleQueryCommand,
"echo",
"1", "abc", "1foo",
"--an-address", "regen1y74p8wyy4enfhfn342njve6cjmj5c8dtlqj7ule2",
)
assert.ErrorContains(t, err, "invalid account address")
_, err = runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
_, err = runCmd(fixture, buildModuleQueryCommand,
"echo",
"1", "abc", "1foo",
"--an-address", "cosmps1BAD_ENCODING",
@ -596,7 +604,7 @@ func TestAddressValidation(t *testing.T) {
func TestOutputFormat(t *testing.T) {
fixture := initFixture(t)
out, err := runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
out, err := runCmd(fixture, buildModuleQueryCommand,
"echo",
"1", "abc", "1foo",
"--output", "json",
@ -604,7 +612,7 @@ func TestOutputFormat(t *testing.T) {
assert.NilError(t, err)
assert.Assert(t, strings.Contains(out.String(), "{"))
out, err = runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
out, err = runCmd(fixture, buildModuleQueryCommand,
"echo",
"1", "abc", "1foo",
"--output", "text",
@ -616,19 +624,19 @@ func TestOutputFormat(t *testing.T) {
func TestHelpQuery(t *testing.T) {
fixture := initFixture(t)
out, err := runCmd(fixture.conn, fixture.b, buildModuleQueryCommand, "-h")
out, err := runCmd(fixture, buildModuleQueryCommand, "-h")
assert.NilError(t, err)
golden.Assert(t, out.String(), "help-toplevel.golden")
out, err = runCmd(fixture.conn, fixture.b, buildModuleQueryCommand, "echo", "-h")
out, err = runCmd(fixture, buildModuleQueryCommand, "echo", "-h")
assert.NilError(t, err)
golden.Assert(t, out.String(), "help-echo.golden")
out, err = runCmd(fixture.conn, fixture.b, buildModuleQueryCommand, "deprecatedecho", "echo", "-h")
out, err = runCmd(fixture, buildModuleQueryCommand, "deprecatedecho", "echo", "-h")
assert.NilError(t, err)
golden.Assert(t, out.String(), "help-deprecated.golden")
out, err = runCmd(fixture.conn, fixture.b, buildModuleQueryCommand, "skipecho", "-h")
out, err = runCmd(fixture, buildModuleQueryCommand, "skipecho", "-h")
assert.NilError(t, err)
golden.Assert(t, out.String(), "help-skip.golden")
}
@ -636,12 +644,12 @@ func TestHelpQuery(t *testing.T) {
func TestDeprecatedQuery(t *testing.T) {
fixture := initFixture(t)
out, err := runCmd(fixture.conn, fixture.b, buildModuleQueryCommand, "echo",
out, err := runCmd(fixture, buildModuleQueryCommand, "echo",
"1", "abc", "--deprecated-field", "foo")
assert.NilError(t, err)
assert.Assert(t, strings.Contains(out.String(), "--deprecated-field has been deprecated"))
out, err = runCmd(fixture.conn, fixture.b, buildModuleQueryCommand, "echo",
out, err = runCmd(fixture, buildModuleQueryCommand, "echo",
"1", "abc", "-s", "foo")
assert.NilError(t, err)
assert.Assert(t, strings.Contains(out.String(), "--shorthand-deprecated-field has been deprecated"))
@ -659,7 +667,7 @@ func TestBuildCustomQueryCommand(t *testing.T) {
},
}
cmd, err := b.BuildQueryCommand(appOptions, map[string]*cobra.Command{
cmd, err := b.BuildQueryCommand(context.Background(), appOptions, map[string]*cobra.Command{
"test": {Use: "test", Run: func(cmd *cobra.Command, args []string) {
customCommandCalled = true
}},
@ -677,7 +685,7 @@ func TestNotFoundErrorsQuery(t *testing.T) {
b.AddTxConnFlags = nil
buildModuleQueryCommand := func(moduleName string, cmdDescriptor *autocliv1.ServiceCommandDescriptor) (*cobra.Command, error) {
cmd := topLevelCmd("query", "Querying subcommands")
cmd := topLevelCmd(context.Background(), "query", "Querying subcommands")
err := b.AddMsgServiceCommands(cmd, cmdDescriptor)
return cmd, err
}
@ -727,7 +735,7 @@ func TestNotFoundErrorsQuery(t *testing.T) {
func TestDurationMarshal(t *testing.T) {
fixture := initFixture(t)
out, err := runCmd(fixture.conn, fixture.b, buildModuleQueryCommand, "echo", "1", "abc", "--duration", "1s")
out, err := runCmd(fixture, buildModuleQueryCommand, "echo", "1", "abc", "--duration", "1s")
assert.NilError(t, err)
assert.Assert(t, strings.Contains(out.String(), "duration: 1s"))
}

View File

@ -1,6 +1,7 @@
package autocli
import (
"context"
"strings"
"github.com/spf13/cobra"
@ -31,14 +32,17 @@ func findSubCommand(cmd *cobra.Command, subCmdName string) *cobra.Command {
// topLevelCmd creates a new top-level command with the provided name and
// description. The command will have DisableFlagParsing set to false and
// SuggestionsMinimumDistance set to 2.
func topLevelCmd(use, short string) *cobra.Command {
return &cobra.Command{
func topLevelCmd(ctx context.Context, use, short string) *cobra.Command {
cmd := &cobra.Command{
Use: use,
Short: short,
DisableFlagParsing: false,
SuggestionsMinimumDistance: 2,
RunE: validateCmd,
}
cmd.SetContext(ctx)
return cmd
}
func protoNameToCliName(name protoreflect.Name) string {

View File

@ -9,8 +9,8 @@ $SIMD_BIN config set client chain-id demo
$SIMD_BIN config set client keyring-backend test
$SIMD_BIN config set client keyring-default-keyname alice
$SIMD_BIN config set app api.enable true
$SIMD_BIN keys add alice
$SIMD_BIN keys add bob
$SIMD_BIN keys add alice --indiscreet
$SIMD_BIN keys add bob --indiscreet
$SIMD_BIN init test --chain-id demo
$SIMD_BIN genesis add-genesis-account alice 5000000000stake --keyring-backend test
$SIMD_BIN genesis add-genesis-account bob 5000000000stake --keyring-backend test