From 18bfca1c2c63e113ce76c9eb673de38b9a699591 Mon Sep 17 00:00:00 2001 From: Felipe Martin Date: Mon, 28 Jul 2025 16:50:42 +0200 Subject: [PATCH] Add non-interactive flag support to create-plugin command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add --name and --module flags for non-interactive plugin creation - Implement flag parsing and validation using existing validation functions - Support plugin names with or without mattermost-plugin- prefix - Maintain backward compatibility with interactive mode as fallback - Update help text and examples to document new flag options 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- cmd/pluginctl/main.go | 6 ++- create-plugin.go | 87 ++++++++++++++++++++++++++++++++++++++----- go.mod | 4 +- updateassets.go | 3 +- 4 files changed, 85 insertions(+), 15 deletions(-) diff --git a/cmd/pluginctl/main.go b/cmd/pluginctl/main.go index ebaed47..96d5e59 100644 --- a/cmd/pluginctl/main.go +++ b/cmd/pluginctl/main.go @@ -133,7 +133,7 @@ Commands: updateassets Update plugin files from embedded assets manifest Get plugin manifest information (id, version, has_server, has_webapp, check) logs View plugin logs (use --watch to follow logs in real-time) - create-plugin Create a new plugin from the starter template + create-plugin Create a new plugin from the starter template (supports --name and --module flags) help Show this help message version Show version information @@ -153,7 +153,9 @@ Examples: pluginctl manifest check # Validate plugin manifest pluginctl logs # View recent plugin logs pluginctl logs --watch # Watch plugin logs in real-time - pluginctl create-plugin # Create a new plugin from the starter template + pluginctl create-plugin # Create a new plugin from the starter template (interactive) + pluginctl create-plugin --name example \ + --module github.com/user/mattermost-plugin-example # Create plugin non-interactively export PLUGINCTL_PLUGIN_PATH=/path/to/plugin pluginctl info # Show info using environment variable pluginctl version # Show version information diff --git a/create-plugin.go b/create-plugin.go index ec31a6a..488fda7 100644 --- a/create-plugin.go +++ b/create-plugin.go @@ -277,23 +277,90 @@ func promptForModuleName(pluginName string) (string, error) { return result.input, nil } +func parseCreatePluginFlags(args []string) (pluginName, moduleName string, err error) { + // Parse flags similar to how logs command handles --watch + for i, arg := range args { + switch arg { + case "--name": + if i+1 >= len(args) { + return "", "", fmt.Errorf("--name flag requires a value") + } + pluginName = args[i+1] + case "--module": + if i+1 >= len(args) { + return "", "", fmt.Errorf("--module flag requires a value") + } + moduleName = args[i+1] + } + } + + // Validate and process plugin name if provided + if pluginName != "" { + pluginName, err = validateAndProcessPluginName(pluginName) + if err != nil { + return "", "", err + } + } + + // Validate module name if provided + if moduleName != "" { + if validationErr := validateModuleName(moduleName); validationErr != "" { + return "", "", fmt.Errorf("invalid module name: %s", validationErr) + } + } + + return pluginName, moduleName, nil +} + +// validateAndProcessPluginName checks if the plugin name has the correct prefix and adds it if necessary. +// Example: +// - If the input is "my-plugin", it returns "mattermost-plugin-my-plugin". +// - If the input is "mattermost-plugin-my-plugin", it returns "mattermost-plugin-my-plugin". +func validateAndProcessPluginName(name string) (string, error) { + // Check if the name already has the prefix + if !strings.HasPrefix(name, pluginPrefix) { + // If not, validate the suffix and add prefix + if err := validatePluginSuffix(name); err != "" { + return "", fmt.Errorf("invalid plugin name: %s", err) + } + + return pluginPrefix + name, nil + } + + // If it has the prefix, validate the suffix part + suffix := strings.TrimPrefix(name, pluginPrefix) + if err := validatePluginSuffix(suffix); err != "" { + return "", fmt.Errorf("invalid plugin name: %s", err) + } + + return name, nil +} + func RunCreatePluginCommand(args []string, pluginPath string) error { - if len(args) > 0 { - return fmt.Errorf("create-plugin command does not accept arguments") + // Parse flags + var pluginName, moduleName string + var err error + + pluginName, moduleName, err = parseCreatePluginFlags(args) + if err != nil { + return fmt.Errorf("failed to parse flags: %w", err) } Logger.Info("Starting plugin creation process") - // Prompt for plugin name - pluginName, err := promptForPluginName() - if err != nil { - return fmt.Errorf("failed to get plugin name: %w", err) + // If flags were not provided, fall back to interactive mode + if pluginName == "" { + pluginName, err = promptForPluginName() + if err != nil { + return fmt.Errorf("failed to get plugin name: %w", err) + } } - // Prompt for module name - moduleName, err := promptForModuleName(pluginName) - if err != nil { - return fmt.Errorf("failed to get module name: %w", err) + if moduleName == "" { + moduleName, err = promptForModuleName(pluginName) + if err != nil { + return fmt.Errorf("failed to get module name: %w", err) + } } Logger.Info("Creating plugin", "name", pluginName, "module", moduleName) diff --git a/go.mod b/go.mod index 4bfac4f..736b43a 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,8 @@ module github.com/mattermost/pluginctl go 1.24.3 require ( + github.com/charmbracelet/bubbletea v1.3.0 + github.com/charmbracelet/lipgloss v1.1.0 github.com/lmittmann/tint v1.1.2 github.com/mattermost/mattermost/server/public v0.1.15 ) @@ -129,9 +131,7 @@ require ( github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/charithe/durationcheck v0.0.10 // indirect - github.com/charmbracelet/bubbletea v1.3.0 // indirect github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect - github.com/charmbracelet/lipgloss v1.1.0 // indirect github.com/charmbracelet/x/ansi v0.8.0 // indirect github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect github.com/charmbracelet/x/term v0.2.1 // indirect diff --git a/updateassets.go b/updateassets.go index 0822b8f..9ce6222 100644 --- a/updateassets.go +++ b/updateassets.go @@ -13,7 +13,8 @@ import ( "github.com/mattermost/mattermost/server/public/model" ) -//go:embed assets/.editorconfig assets/.gitattributes assets/.nvmrc assets/Makefile assets/*.yml assets/build/*.mk assets/.github/**/*.yml assets/webapp/.npmrc assets/webapp/*.config.js +//go:embed assets/.editorconfig assets/.gitattributes assets/.nvmrc assets/Makefile assets/*.yml +//go:embed assets/build/*.mk assets/.github/**/*.yml assets/webapp/.npmrc assets/webapp/*.config.js var assetsFS embed.FS const (