Skip to content

Commit

Permalink
Support slash as a command trigger
Browse files Browse the repository at this point in the history
Track the environment variable `use_slash_trigger`
and make it possible to use `/` as the command trigger
that the bot uses instead of "Derek ".

- Update unit tests in commentHandler_test.go.
- Update README.md

Signed-off-by: Martin Dekov (VMware) <mdekov@vmware.com>
Signed-off-by: Lubomir I. Ivanov <lubomirivanov@vmware.com>
  • Loading branch information
martindekov authored and alexellis committed Sep 25, 2018
1 parent ec0ea2e commit 8d8aa15
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 77 deletions.
4 changes: 4 additions & 0 deletions README.md
Expand Up @@ -57,6 +57,10 @@ redirect: https://github.com/<some-user>/<some-repo>/.DEREK.yaml
If this optional field is non-empty, Derek will read it's configuration from another location. This allows multiple projects to use the same configuration.
Please note that redirection is only supported for GitHub repository URLs.

* Command triggers

By default, Derek commands can be called with `Derek <some-command>`. The prefix `Derek ` is the default trigger, but the bot also supports the `/` trigger which can be enabled by setting the `use_slash_trigger` environment variable to `true`.

### Examples:

* Update the title of a PR or issue
Expand Down
39 changes: 25 additions & 14 deletions commentHandler.go
Expand Up @@ -31,8 +31,19 @@ const (
addLabelConstant string = "AddLabel"
setMilestoneConstant string = "SetMilestone"
removeMilestoneConstant string = "RemoveMilestone"

commandTriggerDefault string = "Derek "
commandTriggerSlash string = "/"
)

func getCommandTrigger() string {
commandTrigger := commandTriggerDefault
if os.Getenv("use_slash_trigger") == "true" {
commandTrigger = commandTriggerSlash
}
return commandTrigger
}

func makeClient(installation int) (*github.Client, context.Context) {
ctx := context.Background()

Expand Down Expand Up @@ -65,7 +76,7 @@ func handleComment(req types.IssueCommentOuter) {
var feedback string
var err error

command := parse(req.Comment.Body)
command := parse(req.Comment.Body, getCommandTrigger())

switch command.Type {

Expand Down Expand Up @@ -319,23 +330,23 @@ func updateMilestone(req types.IssueCommentOuter, cmdType string, cmdValue strin
return buffer.String(), nil
}

func parse(body string) *types.CommentAction {
func parse(body, commandTrigger string) *types.CommentAction {

commentAction := types.CommentAction{}

commands := map[string]string{
"Derek add label: ": addLabelConstant,
"Derek remove label: ": removeLabelConstant,
"Derek assign: ": assignConstant,
"Derek unassign: ": unassignConstant,
"Derek close": closeConstant,
"Derek reopen": reopenConstant,
"Derek set title: ": setTitleConstant,
"Derek edit title: ": setTitleConstant,
"Derek lock": lockConstant,
"Derek unlock": unlockConstant,
"Derek set milestone: ": setMilestoneConstant,
"Derek remove milestone: ": removeMilestoneConstant,
commandTrigger + "add label: ": addLabelConstant,
commandTrigger + "remove label: ": removeLabelConstant,
commandTrigger + "assign: ": assignConstant,
commandTrigger + "unassign: ": unassignConstant,
commandTrigger + "close": closeConstant,
commandTrigger + "reopen": reopenConstant,
commandTrigger + "set title: ": setTitleConstant,
commandTrigger + "edit title: ": setTitleConstant,
commandTrigger + "lock": lockConstant,
commandTrigger + "unlock": unlockConstant,
commandTrigger + "set milestone: ": setMilestoneConstant,
commandTrigger + "remove milestone: ": removeMilestoneConstant,
}

for trigger, commandType := range commands {
Expand Down
160 changes: 97 additions & 63 deletions commentHandler_test.go
Expand Up @@ -4,54 +4,79 @@
package main

import (
"os"
"testing"

"github.com/alexellis/derek/types"
)

var actionOptions = []struct {
title string
body string
expectedAction string
}{
{
title: "Correct reopen command",
body: "Derek reopen",
expectedAction: "reopen",
},
{ //this case replaces Test_Parsing_Close
title: "Correct close command",
body: "Derek close",
expectedAction: "close",
},
{
title: "invalid command",
body: "Derek dance",
expectedAction: "",
},
{
title: "Longer reopen command",
body: "Derek reopen: ",
expectedAction: "reopen",
},
{
title: "Longer close command",
body: "Derek close: ",
expectedAction: "close",
},
var commandTriggers = []string{commandTriggerDefault, commandTriggerSlash}

func Test_getCommandTrigger(t *testing.T) {
const (
envVar = "use_slash_trigger"
errorMessage = "expected trigger to be: %s, got: %s"
)
var trigger string

// test default trigger
os.Unsetenv(envVar)
trigger = getCommandTrigger()
if trigger != commandTriggerDefault {
t.Errorf(errorMessage, commandTriggerDefault, trigger)
}

// test slash trigger
os.Setenv(envVar, "true")
trigger = getCommandTrigger()
if trigger != commandTriggerSlash {
t.Errorf(errorMessage, commandTriggerSlash, trigger)
}
}

func Test_Parsing_OpenClose(t *testing.T) {

var actionOptions = []struct {
title string
body string
expectedAction string
}{
{
title: "Correct reopen command",
body: "reopen",
expectedAction: "reopen",
},
{ //this case replaces Test_Parsing_Close
title: "Correct close command",
body: "close",
expectedAction: "close",
},
{
title: "invalid command",
body: "dance",
expectedAction: "",
},
{
title: "Longer reopen command",
body: "reopen: ",
expectedAction: "reopen",
},
{
title: "Longer close command",
body: "close: ",
expectedAction: "close",
},
}

for _, test := range actionOptions {
t.Run(test.title, func(t *testing.T) {

action := parse(test.body)

if action.Type != test.expectedAction {
t.Errorf("Action - want: %s, got %s", test.expectedAction, action.Type)
for _, trigger := range commandTriggers {
action := parse(trigger+test.body, trigger)
if action.Type != test.expectedAction {
t.Errorf("Action - want: %s, got %s", test.expectedAction, action.Type)
}
}

})
}
}
Expand All @@ -66,19 +91,19 @@ func Test_Parsing_Labels(t *testing.T) {
}{
{ //this case replaces Test_Parsing_AddLabel
title: "Add label of demo",
body: "Derek add label: demo",
body: "add label: demo",
expectedType: "AddLabel",
expectedVal: "demo",
},
{
title: "Remove label of demo",
body: "Derek remove label: demo",
body: "remove label: demo",
expectedType: "RemoveLabel",
expectedVal: "demo",
},
{
title: "Invalid label action",
body: "Derek peel label: demo",
body: "peel label: demo",
expectedType: "",
expectedVal: "",
},
Expand All @@ -87,9 +112,11 @@ func Test_Parsing_Labels(t *testing.T) {
for _, test := range labelOptions {
t.Run(test.title, func(t *testing.T) {

action := parse(test.body)
if action.Type != test.expectedType || action.Value != test.expectedVal {
t.Errorf("Action - wanted: %s, got %s\nLabel - wanted: %s, got %s", test.expectedType, action.Type, test.expectedVal, action.Value)
for _, trigger := range commandTriggers {
action := parse(trigger+test.body, trigger)
if action.Type != test.expectedType || action.Value != test.expectedVal {
t.Errorf("Action - wanted: %s, got %s\nLabel - wanted: %s, got %s", test.expectedType, action.Type, test.expectedVal, action.Value)
}
}
})
}
Expand All @@ -105,37 +132,37 @@ func Test_Parsing_Assignments(t *testing.T) {
}{
{
title: "Assign to burt",
body: "Derek assign: burt",
body: "assign: burt",
expectedType: assignConstant,
expectedVal: "burt",
},
{
title: "Unassign burt",
body: "Derek unassign: burt",
body: "unassign: burt",
expectedType: unassignConstant,
expectedVal: "burt",
},
{
title: "Assign to me",
body: "Derek assign: me",
body: "assign: me",
expectedType: assignConstant,
expectedVal: "me",
},
{
title: "Unassign me",
body: "Derek unassign: me",
body: "unassign: me",
expectedType: unassignConstant,
expectedVal: "me",
},
{
title: "Invalid assignment action",
body: "Derek consign: burt",
body: "consign: burt",
expectedType: "",
expectedVal: "",
},
{
title: "Unassign blank",
body: "Derek unassign: ",
body: "unassign: ",
expectedType: "",
expectedVal: "",
},
Expand All @@ -144,9 +171,11 @@ func Test_Parsing_Assignments(t *testing.T) {
for _, test := range assignmentOptions {
t.Run(test.title, func(t *testing.T) {

action := parse(test.body)
if action.Type != test.expectedType || action.Value != test.expectedVal {
t.Errorf("Action - wanted: %s, got %s\nMaintainer - wanted: %s, got %s", test.expectedType, action.Type, test.expectedVal, action.Value)
for _, trigger := range commandTriggers {
action := parse(trigger+test.body, trigger)
if action.Type != test.expectedType || action.Value != test.expectedVal {
t.Errorf("Action - wanted: %s, got %s\nMaintainer - wanted: %s, got %s", test.expectedType, action.Type, test.expectedVal, action.Value)
}
}
})
}
Expand All @@ -162,25 +191,25 @@ func Test_Parsing_Titles(t *testing.T) {
}{
{
title: "Set Title",
body: "Derek set title: This is a really great Title!",
body: "set title: This is a really great Title!",
expectedType: setTitleConstant,
expectedVal: "This is a really great Title!",
},
{
title: "Mis-spelling of title",
body: "Derek set titel: This is a really great Title!",
body: "set titel: This is a really great Title!",
expectedType: "",
expectedVal: "",
},
{
title: "Empty Title",
body: "Derek set title: ",
body: "set title: ",
expectedType: "", //blank because it should fail isValidCommand
expectedVal: "",
},
{
title: "Empty Title (Double Space)",
body: "Derek set title: ",
body: "set title: ",
expectedType: setTitleConstant,
expectedVal: "",
},
Expand All @@ -189,9 +218,11 @@ func Test_Parsing_Titles(t *testing.T) {
for _, test := range titleOptions {
t.Run(test.title, func(t *testing.T) {

action := parse(test.body)
if action.Type != test.expectedType || action.Value != test.expectedVal {
t.Errorf("\nAction - wanted: %s, got %s\nValue - wanted: %s, got %s", test.expectedType, action.Type, test.expectedVal, action.Value)
for _, trigger := range commandTriggers {
action := parse(trigger+test.body, trigger)
if action.Type != test.expectedType || action.Value != test.expectedVal {
t.Errorf("\nAction - wanted: %s, got %s\nValue - wanted: %s, got %s", test.expectedType, action.Type, test.expectedVal, action.Value)
}
}
})
}
Expand Down Expand Up @@ -411,29 +442,32 @@ func Test_Parsing_Milestones(t *testing.T) {
}{
{
title: "Right set milestone",
body: "Derek set milestone: demo",
body: "set milestone: demo",
expectedType: "SetMilestone",
expectedVal: "demo",
},
{
title: "Right remove milestone",
body: "Derek remove milestone: demo",
body: "remove milestone: demo",
expectedType: "RemoveMilestone",
expectedVal: "demo",
},
{
title: "Wrong set milestone",
body: "Derek you ok label: demo",
body: "you ok label: demo",
expectedType: "",
expectedVal: "",
},
}

for _, test := range milestonesOptions {
t.Run(test.title, func(t *testing.T) {
action := parse(test.body)
if action.Type != test.expectedType || action.Value != test.expectedVal {
t.Errorf("Action - wanted: %s, got %s\nLabel - wanted: %s, got %s", test.expectedType, action.Type, test.expectedVal, action.Value)

for _, trigger := range commandTriggers {
action := parse(trigger+test.body, trigger)
if action.Type != test.expectedType || action.Value != test.expectedVal {
t.Errorf("Action - wanted: %s, got %s\nLabel - wanted: %s, got %s", test.expectedType, action.Type, test.expectedVal, action.Value)
}
}
})
}
Expand Down

0 comments on commit 8d8aa15

Please sign in to comment.