Skip to content

Commit 1313c0e

Browse files
fix(client/v2): fix short command description if not set and skip unsupported commands (backport #18324) (#18371)
Co-authored-by: Julien Robert <julien@rbrt.fr>
1 parent 57637f7 commit 1313c0e

7 files changed

Lines changed: 244 additions & 5 deletions

File tree

client/v2/autocli/common.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ func (b *Builder) buildMethodCommandCommon(descriptor protoreflect.MethodDescrip
2626
options = &autocliv1.RpcCommandOptions{}
2727
}
2828

29+
short := options.Short
30+
if short == "" {
31+
short = fmt.Sprintf("Execute the %s RPC method", descriptor.Name())
32+
}
33+
2934
long := options.Long
3035
if long == "" {
3136
long = util.DescriptorDocs(descriptor)
@@ -43,7 +48,7 @@ func (b *Builder) buildMethodCommandCommon(descriptor protoreflect.MethodDescrip
4348
SilenceUsage: false,
4449
Use: use,
4550
Long: long,
46-
Short: options.Short,
51+
Short: short,
4752
Example: options.Example,
4853
Aliases: options.Alias,
4954
SuggestFor: options.SuggestFor,

client/v2/autocli/msg.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
1414
"cosmossdk.io/client/v2/autocli/flag"
15+
"cosmossdk.io/client/v2/internal/util"
1516

1617
"github.com/cosmos/cosmos-sdk/client"
1718
clienttx "github.com/cosmos/cosmos-sdk/client/tx"
@@ -85,6 +86,10 @@ func (b *Builder) AddMsgServiceCommands(cmd *cobra.Command, cmdDescriptor *autoc
8586
continue
8687
}
8788

89+
if !util.IsSupportedVersion(util.DescriptorDocs(methodDescriptor)) {
90+
continue
91+
}
92+
8893
methodCmd, err := b.BuildMsgMethodCommand(methodDescriptor, methodOpts)
8994
if err != nil {
9095
return err

client/v2/autocli/query.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ func (b *Builder) AddQueryServiceCommands(cmd *cobra.Command, cmdDescriptor *aut
8282
continue
8383
}
8484

85+
if !util.IsSupportedVersion(util.DescriptorDocs(methodDescriptor)) {
86+
continue
87+
}
88+
8589
methodCmd, err := b.BuildQueryMethodCommand(methodDescriptor, methodOpts)
8690
if err != nil {
8791
return err

client/v2/autocli/testdata/help-deprecated.golden

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
Command "echo" is deprecated, don't use this
2+
Execute the Echo RPC method
3+
24
Usage:
35
test deprecatedecho echo [flags]
46

client/v2/autocli/testdata/help-toplevel-msg.golden

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ Usage:
55
test [command]
66

77
Available Commands:
8-
burn
8+
burn Execute the Burn RPC method
99
completion Generate the autocompletion script for the specified shell
1010
help Help about any command
11-
multi-send
11+
multi-send Execute the MultiSend RPC method
1212
send Send coins from one account to another
13-
set-send-enabled
14-
update-params
13+
set-send-enabled Execute the SetSendEnabled RPC method
14+
update-params Execute the UpdateParams RPC method
1515

1616
Flags:
1717
-h, --help help for test

client/v2/internal/util/util.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,29 @@
11
package util
22

33
import (
4+
"regexp"
5+
"runtime/debug"
6+
"strings"
7+
48
"google.golang.org/protobuf/reflect/protoreflect"
59
"google.golang.org/protobuf/reflect/protoregistry"
610
"google.golang.org/protobuf/types/dynamicpb"
711

812
"cosmossdk.io/client/v2/internal/strcase"
913
)
1014

15+
// get build info to verify later if comment is supported
16+
// this is a hack in because of the global api module package
17+
// later versions unsupported by the current version can be added
18+
var buildInfo, _ = debug.ReadBuildInfo()
19+
20+
// DescriptorName returns the name of the descriptor in kebab case.
1121
func DescriptorKebabName(descriptor protoreflect.Descriptor) string {
1222
return strcase.ToKebab(string(descriptor.Name()))
1323
}
1424

25+
// DescriptorDocs returns the leading comments of the descriptor.
26+
// TODO this does not work, to fix.
1527
func DescriptorDocs(descriptor protoreflect.Descriptor) string {
1628
return descriptor.ParentFile().SourceLocations().ByDescriptor(descriptor).LeadingComments
1729
}
@@ -24,3 +36,53 @@ func ResolveMessageType(resolver protoregistry.MessageTypeResolver, descriptor p
2436

2537
return dynamicpb.NewMessageType(descriptor)
2638
}
39+
40+
// IsSupportedVersion is used to determine in which version of a module / sdk a rpc was introduced.
41+
// It returns false if the rpc has comment for an higher version than the current one.
42+
func IsSupportedVersion(input string) bool {
43+
return isSupportedVersion(input, buildInfo)
44+
}
45+
46+
// isSupportedVersion is used to determine in which version of a module / sdk a rpc was introduced.
47+
// It returns false if the rpc has comment for an higher version than the current one.
48+
// It takes a buildInfo as argument to be able to test it.
49+
func isSupportedVersion(input string, buildInfo *debug.BuildInfo) bool {
50+
if input == "" || buildInfo == nil {
51+
return true
52+
}
53+
54+
moduleName, version := parseSinceComment(input)
55+
for _, dep := range buildInfo.Deps {
56+
if !strings.Contains(dep.Path, moduleName) {
57+
continue
58+
}
59+
60+
return version <= dep.Version
61+
}
62+
63+
return true // if cannot find the module consider it's supported
64+
}
65+
66+
var sinceCommentRegex = regexp.MustCompile(`\/\/\s*since: (\S+) (\S+)`)
67+
68+
// parseSinceComment parses the `// Since: cosmos-sdk v0.xx` comment on rpc.
69+
func parseSinceComment(input string) (string, string) {
70+
var (
71+
moduleName string
72+
version string
73+
)
74+
75+
input = strings.ToLower(input)
76+
input = strings.ReplaceAll(input, "cosmos sdk", "cosmos-sdk")
77+
78+
matches := sinceCommentRegex.FindStringSubmatch(input)
79+
if len(matches) >= 3 {
80+
moduleName, version = matches[1], matches[2]
81+
82+
if !strings.HasPrefix(version, "v") {
83+
version = "v" + version
84+
}
85+
}
86+
87+
return moduleName, version
88+
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package util
2+
3+
import (
4+
"runtime/debug"
5+
"testing"
6+
)
7+
8+
func TestIsSupportedVersion(t *testing.T) {
9+
mockBuildInfo := &debug.BuildInfo{
10+
Deps: []*debug.Module{
11+
{
12+
Path: "github.com/cosmos/cosmos-sdk",
13+
Version: "v0.50.0",
14+
},
15+
{
16+
Path: "cosmossdk.io/feegrant",
17+
Version: "v0.1.0",
18+
},
19+
},
20+
}
21+
22+
cases := []struct {
23+
input string
24+
expected bool
25+
}{
26+
{
27+
input: "",
28+
expected: true,
29+
},
30+
{
31+
input: "not a since comment",
32+
expected: true,
33+
},
34+
{
35+
input: "// Since: cosmos-sdk v0.47",
36+
expected: true,
37+
},
38+
{
39+
input: "// since: Cosmos-SDK 0.50",
40+
expected: true,
41+
},
42+
{
43+
input: "// Since: cosmos-sdk v0.51",
44+
expected: false,
45+
},
46+
{
47+
input: "// Since: cosmos-sdk v1.0.0",
48+
expected: false,
49+
},
50+
{
51+
input: "// since: x/feegrant v0.1.0",
52+
expected: true,
53+
},
54+
{
55+
input: "// since: feegrant v0.0.1",
56+
expected: true,
57+
},
58+
{
59+
input: "// since: feegrant v0.1.0",
60+
expected: true,
61+
},
62+
{
63+
input: "// since: feegrant v0.1",
64+
expected: true,
65+
},
66+
{
67+
input: "// since: feegrant v0.1.1",
68+
expected: false,
69+
},
70+
{
71+
input: "// since: feegrant v0.2.0",
72+
expected: false,
73+
},
74+
}
75+
76+
for _, tc := range cases {
77+
resp := isSupportedVersion(tc.input, mockBuildInfo)
78+
if resp != tc.expected {
79+
t.Errorf("expected %v, got %v", tc.expected, resp)
80+
}
81+
82+
resp = isSupportedVersion(tc.input, &debug.BuildInfo{})
83+
if !resp {
84+
t.Errorf("expected %v, got %v", true, resp)
85+
}
86+
}
87+
}
88+
89+
func TestParseSinceComment(t *testing.T) {
90+
cases := []struct {
91+
input string
92+
expectedModuleName string
93+
expectedVersion string
94+
}{
95+
{
96+
input: "",
97+
expectedModuleName: "",
98+
expectedVersion: "",
99+
},
100+
{
101+
input: "not a since comment",
102+
expectedModuleName: "",
103+
expectedVersion: "",
104+
},
105+
{
106+
input: "// Since: Cosmos SDK 0.50",
107+
expectedModuleName: "cosmos-sdk",
108+
expectedVersion: "v0.50",
109+
},
110+
{
111+
input: "// since: Cosmos SDK 0.50",
112+
expectedModuleName: "cosmos-sdk",
113+
expectedVersion: "v0.50",
114+
},
115+
{
116+
input: "// since: cosmos sdk 0.50",
117+
expectedModuleName: "cosmos-sdk",
118+
expectedVersion: "v0.50",
119+
},
120+
{
121+
input: "// since: Cosmos-SDK 0.50",
122+
expectedModuleName: "cosmos-sdk",
123+
expectedVersion: "v0.50",
124+
},
125+
{
126+
input: "// Since: cosmos-sdk v0.50",
127+
expectedModuleName: "cosmos-sdk",
128+
expectedVersion: "v0.50",
129+
},
130+
{
131+
input: "//since: cosmos-sdk v0.50.1",
132+
expectedModuleName: "cosmos-sdk",
133+
expectedVersion: "v0.50.1",
134+
},
135+
{
136+
input: "// since: cosmos-sdk 0.47.0-veronica",
137+
expectedModuleName: "cosmos-sdk",
138+
expectedVersion: "v0.47.0-veronica",
139+
},
140+
{
141+
input: "// Since: x/feegrant v0.1.0",
142+
expectedModuleName: "x/feegrant",
143+
expectedVersion: "v0.1.0",
144+
},
145+
{
146+
input: "// since: x/feegrant 0.1",
147+
expectedModuleName: "x/feegrant",
148+
expectedVersion: "v0.1",
149+
},
150+
}
151+
152+
for _, tc := range cases {
153+
moduleName, version := parseSinceComment(tc.input)
154+
if moduleName != tc.expectedModuleName {
155+
t.Errorf("expected module name %s, got %s", tc.expectedModuleName, moduleName)
156+
}
157+
if version != tc.expectedVersion {
158+
t.Errorf("expected version %s, got %s", tc.expectedVersion, version)
159+
}
160+
}
161+
}

0 commit comments

Comments
 (0)