Skip to content

Commit

Permalink
feat: support regex capture groups as arguments (#276)
Browse files Browse the repository at this point in the history
  • Loading branch information
justmiles authored Jun 28, 2022
1 parent e6aaced commit b3f5996
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 0 deletions.
39 changes: 39 additions & 0 deletions core/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"fmt"
"html"
"html/template"
"regexp"
"strconv"
"strings"

Expand Down Expand Up @@ -217,6 +218,15 @@ func isValidHitChatRule(message *models.Message, rule models.Rule, processedInpu

return false
}

for name, value := range parseArgumentsFromRegex(rule.Hear, message.Input) {
message.Vars[name] = value
}

for name, value := range parseArgumentsFromRegex(rule.Respond, message.Input) {
message.Vars[name] = value
}

// If this wasn't a 'hear' rule, handle the args
if rule.Hear == "" {
// Get all the args that the message sender supplied
Expand Down Expand Up @@ -591,3 +601,32 @@ func updateReaction(action models.Action, rule *models.Rule, vars map[string]str
}
}
}

// parseArgumentsFromRegex parses an input string against a regex rule
// and returns a map of argument names and their value.
func parseArgumentsFromRegex(re, input string) map[string]string {
args := make(map[string]string)

// try compliling the rule as regex, ignoring non-regex rules
r, err := regexp.Compile(strings.Trim(re, "/"))
if err != nil {
return args
}

// get all capture group names.
reNames := r.SubexpNames()

// get all capture group values.
reValues := r.FindStringSubmatch(input)

// assign capture group key/value to args map.
for index, name := range reNames {
if index == 0 || name == "" {
continue
}

args[name] = reValues[index]
}

return args
}
73 changes: 73 additions & 0 deletions core/matcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1178,3 +1178,76 @@ func Test_matcherLoop(t *testing.T) {
})
}
}

func Test_captureGroups(t *testing.T) {
type args struct {
message models.Message
outputMsgs chan<- models.Message
rules map[string]models.Rule
hitRule chan<- models.Rule
bot *models.Bot
}

testBot := new(models.Bot)

testMessage1 := models.Message{
Service: models.MsgServiceChat,
Input: "deploy flottbot@v0.0.1 to qa",
Attributes: make(map[string]string),
BotMentioned: true,
Vars: make(map[string]string),
}
testRules1 := make(map[string]models.Rule)
testRule1 := models.Rule{
Name: "testmatch",
Active: true,
Respond: "/deploy (?P<application>.*)@(?P<version>.*) to (?P<environment>.*)/",
IncludeInHelp: true,
HelpText: "hello <application>@<version> to <environment>",
FormatOutput: "deploying ${application} at version ${version} to environment ${environment}",
}
testRules1["test"] = testRule1

testMessage2 := models.Message{
Service: models.MsgServiceChat,
Input: "example ticket XYZ-123 should be heard",
BotMentioned: false,
Vars: make(map[string]string),
}
testRules2 := make(map[string]models.Rule)
testRule2 := models.Rule{
Name: "testmatch",
Active: true,
Hear: "/(?P<ticket>[A-Z]+-[0-9]+)/",
Args: []string{},
IncludeInHelp: true,
HelpText: "",
FormatOutput: "response with ${ticket} details",
}
testRules2["test"] = testRule2

tests := []struct {
name string
args args
expectedOutput string
}{
{"Capture groups, respond", args{message: testMessage1, rules: testRules1, bot: testBot}, "deploying flottbot at version v0.0.1 to environment qa"},
{"Capture groups, hear", args{message: testMessage2, rules: testRules2, bot: testBot}, "response with XYZ-123 details"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
testOutput := make(chan models.Message, 1)
testHitRule := make(chan models.Rule, 1)

tt.args.outputMsgs = testOutput
tt.args.hitRule = testHitRule

matcherLoop(tt.args.message, tt.args.outputMsgs, tt.args.rules, tt.args.hitRule, tt.args.bot)

output := <-testOutput
if output.Output != tt.expectedOutput {
t.Errorf("Message expected to be: %s, but got: %s", tt.expectedOutput, output.Output)
}
})
}
}

0 comments on commit b3f5996

Please sign in to comment.