cli: link cli-ext plugin with cli version (close #4105) (#4280)

This commit is contained in:
Aravind Shankar 2020-04-13 08:46:06 +05:30 committed by GitHub
parent 76fbe90b60
commit 491a50b1e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 86 additions and 46 deletions

View File

@ -119,7 +119,11 @@ deploy_cli_ext() {
git clone https://github.com/hasura/cli-plugins-index.git ~/plugins-index
cd ~/plugins-index
git checkout -b cli-ext-${LATEST_TAG}
mkdir -p ./plugins/cli-ext/${LATEST_TAG}
# Replace existing cli-ext.yaml to work with previous versions of plugin system
cp ${DIST_PATH}/manifest.yaml ./plugins/cli-ext.yaml
# Copy the manifest to versioned folder structure
cp ${DIST_PATH}/manifest.yaml ./plugins/cli-ext/${LATEST_TAG}/manifest.yaml
git add .
git commit -m "update cli-ext manifest to ${LATEST_TAG}"
git push -q https://${GITHUB_TOKEN}@github.com/hasura/cli-plugins-index.git cli-ext-${LATEST_TAG}

View File

@ -19,8 +19,7 @@ import (
"strings"
"time"
"gopkg.in/yaml.v2"
"github.com/Masterminds/semver"
"github.com/briandowns/spinner"
"github.com/gofrs/uuid"
"github.com/hasura/graphql-engine/cli/metadata/actions/types"
@ -32,6 +31,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
"golang.org/x/crypto/ssh/terminal"
"gopkg.in/yaml.v2"
)
// Other constants used in the package
@ -43,6 +43,9 @@ const (
// Name of the file to store last update check time
LastUpdateCheckFileName = "last_update_check_at"
// Name of the cli extension plugin
CLIExtPluginName = "cli-ext"
)
const (
@ -606,6 +609,40 @@ func (ec *ExecutionContext) setVersion() {
}
}
// InstallPlugin installs a plugin depending on forceCLIVersion.
// If forceCLIVersion is set, it uses ec.Version.CLISemver version for the plugin to be installed.
// Else, it installs the latest version of the plugin
func (ec ExecutionContext) InstallPlugin(name string, forceCLIVersion bool) error {
prevPrefix := ec.Spinner.Prefix
ec.Spin(fmt.Sprintf("Installing plugin %s...", name))
defer ec.Spin(prevPrefix)
var version *semver.Version
if forceCLIVersion {
err := ec.PluginsConfig.Repo.EnsureUpdated()
if err != nil {
ec.Logger.Debugf("cannot update plugin index %v", err)
}
version = ec.Version.CLISemver
}
err := ec.PluginsConfig.Install(name, plugins.InstallOpts{
Version: version,
})
if err != nil {
if err != plugins.ErrIsAlreadyInstalled {
msg := fmt.Sprintf(`unable to install %s plugin. execute the following commands to continue:
hasura plugins install %s
`, name, name)
ec.Logger.Info(msg)
return errors.Wrapf(err, "cannot install plugin %s", name)
}
return nil
}
ec.Logger.WithField("name", name).Infoln("plugin installed")
return nil
}
func GetAdminSecretHeaderName(v *version.Version) string {
if v.ServerFeatureFlags.HasAccessKey {
return XHasuraAccessKey

View File

@ -77,5 +77,8 @@ type PluginInstallOptions struct {
}
func (o *PluginInstallOptions) Run() error {
return o.EC.PluginsConfig.Install(o.Name, o.ManifestFile, o.Version.Version)
return o.EC.PluginsConfig.Install(o.Name, plugins.InstallOpts{
ManifestFile: o.ManifestFile,
Version: o.Version.Version,
})
}

View File

@ -16,7 +16,6 @@ import (
"github.com/hasura/graphql-engine/cli/migrate/database/hasuradb"
"github.com/hasura/graphql-engine/cli/migrate/source"
"github.com/hasura/graphql-engine/cli/migrate/source/file"
"github.com/hasura/graphql-engine/cli/plugins"
"github.com/hasura/graphql-engine/cli/util"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -66,10 +65,10 @@ func newScriptsUpdateConfigV2Cmd(ec *cli.ExecutionContext) *cobra.Command {
return errors.Wrap(err, "cannot update plugin index")
}
// install the plugin
ec.Spin("Installing cli-ext plugin...")
err = ec.PluginsConfig.Install("cli-ext", "", nil)
if err != nil && err != plugins.ErrIsAlreadyInstalled {
return errors.Wrap(err, "cannot install plugin")
ec.Spin(fmt.Sprintf("Installing %s plugin...", cli.CLIExtPluginName))
err = ec.InstallPlugin(cli.CLIExtPluginName, true)
if err != nil {
return err
}
// Move copy migrations directory to migrations_backup
ec.Spin("Backing up migrations...")

View File

@ -94,12 +94,12 @@ func TestCommands(t *testing.T) {
t.Run("cli-ext-plugin-install", func(t *testing.T) {
installOpts := &commands.PluginInstallOptions{
EC: ec,
Name: "cli-ext",
Name: cli.CLIExtPluginName,
ManifestFile: "/build/_cli_ext_output/manifest-dev.yaml",
}
err := installOpts.Run()
if err != nil {
t.Fatalf("unable to install cli-ext plugin, got %v", err)
t.Fatalf("unable to install %s plugin, got %v", cli.CLIExtPluginName, err)
}
})

View File

@ -24,7 +24,6 @@ import (
const (
actionsFileName string = "actions.yaml"
graphqlFileName = "actions.graphql"
pluginName = "cli-ext"
)
type ActionConfig struct {
@ -33,6 +32,7 @@ type ActionConfig struct {
serverFeatureFlags *version.ServerFeatureFlags
pluginsCfg *plugins.Config
cliExtensionConfig *cliextension.Config
pluginInstallFunc func(string, bool) error
logger *logrus.Logger
}
@ -45,15 +45,16 @@ func New(ec *cli.ExecutionContext, baseDir string) *ActionConfig {
logger: ec.Logger,
pluginsCfg: ec.PluginsConfig,
cliExtensionConfig: cliextension.NewCLIExtensionConfig(ec.PluginsConfig.Paths.BinPath(), ec.Logger),
pluginInstallFunc: ec.InstallPlugin,
}
return cfg
}
func (a *ActionConfig) Create(name string, introSchema interface{}, deriveFrom string) error {
// Ensure CLI Extesnion
err := a.ensureCLIExtension()
err := a.pluginInstallFunc(cli.CLIExtPluginName, true)
if err != nil {
return errors.Wrap(err, "error in install cli-extension plugin")
return err
}
// Read the content of graphql file
graphqlFileContent, err := a.GetActionsGraphQLFileContent()
@ -283,9 +284,9 @@ input SampleInput {
}
func (a *ActionConfig) Codegen(name string, derivePld types.DerivePayload) error {
err := a.ensureCLIExtension()
err := a.pluginInstallFunc(cli.CLIExtPluginName, true)
if err != nil {
return errors.Wrap(err, "error in install cli-extension plugin")
return err
}
graphqlFileContent, err := a.GetActionsGraphQLFileContent()
@ -350,9 +351,9 @@ func (a *ActionConfig) Build(metadata *yaml.MapSlice) error {
}
return nil
}
err := a.ensureCLIExtension()
err := a.pluginInstallFunc(cli.CLIExtPluginName, true)
if err != nil {
return errors.Wrap(err, "error in install cli-extension plugin")
return err
}
// Read actions.graphql
graphqlFileContent, err := a.GetActionsGraphQLFileContent()
@ -471,9 +472,9 @@ func (a *ActionConfig) Export(metadata yaml.MapSlice) (map[string][]byte, error)
a.logger.Debugf("Skipping creating %s and %s", actionsFileName, graphqlFileName)
return make(map[string][]byte), nil
}
err := a.ensureCLIExtension()
err := a.pluginInstallFunc(cli.CLIExtPluginName, true)
if err != nil {
return nil, errors.Wrap(err, "error in install cli-extension plugin")
return nil, err
}
var actions yaml.MapSlice
for _, item := range metadata {
@ -520,19 +521,6 @@ func (a *ActionConfig) Name() string {
return "actions"
}
func (a *ActionConfig) ensureCLIExtension() error {
err := a.pluginsCfg.Install(pluginName, "", nil)
if err != nil && err != plugins.ErrIsAlreadyInstalled {
msg := fmt.Sprintf(`unable to install cli-ext plugin. execute the following commands to continue:
hasura plugins install %s
`, pluginName)
a.logger.Info(msg)
return errors.Wrap(err, "cannot install cli-ext plugin")
}
return nil
}
func (a *ActionConfig) GetActionsFileContent() (content types.Common, err error) {
commonByt, err := ioutil.ReadFile(filepath.Join(a.MetadataDir, actionsFileName))
if err != nil {

View File

@ -9,8 +9,11 @@ import (
"os/exec"
"path/filepath"
"github.com/hasura/graphql-engine/cli"
gyaml "github.com/ghodss/yaml"
"github.com/hasura/graphql-engine/cli/metadata/actions/types"
"github.com/hasura/graphql-engine/cli/plugins"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"gopkg.in/yaml.v2"
@ -25,7 +28,7 @@ type Config struct {
// NewCLIExtensionConfig creates CLIExtensionConfig to interact with cli-extension plugin
func NewCLIExtensionConfig(binDir string, logger *logrus.Logger) *Config {
return &Config{
binPath: filepath.Join(binDir, "hasura-cli_ext"),
binPath: filepath.Join(binDir, plugins.PluginNameToBin(cli.CLIExtPluginName, plugins.IsWindows())),
logger: logger,
}
}

View File

@ -45,11 +45,18 @@ type Config struct {
Logger *logrus.Logger
}
// InstallOpts - options available during plugin install
type InstallOpts struct {
ManifestFile string
Version *semver.Version
}
func New(base string) *Config {
p := paths.NewPaths(base)
return &Config{
Paths: p,
Repo: util.NewGitUtil(indexURI, p.IndexPath(), ""),
Repo: util.NewGitUtil(indexURI, p.IndexPath(), "multiple-version"),
}
}
@ -86,10 +93,10 @@ func (c *Config) ListPlugins() (Plugins, error) {
return c.LoadPluginListFromFS(c.Paths.IndexPluginsPath())
}
func (c *Config) Install(pluginName string, mainfestFile string, version *semver.Version) error {
func (c *Config) Install(pluginName string, opts InstallOpts) error {
var plugin Plugin
var err error
if mainfestFile == "" {
if opts.ManifestFile == "" {
// Load the plugin index by name
ps, err := c.LoadPluginByName(pluginName)
if err != nil {
@ -105,12 +112,12 @@ func (c *Config) Install(pluginName string, mainfestFile string, version *semver
return errors.Wrap(err, "failed to look up plugin receipt")
}
if version != nil {
if pluginReceipt.Version == version.Original() {
if opts.Version != nil {
if pluginReceipt.Version == opts.Version.Original() {
return ErrIsAlreadyInstalled
}
// check if version is available
ver := ps.Index.Search(version)
ver := ps.Index.Search(opts.Version)
if ver != nil {
plugin = ps.Versions[ver]
} else {
@ -125,12 +132,12 @@ func (c *Config) Install(pluginName string, mainfestFile string, version *semver
plugin = ps.Versions[latestVersion]
}
} else {
plugin, err = c.ReadPluginFromFile(mainfestFile)
plugin, err = c.ReadPluginFromFile(opts.ManifestFile)
if err != nil {
return errors.Wrap(err, "failed to load plugin manifest from file")
}
if plugin.Name != pluginName {
return fmt.Errorf("plugin name %s doesn't match with plugin in the manifest file %s", pluginName, mainfestFile)
return fmt.Errorf("plugin name %s doesn't match with plugin in the manifest file %s", pluginName, opts.ManifestFile)
}
}
@ -142,7 +149,6 @@ func (c *Config) Install(pluginName string, mainfestFile string, version *semver
if !ok {
return errors.Errorf("plugin %q does not offer installation for this platform", plugin.Name)
}
if err := c.installPlugin(plugin, platform); err != nil {
return errors.Wrap(err, "install failed")
}
@ -159,7 +165,7 @@ func (c *Config) Uninstall(name string) error {
return errors.Wrapf(err, "failed to look up install receipt for plugin %q", name)
}
symlinkPath := filepath.Join(c.Paths.BinPath(), pluginNameToBin(name, IsWindows()))
symlinkPath := filepath.Join(c.Paths.BinPath(), PluginNameToBin(name, IsWindows()))
if err := removeLink(symlinkPath); err != nil {
return errors.Wrap(err, "could not uninstall symlink of plugin")
}

View File

@ -134,7 +134,7 @@ func IsWindows() bool {
}
func createOrUpdateLink(binDir, binary, plugin string) error {
dst := filepath.Join(binDir, pluginNameToBin(plugin, IsWindows()))
dst := filepath.Join(binDir, PluginNameToBin(plugin, IsWindows()))
if err := removeLink(dst); err != nil {
return errors.Wrap(err, "failed to remove old symlink")
@ -168,9 +168,9 @@ func removeLink(path string) error {
return nil
}
// pluginNameToBin creates the name of the symlink file for the plugin name.
// PluginNameToBin creates the name of the symlink file for the plugin name.
// It converts dashes to underscores.
func pluginNameToBin(name string, isWindows bool) string {
func PluginNameToBin(name string, isWindows bool) string {
name = strings.ReplaceAll(name, "-", "_")
name = "hasura-" + name
if isWindows {