变更记录
- 2022-05-04:初始草案
状态
已接受,部分已实现摘要
为了让开发者更容易编写 Cosmos SDK 模块,我们提供了一套基础设施,可基于 protobuf 定义自动生成 CLI 命令。背景
当前的 Cosmos SDK 模块通常会为模块支持的每一笔交易和每一个查询实现一个 CLI 命令。这些命令都需要逐个手写,本质上是为 protobuf 消息中的特定字段提供一些 CLI 标志或位置参数。 为了确保 CLI 命令实现正确,并保证应用在端到端场景下能够正常工作,我们会使用 CLI 命令进行集成测试。尽管这些测试在一定程度上很有价值,但它们往往难以编写和维护,而且运行较慢。一些团队曾讨论从 CLI 风格的集成测试(实际上属于端到端测试)转向更窄范围的集成测试,直接对MsgClient 和 QueryClient 进行验证。这可能意味着用单元测试替代当前的端到端 CLI 测试,因为仍然需要某种方式来测试这些 CLI 命令,以确保完整的质量保障。
决策
为了简化模块开发,我们在新的client/v2 Go 模块中提供基础设施,可基于 protobuf 定义自动生成 CLI 命令,以替代或补充手写 CLI 命令。这意味着在开发模块时,可以跳过 CLI 命令的编写和测试,因为这些工作都可以由框架处理。
自动生成 CLI 命令的基本设计如下:
- 为 protobuf
Query或Msg服务中的每个rpc方法创建一个 CLI 命令 - 为
rpc请求类型中的每个字段创建一个 CLI 标志 - 对于
query命令,调用 gRPC,并将响应以 protobuf JSON 或 YAML 形式输出(通过-o/--output标志) - 对于
tx命令,创建交易并应用通用交易标志
Coin、Coins、DecCoin和DecCoins应使用现有格式输入(即1000uatom)- 应支持使用 bech32 地址字符串或 keyring 中命名的密钥来指定地址
Timestamp和Duration应分别接受类似2001-01-01T00:00:00Z和1h3m的字符串- 分页应通过
--page-limit、--page-offset等标志处理 - 还应能够通过消息名称或
cosmos_proto.scalar注解来自定义其他任意 protobuf 类型
rpc 方法生成命令,也能够为整个 protobuf service 定义生成所有命令。同时,应支持将自动生成命令与手写命令混合使用。
影响
向后兼容性
现有模块可以混合使用自动生成和手写的 CLI 命令,因此是否通过用略有差异的自动生成命令替换手写命令而引入破坏性变更,由各模块自行决定。 目前,SDK 将继续保留现有这套 CLI 命令以保持向后兼容性,但新命令将使用这一功能。正面影响
- 模块开发者无需编写 CLI 命令
- 模块开发者无需测试 CLI 命令
- lens 可能会从中受益
负面影响
中性影响
后续讨论
我们希望能够自定义以下内容:- 命令的简短和详细用法说明字符串
- 标志的别名(例如
--amount的-a) - 哪些字段应作为位置参数而不是标志
.proto文件本身- 单独的配置文件(例如 YAML)
- 直接写在代码中
.proto 文件中,动态客户端就可以即时自动生成 CLI 命令。然而,这也可能会让 .proto 文件本身混入只与一小部分用户相关的信息。
参考资料
Changelog
- 2022-05-04: Initial Draft
Status
ACCEPTED Partially ImplementedAbstract
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 exerciseMsgClient 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 newclient/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
rpcmethod in a protobufQueryorMsgservice - create a CLI flag for each field in the
rpcrequest type - for
querycommands call gRPC and print the response as protobuf JSON or YAML (via the-o/--outputflag) - for
txcommands, create a transaction and apply common transaction flags
Coin,Coins,DecCoin, andDecCoinsshould 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
TimestampandDurationshould accept strings like2001-01-01T00:00:00Zand1h3mrespectively- 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.scalarannotation
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.
-afor--amount) - which fields are positional parameters rather than flags
- the .proto files themselves,
- separate config files (ex. YAML), or
- directly in code