diff --git a/changelog.md b/changelog.md index fbe70ea023..a87f47668f 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,9 @@ ### Features +- [#4019](https://github.com/ignite/cli/pull/4019) Add `skip-proto` flag to `s chain` command +- [#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 - [#3985](https://github.com/ignite/cli/pull/3985) Make some `cmd` pkg functions public - [#3956](https://github.com/ignite/cli/pull/3956) Prepare for wasm app - [#3660](https://github.com/ignite/cli/pull/3660) Add ability to scaffold ICS consumer chain diff --git a/ignite/cmd/scaffold_chain.go b/ignite/cmd/scaffold_chain.go index 3e2719a3d9..e1eeccdea6 100644 --- a/ignite/cmd/scaffold_chain.go +++ b/ignite/cmd/scaffold_chain.go @@ -83,6 +83,7 @@ about Cosmos SDK on https://docs.cosmos.network c.Flags().Bool(flagNoDefaultModule, false, "create a project without a default module") c.Flags().StringSlice(flagParams, []string{}, "add default module parameters") c.Flags().Bool(flagSkipGit, false, "skip Git repository initialization") + c.Flags().Bool(flagSkipProto, false, "skip proto generation") c.Flags().Bool(flagMinimal, false, "create a minimal blockchain (with the minimum required Cosmos SDK modules)") c.Flags().Bool(flagIsConsumer, false, "scafffold an ICS consumer chain") // Cannot have both minimal and consumer flag @@ -104,6 +105,11 @@ func scaffoldChainHandler(cmd *cobra.Command, args []string) error { minimal, _ = cmd.Flags().GetBool(flagMinimal) isConsumer, _ = cmd.Flags().GetBool(flagIsConsumer) params, _ = cmd.Flags().GetStringSlice(flagParams) +<<<<<<< HEAD +======= + moduleConfigs, _ = cmd.Flags().GetStringSlice(flagModuleConfigs) + skipProto, _ = cmd.Flags().GetBool(flagSkipProto) +>>>>>>> c05237b5 (feat(cli): add `skip-proto` flag to `s chain` command (#4019)) ) if noDefaultModule && len(params) > 0 { @@ -124,6 +130,7 @@ func scaffoldChainHandler(cmd *cobra.Command, args []string) error { addressPrefix, noDefaultModule, skipGit, + skipProto, minimal, isConsumer, params, diff --git a/ignite/services/scaffolder/configs.go b/ignite/services/scaffolder/configs.go new file mode 100644 index 0000000000..bba68673f6 --- /dev/null +++ b/ignite/services/scaffolder/configs.go @@ -0,0 +1,95 @@ +package scaffolder + +import ( + "context" + "path/filepath" + "strings" + + "github.com/gobuffalo/genny/v2" + + "github.com/ignite/cli/v28/ignite/pkg/cache" + "github.com/ignite/cli/v28/ignite/pkg/errors" + "github.com/ignite/cli/v28/ignite/pkg/goanalysis" + "github.com/ignite/cli/v28/ignite/pkg/multiformatname" + "github.com/ignite/cli/v28/ignite/pkg/placeholder" + "github.com/ignite/cli/v28/ignite/pkg/xgenny" + "github.com/ignite/cli/v28/ignite/templates/field" + modulecreate "github.com/ignite/cli/v28/ignite/templates/module/create" +) + +// CreateConfigs creates a new configs in the scaffolded module. +func (s Scaffolder) CreateConfigs( + ctx context.Context, + cacheStorage cache.Storage, + tracer *placeholder.Tracer, + moduleName string, + configs ...string, +) (sm xgenny.SourceModification, err error) { + appName := s.modpath.Package + // If no module is provided, we add the type to the app's module + if moduleName == "" { + moduleName = s.modpath.Package + } + mfName, err := multiformatname.NewName(moduleName, multiformatname.NoNumber) + if err != nil { + return sm, err + } + moduleName = mfName.LowerCase + + // Check if the module already exist + ok, err := moduleExists(s.path, moduleName) + if err != nil { + return sm, err + } + if !ok { + return sm, errors.Errorf("the module %v not exist", moduleName) + } + + if err := checkConfigCreated(s.path, appName, moduleName, configs); err != nil { + return sm, err + } + + // Parse config with the associated type + configsFields, err := field.ParseFields(configs, checkForbiddenTypeIndex) + if err != nil { + return sm, err + } + + opts := modulecreate.ConfigsOptions{ + ModuleName: moduleName, + Configs: configsFields, + AppName: s.modpath.Package, + AppPath: s.path, + } + + g, err := modulecreate.NewModuleConfigs(opts) + if err != nil { + return sm, err + } + gens := []*genny.Generator{g} + + sm, err = xgenny.RunWithValidation(tracer, gens...) + if err != nil { + return sm, err + } + + return sm, finish(ctx, cacheStorage, opts.AppPath, s.modpath.RawPath, false) +} + +// checkConfigCreated checks if the config has been already created. +func checkConfigCreated(appPath, appName, moduleName string, configs []string) (err error) { + path := filepath.Join(appPath, "api", appName, moduleName, "module") + ok, err := goanalysis.HasAnyStructFieldsInPkg(path, "Module", configs) + if err != nil { + return err + } + + if ok { + return errors.Errorf( + "duplicated configs (%s) module %s", + strings.Join(configs, " "), + moduleName, + ) + } + return nil +} diff --git a/ignite/services/scaffolder/init.go b/ignite/services/scaffolder/init.go index 53d1d41a5e..9e26609dd9 100644 --- a/ignite/services/scaffolder/init.go +++ b/ignite/services/scaffolder/init.go @@ -25,8 +25,13 @@ func Init( cacheStorage cache.Storage, tracer *placeholder.Tracer, root, name, addressPrefix string, +<<<<<<< HEAD noDefaultModule, skipGit, minimal, isConsumerChain bool, params []string, +======= + noDefaultModule, skipGit, skipProto, minimal, isConsumerChain bool, + params, moduleConfigs []string, +>>>>>>> c05237b5 (feat(cli): add `skip-proto` flag to `s chain` command (#4019)) ) (path string, err error) { pathInfo, err := gomodulepath.Parse(name) if err != nil { @@ -60,8 +65,7 @@ func Init( return "", err } - err = finish(ctx, cacheStorage, path, pathInfo.RawPath) - if err != nil { + if err = finish(ctx, cacheStorage, path, pathInfo.RawPath, skipProto); err != nil { return "", err } diff --git a/ignite/services/scaffolder/message.go b/ignite/services/scaffolder/message.go index f3e167f4f7..3d49028662 100644 --- a/ignite/services/scaffolder/message.go +++ b/ignite/services/scaffolder/message.go @@ -158,7 +158,7 @@ func (s Scaffolder) AddMessage( if err != nil { return sm, err } - return sm, finish(ctx, cacheStorage, opts.AppPath, s.modpath.RawPath) + return sm, finish(ctx, cacheStorage, opts.AppPath, s.modpath.RawPath, false) } // checkForbiddenMessageField returns true if the name is forbidden as a message name. diff --git a/ignite/services/scaffolder/module.go b/ignite/services/scaffolder/module.go index 6840b2732a..9998ada646 100644 --- a/ignite/services/scaffolder/module.go +++ b/ignite/services/scaffolder/module.go @@ -240,7 +240,7 @@ func (s Scaffolder) CreateModule( return sm, runErr } - return sm, finish(ctx, cacheStorage, opts.AppPath, s.modpath.RawPath) + return sm, finish(ctx, cacheStorage, opts.AppPath, s.modpath.RawPath, false) } // moduleExists checks if the module exists in the app. diff --git a/ignite/services/scaffolder/packet.go b/ignite/services/scaffolder/packet.go index f914d5741b..87088e7c80 100644 --- a/ignite/services/scaffolder/packet.go +++ b/ignite/services/scaffolder/packet.go @@ -143,7 +143,7 @@ func (s Scaffolder) AddPacket( if err != nil { return sm, err } - return sm, finish(ctx, cacheStorage, opts.AppPath, s.modpath.RawPath) + return sm, finish(ctx, cacheStorage, opts.AppPath, s.modpath.RawPath, false) } // isIBCModule returns true if the provided module implements the IBC module interface diff --git a/ignite/services/scaffolder/params.go b/ignite/services/scaffolder/params.go new file mode 100644 index 0000000000..2b67424644 --- /dev/null +++ b/ignite/services/scaffolder/params.go @@ -0,0 +1,94 @@ +package scaffolder + +import ( + "context" + "path/filepath" + "strings" + + "github.com/gobuffalo/genny/v2" + + "github.com/ignite/cli/v28/ignite/pkg/cache" + "github.com/ignite/cli/v28/ignite/pkg/errors" + "github.com/ignite/cli/v28/ignite/pkg/goanalysis" + "github.com/ignite/cli/v28/ignite/pkg/multiformatname" + "github.com/ignite/cli/v28/ignite/pkg/placeholder" + "github.com/ignite/cli/v28/ignite/pkg/xgenny" + "github.com/ignite/cli/v28/ignite/templates/field" + modulecreate "github.com/ignite/cli/v28/ignite/templates/module/create" +) + +// CreateParams creates a new params in the scaffolded module. +func (s Scaffolder) CreateParams( + ctx context.Context, + cacheStorage cache.Storage, + tracer *placeholder.Tracer, + moduleName string, + params ...string, +) (sm xgenny.SourceModification, err error) { + // If no module is provided, we add the type to the app's module + if moduleName == "" { + moduleName = s.modpath.Package + } + mfName, err := multiformatname.NewName(moduleName, multiformatname.NoNumber) + if err != nil { + return sm, err + } + moduleName = mfName.LowerCase + + // Check if the module already exist + ok, err := moduleExists(s.path, moduleName) + if err != nil { + return sm, err + } + if !ok { + return sm, errors.Errorf("the module %v not exist", moduleName) + } + + if err := checkParamCreated(s.path, moduleName, params); err != nil { + return sm, err + } + + // Parse params with the associated type + paramsFields, err := field.ParseFields(params, checkForbiddenTypeIndex) + if err != nil { + return sm, err + } + + opts := modulecreate.ParamsOptions{ + ModuleName: moduleName, + Params: paramsFields, + AppName: s.modpath.Package, + AppPath: s.path, + } + + g, err := modulecreate.NewModuleParam(opts) + if err != nil { + return sm, err + } + gens := []*genny.Generator{g} + + sm, err = xgenny.RunWithValidation(tracer, gens...) + if err != nil { + return sm, err + } + + return sm, finish(ctx, cacheStorage, opts.AppPath, s.modpath.RawPath, false) +} + +// checkParamCreated checks if the parameter has been already created. +func checkParamCreated(appPath, moduleName string, params []string) error { + path := filepath.Join(appPath, "x", moduleName, "types") + ok, err := goanalysis.HasAnyStructFieldsInPkg(path, "Params", params) + if err != nil { + return err + } + + if ok { + return errors.Errorf( + "duplicated params (%s) module %s", + strings.Join(params, " "), + moduleName, + ) + } + return nil +} diff --git a/ignite/services/scaffolder/query.go b/ignite/services/scaffolder/query.go index 7279abebe3..610f72a486 100644 --- a/ignite/services/scaffolder/query.go +++ b/ignite/services/scaffolder/query.go @@ -87,5 +87,5 @@ func (s Scaffolder) AddQuery( if err != nil { return sm, err } - return sm, finish(ctx, cacheStorage, opts.AppPath, s.modpath.RawPath) + return sm, finish(ctx, cacheStorage, opts.AppPath, s.modpath.RawPath, false) } diff --git a/ignite/services/scaffolder/scaffolder.go b/ignite/services/scaffolder/scaffolder.go index 4b2c5a9e54..3d765de913 100644 --- a/ignite/services/scaffolder/scaffolder.go +++ b/ignite/services/scaffolder/scaffolder.go @@ -63,10 +63,11 @@ func New(appPath string) (Scaffolder, error) { return s, nil } -func finish(ctx context.Context, cacheStorage cache.Storage, path, gomodPath string) error { - err := protoc(ctx, cacheStorage, path, gomodPath) - if err != nil { - return err +func finish(ctx context.Context, cacheStorage cache.Storage, path, gomodPath string, skipProto bool) error { + if !skipProto { + if err := protoc(ctx, cacheStorage, path, gomodPath); err != nil { + return err + } } if err := gocmd.Fmt(ctx, path); err != nil { diff --git a/ignite/services/scaffolder/type.go b/ignite/services/scaffolder/type.go index 43112d6a6f..d806b8d92c 100644 --- a/ignite/services/scaffolder/type.go +++ b/ignite/services/scaffolder/type.go @@ -219,7 +219,7 @@ func (s Scaffolder) AddType( return sm, err } - return sm, finish(ctx, cacheStorage, opts.AppPath, s.modpath.RawPath) + return sm, finish(ctx, cacheStorage, opts.AppPath, s.modpath.RawPath, false) } // checkForbiddenTypeIndex returns true if the name is forbidden as a index name. diff --git a/ignite/templates/app/files/app/ibc.go.plush b/ignite/templates/app/files/app/ibc.go.plush index 9b82bc7b91..f235cd1c65 100644 --- a/ignite/templates/app/files/app/ibc.go.plush +++ b/ignite/templates/app/files/app/ibc.go.plush @@ -4,6 +4,7 @@ import ( "cosmossdk.io/core/appmodule" storetypes "cosmossdk.io/store/types" cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + servertypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/types/module" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"