Skip to content

Commit

Permalink
feat: Improve app scaffolding (#3839)
Browse files Browse the repository at this point in the history
* Add new structure for app scaffolding

* Fix some minor issues

* Fix integration test plush

* Add go mod tidy and fmt to scaffolding apps

* Add changelog

* Fix tests

* Fix integration test package name

* New app.ignite.yml format

* Add AppYML

* Add go.work.sum to app scaffold .gitignore

* Upgrade app scaffold go.mod

* Rename AppYML to AppsConfig

* Add additional test for app scaffolding

* Fix changelog

* Improve app testing

* Fix app_test.go

* Move to cobra independent arch for app scaffolding

* Fix plugin test

* Fix changelog

* Increase app scaffold integration test time

* Update ignite/services/plugin/template/cmd/hello.go.plush

Co-authored-by: Julien Robert <[email protected]>

* Update ignite/services/plugin/template/integration/app_test.go.plush

Co-authored-by: Danny <[email protected]>

* Update ignite/services/plugin/template/cmd/cmd.go.plush

Co-authored-by: Danny <[email protected]>

* Update ignite/services/plugin/template/app.ignite.yml.plush

Co-authored-by: Danny <[email protected]>

* Update ignite/services/plugin/template/.gitignore.plush

Co-authored-by: Danny <[email protected]>

---------

Co-authored-by: Danilo Pantani <[email protected]>
Co-authored-by: Julien Robert <[email protected]>
Co-authored-by: Danny <[email protected]>
  • Loading branch information
4 people authored Jan 29, 2024
1 parent 2900024 commit 86ebb55
Show file tree
Hide file tree
Showing 13 changed files with 215 additions and 89 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Features

- [#3839](https://github.com/ignite/cli/pull/3839) New structure for app scaffolding
- [#3835](https://github.com/ignite/cli/pull/3835) Add `--minimal` flag to `scaffold chain` to scaffold a chain with the least amount of sdk modules

### Changes
Expand Down
12 changes: 12 additions & 0 deletions ignite/pkg/gocmd/gocmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ const (
// CommandList represents go "list" command.
CommandList = "list"

// CommandTest represents go "test" command.
CommandTest = "test"

// EnvGOARCH represents GOARCH variable.
EnvGOARCH = "GOARCH"
// EnvGOMOD represents GOMOD variable.
Expand Down Expand Up @@ -199,6 +202,15 @@ func List(ctx context.Context, path string, flags []string, options ...exec.Opti
return strings.Fields(b.String()), nil
}

func Test(ctx context.Context, path string, flags []string, options ...exec.Option) error {
command := []string{
Name(),
CommandTest,
}
command = append(command, flags...)
return exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)))...)
}

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

// AppsConfig is the structure of app.ignite.yml file.
type AppsConfig struct {
Version uint `yaml:"version"`
Apps map[string]AppInfo `yaml:"apps"`
}

// AppInfo is the structure of app info in app.ignite.yml file which only holds
// the description and the relative path of the app.
type AppInfo struct {
Description string `yaml:"description"`
Path string `yaml:"path"`
}
2 changes: 1 addition & 1 deletion ignite/services/plugin/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ func TestPluginLoad(t *testing.T) {
manifest, err := p.Interface.Manifest(ctx)
require.NoError(err)
assert.Equal(p.name, manifest.Name)
assert.NoError(p.Interface.Execute(ctx, &ExecutedCommand{}, clientAPI))
assert.NoError(p.Interface.Execute(ctx, &ExecutedCommand{OsArgs: []string{"ignite", p.name, "hello"}}, clientAPI))
assert.NoError(p.Interface.ExecuteHookPre(ctx, &ExecutedHook{}, clientAPI))
assert.NoError(p.Interface.ExecuteHookPost(ctx, &ExecutedHook{}, clientAPI))
assert.NoError(p.Interface.ExecuteHookCleanUp(ctx, &ExecutedHook{}, clientAPI))
Expand Down
17 changes: 17 additions & 0 deletions ignite/services/plugin/scaffold.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ import (
"os"
"path"
"path/filepath"
"strings"

"github.com/gobuffalo/genny/v2"
"github.com/gobuffalo/plush/v4"
"golang.org/x/text/cases"
"golang.org/x/text/language"

"github.com/ignite/cli/v28/ignite/pkg/errors"
"github.com/ignite/cli/v28/ignite/pkg/gocmd"
"github.com/ignite/cli/v28/ignite/pkg/xgenny"
)

Expand All @@ -21,6 +25,7 @@ var fsPluginSource embed.FS
func Scaffold(ctx context.Context, dir, moduleName string, sharedHost bool) (string, error) {
var (
name = filepath.Base(moduleName)
title = toTitle(name)
finalDir = path.Join(dir, name)
g = genny.New()
template = xgenny.NewEmbedWalker(
Expand All @@ -42,6 +47,7 @@ func Scaffold(ctx context.Context, dir, moduleName string, sharedHost bool) (str
pctx := plush.NewContextWithContext(ctx)
pctx.Set("ModuleName", moduleName)
pctx.Set("Name", name)
pctx.Set("Title", title)
pctx.Set("SharedHost", sharedHost)

g.Transformer(xgenny.Transformer(pctx))
Expand All @@ -55,5 +61,16 @@ func Scaffold(ctx context.Context, dir, moduleName string, sharedHost bool) (str
return "", errors.WithStack(err)
}

if err := gocmd.ModTidy(ctx, finalDir); err != nil {
return "", errors.WithStack(err)
}
if err := gocmd.Fmt(ctx, finalDir); err != nil {
return "", errors.WithStack(err)
}

return finalDir, nil
}

func toTitle(s string) string {
return strings.ReplaceAll(strings.ReplaceAll(cases.Title(language.English).String(s), "_", ""), "-", "")
}
21 changes: 21 additions & 0 deletions ignite/services/plugin/scaffold_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ package plugin

import (
"context"
"os"
"path/filepath"
"testing"

"github.com/ignite/cli/v28/ignite/pkg/gocmd"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v2"
)

func TestScaffold(t *testing.T) {
Expand All @@ -21,4 +24,22 @@ func TestScaffold(t *testing.T) {
require.DirExists(t, path)
require.FileExists(t, filepath.Join(path, "go.mod"))
require.FileExists(t, filepath.Join(path, "main.go"))

// app.ignite.yml check
appYML, err := os.ReadFile(filepath.Join(path, "app.ignite.yml"))
require.NoError(t, err)
var config AppsConfig
err = yaml.Unmarshal(appYML, &config)
require.NoError(t, err)
require.EqualValues(t, 1, config.Version)
require.Len(t, config.Apps, 1)

// Integration test check
err = gocmd.Test(ctx, filepath.Join(path, "integration"), []string{
"-timeout",
"5m",
"-run",
"^TestBar$",
})
require.NoError(t, err)
}
22 changes: 22 additions & 0 deletions ignite/services/plugin/template/.gitignore.plush
Original file line number Diff line number Diff line change
@@ -1 +1,23 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
*.ign

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

# Go workspace file
go.work
go.work.sum

# App
<%= Name %>*
6 changes: 6 additions & 0 deletions ignite/services/plugin/template/app.ignite.yml.plush
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 1
apps:
<%= Name %>:
description: <%= Name %> is an awesome Ignite application!
path: ./

19 changes: 19 additions & 0 deletions ignite/services/plugin/template/cmd/cmd.go.plush
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cmd

import "github.com/ignite/cli/v28/ignite/services/plugin"

// GetCommands returns the list of <%= Name %> app commands.
func GetCommands() []*plugin.Command {
return []*plugin.Command{
{
Use: "<%= Name %> [command]",
Short: "<%= Name %> is an awesome Ignite application!",
Commands: []*plugin.Command{
{
Use: "hello",
Short: "Say hello to the world of ignite!",
},
},
},
}
}
14 changes: 14 additions & 0 deletions ignite/services/plugin/template/cmd/hello.go.plush
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package cmd

import (
"context"
"fmt"

"github.com/ignite/cli/v28/ignite/services/plugin"
)

// ExecuteHello executes the hello subcommand.
func ExecuteHello(ctx context.Context, cmd *plugin.ExecutedCommand) error {
fmt.Println("Hello, world!")
return nil
}
1 change: 1 addition & 0 deletions ignite/services/plugin/template/go.mod.plush
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ go 1.21
require (
github.com/hashicorp/go-plugin v1.5.0
github.com/ignite/cli/v28 v28.0.0
github.com/stretchr/testify v1.8.4
)
70 changes: 70 additions & 0 deletions ignite/services/plugin/template/integration/app_test.go.plush
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package integration_test

import (
"bytes"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"

pluginsconfig "github.com/ignite/cli/v28/ignite/config/plugins"
"github.com/ignite/cli/v28/ignite/pkg/cmdrunner/step"
"github.com/ignite/cli/v28/ignite/services/plugin"
envtest "github.com/ignite/cli/v28/integration"
)

func Test<%= Title %>(t *testing.T) {
var (
require = require.New(t)
env = envtest.New(t)
app = env.Scaffold("github.com/test/test")
)

dir, err := os.Getwd()
require.NoError(err)
pluginPath := filepath.Join(filepath.Dir(filepath.Dir(dir)), "<%= Name %>")

env.Must(env.Exec("install <%= Name %> app locally",
step.NewSteps(step.New(
step.Exec(envtest.IgniteApp, "app", "install", pluginPath),
step.Workdir(app.SourcePath()),
)),
))

// One local plugin expected
assertLocalPlugins(t, app, []pluginsconfig.Plugin{
{
Path: pluginPath,
},
})
assertGlobalPlugins(t, app, nil)

buf := &bytes.Buffer{}
env.Must(env.Exec("run <%= Name %>",
step.NewSteps(step.New(
step.Exec(
envtest.IgniteApp,
"<%= Name %>",
"hello",
),
step.Workdir(app.SourcePath()),
step.Stdout(buf),
)),
))
require.Equal("Hello, world!\n", buf.String())
}

func assertLocalPlugins(t *testing.T, app envtest.App, expectedPlugins []pluginsconfig.Plugin) {
cfg, err := pluginsconfig.ParseDir(app.SourcePath())
require.NoError(t, err)
require.ElementsMatch(t, expectedPlugins, cfg.Apps, "unexpected local apps")
}

func assertGlobalPlugins(t *testing.T, app envtest.App, expectedPlugins []pluginsconfig.Plugin) {
cfgPath, err := plugin.PluginsPath()
require.NoError(t, err)
cfg, err := pluginsconfig.ParseDir(cfgPath)
require.NoError(t, err)
require.ElementsMatch(t, expectedPlugins, cfg.Apps, "unexpected global apps")
}
Loading

0 comments on commit 86ebb55

Please sign in to comment.