Skip to content

Commit

Permalink
Merge branch 'main' into refactor/plugins-config-file
Browse files Browse the repository at this point in the history
  • Loading branch information
jeronimoalbi committed Sep 27, 2023
2 parents a92c94f + fa47220 commit 919e72e
Show file tree
Hide file tree
Showing 14 changed files with 364 additions and 13 deletions.
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- [#3559](https://github.com/ignite/cli/pull/3559) Bump network plugin version to `v0.1.1`
- [#3522](https://github.com/ignite/cli/pull/3522) Remove indentation from `chain serve` output
- [#3601](https://github.com/ignite/cli/pull/3601) Update ts-relayer version to `0.10.0`
- [#3658](https://github.com/ignite/cli/pull/3658) Rename Marshaler to Codec in EncodingConfig
- [#3653](https://github.com/ignite/cli/pull/3653) Add "app" extension to plugin binaries
- [#3656](https://github.com/ignite/cli/pull/3656) Disable Go toolchain download
- [#3669](https://github.com/ignite/cli/pull/3669) Rename `plugins` config file to `igniteapps`
Expand All @@ -25,6 +26,7 @@
- [#3610](https://github.com/ignite/cli/pull/3610) Fix overflow issue of cosmos faucet in `pkg/cosmosfaucet/transfer.go` and `pkg/cosmosfaucet/cosmosfaucet.go`
- [#3618](https://github.com/ignite/cli/pull/3618) Fix TS client generation import path issue
- [#3631](https://github.com/ignite/cli/pull/3631) Fix unnecessary vue import in hooks/composables template
- [#3661](https://github.com/ignite/cli/pull/3661) Change `pkg/cosmosanalysis` to find Cosmos SDK runtime app registered modules

## [`v0.27.0`](https://github.com/ignite/cli/releases/tag/v0.27.0)

Expand Down
148 changes: 145 additions & 3 deletions ignite/pkg/cosmosanalysis/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,23 @@ import (
"go/format"
"go/parser"
"go/token"
"os"
"path/filepath"

"github.com/pkg/errors"

"github.com/ignite/cli/ignite/pkg/cosmosanalysis"
"github.com/ignite/cli/ignite/pkg/cosmosver"
"github.com/ignite/cli/ignite/pkg/goanalysis"
"github.com/ignite/cli/ignite/pkg/goenv"
"github.com/ignite/cli/ignite/pkg/gomodule"
"github.com/ignite/cli/ignite/pkg/xast"
)

const (
appWiringImport = "cosmossdk.io/depinject"
appWiringCallMethod = "Inject"
appWiringImport = "cosmossdk.io/depinject"
appWiringCallMethod = "Inject"
registerRoutesMethod = "RegisterAPIRoutes"
)

// CheckKeeper checks for the existence of the keeper with the provided name in the app structure.
Expand Down Expand Up @@ -96,6 +101,10 @@ func FindRegisteredModules(chainRoot string) (modules []string, err error) {
return nil, err
}

// The modules registered by Cosmos SDK `rumtime.App` are included
// when the app registers API modules though the `App` instance.
var includeRuntimeModules bool

// Loop on package's files
for _, f := range appPkg.Files {
fileImports := goanalysis.FormatImports(f)
Expand All @@ -118,6 +127,11 @@ func FindRegisteredModules(chainRoot string) (modules []string, err error) {
return xast.ErrStop
}

// Check if Cosmos SDK runtime App is called to register API routes
if !includeRuntimeModules {
includeRuntimeModules = checkRuntimeAppCalled(n)
}

// Find modules in RegisterAPIRoutes declaration
if pkgs := findRegisterAPIRoutesRegistrations(n); pkgs != nil {
for _, p := range pkgs {
Expand All @@ -127,6 +141,7 @@ func FindRegisteredModules(chainRoot string) (modules []string, err error) {
}
modules = append(modules, importModule)
}

return xast.ErrStop
}

Expand All @@ -136,6 +151,19 @@ func FindRegisteredModules(chainRoot string) (modules []string, err error) {
return nil, err
}
}

// Try to find the modules registered in Cosmos SDK `runtime.App`.
// This is required to properly generate OpenAPI specs for these
// modules when `app.App.RegisterAPIRoutes` is called.
if includeRuntimeModules {
runtimeModules, err := findRuntimeRegisteredModules(chainRoot)
if err != nil {
return nil, err
}

modules = append(modules, runtimeModules...)
}

return modules, nil
}

Expand Down Expand Up @@ -270,7 +298,7 @@ func findRegisterAPIRoutesRegistrations(n ast.Node) []string {
return nil
}

if funcLitType.Name.Name != "RegisterAPIRoutes" {
if funcLitType.Name.Name != registerRoutesMethod {
return nil
}

Expand Down Expand Up @@ -306,3 +334,117 @@ func findRegisterAPIRoutesRegistrations(n ast.Node) []string {

return packagesRegistered
}

func checkRuntimeAppCalled(n ast.Node) bool {
funcLitType, ok := n.(*ast.FuncDecl)
if !ok {
return false
}

if funcLitType.Name.Name != registerRoutesMethod {
return false
}

for _, stmt := range funcLitType.Body.List {
exprStmt, ok := stmt.(*ast.ExprStmt)
if !ok {
continue
}

exprCall, ok := exprStmt.X.(*ast.CallExpr)
if !ok {
continue
}

exprFun, ok := exprCall.Fun.(*ast.SelectorExpr)
if !ok || exprFun.Sel.Name != registerRoutesMethod {
continue
}

exprSel, ok := exprFun.X.(*ast.SelectorExpr)
if !ok || exprSel.Sel.Name != "App" {
continue
}

identType, ok := exprSel.X.(*ast.Ident)
if !ok || identType.Name != "app" {
continue
}

return true
}

return false
}

func findRuntimeRegisteredModules(chainRoot string) ([]string, error) {
// Resolve the absolute path to the Cosmos SDK module
cosmosPath, err := resolveCosmosPackagePath(chainRoot)
if err != nil {
return nil, err
}

var modules []string

// When runtime package doesn't exists it means is an older Cosmos SDK version,
// so all the module API registrations are defined within user's app.
path := filepath.Join(cosmosPath, "runtime", "app.go")
if _, err := os.Stat(path); os.IsNotExist(err) {
return modules, nil
}

f, _, err := xast.ParseFile(path)
if err != nil {
return nil, err
}

imports := goanalysis.FormatImports(f)
err = xast.Inspect(f, func(n ast.Node) error {
if pkgs := findRegisterAPIRoutesRegistrations(n); pkgs != nil {
for _, p := range pkgs {
if m := imports[p]; m != "" {
modules = append(modules, m)
}
}
return xast.ErrStop
}
return nil
})

if err != nil {
return nil, err
}
return modules, nil
}

func resolveCosmosPackagePath(chainRoot string) (string, error) {
modFile, err := gomodule.ParseAt(chainRoot)
if err != nil {
return "", err
}

deps, err := gomodule.ResolveDependencies(modFile)
if err != nil {
return "", err
}

var pkg string
for _, dep := range deps {
if dep.Path == cosmosver.CosmosModulePath {
pkg = dep.String()
break
}
}

if pkg == "" {
return "", errors.New("Cosmos SDK package version not found")
}

// Check path of the package directory within Go's module cache
path := filepath.Join(goenv.GoModCache(), pkg)
info, err := os.Stat(path)
if os.IsNotExist(err) || !info.IsDir() {
return "", errors.New("local path to Cosmos SDK package not found")
}
return path, nil
}
11 changes: 11 additions & 0 deletions ignite/pkg/cosmosanalysis/app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,17 @@ func TestFindRegisteredModules(t *testing.T) {
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice",
),
},
{
name: "with runtime api routes",
path: "testdata/modules/runtime_api_routes",
expectedModules: append(
basicModules,
"github.com/cosmos/cosmos-sdk/x/auth/tx",
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice",
"github.com/username/test/x/foo",
"github.com/cosmos/cosmos-sdk/client/grpc/node",
),
},
{
name: "same file function",
path: "testdata/modules/file_function",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package app

import (
"cosmossdk.io/api/tendermint/abci"
"cosmossdk.io/client/v2/autocli"
"github.com/cosmos/cosmos-sdk/client"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/runtime"
"github.com/cosmos/cosmos-sdk/server/api"
"github.com/cosmos/cosmos-sdk/server/config"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/gov"
govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
paramsclient "github.com/cosmos/cosmos-sdk/x/params/client"
"github.com/cosmos/cosmos-sdk/x/staking"
foomodule "github.com/username/test/x/foo"
)

// App modules are defined as NewBasicManager arguments
var ModuleBasics = module.NewBasicManager(
auth.AppModuleBasic{},
bank.AppModuleBasic{},
staking.AppModuleBasic{},
gov.NewAppModuleBasic([]govclient.ProposalHandler{
paramsclient.ProposalHandler,
}),
foomodule.AppModuleBasic{},
)

type Foo struct {
*runtime.App
}

func (Foo) Name() string { return "foo" }
func (Foo) InterfaceRegistry() codectypes.InterfaceRegistry { return nil }
func (Foo) TxConfig() client.TxConfig { return nil }
func (Foo) AutoCliOpts() autocli.AppOptions { return autocli.AppOptions{} }

func (Foo) BeginBlocker(sdk.Context, abci.RequestBeginBlock) abci.ResponseBeginBlock {
return abci.ResponseBeginBlock{}
}

func (Foo) EndBlocker(sdk.Context, abci.RequestEndBlock) abci.ResponseEndBlock {
return abci.ResponseEndBlock{}
}

func (app *Foo) RegisterAPIRoutes(s *api.Server, cfg config.APIConfig) {
// This module should be discovered
foomodule.RegisterGRPCGatewayRoutes(s.ClientCtx, s.GRPCGatewayRouter)
// Runtime app modules for the current Cosmos SDK should be discovered too
app.App.RegisterAPIRoutes(apiSvr, apiConfig)
}

func (Foo) GetKey(storeKey string) *storetypes.KVStoreKey { return nil }

func (Foo) TxConfig() client.TxConfig { return nil }
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module app

go 1.20

require (
cosmossdk.io/api v0.3.1
cosmossdk.io/core v0.5.1
cosmossdk.io/depinject v1.0.0-alpha.3
cosmossdk.io/errors v1.0.0-beta.7
cosmossdk.io/math v1.0.1
github.com/bufbuild/buf v1.23.1
github.com/cometbft/cometbft v0.37.2
github.com/cometbft/cometbft-db v0.8.0
github.com/cosmos/cosmos-proto v1.0.0-beta.2
github.com/cosmos/cosmos-sdk v0.47.3
github.com/cosmos/gogoproto v1.4.10
github.com/cosmos/ibc-go/v7 v7.2.0
github.com/golang/protobuf v1.5.3
github.com/gorilla/mux v1.8.0
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2
github.com/spf13/cast v1.5.1
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.4
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1
google.golang.org/grpc v1.55.0
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0
google.golang.org/protobuf v1.31.0
)

replace (
// use cosmos fork of keyring
github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0
// replace broken goleveldb
github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
)
19 changes: 19 additions & 0 deletions ignite/pkg/gocmd/gocmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ const (
// CommandEnv represents go "env" command.
CommandEnv = "env"

// CommandList represents go "list" command.
CommandList = "list"

// EnvGOARCH represents GOARCH variable.
EnvGOARCH = "GOARCH"
// EnvGOMOD represents GOMOD variable.
Expand Down Expand Up @@ -168,6 +171,22 @@ func Get(ctx context.Context, path string, pkgs []string, options ...exec.Option
return exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)))...)
}

// List returns the list of packages in path.
func List(ctx context.Context, path string, flags []string, options ...exec.Option) ([]string, error) {
command := []string{
Name(),
CommandList,
}
command = append(command, flags...)
var b bytes.Buffer
err := exec.Exec(ctx, command,
append(options, exec.StepOption(step.Workdir(path)), exec.StepOption(step.Stdout(&b)))...)
if err != nil {
return nil, err
}
return strings.Fields(b.String()), nil
}

// Ldflags returns a combined ldflags set from flags.
func Ldflags(flags ...string) string {
return strings.Join(flags, " ")
Expand Down
13 changes: 13 additions & 0 deletions ignite/pkg/gocmd/gocmd_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package gocmd_test

import (
"context"
"errors"
"os"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -16,3 +18,14 @@ func TestIsInstallError(t *testing.T) {
go get github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2`)
assert.True(t, gocmd.IsInstallError(err))
}

func TestList(t *testing.T) {
wd, err := os.Getwd()
assert.NoError(t, err)

ctx := context.Background()
packages, err := gocmd.List(ctx, wd, []string{"-m", "-f={{.Path}}", "github.com/ignite/cli"})
assert.NoError(t, err)

assert.Contains(t, packages, "github.com/ignite/cli")
}
Loading

0 comments on commit 919e72e

Please sign in to comment.