Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ignite/cmd/scaffold.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ with an "--ibc" flag. Note that the default module is not IBC-enabled.
NewScaffoldTypeList(),
NewScaffoldChain(),
NewScaffoldModule(),
NewScaffoldMigration(),
NewScaffoldList(),
NewScaffoldMap(),
NewScaffoldSingle(),
Expand Down
78 changes: 78 additions & 0 deletions ignite/cmd/scaffold_migration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package ignitecmd

import (
"github.com/spf13/cobra"

"github.com/ignite/cli/v29/ignite/pkg/cache"
"github.com/ignite/cli/v29/ignite/pkg/cliui"
"github.com/ignite/cli/v29/ignite/pkg/xgenny"
"github.com/ignite/cli/v29/ignite/services/scaffolder"
)

// NewScaffoldMigration returns the command to scaffold a module migration.
func NewScaffoldMigration() *cobra.Command {
c := &cobra.Command{
Use: "migration [module] [name]",
Short: "Module migration boilerplate",
Long: `Scaffold no-op migration boilerplate for an existing Cosmos SDK module.

This command creates a new migration file in "x/<module>/migrations/vN/",
increments the module consensus version, and registers the new migration handler
inside "x/<module>/module/module.go".`,
Args: cobra.ExactArgs(2),
PreRunE: migrationPreRunHandler,
RunE: scaffoldMigrationHandler,
}

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

return c
}

func scaffoldMigrationHandler(cmd *cobra.Command, args []string) error {
var (
moduleName = args[0]
migrationName = args[1]
appPath = flagGetPath(cmd)
)

session := cliui.New(
cliui.StartSpinnerWithText(statusScaffolding),
cliui.WithoutUserInteraction(getYes(cmd)),
)
defer session.End()

cfg, _, err := getChainConfig(cmd)
if err != nil {
return err
}

sc, err := scaffolder.New(cmd.Context(), appPath, cfg.Build.Proto.Path)
if err != nil {
return err
}

if err := sc.CreateModuleMigration(moduleName, migrationName); err != nil {
return err
}

sm, err := sc.ApplyModifications(xgenny.ApplyPreRun(scaffolder.AskOverwriteFiles(session)))
if err != nil {
return err
}

if err := sc.PostScaffold(cmd.Context(), cache.Storage{}, true); err != nil {
return err
}

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

session.Println(modificationsStr)
session.Printf("\n🎉 Migration %s added to module %s.\n\n", migrationName, moduleName)

return nil
}
68 changes: 68 additions & 0 deletions ignite/services/scaffolder/migration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package scaffolder

import (
"os"
"path/filepath"

"github.com/ignite/cli/v29/ignite/pkg/errors"
"github.com/ignite/cli/v29/ignite/pkg/multiformatname"
modulemigration "github.com/ignite/cli/v29/ignite/templates/module/migration"
)

// CreateModuleMigration scaffolds a new module migration inside an existing module.
func (s Scaffolder) CreateModuleMigration(moduleName, migrationName string) error {
mfModuleName, err := multiformatname.NewName(moduleName, multiformatname.NoNumber)
if err != nil {
return err
}
moduleName = mfModuleName.LowerCase

mfMigrationName, err := multiformatname.NewName(migrationName)
if err != nil {
return err
}
if err := checkGoReservedWord(mfMigrationName.LowerCamel); err != nil {
return errors.Errorf("%s can't be used as a migration name: %w", migrationName, err)
}

ok, err := moduleExists(s.appPath, moduleName)
if err != nil {
return err
}
if !ok {
return errors.Errorf("the module %s doesn't exist", moduleName)
}

moduleFilePath := filepath.Join(s.appPath, moduleDir, moduleName, modulePkg, "module.go")
content, err := os.ReadFile(moduleFilePath)
if err != nil {
return err
}

fromVersion, err := modulemigration.ConsensusVersion(string(content))
if err != nil {
return err
}

opts := &modulemigration.Options{
ModuleName: moduleName,
ModulePath: s.modpath.RawPath,
MigrationName: mfMigrationName,
FromVersion: fromVersion,
ToVersion: fromVersion + 1,
}

versionDir := filepath.Join(s.appPath, opts.MigrationDir())
if _, err := os.Stat(versionDir); err == nil {
return errors.Errorf("migration version %s already exists for module %s", opts.MigrationVersion(), moduleName)
} else if !os.IsNotExist(err) {
return err
}

g, err := modulemigration.NewGenerator(opts)
if err != nil {
return err
}

return s.Run(g)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package <%= migrationVersion %>

import sdk "github.com/cosmos/cosmos-sdk/types"

// <%= migrationFunc %> performs in-place store migrations from version <%= fromVersion %> to <%= toVersion %>.
func <%= migrationFunc %>(_ sdk.Context) error {
return nil
}
40 changes: 40 additions & 0 deletions ignite/templates/module/migration/migration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package modulemigration

import (
"io/fs"

"github.com/gobuffalo/genny/v2"
"github.com/gobuffalo/plush/v4"

"github.com/ignite/cli/v29/ignite/pkg/errors"
"github.com/ignite/cli/v29/ignite/pkg/xgenny"
)

// NewGenerator returns the generator to scaffold a new module migration.
func NewGenerator(opts *Options) (*genny.Generator, error) {
subFS, err := fs.Sub(files, "files")
if err != nil {
return nil, errors.Errorf("fail to generate sub: %w", err)
}

g := genny.New()
if err := g.OnlyFS(subFS, nil, nil); err != nil {
return g, err
}

ctx := plush.NewContext()
ctx.Set("fromVersion", opts.FromVersion)
ctx.Set("migrationFunc", opts.MigrationFunc())
ctx.Set("migrationName", opts.MigrationName)
ctx.Set("migrationVersion", opts.MigrationVersion())
ctx.Set("moduleName", opts.ModuleName)
ctx.Set("toVersion", opts.ToVersion)

g.Transformer(xgenny.Transformer(ctx))
g.Transformer(genny.Replace("{{migrationName}}", opts.MigrationName.Snake))
g.Transformer(genny.Replace("{{migrationVersion}}", opts.MigrationVersion()))
g.Transformer(genny.Replace("{{moduleName}}", opts.ModuleName))
g.RunFn(moduleModify(opts))

return g, nil
}
Loading
Loading