Skip to content

Commit

Permalink
feat(autocli): add text|json output for flag output (#15252)
Browse files Browse the repository at this point in the history
  • Loading branch information
JeancarloBarrios authored Mar 3, 2023
1 parent fab029b commit 34192a0
Show file tree
Hide file tree
Showing 12 changed files with 148 additions and 16 deletions.
1 change: 1 addition & 0 deletions client/v2/autocli/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func (appOptions AppOptions) EnhanceRootCommand(rootCmd *cobra.Command) error {
return client.GetClientQueryContext(cmd)
},
AddQueryConnFlags: flags.AddQueryFlagsToCmd,
AddTxConnFlags: flags.AddTxFlagsToCmd,
}

return appOptions.EnhanceRootCommandWithBuilder(rootCmd, builder)
Expand Down
2 changes: 2 additions & 0 deletions client/v2/autocli/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ type Builder struct {
GetClientConn func(*cobra.Command) (grpc.ClientConnInterface, error)

AddQueryConnFlags func(*cobra.Command)

AddTxConnFlags func(*cobra.Command)
}
30 changes: 22 additions & 8 deletions client/v2/autocli/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package autocli

import (
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
"fmt"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/spf13/cobra"
"google.golang.org/protobuf/reflect/protoreflect"
"sigs.k8s.io/yaml"

"cosmossdk.io/client/v2/internal/util"
)
Expand All @@ -14,10 +17,6 @@ func (b *Builder) buildMethodCommandCommon(descriptor protoreflect.MethodDescrip
options = &autocliv1.RpcCommandOptions{}
}

if options.Skip {
return nil, nil
}

long := options.Long
if long == "" {
long = util.DescriptorDocs(descriptor)
Expand Down Expand Up @@ -58,10 +57,6 @@ func (b *Builder) buildMethodCommandCommon(descriptor protoreflect.MethodDescrip
return exec(cmd, input)
}

if b.AddQueryConnFlags != nil {
b.AddQueryConnFlags(cmd)
}

return cmd, nil
}

Expand Down Expand Up @@ -108,3 +103,22 @@ func (b *Builder) enhanceCommandCommon(cmd *cobra.Command, moduleOptions map[str

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 outputType == nil {
return fmt.Errorf("output flag not found")

}
if outputType.Value.String() == "text" {
out, err = yaml.JSONToYAML(out)
if err != nil {
return err
}
}
_, err = fmt.Fprintln(cmd.OutOrStdout(), string(out))

return nil
}
3 changes: 3 additions & 0 deletions client/v2/autocli/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package autocli
import (
"bytes"
"cosmossdk.io/client/v2/internal/testpb"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"gotest.tools/v3/assert"
Expand Down Expand Up @@ -43,6 +44,8 @@ func testExecCommon(t *testing.T, buildModuleCommand func(string, *Builder) (*co
GetClientConn: func(*cobra.Command) (grpc.ClientConnInterface, error) {
return conn, nil
},
AddQueryConnFlags: flags.AddQueryFlagsToCmd,
AddTxConnFlags: flags.AddTxFlagsToCmd,
}

cmd, err := buildModuleCommand("test", b)
Expand Down
17 changes: 14 additions & 3 deletions client/v2/autocli/msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,14 @@ func (b *Builder) AddMsgServiceCommands(cmd *cobra.Command, cmdDescriptor *autoc
methodsLength := methods.Len()
for i := 0; i < methodsLength; i++ {
methodDescriptor := methods.Get(i)
methodOpts := rpcOptMap[methodDescriptor.Name()]
methodOpts, ok := rpcOptMap[methodDescriptor.Name()]
if !ok {
methodOpts = &autocliv1.RpcCommandOptions{}
}

if methodOpts.Skip {
continue
}
methodCmd, err := b.BuildMsgMethodCommand(methodDescriptor, methodOpts)
if err != nil {
return err
Expand All @@ -104,13 +111,17 @@ func (b *Builder) BuildMsgMethodCommand(descriptor protoreflect.MethodDescriptor
Resolver: b.TypeResolver,
}

return b.buildMethodCommandCommon(descriptor, options, func(cmd *cobra.Command, input protoreflect.Message) error {
cmd, err := b.buildMethodCommandCommon(descriptor, options, func(cmd *cobra.Command, input protoreflect.Message) error {
bz, err := jsonMarshalOptions.Marshal(input.Interface())
if err != nil {
return err
}

_, err = fmt.Fprintln(cmd.OutOrStdout(), string(bz))
err = b.outOrStdoutFormat(cmd, bz)
return err
})
if b.AddTxConnFlags != nil {
b.AddTxConnFlags(cmd)
}
return cmd, err
}
17 changes: 17 additions & 0 deletions client/v2/autocli/msg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ func TestMsgOptions(t *testing.T) {
"send", "5", "6", `{"denom":"foo","amount":"1"}`,
"--uint32", "7",
"--u64", "8",
"--output", "json",
)
response := conn.out.String()
var output testpb.MsgRequest
Expand All @@ -114,6 +115,21 @@ func TestMsgOptions(t *testing.T) {
assert.Equal(t, output.GetPositional2(), "6")
}

func TestMsgOutputFormat(t *testing.T) {
conn := testExecCommon(t, buildModuleMsgCommand,
"send", "5", "6", `{"denom":"foo","amount":"1"}`,
"--output", "json",
)
assert.Assert(t, strings.Contains(conn.out.String(), "{"))
conn = testExecCommon(t, buildModuleMsgCommand,
"send", "5", "6", `{"denom":"foo","amount":"1"}`,
"--output", "text",
)

assert.Assert(t, strings.Contains(conn.out.String(), "positional1: 5"))

}

func TestMsgOptionsError(t *testing.T) {
conn := testExecCommon(t, buildModuleMsgCommand,
"send", "5",
Expand Down Expand Up @@ -151,6 +167,7 @@ func TestEverythingMsg(t *testing.T) {
"abc",
`{"denom":"foo","amount":"1234"}`,
`{"denom":"bar","amount":"4321"}`,
"--output", "json",
"--a-bool",
"--an-enum", "two",
"--a-message", `{"bar":"abc", "baz":-3}`,
Expand Down
17 changes: 12 additions & 5 deletions client/v2/autocli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,22 @@ func (b *Builder) AddQueryServiceCommands(cmd *cobra.Command, cmdDescriptor *aut
n := methods.Len()
for i := 0; i < n; i++ {
methodDescriptor := methods.Get(i)
methodOpts := rpcOptMap[methodDescriptor.Name()]
methodOpts, ok := rpcOptMap[methodDescriptor.Name()]
if !ok {
methodOpts = &autocliv1.RpcCommandOptions{}
}

if methodOpts.Skip {
continue
}

methodCmd, err := b.BuildQueryMethodCommand(methodDescriptor, methodOpts)
if err != nil {
return err
}

if methodCmd != nil {
cmd.AddCommand(methodCmd)
}
cmd.AddCommand(methodCmd)

}

return nil
Expand Down Expand Up @@ -131,7 +138,7 @@ func (b *Builder) BuildQueryMethodCommand(descriptor protoreflect.MethodDescript
return err
}

_, err = fmt.Fprintln(cmd.OutOrStdout(), string(bz))
err = b.outOrStdoutFormat(cmd, bz)
return err
})
if err != nil {
Expand Down
17 changes: 17 additions & 0 deletions client/v2/autocli/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,23 @@ func TestOptions(t *testing.T) {
assert.Equal(t, uint64(5), lastReq.U64) // no opt default value got set
}

func TestOutputFormat(t *testing.T) {
conn := testExecCommon(t, buildModuleQueryCommand,
"echo",
"1", "abc", `{"denom":"foo","amount":"1"}`,
"--output", "json",
)
assert.Assert(t, strings.Contains(conn.out.String(), "{"))
conn = testExecCommon(t, buildModuleQueryCommand,
"echo",
"1", "abc", `{"denom":"foo","amount":"1"}`,
"--output", "text",
)
fmt.Println(conn.out.String())
assert.Assert(t, strings.Contains(conn.out.String(), " positional1: 1"))

}

func TestHelp(t *testing.T) {
conn := testExecCommon(t, buildModuleQueryCommand, "-h")
golden.Assert(t, conn.out.String(), "help-toplevel.golden")
Expand Down
25 changes: 25 additions & 0 deletions client/v2/autocli/testdata/help-deprecated-msg.golden
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,38 @@ Flags:
--a-bool
--a-coin cosmos.base.v1beta1.Coin (json)
--a-message testpb.AMessage (json)
-a, --account-number uint The account number of the signing account (offline mode only)
--an-address bech32 account address key name
--an-enum Enum (unspecified | one | two | five | neg-three) (default unspecified)
--aux Generate aux signer data instead of sending a tx
--bools bools (default [])
-b, --broadcast-mode string Transaction broadcasting mode (sync|async) (default "sync")
--bz bytesBase64
--chain-id string The network chain ID
--deprecated-field string
--dry-run ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it (when enabled, the local Keybase is not accessible)
--duration duration
--durations duration (repeated)
--enums Enum (unspecified | one | two | five | neg-three) (repeated)
--fee-granter string Fee granter grants fees for the transaction
--fee-payer string Fee payer pays fees for the transaction instead of deducting from the signer
--fees string Fees to pay along with transaction; eg: 10uatom
--from string Name or address of private key with which to sign
--gas string gas limit to set per-transaction; set to "auto" to calculate sufficient gas automatically. Note: "auto" option doesn't always report accurate results. Set a valid coin value to adjust the result. Can be used instead of "fees". (default 200000)
--gas-adjustment float adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored (default 1)
--gas-prices string Gas prices in decimal format to determine the transaction fee (e.g. 0.1uatom)
--generate-only Build an unsigned transaction and write it to STDOUT (when enabled, the local Keybase only accessed when providing a key name)
-h, --help help for send
--hidden-bool
--i32 int32
--i64 int
--keyring-backend string Select keyring's backend (os|file|kwallet|pass|test|memory) (default "os")
--keyring-dir string The client Keyring directory; if omitted, the default 'home' directory will be used
--ledger Use a connected Ledger device
--node string <host>:<port> to CometBFT rpc interface for this chain (default "tcp://localhost:26657")
--note string Note to add a description to the transaction (previously --memo)
--offline Offline mode (does not allow any online functionality)
-o, --output string Output format (text|json) (default "json")
--page-count-total
--page-key bytesBase64
--page-limit uint
Expand All @@ -28,11 +48,16 @@ Flags:
--positional1 int32
--positional2 string
--positional3-varargs cosmos.base.v1beta1.Coin (json) (repeated)
-s, --sequence uint The sequence number of the signing account (offline mode only)
--shorthand-deprecated-field string
--sign-mode string Choose sign mode (direct|amino-json|direct-aux), this is an advanced feature
--some-messages testpb.AMessage (json) (repeated)
--str string
--strings strings
--timeout-height uint Set a block timeout height to prevent the tx from being committed past a certain height
--timestamp timestamp (RFC 3339)
--tip string Tip is the amount that is going to be transferred to the fee payer on the target chain. This flag is only valid when used with --aux, and is ignored if the target chain didn't enable the TipDecorator
--u32 uint32
--u64 uint
--uints uints (default [])
-y, --yes Skip tx broadcasting prompt confirmation
5 changes: 5 additions & 0 deletions client/v2/autocli/testdata/help-deprecated.golden
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,15 @@ Flags:
--duration duration
--durations duration (repeated)
--enums Enum (unspecified | one | two | five | neg-three) (repeated)
--grpc-addr string the gRPC endpoint to use for this chain
--grpc-insecure allow gRPC over insecure channels, if not the server must use TLS
--height int Use a specific height to query state at (this can error if the node is pruning state)
-h, --help help for echo
--hidden-bool
--i32 int32
--i64 int
--node string <host>:<port> to CometBFT RPC interface for this chain (default "tcp://localhost:26657")
-o, --output string Output format (text|json) (default "text")
--page-count-total
--page-key bytesBase64
--page-limit uint
Expand Down
Loading

0 comments on commit 34192a0

Please sign in to comment.