diff --git a/api/cosmos/autocli/v1/options.pulsar.go b/api/cosmos/autocli/v1/options.pulsar.go index a97a51701f..1742c5fcae 100644 --- a/api/cosmos/autocli/v1/options.pulsar.go +++ b/api/cosmos/autocli/v1/options.pulsar.go @@ -3779,6 +3779,7 @@ var ( md_PositionalArgDescriptor protoreflect.MessageDescriptor fd_PositionalArgDescriptor_proto_field protoreflect.FieldDescriptor fd_PositionalArgDescriptor_varargs protoreflect.FieldDescriptor + fd_PositionalArgDescriptor_optional protoreflect.FieldDescriptor ) func init() { @@ -3786,6 +3787,7 @@ func init() { md_PositionalArgDescriptor = File_cosmos_autocli_v1_options_proto.Messages().ByName("PositionalArgDescriptor") fd_PositionalArgDescriptor_proto_field = md_PositionalArgDescriptor.Fields().ByName("proto_field") fd_PositionalArgDescriptor_varargs = md_PositionalArgDescriptor.Fields().ByName("varargs") + fd_PositionalArgDescriptor_optional = md_PositionalArgDescriptor.Fields().ByName("optional") } var _ protoreflect.Message = (*fastReflection_PositionalArgDescriptor)(nil) @@ -3865,6 +3867,12 @@ func (x *fastReflection_PositionalArgDescriptor) Range(f func(protoreflect.Field return } } + if x.Optional != false { + value := protoreflect.ValueOfBool(x.Optional) + if !f(fd_PositionalArgDescriptor_optional, value) { + return + } + } } // Has reports whether a field is populated. @@ -3884,6 +3892,8 @@ func (x *fastReflection_PositionalArgDescriptor) Has(fd protoreflect.FieldDescri return x.ProtoField != "" case "cosmos.autocli.v1.PositionalArgDescriptor.varargs": return x.Varargs != false + case "cosmos.autocli.v1.PositionalArgDescriptor.optional": + return x.Optional != false default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.autocli.v1.PositionalArgDescriptor")) @@ -3904,6 +3914,8 @@ func (x *fastReflection_PositionalArgDescriptor) Clear(fd protoreflect.FieldDesc x.ProtoField = "" case "cosmos.autocli.v1.PositionalArgDescriptor.varargs": x.Varargs = false + case "cosmos.autocli.v1.PositionalArgDescriptor.optional": + x.Optional = false default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.autocli.v1.PositionalArgDescriptor")) @@ -3926,6 +3938,9 @@ func (x *fastReflection_PositionalArgDescriptor) Get(descriptor protoreflect.Fie case "cosmos.autocli.v1.PositionalArgDescriptor.varargs": value := x.Varargs return protoreflect.ValueOfBool(value) + case "cosmos.autocli.v1.PositionalArgDescriptor.optional": + value := x.Optional + return protoreflect.ValueOfBool(value) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.autocli.v1.PositionalArgDescriptor")) @@ -3950,6 +3965,8 @@ func (x *fastReflection_PositionalArgDescriptor) Set(fd protoreflect.FieldDescri x.ProtoField = value.Interface().(string) case "cosmos.autocli.v1.PositionalArgDescriptor.varargs": x.Varargs = value.Bool() + case "cosmos.autocli.v1.PositionalArgDescriptor.optional": + x.Optional = value.Bool() default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.autocli.v1.PositionalArgDescriptor")) @@ -3974,6 +3991,8 @@ func (x *fastReflection_PositionalArgDescriptor) Mutable(fd protoreflect.FieldDe panic(fmt.Errorf("field proto_field of message cosmos.autocli.v1.PositionalArgDescriptor is not mutable")) case "cosmos.autocli.v1.PositionalArgDescriptor.varargs": panic(fmt.Errorf("field varargs of message cosmos.autocli.v1.PositionalArgDescriptor is not mutable")) + case "cosmos.autocli.v1.PositionalArgDescriptor.optional": + panic(fmt.Errorf("field optional of message cosmos.autocli.v1.PositionalArgDescriptor is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.autocli.v1.PositionalArgDescriptor")) @@ -3991,6 +4010,8 @@ func (x *fastReflection_PositionalArgDescriptor) NewField(fd protoreflect.FieldD return protoreflect.ValueOfString("") case "cosmos.autocli.v1.PositionalArgDescriptor.varargs": return protoreflect.ValueOfBool(false) + case "cosmos.autocli.v1.PositionalArgDescriptor.optional": + return protoreflect.ValueOfBool(false) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.autocli.v1.PositionalArgDescriptor")) @@ -4067,6 +4088,9 @@ func (x *fastReflection_PositionalArgDescriptor) ProtoMethods() *protoiface.Meth if x.Varargs { n += 2 } + if x.Optional { + n += 2 + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -4096,6 +4120,16 @@ func (x *fastReflection_PositionalArgDescriptor) ProtoMethods() *protoiface.Meth i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if x.Optional { + i-- + if x.Optional { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } if x.Varargs { i-- if x.Varargs { @@ -4214,6 +4248,26 @@ func (x *fastReflection_PositionalArgDescriptor) ProtoMethods() *protoiface.Meth } } x.Varargs = bool(v != 0) + case 3: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Optional", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + x.Optional = bool(v != 0) default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -4622,8 +4676,11 @@ type PositionalArgDescriptor struct { ProtoField string `protobuf:"bytes,1,opt,name=proto_field,json=protoField,proto3" json:"proto_field,omitempty"` // varargs makes a positional parameter a varargs parameter. This can only be // applied to last positional parameter and the proto_field must a repeated - // field. + // field. Note: It is mutually exclusive with optional. Varargs bool `protobuf:"varint,2,opt,name=varargs,proto3" json:"varargs,omitempty"` + // optional makes a positional parameter optional. This can only be applied + // to the last positional parameter. Note: It is mutually exclusive with varargs. + Optional bool `protobuf:"varint,3,opt,name=optional,proto3" json:"optional,omitempty"` } func (x *PositionalArgDescriptor) Reset() { @@ -4660,6 +4717,13 @@ func (x *PositionalArgDescriptor) GetVarargs() bool { return false } +func (x *PositionalArgDescriptor) GetOptional() bool { + if x != nil { + return x.Optional + } + return false +} + var File_cosmos_autocli_v1_options_proto protoreflect.FileDescriptor var file_cosmos_autocli_v1_options_proto_rawDesc = []byte{ @@ -4745,25 +4809,26 @@ var file_cosmos_autocli_v1_options_proto_rawDesc = []byte{ 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x68, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x22, 0x54, 0x0a, 0x17, 0x50, 0x6f, 0x73, 0x69, + 0x52, 0x06, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x22, 0x70, 0x0a, 0x17, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x72, 0x67, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x61, 0x72, 0x61, 0x72, 0x67, 0x73, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x76, 0x61, 0x72, 0x61, 0x72, 0x67, 0x73, 0x42, 0xb9, - 0x01, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x75, - 0x74, 0x6f, 0x63, 0x6c, 0x69, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x2f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x6c, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x75, 0x74, - 0x6f, 0x63, 0x6c, 0x69, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x41, 0x58, 0xaa, 0x02, 0x11, 0x43, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x63, 0x6c, 0x69, 0x2e, 0x56, 0x31, - 0xca, 0x02, 0x11, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x75, 0x74, 0x6f, 0x63, 0x6c, - 0x69, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1d, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x75, - 0x74, 0x6f, 0x63, 0x6c, 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, - 0x75, 0x74, 0x6f, 0x63, 0x6c, 0x69, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x76, 0x61, 0x72, 0x61, 0x72, 0x67, 0x73, 0x12, 0x1a, + 0x0a, 0x08, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x08, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0xb9, 0x01, 0x0a, 0x15, 0x63, + 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x6c, + 0x69, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, + 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x61, 0x75, + 0x74, 0x6f, 0x63, 0x6c, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x6c, 0x69, + 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x41, 0x58, 0xaa, 0x02, 0x11, 0x43, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x63, 0x6c, 0x69, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x11, 0x43, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x75, 0x74, 0x6f, 0x63, 0x6c, 0x69, 0x5c, 0x56, 0x31, + 0xe2, 0x02, 0x1d, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x75, 0x74, 0x6f, 0x63, 0x6c, + 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0xea, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, 0x75, 0x74, 0x6f, 0x63, + 0x6c, 0x69, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/client/v2/CHANGELOG.md b/client/v2/CHANGELOG.md index 0c3c9d0385..798cde4380 100644 --- a/client/v2/CHANGELOG.md +++ b/client/v2/CHANGELOG.md @@ -34,4 +34,4 @@ Ref: https://keepachangelog.com/en/1.0.0/ # Changelog -## [Unreleased] +## [Unreleased] \ No newline at end of file diff --git a/client/v2/autocli/app.go b/client/v2/autocli/app.go index 0172b4c3e8..a365af904d 100644 --- a/client/v2/autocli/app.go +++ b/client/v2/autocli/app.go @@ -4,11 +4,12 @@ import ( "errors" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" - "cosmossdk.io/client/v2/autocli/flag" "cosmossdk.io/core/address" "cosmossdk.io/core/appmodule" "cosmossdk.io/depinject" + "cosmossdk.io/client/v2/autocli/flag" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/spf13/cobra" diff --git a/client/v2/autocli/common_test.go b/client/v2/autocli/common_test.go index 4f605a4f48..9cfb9582fe 100644 --- a/client/v2/autocli/common_test.go +++ b/client/v2/autocli/common_test.go @@ -68,6 +68,49 @@ func testExecCommon(t *testing.T, buildModuleCommand func(string, *Builder) (*co return conn } +func testExecCommonWithErr(t *testing.T, expectedErr string, buildModuleCommand func(string, *Builder) (*cobra.Command, error), args ...string) { + server := grpc.NewServer() + testpb.RegisterQueryServer(server, &testEchoServer{}) + reflectionv2alpha1.RegisterReflectionServiceServer(server, &testReflectionServer{}) + listener, err := net.Listen("tcp", "127.0.0.1:0") + assert.NilError(t, err) + go func() { + err := server.Serve(listener) + if err != nil { + panic(err) + } + }() + + clientConn, err := grpc.Dial(listener.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials())) + assert.NilError(t, err) + defer func() { + err := clientConn.Close() + if err != nil { + panic(err) + } + }() + + conn := &testClientConn{ + ClientConn: clientConn, + t: t, + out: &bytes.Buffer{}, + errorOut: &bytes.Buffer{}, + } + b := &Builder{ + Builder: flag.Builder{ + AddressCodec: addresscodec.NewBech32Codec("cosmos"), + }, + GetClientConn: func(*cobra.Command) (grpc.ClientConnInterface, error) { + return conn, nil + }, + AddQueryConnFlags: flags.AddQueryFlagsToCmd, + AddTxConnFlags: flags.AddTxFlagsToCmd, + } + + _, err = buildModuleCommand("test", b) + assert.Equal(t, expectedErr, err.Error()) +} + type testReflectionServer struct { reflectionv2alpha1.UnimplementedReflectionServiceServer } diff --git a/client/v2/autocli/flag/message.go b/client/v2/autocli/flag/message.go index 6d07e3564a..5ea1943cd4 100644 --- a/client/v2/autocli/flag/message.go +++ b/client/v2/autocli/flag/message.go @@ -15,6 +15,7 @@ type MessageBinder struct { positionalFlagSet *pflag.FlagSet positionalArgs []fieldBinding hasVarargs bool + hasOptional bool flagBindings []fieldBinding messageType protoreflect.MessageType @@ -32,8 +33,8 @@ func (m MessageBinder) Bind(msg protoreflect.Message, positionalArgs []string) e // first set positional args in the positional arg flag set n := len(positionalArgs) for i := range m.positionalArgs { - if i >= n { - panic("unexpected: validate args should have caught this") + if i == n { + break } name := fmt.Sprintf("%d", i) diff --git a/client/v2/autocli/flag/register.go b/client/v2/autocli/flag/register.go index a3a525b343..a65b1e0481 100644 --- a/client/v2/autocli/flag/register.go +++ b/client/v2/autocli/flag/register.go @@ -24,6 +24,7 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m isPositional := map[string]bool{} hasVarargs := false + hasOptional := false n := len(commandOptions.PositionalArgs) // positional args are also parsed using a FlagSet so that we can reuse all the same parsers handler.positionalFlagSet = pflag.NewFlagSet("positional", pflag.ContinueOnError) @@ -43,6 +44,14 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m hasVarargs = true } + if arg.Optional { + if i != n-1 { + return nil, fmt.Errorf("optional positional argument %s must be the last argument", arg.ProtoField) + } + + hasOptional = true + } + _, hasValue, err := b.addFieldFlag( ctx, handler.positionalFlagSet, @@ -63,6 +72,9 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m if hasVarargs { handler.CobraArgs = cobra.MinimumNArgs(n) handler.hasVarargs = true + } else if hasOptional { + handler.CobraArgs = cobra.RangeArgs(n-1, n) + handler.hasOptional = true } else { handler.CobraArgs = cobra.ExactArgs(n) } diff --git a/client/v2/autocli/query_test.go b/client/v2/autocli/query_test.go index 635060b3f9..64386aa30e 100644 --- a/client/v2/autocli/query_test.go +++ b/client/v2/autocli/query_test.go @@ -25,6 +25,20 @@ var buildModuleQueryCommand = func(moduleName string, b *Builder) (*cobra.Comman 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)) + + err := 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)) + + err := b.AddQueryServiceCommands(cmd, testCmdDescInvalidOptAndVargas) + return cmd, err +} + var testCmdDesc = &autocliv1.ServiceCommandDescriptor{ Service: testpb.Query_ServiceDesc.ServiceName, RpcCommandOptions: []*autocliv1.RpcCommandOptions{ @@ -117,6 +131,60 @@ var testCmdDesc = &autocliv1.ServiceCommandDescriptor{ }, } +var testCmdDescOptional = &autocliv1.ServiceCommandDescriptor{ + Service: testpb.Query_ServiceDesc.ServiceName, + RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + { + RpcMethod: "Echo", + Use: "echo [pos1] [pos2] [pos3...]", + Version: "1.0", + Alias: []string{"e"}, + SuggestFor: []string{"eco"}, + Example: "echo 1 abc {}", + Short: "echo echos the value provided by the user", + Long: "echo echos the value provided by the user as a proto JSON object with populated with the provided fields and positional arguments", + PositionalArgs: []*autocliv1.PositionalArgDescriptor{ + { + ProtoField: "positional1", + }, + { + ProtoField: "positional2", + Optional: true, + }, + }, + }, + }, +} + +var testCmdDescInvalidOptAndVargas = &autocliv1.ServiceCommandDescriptor{ + Service: testpb.Query_ServiceDesc.ServiceName, + RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + { + RpcMethod: "Echo", + Use: "echo [pos1] [pos2] [pos3...]", + Version: "1.0", + Alias: []string{"e"}, + SuggestFor: []string{"eco"}, + Example: "echo 1 abc {}", + Short: "echo echos the value provided by the user", + Long: "echo echos the value provided by the user as a proto JSON object with populated with the provided fields and positional arguments", + PositionalArgs: []*autocliv1.PositionalArgDescriptor{ + { + ProtoField: "positional1", + }, + { + ProtoField: "positional2", + Optional: true, + }, + { + ProtoField: "positional3_varargs", + Varargs: true, + }, + }, + }, + }, +} + func TestCoin(t *testing.T) { conn := testExecCommon(t, buildModuleQueryCommand, "echo", @@ -130,6 +198,40 @@ func TestCoin(t *testing.T) { assert.DeepEqual(t, conn.lastRequest, conn.lastResponse.(*testpb.EchoResponse).Request, protocmp.Transform()) } +func TestOptional(t *testing.T) { + conn := testExecCommon(t, buildModuleQueryCommandOptional, + "echo", + "1", + "abc", + ) + request := conn.lastRequest.(*testpb.EchoRequest) + assert.Equal(t, request.Positional2, "abc") + assert.DeepEqual(t, conn.lastRequest, conn.lastResponse.(*testpb.EchoResponse).Request, protocmp.Transform()) + + conn = testExecCommon(t, buildModuleQueryCommandOptional, + "echo", + "1", + ) + request = conn.lastRequest.(*testpb.EchoRequest) + assert.Equal(t, request.Positional2, "") + assert.DeepEqual(t, conn.lastRequest, conn.lastResponse.(*testpb.EchoResponse).Request, protocmp.Transform()) + + conn = testExecCommon(t, buildModuleQueryCommandOptional, + "echo", + "1", + "abc", + "extra-arg", + ) + assert.Equal(t, conn.errorOut.String(), "Error: accepts between 1 and 2 arg(s), received 3\n") + + testExecCommonWithErr(t, "optional positional argument positional2 must be the last argument", buildModuleVargasOptional, + "echo", + "1", + "abc", + "extra-arg", + ) +} + func TestMap(t *testing.T) { conn := testExecCommon(t, buildModuleQueryCommand, "echo", diff --git a/client/v2/go.mod b/client/v2/go.mod index 21c58fa31c..e89b893a2a 100644 --- a/client/v2/go.mod +++ b/client/v2/go.mod @@ -3,7 +3,7 @@ module cosmossdk.io/client/v2 go 1.20 require ( - cosmossdk.io/api v0.4.2 + cosmossdk.io/api v0.4.3-0.20230615032830-feb87fce5495 cosmossdk.io/core v0.8.0 cosmossdk.io/depinject v1.0.0-alpha.3 github.com/cockroachdb/errors v1.10.0 diff --git a/client/v2/go.sum b/client/v2/go.sum index 963f11f4f7..b3e7b29e16 100644 --- a/client/v2/go.sum +++ b/client/v2/go.sum @@ -35,8 +35,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cosmossdk.io/api v0.4.2 h1:lQBMl4xINnMnBOR/tQLtjlDnR4exr4e6/SfHR8PILE0= -cosmossdk.io/api v0.4.2/go.mod h1:qrVgOp7DIeAXa+Tt5dDjOC47bZCDrwx8ZHxrmy7STNE= +cosmossdk.io/api v0.4.3-0.20230615032830-feb87fce5495 h1:wreIRQKuKccFCOI4TWoVy/6tQNiDX4ms7VKNrXP4DEM= +cosmossdk.io/api v0.4.3-0.20230615032830-feb87fce5495/go.mod h1:qrVgOp7DIeAXa+Tt5dDjOC47bZCDrwx8ZHxrmy7STNE= cosmossdk.io/collections v0.2.0 h1:CgMfLtE16+qox3zBYrGh60i4yKV8SeExLnIdOS2sbQs= cosmossdk.io/collections v0.2.0/go.mod h1:Oc1FK0vlmxJZsgUn9/o3ldE6zNyWKvobVzaLhWknZJE= cosmossdk.io/core v0.8.0 h1:LcJnu52E1a8f8E317VfQ1xK/RZe+IuhMNQAjnDLh25M= diff --git a/proto/cosmos/autocli/v1/options.proto b/proto/cosmos/autocli/v1/options.proto index b023490c97..4aecf1915a 100644 --- a/proto/cosmos/autocli/v1/options.proto +++ b/proto/cosmos/autocli/v1/options.proto @@ -81,6 +81,7 @@ message RpcCommandOptions { // skip specifies whether to skip this rpc method when generating commands. bool skip = 12; + } // FlagOptions are options for flags generated from rpc request fields. @@ -119,6 +120,10 @@ message PositionalArgDescriptor { // varargs makes a positional parameter a varargs parameter. This can only be // applied to last positional parameter and the proto_field must a repeated - // field. + // field. Note: It is mutually exclusive with optional. bool varargs = 2; + + // optional makes the last positional parameter optional. + // Note: It is mutually exclusive with varargs. + bool optional = 3; } diff --git a/simapp/go.mod b/simapp/go.mod index dc592b5ae4..3559a5f3ca 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -3,7 +3,7 @@ module cosmossdk.io/simapp go 1.20 require ( - cosmossdk.io/api v0.4.2 + cosmossdk.io/api v0.4.3-0.20230615032830-feb87fce5495 cosmossdk.io/client/v2 v2.0.0-20230614103911-b3da8bb4e801 cosmossdk.io/core v0.8.0 cosmossdk.io/depinject v1.0.0-alpha.3 diff --git a/simapp/go.sum b/simapp/go.sum index 0a5e4ed29b..bd6c8040d7 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -188,8 +188,8 @@ 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/api v0.4.2 h1:lQBMl4xINnMnBOR/tQLtjlDnR4exr4e6/SfHR8PILE0= -cosmossdk.io/api v0.4.2/go.mod h1:qrVgOp7DIeAXa+Tt5dDjOC47bZCDrwx8ZHxrmy7STNE= +cosmossdk.io/api v0.4.3-0.20230615032830-feb87fce5495 h1:wreIRQKuKccFCOI4TWoVy/6tQNiDX4ms7VKNrXP4DEM= +cosmossdk.io/api v0.4.3-0.20230615032830-feb87fce5495/go.mod h1:qrVgOp7DIeAXa+Tt5dDjOC47bZCDrwx8ZHxrmy7STNE= cosmossdk.io/collections v0.2.0 h1:CgMfLtE16+qox3zBYrGh60i4yKV8SeExLnIdOS2sbQs= cosmossdk.io/collections v0.2.0/go.mod h1:Oc1FK0vlmxJZsgUn9/o3ldE6zNyWKvobVzaLhWknZJE= cosmossdk.io/core v0.8.0 h1:LcJnu52E1a8f8E317VfQ1xK/RZe+IuhMNQAjnDLh25M= diff --git a/tests/go.mod b/tests/go.mod index a556d485d6..0060550cfe 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -3,7 +3,7 @@ module github.com/cosmos/cosmos-sdk/tests go 1.20 require ( - cosmossdk.io/api v0.4.2 + cosmossdk.io/api v0.4.3-0.20230615032830-feb87fce5495 cosmossdk.io/collections v0.2.0 cosmossdk.io/core v0.8.0 cosmossdk.io/depinject v1.0.0-alpha.3 diff --git a/tests/go.sum b/tests/go.sum index 25dc4a6f27..9f5380d3f2 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -188,8 +188,8 @@ 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/api v0.4.2 h1:lQBMl4xINnMnBOR/tQLtjlDnR4exr4e6/SfHR8PILE0= -cosmossdk.io/api v0.4.2/go.mod h1:qrVgOp7DIeAXa+Tt5dDjOC47bZCDrwx8ZHxrmy7STNE= +cosmossdk.io/api v0.4.3-0.20230615032830-feb87fce5495 h1:wreIRQKuKccFCOI4TWoVy/6tQNiDX4ms7VKNrXP4DEM= +cosmossdk.io/api v0.4.3-0.20230615032830-feb87fce5495/go.mod h1:qrVgOp7DIeAXa+Tt5dDjOC47bZCDrwx8ZHxrmy7STNE= cosmossdk.io/collections v0.2.0 h1:CgMfLtE16+qox3zBYrGh60i4yKV8SeExLnIdOS2sbQs= cosmossdk.io/collections v0.2.0/go.mod h1:Oc1FK0vlmxJZsgUn9/o3ldE6zNyWKvobVzaLhWknZJE= cosmossdk.io/core v0.8.0 h1:LcJnu52E1a8f8E317VfQ1xK/RZe+IuhMNQAjnDLh25M=