From f025e749a903ad7ee621761d6c1a6aa28592ede3 Mon Sep 17 00:00:00 2001 From: Jason Mojica Date: Sat, 13 Oct 2018 08:35:00 -0400 Subject: MM-12355: Add CLI command "command create" (#9569) * Add create command * Create CreateCommand Tests * Change method flag description * Change nil test assertion --- cmd/mattermost/commands/command.go | 90 ++++++++++++++++++++++ cmd/mattermost/commands/command_test.go | 128 ++++++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+) create mode 100644 cmd/mattermost/commands/command_test.go (limited to 'cmd') diff --git a/cmd/mattermost/commands/command.go b/cmd/mattermost/commands/command.go index aee2eb290..63f18bed6 100644 --- a/cmd/mattermost/commands/command.go +++ b/cmd/mattermost/commands/command.go @@ -5,8 +5,10 @@ package commands import ( "errors" + "strings" "fmt" + "github.com/mattermost/mattermost-server/app" "github.com/mattermost/mattermost-server/model" "github.com/spf13/cobra" @@ -17,6 +19,15 @@ var CommandCmd = &cobra.Command{ Short: "Management of slash commands", } +var CommandCreateCmd = &cobra.Command{ + Use: "create [team]", + Short: "Create a custom slash command", + Long: `Create a custom slash command for the specified team.`, + Args: cobra.MinimumNArgs(1), + Example: ` command create myteam --title MyCommand --description "My Command Description" --trigger-word mycommand --url http://localhost:8000/my-slash-handler --creator myusername --response-username my-bot-username --icon http://localhost:8000/my-slash-handler-bot-icon.png --autocomplete --post`, + RunE: createCommandCmdF, +} + var CommandMoveCmd = &cobra.Command{ Use: "move", Short: "Move a slash command to a different team", @@ -34,13 +45,92 @@ var CommandListCmd = &cobra.Command{ } func init() { + CommandCreateCmd.Flags().String("title", "", "Command Title") + CommandCreateCmd.Flags().String("description", "", "Command Description") + CommandCreateCmd.Flags().String("trigger-word", "", "Command Trigger Word (required)") + CommandCreateCmd.MarkFlagRequired("trigger-word") + CommandCreateCmd.Flags().String("url", "", "Command Callback URL (required)") + CommandCreateCmd.MarkFlagRequired("url") + CommandCreateCmd.Flags().String("creator", "", "Command Creator's Username (required)") + CommandCreateCmd.MarkFlagRequired("creator") + CommandCreateCmd.Flags().String("response-username", "", "Command Response Username") + CommandCreateCmd.Flags().String("icon", "", "Command Icon URL") + CommandCreateCmd.Flags().Bool("autocomplete", false, "Show Command in autocomplete list") + CommandCreateCmd.Flags().String("autocompleteDesc", "", "Short Command Description for autocomplete list") + CommandCreateCmd.Flags().String("autocompleteHint", "", "Command Arguments displayed as help in autocomplete list") + CommandCreateCmd.Flags().Bool("post", false, "Use POST method for Callback URL") + CommandCmd.AddCommand( + CommandCreateCmd, CommandMoveCmd, CommandListCmd, ) RootCmd.AddCommand(CommandCmd) } +func createCommandCmdF(command *cobra.Command, args []string) error { + a, err := InitDBCommandContextCobra(command) + if err != nil { + return err + } + defer a.Shutdown() + + team := getTeamFromTeamArg(a, args[0]) + if team == nil { + return errors.New("unable to find team '" + args[0] + "'") + } + + title, _ := command.Flags().GetString("title") + description, _ := command.Flags().GetString("description") + trigger, _ := command.Flags().GetString("trigger-word") + + if strings.HasPrefix(trigger, "/") { + return errors.New("a trigger word cannot begin with a /") + } + if strings.Contains(trigger, " ") { + return errors.New("a trigger word must not contain spaces") + } + + url, _ := command.Flags().GetString("url") + creator, _ := command.Flags().GetString("creator") + user := getUserFromUserArg(a, creator) + if user == nil { + return errors.New("unable to find user '" + creator + "'") + } + responseUsername, _ := command.Flags().GetString("response-username") + icon, _ := command.Flags().GetString("icon") + autocomplete, _ := command.Flags().GetBool("autocomplete") + autocompleteDesc, _ := command.Flags().GetString("autocompleteDesc") + autocompleteHint, _ := command.Flags().GetString("autocompleteHint") + post, errp := command.Flags().GetBool("post") + method := "P" + if errp != nil || post == false { + method = "G" + } + + newCommand := &model.Command{ + CreatorId: user.Id, + TeamId: team.Id, + Trigger: trigger, + Method: method, + Username: responseUsername, + IconURL: icon, + AutoComplete: autocomplete, + AutoCompleteDesc: autocompleteDesc, + AutoCompleteHint: autocompleteHint, + DisplayName: title, + Description: description, + URL: url, + } + + if _, err := a.CreateCommand(newCommand); err != nil { + return errors.New("unable to create command '" + newCommand.Trigger + "'. " + err.Error()) + } + CommandPrettyPrintln("created command '" + newCommand.Trigger + "'") + + return nil +} + func moveCommandCmdF(command *cobra.Command, args []string) error { a, err := InitDBCommandContextCobra(command) if err != nil { diff --git a/cmd/mattermost/commands/command_test.go b/cmd/mattermost/commands/command_test.go new file mode 100644 index 000000000..4e54c56b4 --- /dev/null +++ b/cmd/mattermost/commands/command_test.go @@ -0,0 +1,128 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package commands + +import ( + "os" + "os/exec" + "testing" + + "github.com/mattermost/mattermost-server/api4" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestCreateCommand(t *testing.T) { + th := api4.Setup().InitBasic() + th.InitSystemAdmin() + defer th.TearDown() + team := th.BasicTeam + user := th.BasicUser + + testCases := []struct { + Description string + Args []string + ExpectedErr string + }{ + { + "nil error", + []string{"command", "create", team.Name, "--trigger-word", "testcmd", "--url", "http://localhost:8000/my-slash-handler", "--creator", user.Username}, + "", + }, + { + "Team not specified", + []string{"command", "create", "--trigger-word", "testcmd", "--url", "http://localhost:8000/my-slash-handler", "--creator", user.Username}, + "Error: requires at least 1 arg(s), only received 0", + }, + { + "Team not found", + []string{"command", "create", "fakeTeam", "--trigger-word", "testcmd", "--url", "http://localhost:8000/my-slash-handler", "--creator", user.Username}, + "Error: unable to find team", + }, + { + "Creator not specified", + []string{"command", "create", team.Name, "--trigger-word", "testcmd", "--url", "http://localhost:8000/my-slash-handler"}, + `Error: required flag(s) "creator" not set`, + }, + { + "Creator not found", + []string{"command", "create", team.Name, "--trigger-word", "testcmd", "--url", "http://localhost:8000/my-slash-handler", "--creator", "fakeuser"}, + "unable to find user", + }, + { + "Command not specified", + []string{"command", "", team.Name, "--trigger-word", "testcmd", "--url", "http://localhost:8000/my-slash-handler", "--creator", user.Username}, + "Error: unknown flag: --trigger-word", + }, + { + "Trigger not specified", + []string{"command", "create", team.Name, "--url", "http://localhost:8000/my-slash-handler", "--creator", user.Username}, + `Error: required flag(s) "trigger-word" not set`, + }, + { + "Blank trigger", + []string{"command", "create", team.Name, "--trigger-word", "", "--url", "http://localhost:8000/my-slash-handler", "--creator", user.Username}, + "Invalid trigger", + }, + { + "Trigger with space", + []string{"command", "create", team.Name, "--trigger-word", "test cmd", "--url", "http://localhost:8000/my-slash-handler", "--creator", user.Username}, + "Error: a trigger word must not contain spaces", + }, + { + "Trigger starting with /", + []string{"command", "create", team.Name, "--trigger-word", "/testcmd", "--url", "http://localhost:8000/my-slash-handler", "--creator", user.Username}, + "Error: a trigger word cannot begin with a /", + }, + { + "URL not specified", + []string{"command", "create", team.Name, "--trigger-word", "testcmd", "--creator", user.Username}, + `Error: required flag(s) "url" not set`, + }, + { + "Blank URL", + []string{"command", "create", team.Name, "--trigger-word", "testcmd2", "--url", "", "--creator", user.Username}, + "Invalid URL", + }, + { + "Invalid URL", + []string{"command", "create", team.Name, "--trigger-word", "testcmd2", "--url", "localhost:8000/my-slash-handler", "--creator", user.Username}, + "Invalid URL", + }, + { + "Duplicate Command", + []string{"command", "create", team.Name, "--trigger-word", "testcmd", "--url", "http://localhost:8000/my-slash-handler", "--creator", user.Username}, + "This trigger word is already in use", + }, + { + "Misspelled flag", + []string{"command", "create", team.Name, "--trigger-wor", "testcmd", "--url", "http://localhost:8000/my-slash-handler", "--creator", user.Username}, + "Error: unknown flag:", + }, + } + + path, err := os.Executable() + require.NoError(t, err) + + for _, testCase := range testCases { + t.Run(testCase.Description, func(t *testing.T) { + + actual, _ := exec.Command(path, execArgs(t, testCase.Args)...).CombinedOutput() + + cmds, _ := th.SystemAdminClient.ListCommands(team.Id, true) + + if testCase.ExpectedErr == "" { + if len(cmds) == 0 || cmds[0].Trigger != "testcmd" { + t.Fatal("Failed to create command") + } + assert.Contains(t, string(actual), "PASS") + } else { + if len(cmds) > 1 { + t.Fatal("Created command that shouldn't have been created") + } + assert.Contains(t, string(actual), testCase.ExpectedErr) + } + }) + } +} -- cgit v1.2.3-1-g7c22