Skip to content

Commit 03e8081

Browse files
Jerónimo AlbitbruyelleAlex Johnson
authored
feat(pkg/cosmosanalysis): support discovery of modules defined in a variable (#2820)
* feat: change module discovery to resolve modules from a variable * feat: change module discovery to resolve modules from a pkg variable The changeset resolves the modules defined in a variable within the same package but in a different file. * feat: change module discovery to resolve modules from a other pkg variable * feat: discover app modules created using a function call * refactor: simplify module discovery * chore: update changelog * chore: minor code improvements and documentation * fix: cosmosanalysis to work when proto Go import is missing version Some apps define the Go import path in the proto files without the version suffix while the Go module uses a version suffix. This change allows the custom module discovery to work in such case. * refactor: improve discovery for different custom module layouts Changeset modifies the module discovery to search inside custom module folders for the RPC services implementation. * fix: remove default from typescript client generate output flag * refactor: improve module discovery to work with versioned Go modules The change allows discovery for blockchain apps that are versioned. It also handles the cases where custom app modules are imported using a Go import that might or might not contain the version suffix. * feat: add `cosmos_proto` to protoc includes The protp package is required to generate code for other blockchains like Gaia, otherwise generation would fail because the proto option `cosmos_proto.scalar` won't be available while generating the typescript code for some cosmos SDK modules. Cosmos SDK removed the `cosmos_proto` from its third party proto includes in changeset cosmos/cosmos-sdk@0cb7fd0 * feat: add error support to `NewBasicManager` call discovery * review: add comment to basic manager discovery Co-authored-by: Thomas Bruyelle <thomas.bruyelle@gmail.com> * chore: fix syntax * fix CL * test: registered modules for osmosis * test: add test for standard module discovery cases This case discover registered modules registered as NewBasicManager function arguments. * test: add test for module discovery with API routes * tests: add tests for `cosmosanalysis` module helper functions * tests: add discovery test for versioned apps Blockchain apps are versioned when the import path in the `go.mod` file contains a version suffix. * test: registered modules for current spn, gaia and juno Co-authored-by: Thomas Bruyelle <thomas.bruyelle@gmail.com> Co-authored-by: Thomas Bruyelle <thomas.bruyelle@tendermint.com> Co-authored-by: Alex Johnson <alex@shmeeload.xyz>
1 parent 35201e3 commit 03e8081

File tree

28 files changed

+4645
-153
lines changed

28 files changed

+4645
-153
lines changed

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Changes
66

7+
- Updated `pkg/cosmosanalysis` to discover the list of app modules when defined in variables.
78
- Switch to broadcast mode sync in `cosmosclient`
89
- Updated `nodetime`: `ts-proto` to `v1.123.0`, `protobufjs` to `v7.1.1`, `swagger-typescript-api` to `v9.2.0`
910
- Switched codegen client to use `axios` instead of `fetch`

ignite/cmd/generate_typescript_client.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package ignitecmd
33
import (
44
"github.com/spf13/cobra"
55

6-
"github.com/ignite/cli/ignite/chainconfig"
76
"github.com/ignite/cli/ignite/pkg/cliui"
87
"github.com/ignite/cli/ignite/services/chain"
98
)
@@ -16,7 +15,7 @@ func NewGenerateTSClient() *cobra.Command {
1615
}
1716

1817
c.Flags().AddFlagSet(flagSetProto3rdParty(""))
19-
c.Flags().StringP(flagOutput, "o", chainconfig.DefaultTSClientPath, "typescript client output path")
18+
c.Flags().StringP(flagOutput, "o", "", "typescript client output path")
2019

2120
return c
2221
}

ignite/pkg/cosmosanalysis/app/app.go

Lines changed: 91 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package app
22

33
import (
4+
"bytes"
45
"errors"
56
"fmt"
67
"go/ast"
8+
"go/format"
79
"go/parser"
810
"go/token"
11+
"path/filepath"
912

1013
"github.com/ignite/cli/ignite/pkg/cosmosanalysis"
1114
"github.com/ignite/cli/ignite/pkg/goanalysis"
@@ -77,7 +80,7 @@ func CheckKeeper(path, keeperName string) error {
7780
// 1. Mapping out all the imports and named imports
7881
// 2. Looking for the call to module.NewBasicManager and finds the modules registered there
7982
// 3. Looking for the implementation of RegisterAPIRoutes and find the modules that call their RegisterGRPCGatewayRoutes
80-
func FindRegisteredModules(chainRoot string) ([]string, error) {
83+
func FindRegisteredModules(chainRoot string) (modules []string, err error) {
8184
appFilePath, err := cosmosanalysis.FindAppFilePath(chainRoot)
8285
if err != nil {
8386
return nil, err
@@ -99,24 +102,45 @@ func FindRegisteredModules(chainRoot string) ([]string, error) {
99102
return nil, err
100103
}
101104

102-
var basicModules []string
105+
// The directory where the app file is located.
106+
// This is required to resolve references within the app package.
107+
appDir := filepath.Dir(appFilePath)
108+
103109
ast.Inspect(f, func(n ast.Node) bool {
104-
if pkgsReg := findBasicManagerRegistrations(n, basicManagerModule); pkgsReg != nil {
105-
for _, rp := range pkgsReg {
106-
importModule := packages[rp]
107-
basicModules = append(basicModules, importModule)
110+
// Stop traversing the child nodes when there is an error
111+
if err != nil {
112+
return false
113+
}
114+
115+
var pkgs []string
116+
117+
pkgs, err = findBasicManagerRegistrations(n, basicManagerModule, appDir, packages)
118+
if err != nil {
119+
return false
120+
}
121+
122+
if pkgs != nil {
123+
for _, p := range pkgs {
124+
importModule := packages[p]
125+
if importModule == "" {
126+
// When the package is not defined in the same file use the package name as import
127+
importModule = p
128+
}
129+
130+
modules = append(modules, importModule)
108131
}
109132

110133
return false
111134
}
112135

113-
if pkgsReg := findRegisterAPIRoutersRegistrations(n); pkgsReg != nil {
114-
for _, rp := range pkgsReg {
115-
importModule := packages[rp]
136+
if pkgs = findRegisterAPIRoutersRegistrations(n); pkgs != nil {
137+
for _, p := range pkgs {
138+
importModule := packages[p]
116139
if importModule == "" {
117140
continue
118141
}
119-
basicModules = append(basicModules, importModule)
142+
143+
modules = append(modules, importModule)
120144
}
121145

122146
return false
@@ -125,56 +149,87 @@ func FindRegisteredModules(chainRoot string) ([]string, error) {
125149
return true
126150
})
127151

128-
return basicModules, nil
152+
return modules, err
153+
}
154+
155+
func exprToString(n ast.Expr) (string, error) {
156+
buf := bytes.Buffer{}
157+
fset := token.NewFileSet()
158+
159+
// Convert the expression node to Go
160+
if err := format.Node(&buf, fset, n); err != nil {
161+
return "", err
162+
}
163+
164+
return buf.String(), nil
165+
}
166+
167+
func newExprError(msg string, n ast.Expr) error {
168+
s, err := exprToString(n)
169+
if err != nil {
170+
return fmt.Errorf("%s: %w", msg, err)
171+
}
172+
173+
return fmt.Errorf("%s: %s", msg, s)
129174
}
130175

131-
func findBasicManagerRegistrations(n ast.Node, basicManagerModule string) []string {
176+
func findBasicManagerRegistrations(n ast.Node, basicManagerModule, pkgDir string, pkgs map[string]string) (packages []string, err error) {
132177
callExprType, ok := n.(*ast.CallExpr)
133178
if !ok {
134-
return nil
179+
return
135180
}
136181

137182
selectorExprType, ok := callExprType.Fun.(*ast.SelectorExpr)
138183
if !ok {
139-
return nil
184+
return
140185
}
141186

142187
identExprType, ok := selectorExprType.X.(*ast.Ident)
143188
if !ok || identExprType.Name != basicManagerModule || selectorExprType.Sel.Name != "NewBasicManager" {
144-
return nil
189+
return
145190
}
146191

147-
packagesRegistered := make([]string, len(callExprType.Args))
148-
for i, arg := range callExprType.Args {
149-
argAsCompositeLitType, ok := arg.(*ast.CompositeLit)
150-
if ok {
151-
compositeTypeSelectorExpr, ok := argAsCompositeLitType.Type.(*ast.SelectorExpr)
152-
if !ok {
153-
continue
192+
// Node "n" defines the call to NewBasicManager, let's loop on its args to discover modules
193+
for _, arg := range callExprType.Args {
194+
switch v := arg.(type) {
195+
case *ast.CompositeLit:
196+
// The arg is an app module
197+
p := parsePkgNameFromCompositeLit(v)
198+
if p == "" {
199+
return nil, newExprError("unexpected basic app module reference", arg)
154200
}
155201

156-
compositeTypeX, ok := compositeTypeSelectorExpr.X.(*ast.Ident)
157-
if ok {
158-
packagesRegistered[i] = compositeTypeX.Name
159-
continue
202+
packages = append(packages, p)
203+
case *ast.CallExpr:
204+
// The arg is a function call that returns the app module
205+
p := parsePkgNameFromCall(v)
206+
if p == "" {
207+
return nil, newExprError("unexpected basic app module function format", arg)
160208
}
161-
}
162209

163-
argAsCallType, ok := arg.(*ast.CallExpr)
164-
if ok {
165-
argAsFunctionType, ok := argAsCallType.Fun.(*ast.SelectorExpr)
166-
if !ok {
167-
continue
210+
packages = append(packages, p)
211+
case *ast.Ident:
212+
// The list of modules are defined in a local variable
213+
p := parseAppModulesFromIdent(v, pkgDir)
214+
if len(p) == 0 {
215+
return nil, newExprError("unsupported basic app modules variable format", arg)
168216
}
169217

170-
argX, ok := argAsFunctionType.X.(*ast.Ident)
171-
if ok {
172-
packagesRegistered[i] = argX.Name
218+
packages = append(packages, p...)
219+
case *ast.SelectorExpr:
220+
// The list of modules is defined in a variable of a different package
221+
p := parseAppModulesFromSelectorExpr(v, pkgDir, pkgs)
222+
if len(p) == 0 {
223+
return nil, newExprError("unsupported basic app modules variable reference", arg)
173224
}
225+
226+
packages = append(packages, p...)
227+
default:
228+
return nil, newExprError("unsupported NewBasicManager() argument format", arg)
174229
}
175230
}
176231

177-
return packagesRegistered
232+
return packages, nil
178233
}
179234

180235
func findBasicManagerModule(pkgs map[string]string) (string, error) {

0 commit comments

Comments
 (0)