Skip to content

Commit

Permalink
feat: add scaffold configs and scaffold params commands and start…
Browse files Browse the repository at this point in the history
… remove placeholders (#3770)

* add parameters placeholders and modifier

* add scaffold params command

* add changelog

* check if the parameter already exist

* add integration tests and fix some import issues

* improve the scaffolder logic

* improve the log message

* fix the log message

* fix changelog

* fix 28 imports

* remove params module

* add module configs command

* rollbak empty line for proto

* improve code readbility and add unit tests

* fix changelog

* use cli error package

* Update ignite/cmd/scaffold_configs.go

Co-authored-by: Jerónimo Albi <[email protected]>

* apply pr suggestions

* fix some typos

* remove unused vars and casting

* add replacer pkg for goanalysis

* add TODO comment

* add modify call function

* test readbility

* improve organization

* fix the function modifier logic

* fix the arg idente for caller replace

* add more test cases and last fixes

* start replace the params template to the xast

* add append struct param option

* add support to add new struct params

* fix some lint issues

* add small fixes and improve code readbility

* fix append code parser

* fix changelog

---------

Co-authored-by: Pantani <Pantani>
Co-authored-by: Jerónimo Albi <[email protected]>
  • Loading branch information
2 people authored and julienrbrt committed May 29, 2024
1 parent 002c99d commit 1a276fd
Show file tree
Hide file tree
Showing 33 changed files with 2,614 additions and 70 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Features

- [#3977](https://github.com/ignite/cli/pull/3977) Add `chain lint` command to lint the chain's codebase using `golangci-lint`
- [#3770](https://github.com/ignite/cli/pull/3770) Add `scaffold configs` and `scaffold params` commands

### Changes

Expand Down
3 changes: 2 additions & 1 deletion ignite/cmd/chain_lint.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package ignitecmd

import (
"github.com/spf13/cobra"

"github.com/ignite/cli/v28/ignite/pkg/cliui"
"github.com/ignite/cli/v28/ignite/services/chain"
"github.com/spf13/cobra"
)

// NewChainLint returns a lint command to build a blockchain app.
Expand Down
2 changes: 2 additions & 0 deletions ignite/cmd/scaffold.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ with an "--ibc" flag. Note that the default module is not IBC-enabled.
NewScaffoldMap(),
NewScaffoldSingle(),
NewScaffoldType(),
NewScaffoldParams(),
NewScaffoldConfigs(),
NewScaffoldMessage(),
NewScaffoldQuery(),
NewScaffoldPacket(),
Expand Down
11 changes: 9 additions & 2 deletions ignite/cmd/scaffold_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ about Cosmos SDK on https://docs.cosmos.network
c.Flags().StringP(flagPath, "p", "", "create a project in a specific path")
c.Flags().Bool(flagNoDefaultModule, false, "create a project without a default module")
c.Flags().StringSlice(flagParams, []string{}, "add default module parameters")
c.Flags().StringSlice(flagModuleConfigs, []string{}, "add module configs")
c.Flags().Bool(flagSkipGit, false, "skip Git repository initialization")
c.Flags().Bool(flagMinimal, false, "create a minimal blockchain (with the minimum required Cosmos SDK modules)")

Expand All @@ -98,10 +99,15 @@ func scaffoldChainHandler(cmd *cobra.Command, args []string) error {
skipGit, _ = cmd.Flags().GetBool(flagSkipGit)
minimal, _ = cmd.Flags().GetBool(flagMinimal)
params, _ = cmd.Flags().GetStringSlice(flagParams)
moduleConfigs, _ = cmd.Flags().GetStringSlice(flagModuleConfigs)
)

if noDefaultModule && len(params) > 0 {
return errors.New("params flag is only supported if the default module is enabled")
if noDefaultModule {
if len(params) > 0 {
return errors.New("params flag is only supported if the default module is enabled")
} else if len(moduleConfigs) > 0 {
return errors.New("module configs flag is only supported if the default module is enabled")
}
}

cacheStorage, err := newCache(cmd)
Expand All @@ -120,6 +126,7 @@ func scaffoldChainHandler(cmd *cobra.Command, args []string) error {
skipGit,
minimal,
params,
moduleConfigs,
)
if err != nil {
return err
Expand Down
79 changes: 79 additions & 0 deletions ignite/cmd/scaffold_configs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package ignitecmd

import (
"strings"

"github.com/spf13/cobra"

"github.com/ignite/cli/v28/ignite/pkg/cliui"
"github.com/ignite/cli/v28/ignite/pkg/placeholder"
"github.com/ignite/cli/v28/ignite/services/scaffolder"
)

// NewScaffoldConfigs returns the command to scaffold a Cosmos SDK configs into a module.
func NewScaffoldConfigs() *cobra.Command {
c := &cobra.Command{
Use: "configs [configs]...",
Short: "Configs for a custom Cosmos SDK module",
Long: `Scaffold a new config for a Cosmos SDK module.
A Cosmos SDK module can have configurations. An example of a config is "address prefix" of the
"auth" module. A config can be scaffolded into a module using the "--module-configs" into
the scaffold module command or using the "scaffold configs" command. By default
configs are of type "string", but you can specify a type for each config. For example:
ignite scaffold configs foo baz:uint bar:bool
Refer to Cosmos SDK documentation to learn more about modules, dependencies and
configs.
`,
Args: cobra.MinimumNArgs(1),
PreRunE: migrationPreRunHandler,
RunE: scaffoldConfigsHandler,
}

flagSetPath(c)
flagSetClearCache(c)

c.Flags().AddFlagSet(flagSetYes())

c.Flags().String(flagModule, "", "module to add the query into (default: app's main module)")

return c
}

func scaffoldConfigsHandler(cmd *cobra.Command, args []string) error {
var (
configs = args[0:]
appPath = flagGetPath(cmd)
moduleName = flagGetModule(cmd)
)

session := cliui.New(cliui.StartSpinnerWithText(statusScaffolding))
defer session.End()

cacheStorage, err := newCache(cmd)
if err != nil {
return err
}

sc, err := scaffolder.New(appPath)
if err != nil {
return err
}

sm, err := sc.CreateConfigs(cmd.Context(), cacheStorage, placeholder.New(), moduleName, configs...)
if err != nil {
return err
}

modificationsStr, err := sourceModificationToString(sm)
if err != nil {
return err
}

session.Println(modificationsStr)
session.Printf("\n🎉 New configs added to the module:\n\n- %s\n\n", strings.Join(configs, "\n- "))

return nil
}
8 changes: 8 additions & 0 deletions ignite/cmd/scaffold_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const (
flagDep = "dep"
flagIBC = "ibc"
flagParams = "params"
flagModuleConfigs = "module-configs"
flagIBCOrdering = "ordering"
flagRequireRegistration = "require-registration"

Expand Down Expand Up @@ -115,6 +116,7 @@ params.
c.Flags().String(flagIBCOrdering, "none", "channel ordering of the IBC module [none|ordered|unordered]")
c.Flags().Bool(flagRequireRegistration, false, "fail if module can't be registered")
c.Flags().StringSlice(flagParams, []string{}, "add module parameters")
c.Flags().StringSlice(flagModuleConfigs, []string{}, "add module configs")

return c
}
Expand All @@ -133,13 +135,19 @@ func scaffoldModuleHandler(cmd *cobra.Command, args []string) error {
requireRegistration, _ := cmd.Flags().GetBool(flagRequireRegistration)
params, _ := cmd.Flags().GetStringSlice(flagParams)

moduleConfigs, err := cmd.Flags().GetStringSlice(flagModuleConfigs)
if err != nil {
return err
}

cacheStorage, err := newCache(cmd)
if err != nil {
return err
}

options := []scaffolder.ModuleCreationOption{
scaffolder.WithParams(params),
scaffolder.WithModuleConfigs(moduleConfigs),
}

// Check if the module must be an IBC module
Expand Down
81 changes: 81 additions & 0 deletions ignite/cmd/scaffold_params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package ignitecmd

import (
"strings"

"github.com/spf13/cobra"

"github.com/ignite/cli/v28/ignite/pkg/cliui"
"github.com/ignite/cli/v28/ignite/pkg/placeholder"
"github.com/ignite/cli/v28/ignite/services/scaffolder"
)

// NewScaffoldParams returns the command to scaffold a Cosmos SDK parameters into a module.
func NewScaffoldParams() *cobra.Command {
c := &cobra.Command{
Use: "params [param]...",
Short: "Parameters for a custom Cosmos SDK module",
Long: `Scaffold a new parameter for a Cosmos SDK module.
A Cosmos SDK module can have parameters (or "params"). Params are values that
can be set at the genesis of the blockchain and can be modified while the
blockchain is running. An example of a param is "Inflation rate change" of the
"mint" module. A params can be scaffolded into a module using the "--params" into
the scaffold module command or using the "scaffold params" command. By default
params are of type "string", but you can specify a type for each param. For example:
ignite scaffold params foo baz:uint bar:bool
Refer to Cosmos SDK documentation to learn more about modules, dependencies and
params.
`,
Args: cobra.MinimumNArgs(1),
PreRunE: migrationPreRunHandler,
RunE: scaffoldParamsHandler,
}

flagSetPath(c)
flagSetClearCache(c)

c.Flags().AddFlagSet(flagSetYes())

c.Flags().String(flagModule, "", "module to add the query into. Default: app's main module")

return c
}

func scaffoldParamsHandler(cmd *cobra.Command, args []string) error {
var (
params = args[0:]
appPath = flagGetPath(cmd)
moduleName = flagGetModule(cmd)
)

session := cliui.New(cliui.StartSpinnerWithText(statusScaffolding))
defer session.End()

cacheStorage, err := newCache(cmd)
if err != nil {
return err
}

sc, err := scaffolder.New(appPath)
if err != nil {
return err
}

sm, err := sc.CreateParams(cmd.Context(), cacheStorage, placeholder.New(), moduleName, params...)
if err != nil {
return err
}

modificationsStr, err := sourceModificationToString(sm)
if err != nil {
return err
}

session.Println(modificationsStr)
session.Printf("\n🎉 New parameters added to the module:\n\n- %s\n\n", strings.Join(params, "\n- "))

return nil
}
56 changes: 56 additions & 0 deletions ignite/pkg/goanalysis/goanalysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,3 +338,59 @@ func ReplaceCode(pkgPath, oldFunctionName, newFunction string) (err error) {
}
return nil
}

// HasAnyStructFieldsInPkg finds the struct within a package folder and checks
// if any of the fields are defined in the struct.
func HasAnyStructFieldsInPkg(pkgPath, structName string, fields []string) (bool, error) {
absPath, err := filepath.Abs(pkgPath)
if err != nil {
return false, err
}
fileSet := token.NewFileSet()
all, err := parser.ParseDir(fileSet, absPath, nil, parser.ParseComments)
if err != nil {
return false, err
}

fieldsNames := make(map[string]struct{})
for _, field := range fields {
fieldsNames[strings.ToLower(field)] = struct{}{}
}

exist := false
for _, pkg := range all {
for _, f := range pkg.Files {
ast.Inspect(f, func(x ast.Node) bool {
typeSpec, ok := x.(*ast.TypeSpec)
if !ok {
return true
}

if _, ok := typeSpec.Type.(*ast.StructType); !ok ||
typeSpec.Name.Name != structName ||
typeSpec.Type == nil {
return true
}

// Check if the struct has fields.
structType, ok := typeSpec.Type.(*ast.StructType)
if !ok {
return true
}

// Iterate through the fields of the struct.
for _, field := range structType.Fields.List {
for _, fieldName := range field.Names {
if _, ok := fieldsNames[strings.ToLower(fieldName.Name)]; !ok {
continue
}
exist = true
return false
}
}
return true
})
}
}
return exist, nil
}
Loading

0 comments on commit 1a276fd

Please sign in to comment.