ADR 058: Auto-Generated CLI
Changelog​
- 2022-05-04: Initial Draft
Status​
ACCEPTED Partially Implemented
Abstract​
In order to make it easier for developers to write Cosmos SDK modules, we provide infrastructure which automatically generates CLI commands based on protobuf definitions.
Context​
Current Cosmos SDK modules generally implement a CLI command for every transaction and every query supported by the module. These are handwritten for each command and essentially amount to providing some CLI flags or positional arguments for specific fields in protobuf messages.
In order to make sure CLI commands are correctly implemented as well as to make sure that the application works
in end-to-end scenarios, we do integration tests using CLI commands. While these tests are valuable on some-level,
they can be hard to write and maintain, and run slowly. Some teams have contemplated
moving away from CLI-style integration tests (which are really end-to-end tests) towards narrower integration tests
which exercise MsgClient
and QueryClient
directly. This might involve replacing the current end-to-end CLI
tests with unit tests as there still needs to be some way to test these CLI commands for full quality assurance.
Decision​
To make module development simpler, we provide infrastructure - in the new client/v2
go module - for automatically generating CLI commands based on protobuf definitions to either replace or complement
handwritten CLI commands. This will mean that when developing a module, it will be possible to skip both writing and
testing CLI commands as that can all be taken care of by the framework.
The basic design for automatically generating CLI commands is to:
- create one CLI command for each
rpc
method in a protobufQuery
orMsg
service - create a CLI flag for each field in the
rpc
request type - for
query
commands call gRPC and print the response as protobuf JSON or YAML (via the-o
/--output
flag) - for
tx
commands, create a transaction and apply common transaction flags
In order to make the auto-generated CLI as easy to use (or easier) than handwritten CLI, we need to do custom handling of specific protobuf field types so that the input format is easy for humans:
Coin
,Coins
,DecCoin
, andDecCoins
should be input using the existing format (i.e.1000uatom
)- it should be possible to specify an address using either the bech32 address string or a named key in the keyring
Timestamp
andDuration
should accept strings like2001-01-01T00:00:00Z
and1h3m
respectively- pagination should be handled with flags like
--page-limit
,--page-offset
, etc. - it should be possible to customize any other protobuf type either via its message name or a
cosmos_proto.scalar
annotation
At a basic level it should be possible to generate a command for a single rpc
method as well as all the commands for
a whole protobuf service
definition. It should be possible to mix and match auto-generated and handwritten commands.
Consequences​
Backwards Compatibility​
Existing modules can mix and match auto-generated and handwritten CLI commands so it is up to them as to whether they make breaking changes by replacing handwritten commands with slightly different auto-generated ones.
For now the SDK will maintain the existing set of CLI commands for backwards compatibility but new commands will use this functionality.
Positive​
- module developers will not need to write CLI commands
- module developers will not need to test CLI commands
- lens may benefit from this
Negative​
Neutral​
Further Discussions​
We would like to be able to customize:
- short and long usage strings for commands
- aliases for flags (ex.
-a
for--amount
) - which fields are positional parameters rather than flags
It is an open discussion as to whether these customizations options should line in:
- the .proto files themselves,
- separate config files (ex. YAML), or
- directly in code
Providing the options in .proto files would allow a dynamic client to automatically generate CLI commands on the fly. However, that may pollute the .proto files themselves with information that is only relevant for a small subset of users.