Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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 changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- The `--release` flag for the `build` command adds the ability to release binaries in a tarball with a checksum file.
- Added the flag `--no-default-module` to the command `starport app` to prevent scaffolding a default module when creating a new app
- Added support for multiple naming conventions for component names and field names
- Print created and modified files when scaffolding a new component

## `v0.16.1`

Expand Down
32 changes: 32 additions & 0 deletions starport/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package starportcmd
import (
"fmt"
"path/filepath"
"sort"
"strings"

"github.com/fatih/color"
"github.com/spf13/cobra"
flag "github.com/spf13/pflag"
"github.com/tendermint/starport/starport/pkg/clispinner"
"github.com/tendermint/starport/starport/pkg/events"
"github.com/tendermint/starport/starport/pkg/goenv"
"github.com/tendermint/starport/starport/pkg/xgenny"
"github.com/tendermint/starport/starport/services/chain"
"github.com/tendermint/starport/starport/services/networkbuilder"
)
Expand Down Expand Up @@ -102,3 +105,32 @@ func initOptionWithHomeFlag(cmd *cobra.Command, initOptions []networkbuilder.Ini

return initOptions
}

var (
modifyPrefix = color.New(color.FgMagenta).SprintFunc()("modify ")
createPrefix = color.New(color.FgGreen).SprintFunc()("create ")
removePrefix = func(s string) string {
return strings.TrimPrefix(strings.TrimPrefix(s, modifyPrefix), createPrefix)
}
)

func sourceModificationToString(sm xgenny.SourceModification) string {
// get file names and add prefix
var files []string
for _, modified := range sm.ModifiedFiles() {
files = append(files, modifyPrefix+modified)
}
for _, created := range sm.CreatedFiles() {
files = append(files, createPrefix+created)
}

// sort filenames without prefix
sort.Slice(files, func(i, j int) bool {
s1 := removePrefix(files[i])
s2 := removePrefix(files[j])

return strings.Compare(s1, s2) == -1
})

return "\n" + strings.Join(files, "\n")
}
4 changes: 3 additions & 1 deletion starport/cmd/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,14 @@ func messageHandler(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
if err := sc.AddMessage(placeholder.New(), module, args[0], desc, args[1:], resFields); err != nil {
sm, err := sc.AddMessage(placeholder.New(), module, args[0], desc, args[1:], resFields)
if err != nil {
return err
}

s.Stop()

fmt.Println(sourceModificationToString(sm))
fmt.Printf("\n🎉 Created a message `%[1]v`.\n\n", args[0])
return nil
}
7 changes: 5 additions & 2 deletions starport/cmd/module-create.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ func createModuleHandler(cmd *cobra.Command, args []string) error {
}
var msg bytes.Buffer
fmt.Fprintf(&msg, "\n🎉 Module created %s.\n\n", name)
if err := sc.CreateModule(placeholder.New(), name, options...); err != nil {
sm, err := sc.CreateModule(placeholder.New(), name, options...)
s.Stop()
if err != nil {
// If this is an old scaffolded application that doesn't contain the necessary placeholder
// We give instruction to the user to modify the application
if err == scaffolder.ErrNoIBCRouterPlaceholder {
Expand All @@ -105,8 +107,9 @@ func createModuleHandler(cmd *cobra.Command, args []string) error {
} else {
return err
}
} else {
fmt.Println(sourceModificationToString(sm))
}
s.Stop()

io.Copy(cmd.OutOrStdout(), &msg)
return nil
Expand Down
4 changes: 3 additions & 1 deletion starport/cmd/module-import.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ func importModuleHandler(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
if err := sc.ImportModule(placeholder.New(), name); err != nil {
sm, err := sc.ImportModule(placeholder.New(), name)
if err != nil {
return err
}

s.Stop()

fmt.Println(sourceModificationToString(sm))
fmt.Printf("\n🎉 Imported module `%s`.\n\n", name)
return nil
}
4 changes: 3 additions & 1 deletion starport/cmd/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,14 @@ func createPacketHandler(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
if err := sc.AddPacket(placeholder.New(), module, packet, packetFields, ackFields, noMessage); err != nil {
sm, err := sc.AddPacket(placeholder.New(), module, packet, packetFields, ackFields, noMessage)
if err != nil {
return err
}

s.Stop()

fmt.Println(sourceModificationToString(sm))
fmt.Printf("\n🎉 Created a packet `%[1]v`.\n\n", args[0])
return nil
}
4 changes: 3 additions & 1 deletion starport/cmd/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,14 @@ func queryHandler(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
if err := sc.AddQuery(placeholder.New(), module, args[0], desc, args[1:], resFields, paginated); err != nil {
sm, err := sc.AddQuery(placeholder.New(), module, args[0], desc, args[1:], resFields, paginated)
if err != nil {
return err
}

s.Stop()

fmt.Println(sourceModificationToString(sm))
fmt.Printf("\n🎉 Created a query `%[1]v`.\n\n", args[0])
return nil
}
4 changes: 3 additions & 1 deletion starport/cmd/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@ func typeHandler(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
if err := sc.AddType(placeholder.New(), opts, module, args[0], args[1:]...); err != nil {
sm, err := sc.AddType(placeholder.New(), opts, module, args[0], args[1:]...)
if err != nil {
return err
}

s.Stop()

fmt.Println(sourceModificationToString(sm))
fmt.Printf("\n🎉 Created a type `%[1]v`.\n\n", args[0])
return nil
}
42 changes: 35 additions & 7 deletions starport/pkg/xgenny/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,62 @@ type dryRunError struct {
error
}

// ValidationInfo returns validation info
func (d *dryRunError) ValidationInfo() string {
return d.Error()
}

// DryRunner is a genny DryRunner with a logger
func DryRunner(ctx context.Context) *genny.Runner {
runner := genny.DryRunner(context.Background())
runner.Logger = logger.New(genny.DefaultLogLvl)
return runner
}

func RunWithValidation(tracer *placeholder.Tracer, gens ...*genny.Generator) error {
// RunWithValidation checks the generators with a dry run and then execute the wet runner to the generators
func RunWithValidation(
tracer *placeholder.Tracer,
gens ...*genny.Generator,
) (sm SourceModification, err error) {
// run executes the provided runner with the provided generator
run := func(runner *genny.Runner, gen *genny.Generator) error {
runner.With(gen)
return runner.Run()
}
for _, gen := range gens {
if err := run(DryRunner(context.Background()), gen); err != nil {
// check with a dry runner the generators
dryRunner := DryRunner(context.Background())
if err := run(dryRunner, gen); err != nil {
if errors.Is(err, os.ErrNotExist) {
return &dryRunError{err}
return sm, &dryRunError{err}
}
return err
return sm, err
}
if err := tracer.Err(); err != nil {
return err
return sm, err
}

// fetch the source modification
sm = NewSourceModification()
for _, file := range dryRunner.Results().Files {
_, err := os.Stat(file.Name())

// nolint:gocritic
if os.IsNotExist(err) {
// if the file doesn't exist in the source, it means it has been created by the runner
sm.AppendCreatedFiles(file.Name())
} else if err != nil {
return sm, err
} else {
// the file has been modified by the runner
sm.AppendModifiedFiles(file.Name())
}
}

// execute the modification with a wet runner
if err := run(genny.WetRunner(context.Background()), gen); err != nil {
return err
return sm, err
}
}
return nil
return sm, nil
}
58 changes: 58 additions & 0 deletions starport/pkg/xgenny/sourcemodification.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package xgenny

// SourceModification describes modified and created files in the source code after a run
type SourceModification struct {
modified map[string]struct{}
created map[string]struct{}
}

func NewSourceModification() SourceModification {
return SourceModification{
make(map[string]struct{}),
make(map[string]struct{}),
}
}

// ModifiedFiles returns the modified files of the source modification
func (sm SourceModification) ModifiedFiles() (modifiedFiles []string) {
for modified := range sm.modified {
modifiedFiles = append(modifiedFiles, modified)
}
return
}

// CreatedFiles returns the created files of the source modification
func (sm SourceModification) CreatedFiles() (createdFiles []string) {
for created := range sm.created {
createdFiles = append(createdFiles, created)
}
return
}

// AppendModifiedFile appends modified files in the source modification that are not already documented
func (sm *SourceModification) AppendModifiedFiles(modifiedFiles ...string) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func (sm *SourceModification) AppendModifiedFiles(modifiedFiles ...string) {
func (sm *SourceModification) appendModifiedFiles(modifiedFiles ...string) {

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those are actually part of the encapsulated interface, this also allows us to use a separate package for the tests

for _, modifiedFile := range modifiedFiles {
_, alreadyModified := sm.modified[modifiedFile]
_, alreadyCreated := sm.created[modifiedFile]
if !alreadyModified && !alreadyCreated {
sm.modified[modifiedFile] = struct{}{}
}
}
}

// AppendCreatedFiles appends a created files in the source modification that are not already documented
func (sm *SourceModification) AppendCreatedFiles(createdFiles ...string) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func (sm *SourceModification) AppendCreatedFiles(createdFiles ...string) {
func (sm *SourceModification) appendCreatedFiles(createdFiles ...string) {

?

for _, createdFile := range createdFiles {
_, alreadyModified := sm.modified[createdFile]
_, alreadyCreated := sm.created[createdFile]
if !alreadyModified && !alreadyCreated {
sm.created[createdFile] = struct{}{}
}
}
}

// Merge merges new source modification to an existing one
func (sm *SourceModification) Merge(newSm SourceModification) {
sm.AppendModifiedFiles(newSm.ModifiedFiles()...)
sm.AppendCreatedFiles(newSm.CreatedFiles()...)
}
81 changes: 81 additions & 0 deletions starport/pkg/xgenny/sourcemodification_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package xgenny_test

import (
"github.com/stretchr/testify/require"
"github.com/tendermint/starport/starport/pkg/xgenny"
"testing"
)

var (
modifiedExample = []string{"mfoo", "mbar", "mfoobar"}
createdExample = []string{"cfoo", "cbar", "cfoobar"}
)

func sourceModificationExample() xgenny.SourceModification {
sourceModification := xgenny.NewSourceModification()
sourceModification.AppendModifiedFiles(modifiedExample...)
sourceModification.AppendCreatedFiles(createdExample...)
return sourceModification
}

func TestNewSourceModification(t *testing.T) {
sm := xgenny.NewSourceModification()
require.Empty(t, sm.ModifiedFiles())
require.Empty(t, sm.CreatedFiles())
}

func TestModifiedFiles(t *testing.T) {
sm := sourceModificationExample()
require.Len(t, sm.ModifiedFiles(), len(modifiedExample))
require.Subset(t, sm.ModifiedFiles(), modifiedExample)
}

func TestCreatedFiles(t *testing.T) {
sm := sourceModificationExample()
require.Len(t, sm.CreatedFiles(), len(createdExample))
require.Subset(t, sm.CreatedFiles(), createdExample)
}

func TestAppendModifiedFiles(t *testing.T) {
sm := sourceModificationExample()
sm.AppendModifiedFiles("foo1")
require.Len(t, sm.ModifiedFiles(), len(modifiedExample)+1)
require.Contains(t, sm.ModifiedFiles(), "foo1")

// Do not append a existing element
sm.AppendModifiedFiles("foo1")
require.Len(t, sm.ModifiedFiles(), len(modifiedExample)+1)
sm.AppendCreatedFiles("foo2")
sm.AppendModifiedFiles("foo2")
require.Len(t, sm.ModifiedFiles(), len(modifiedExample)+1)
}

func TestAppendCreatedFiles(t *testing.T) {
sm := sourceModificationExample()
sm.AppendCreatedFiles("foo1")
require.Len(t, sm.CreatedFiles(), len(createdExample)+1)
require.Contains(t, sm.CreatedFiles(), "foo1")

// Do not append a existing element
sm.AppendCreatedFiles("foo1")
require.Len(t, sm.CreatedFiles(), len(createdExample)+1)
sm.AppendModifiedFiles("foo2")
sm.AppendCreatedFiles("foo2")
require.Len(t, sm.ModifiedFiles(), len(modifiedExample)+1)
}

func TestMerge(t *testing.T) {
sm1 := xgenny.NewSourceModification()
sm2 := xgenny.NewSourceModification()

sm1.AppendModifiedFiles("foo1", "foo2", "foo3")
sm2.AppendModifiedFiles("foo3", "foo4", "foo5")
sm1.AppendCreatedFiles("bar1", "bar2", "bar3")
sm2.AppendCreatedFiles("foo1", "bar2", "bar3")

sm1.Merge(sm2)
require.Len(t, sm1.ModifiedFiles(), 5)
require.Len(t, sm1.CreatedFiles(), 3)
require.Subset(t, sm1.ModifiedFiles(), []string{"foo1", "foo2", "foo3", "foo4", "foo5"})
require.Subset(t, sm1.CreatedFiles(), []string{"bar1", "bar2", "bar3"})
}
Loading