feat(autocli): add text|json output for flag output (#15252)

This commit is contained in:
Jeancarlo Barrios 2023-03-03 17:00:06 -05:00 committed by GitHub
parent fab029bff5
commit 34192a089b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 148 additions and 16 deletions

View File

@ -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)

View File

@ -17,4 +17,6 @@ type Builder struct {
GetClientConn func(*cobra.Command) (grpc.ClientConnInterface, error)
AddQueryConnFlags func(*cobra.Command)
AddTxConnFlags func(*cobra.Command)
}

View File

@ -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"
)
@ -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)
@ -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
}
@ -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
}

View File

@ -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"
@ -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)

View File

@ -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
@ -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
}

View File

@ -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
@ -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",
@ -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}`,

View File

@ -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
@ -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 {

View File

@ -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")

View File

@ -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
@ -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

View File

@ -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

View File

@ -13,28 +13,53 @@ 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 (DEPRECATED: don't use this)
--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
--i32 int32 some random 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
--page-offset uint
--page-reverse
-s, --sequence uint The sequence number of the signing account (offline mode only)
-d, --shorthand-deprecated-field string (DEPRECATED: bad idea)
--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
--u64 uint some random uint64
-u, --uint32 uint32 some random uint32
--uints uints (default [])
-v, --version version for send
-y, --yes Skip tx broadcasting prompt confirmation

View File

@ -21,9 +21,14 @@ 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
--i32 int32 some random 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