MM-12355: Add CLI command "command create" (#9569)
* Add create command * Create CreateCommand Tests * Change method flag description * Change nil test assertion
Этот коммит содержится в:
коммит произвёл
George Goldberg
родитель
908ed5555f
Коммит
f025e749a9
@@ -5,8 +5,10 @@ package commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/app"
|
"github.com/mattermost/mattermost-server/app"
|
||||||
"github.com/mattermost/mattermost-server/model"
|
"github.com/mattermost/mattermost-server/model"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -17,6 +19,15 @@ var CommandCmd = &cobra.Command{
|
|||||||
Short: "Management of slash commands",
|
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{
|
var CommandMoveCmd = &cobra.Command{
|
||||||
Use: "move",
|
Use: "move",
|
||||||
Short: "Move a slash command to a different team",
|
Short: "Move a slash command to a different team",
|
||||||
@@ -34,13 +45,92 @@ var CommandListCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
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(
|
CommandCmd.AddCommand(
|
||||||
|
CommandCreateCmd,
|
||||||
CommandMoveCmd,
|
CommandMoveCmd,
|
||||||
CommandListCmd,
|
CommandListCmd,
|
||||||
)
|
)
|
||||||
RootCmd.AddCommand(CommandCmd)
|
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 {
|
func moveCommandCmdF(command *cobra.Command, args []string) error {
|
||||||
a, err := InitDBCommandContextCobra(command)
|
a, err := InitDBCommandContextCobra(command)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
128
cmd/mattermost/commands/command_test.go
Обычный файл
128
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Ссылка в новой задаче
Block a user