Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(plugin): execute from function #3899

Merged
merged 10 commits into from
Jan 24, 2024
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
5 changes: 5 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

- [#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

- [#3899](https://github.com/ignite/cli/pull/3899) Introduce plugin.Execute function
jeronimoalbi marked this conversation as resolved.
Show resolved Hide resolved

## [`v28.1.1`](https://github.com/ignite/cli/releases/tag/v28.1.1)

### Fixes
Expand Down
10 changes: 10 additions & 0 deletions ignite/services/plugin/client_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
// ErrAppChainNotFound indicates that the plugin command is not running inside a blockchain app.
var ErrAppChainNotFound = errors.New("blockchain app not found")

//go:generate mockery --srcpkg . --name Chainer --structname ChainerInterface --filename chainer.go --with-expecter
type Chainer interface {
// AppPath returns the configured App's path.
AppPath() string
Expand All @@ -21,6 +22,9 @@ type Chainer interface {

// RPCPublicAddress returns the configured App's rpc endpoint.
RPCPublicAddress() (string, error)

// Home returns the App's home dir.
Home() (string, error)
}

// APIOption defines options for the client API.
Expand Down Expand Up @@ -66,11 +70,17 @@ func (api clientAPI) GetChainInfo(context.Context) (*ChainInfo, error) {
return nil, err
}

home, err := chain.Home()
if err != nil {
return nil, err
}

return &ChainInfo{
ChainId: chainID,
AppPath: chain.AppPath(),
ConfigPath: chain.ConfigPath(),
RpcAddress: rpc,
Home: home,
}, nil
}

Expand Down
28 changes: 18 additions & 10 deletions ignite/services/plugin/grpc/v1/client_api.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 3 additions & 4 deletions ignite/services/plugin/grpc/v1/interface.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 3 additions & 4 deletions ignite/services/plugin/grpc/v1/service.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion ignite/services/plugin/grpc/v1/service_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 45 additions & 0 deletions ignite/services/plugin/internal/execute.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package plugininternal

import (
"bytes"
"context"
"time"

"google.golang.org/grpc/status"

pluginsconfig "github.com/ignite/cli/v28/ignite/config/plugins"
"github.com/ignite/cli/v28/ignite/pkg/errors"
"github.com/ignite/cli/v28/ignite/services/plugin"
)

// Execute starts and executes a plugin, then shutdowns it.
func Execute(ctx context.Context, path string, args []string, options ...plugin.APIOption) (string, error) {
var buf bytes.Buffer
plugins, err := plugin.Load(
ctx,
[]pluginsconfig.Plugin{{Path: path}},
plugin.RedirectStdout(&buf),
)
if err != nil {
return "", err
}
defer plugins[0].KillClient()
if plugins[0].Error != nil {
return "", plugins[0].Error
}
err = plugins[0].Interface.Execute(
ctx,
&plugin.ExecutedCommand{Args: args},
plugin.NewClientAPI(options...),
)
if err != nil {
// Extract the rpc status message and create a simple error from it.
// We don't want Execute to return rpc errors.
err = errors.New(status.Convert(err).Message())
}
// NOTE(tb): This pause gives enough time for go-plugin to sync the
// output from stdout/stderr of the plugin. Without that pause, this
// output can be discarded and absent from buf.
time.Sleep(100 * time.Millisecond)
return buf.String(), err
}
70 changes: 70 additions & 0 deletions ignite/services/plugin/internal/execute_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package plugininternal

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

"github.com/stretchr/testify/require"

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

func TestPluginExecute(t *testing.T) {
tests := []struct {
name string
pluginPath string
expectedOut string
expectedError string
}{
{
name: "fail: plugin doesnt exist",
pluginPath: "/not/exists",
expectedError: "local app path \"/not/exists\" not found: stat /not/exists: no such file or directory",
},
{
name: "ok: plugin execute ok ",
pluginPath: "testdata/execute_ok",
expectedOut: "ok args=[arg1 arg2] chainid=id appPath=apppath configPath=configpath home=home rpcAddress=rpcPublicAddress\n",
},
{
name: "ok: plugin execute fail ",
pluginPath: "testdata/execute_fail",
expectedError: "fail",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pluginPath := tt.pluginPath
if !strings.HasPrefix(pluginPath, "/") {
// add working dir to relative paths
wd, err := os.Getwd()
require.NoError(t, err)
pluginPath = filepath.Join(wd, pluginPath)
}
chainer := mocks.NewChainerInterface(t)
chainer.EXPECT().ID().Return("id", nil).Maybe()
chainer.EXPECT().AppPath().Return("apppath").Maybe()
chainer.EXPECT().ConfigPath().Return("configpath").Maybe()
chainer.EXPECT().Home().Return("home", nil).Maybe()
chainer.EXPECT().RPCPublicAddress().Return("rpcPublicAddress", nil).Maybe()

out, err := Execute(
context.Background(),
pluginPath,
[]string{"arg1", "arg2"},
plugin.WithChain(chainer),
)

if tt.expectedError != "" {
require.EqualError(t, err, tt.expectedError)
return
}
require.NoError(t, err)
require.Equal(t, tt.expectedOut, out)
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
execute_fail*
99 changes: 99 additions & 0 deletions ignite/services/plugin/internal/testdata/execute_fail/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
module execute_fail

go 1.21.1

toolchain go1.21.5

require (
github.com/hashicorp/go-plugin v1.5.2
github.com/ignite/cli/v28 v28.0.0
)

replace github.com/ignite/cli/v28 => ../../../../../..

require (
dario.cat/mergo v1.0.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
github.com/aymanbagabas/go-osc52 v1.2.1 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/charmbracelet/lipgloss v0.6.0 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/cockroachdb/errors v1.11.1 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/redact v1.1.5 // indirect
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/cosmos-sdk v0.50.3 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/getsentry/sentry-go v0.25.0 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.5.0 // indirect
github.com/go-git/go-git/v5 v5.11.0 // indirect
github.com/gobuffalo/flect v0.3.0 // indirect
github.com/gobuffalo/genny/v2 v2.1.0 // indirect
github.com/gobuffalo/github_flavored_markdown v1.1.4 // indirect
github.com/gobuffalo/helpers v0.6.7 // indirect
github.com/gobuffalo/logger v1.0.7 // indirect
github.com/gobuffalo/packd v1.0.2 // indirect
github.com/gobuffalo/plush/v4 v4.1.19 // indirect
github.com/gobuffalo/tags/v3 v3.1.4 // indirect
github.com/gobuffalo/validate/v3 v3.3.3 // indirect
github.com/goccy/go-yaml v1.11.2 // indirect
github.com/gofrs/uuid v4.4.0+incompatible // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-github/v48 v48.2.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/hashicorp/go-hclog v1.5.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/microcosm-cc/bluemonday v1.0.23 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.14.0 // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/sergi/go-diff v1.3.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/skeema/knownhosts v1.2.1 // indirect
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d // indirect
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e // indirect
github.com/spf13/cobra v1.8.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
go.etcd.io/bbolt v1.3.8 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/term v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.15.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect
google.golang.org/grpc v1.60.1 // indirect
google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
Loading
Loading