aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2019-05-08 16:28:17 +0200
committerDmitry Vyukov <dvyukov@google.com>2019-05-08 16:29:04 +0200
commitb12c1ab14cf7312fefd126d40968bb8cc322a960 (patch)
treed6da340b65c09958288e1c12d55c68583c06b7d7
parenta7383bfac17332db9afdad436b6c06c48bfe4815 (diff)
dashboard/app: restore printing of email commands
After commit 9ad9ef29caa52714dd5faff167e4b61643e40a7e we started saying "your command '3' is accepted" because we use numbers now. Keep string representation of the command when parsing and use it in reply emails.
-rw-r--r--dashboard/app/email_test.go9
-rw-r--r--dashboard/app/reporting_email.go6
-rw-r--r--pkg/email/parser.go13
-rw-r--r--pkg/email/parser_test.go46
4 files changed, 50 insertions, 24 deletions
diff --git a/dashboard/app/email_test.go b/dashboard/app/email_test.go
index 2d848c9fa..be7d54a5f 100644
--- a/dashboard/app/email_test.go
+++ b/dashboard/app/email_test.go
@@ -317,8 +317,13 @@ unknown command "bad-command"
}
// Now mark the bug as fixed.
- c.incomingEmail(sender1, "#syz fix: some: commit title")
- c.expectNoEmail()
+ c.incomingEmail(sender1, "#syz fix: some: commit title", EmailOptCC(nil))
+ reply := c.pollEmailBug().Body
+ c.expectEQ(reply, `> #syz fix: some: commit title
+
+Your 'fix:' command is accepted, but please keep bugs@syzkaller.com mailing list in CC next time. It serves as a history of what happened with each bug report. Thank you.
+
+`)
// Check that the commit is now passed to builders.
builderPollResp, _ := c.client2.BuilderPoll(build.Manager)
diff --git a/dashboard/app/reporting_email.go b/dashboard/app/reporting_email.go
index ee45a759a..59fef0458 100644
--- a/dashboard/app/reporting_email.go
+++ b/dashboard/app/reporting_email.go
@@ -316,9 +316,9 @@ func incomingMail(c context.Context, r *http.Request) error {
cmd.CC = []string{email.CanonicalEmail(msg.From)}
default:
if msg.Command != email.CmdUnknown {
- log.Errorf(c, "unknown email command %v %q", msg.Command, msg.CommandArgs)
+ log.Errorf(c, "unknown email command %v %q", msg.Command, msg.CommandStr)
}
- return replyTo(c, msg, fmt.Sprintf("unknown command %q", msg.CommandArgs), nil)
+ return replyTo(c, msg, fmt.Sprintf("unknown command %q", msg.CommandStr), nil)
}
ok, reply, err := incomingCommand(c, cmd)
if err != nil {
@@ -444,7 +444,7 @@ func warnMailingListInCC(c context.Context, msg *email.Email, mailingList string
reply := fmt.Sprintf("Your '%v' command is accepted, but please keep %v mailing list"+
" in CC next time. It serves as a history of what happened with each bug report."+
" Thank you.",
- msg.Command, mailingList)
+ msg.CommandStr, mailingList)
if err := replyTo(c, msg, reply, nil); err != nil {
log.Errorf(c, "failed to send email reply: %v", err)
}
diff --git a/pkg/email/parser.go b/pkg/email/parser.go
index 2566ae1d5..0f4e1d40c 100644
--- a/pkg/email/parser.go
+++ b/pkg/email/parser.go
@@ -28,6 +28,7 @@ type Email struct {
Body string // text/plain part
Patch string // attached patch, if any
Command Command // command to bot
+ CommandStr string // string representation of the command
CommandArgs string // arguments for the command
}
@@ -104,7 +105,7 @@ func Parse(r io.Reader, ownEmails []string) (*Email, error) {
}
bodyStr := string(body)
cmd := CmdNone
- patch, cmdArgs := "", ""
+ patch, cmdStr, cmdArgs := "", "", ""
if !fromMe {
for _, a := range attachments {
_, patch, _ = ParsePatch(string(a))
@@ -115,7 +116,7 @@ func Parse(r io.Reader, ownEmails []string) (*Email, error) {
if patch == "" {
_, patch, _ = ParsePatch(bodyStr)
}
- cmd, cmdArgs = extractCommand(body)
+ cmd, cmdStr, cmdArgs = extractCommand(body)
}
link := ""
if match := groupsLinkRe.FindStringSubmatchIndex(bodyStr); match != nil {
@@ -131,6 +132,7 @@ func Parse(r io.Reader, ownEmails []string) (*Email, error) {
Body: string(body),
Patch: patch,
Command: cmd,
+ CommandStr: cmdStr,
CommandArgs: cmdArgs,
}
return email, nil
@@ -193,7 +195,7 @@ func CanonicalEmail(email string) string {
// extractCommand extracts command to syzbot from email body.
// Commands are of the following form:
// ^#syz cmd args...
-func extractCommand(body []byte) (cmd Command, args string) {
+func extractCommand(body []byte) (cmd Command, str, args string) {
cmdPos := bytes.Index(append([]byte{'\n'}, body...), []byte("\n"+commandPrefix))
if cmdPos == -1 {
cmd = CmdNone
@@ -213,7 +215,8 @@ func extractCommand(body []byte) (cmd Command, args string) {
if cmdEnd1 := bytes.IndexByte(body[cmdPos:], ' '); cmdEnd1 != -1 && cmdEnd1 < cmdEnd {
cmdEnd = cmdEnd1
}
- switch string(body[cmdPos : cmdPos+cmdEnd]) {
+ str = string(body[cmdPos : cmdPos+cmdEnd])
+ switch str {
default:
cmd = CmdUnknown
case "":
@@ -246,8 +249,6 @@ func extractCommand(body []byte) (cmd Command, args string) {
args = extractArgsTokens(body[cmdPos+cmdEnd:], 5)
case CmdFix, CmdDup:
args = extractArgsLine(body[cmdPos+cmdEnd:])
- case CmdUnknown:
- args = extractArgsLine(body[cmdPos:])
}
return
}
diff --git a/pkg/email/parser_test.go b/pkg/email/parser_test.go
index 06e383c45..0085adeb9 100644
--- a/pkg/email/parser_test.go
+++ b/pkg/email/parser_test.go
@@ -15,16 +15,16 @@ import (
func TestExtractCommand(t *testing.T) {
for i, test := range extractCommandTests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
- cmd, args := extractCommand([]byte(test.body))
- if cmd != test.cmd || !reflect.DeepEqual(args, test.args) {
- t.Logf("expect: %v %q", test.cmd, test.args)
- t.Logf("got : %v %q", cmd, args)
+ cmd, str, args := extractCommand([]byte(test.body))
+ if cmd != test.cmd || str != test.str || !reflect.DeepEqual(args, test.args) {
+ t.Logf("expect: %v %q %q", test.cmd, test.str, test.args)
+ t.Logf("got : %v %q %q", cmd, str, args)
t.Fail()
}
- cmd, args = extractCommand([]byte(strings.Replace(test.body, "\n", "\r\n", -1)))
- if cmd != test.cmd || !reflect.DeepEqual(args, test.args) {
- t.Logf("expect: %v %q", test.cmd, test.args)
- t.Logf("got : %v %q", cmd, args)
+ cmd, str, args = extractCommand([]byte(strings.Replace(test.body, "\n", "\r\n", -1)))
+ if cmd != test.cmd || str != test.str || !reflect.DeepEqual(args, test.args) {
+ t.Logf("expect: %v %q %q", test.cmd, test.str, test.args)
+ t.Logf("got : %v %q %q", cmd, str, args)
t.Fail()
}
})
@@ -139,6 +139,7 @@ func TestParse(t *testing.T) {
var extractCommandTests = []struct {
body string
cmd Command
+ str string
args string
}{
{
@@ -147,6 +148,7 @@ var extractCommandTests = []struct {
line1
#syz fix: bar baz `,
cmd: CmdFix,
+ str: "fix:",
args: "bar baz",
},
{
@@ -157,6 +159,7 @@ line1
line 2
`,
cmd: CmdFix,
+ str: "fix",
args: "bar baz",
},
{
@@ -176,6 +179,7 @@ line 2
locking/core
`,
cmd: CmdTest,
+ str: "test:",
args: "git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core",
},
{
@@ -184,6 +188,7 @@ locking/core
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core
`,
cmd: CmdTest,
+ str: "test",
args: "git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core",
},
{
@@ -194,6 +199,7 @@ locking/core
locking/core
`,
cmd: CmdTest,
+ str: "test:",
args: "git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core",
},
{
@@ -206,6 +212,7 @@ arg4
arg5
`,
cmd: cmdTest5,
+ str: "test_5_arg_cmd",
args: "arg1 arg2 arg3 arg4 arg5",
},
{
@@ -213,6 +220,7 @@ arg5
#syz test_5_arg_cmd arg1
arg2`,
cmd: cmdTest5,
+ str: "test_5_arg_cmd",
args: "arg1 arg2",
},
{
@@ -221,6 +229,7 @@ arg2`,
arg2
`,
cmd: cmdTest5,
+ str: "test_5_arg_cmd",
args: "arg1 arg2",
},
{
@@ -231,6 +240,7 @@ arg2
`,
cmd: cmdTest5,
+ str: "test_5_arg_cmd",
args: "arg1 arg2",
},
{
@@ -241,6 +251,7 @@ arg4 arg5
`,
cmd: CmdFix,
+ str: "fix:",
args: "arg1 arg2 arg3",
},
{
@@ -249,6 +260,7 @@ arg4 arg5
arg4 arg5
`,
cmd: CmdFix,
+ str: "fix:",
args: "arg1 arg2 arg3",
},
{
@@ -257,6 +269,7 @@ arg4 arg5
baz
`,
cmd: CmdDup,
+ str: "dup:",
args: "title goes here",
},
{
@@ -266,6 +279,7 @@ title on the next line goes here
but not this one
`,
cmd: CmdDup,
+ str: "dup",
args: "title on the next line goes here",
},
{
@@ -273,8 +287,8 @@ but not this one
#syz foo bar
baz
`,
- cmd: CmdUnknown,
- args: "foo bar",
+ cmd: CmdUnknown,
+ str: "foo",
},
}
@@ -321,6 +335,7 @@ To view this discussion on the web visit https://groups.google.com/d/msgid/syzka
For more options, visit https://groups.google.com/d/optout.`,
Patch: "",
Command: CmdFix,
+ CommandStr: "fix:",
CommandArgs: "arg1 arg2 arg3",
}},
@@ -366,6 +381,7 @@ second line
last line`,
Patch: "",
Command: CmdInvalid,
+ CommandStr: "invalid",
CommandArgs: "",
}},
@@ -389,9 +405,9 @@ last line
second line
last line
#syz command`,
- Patch: "",
- Command: CmdUnknown,
- CommandArgs: "command",
+ Patch: "",
+ Command: CmdUnknown,
+ CommandStr: "command",
}},
{`Date: Sun, 7 May 2017 19:54:00 -0700
@@ -554,6 +570,7 @@ index 3d85747bd86e..a257b872a53d 100644
if (error)
`,
Command: CmdTest,
+ CommandStr: "test",
CommandArgs: "commit 59372bbf3abd5b24a7f6f676a3968685c280f955",
}},
@@ -602,6 +619,7 @@ d
#syz dup: BUG: unable to handle kernel NULL pointer dereference in corrupted
`,
Command: CmdDup,
+ CommandStr: "dup:",
CommandArgs: "BUG: unable to handle kernel NULL pointer dereference in corrupted",
}},
@@ -618,6 +636,7 @@ BUG: unable to handle kernel NULL pointer dereference in corrupted
BUG: unable to handle kernel NULL pointer dereference in corrupted
`,
Command: CmdDup,
+ CommandStr: "dup:",
CommandArgs: "BUG: unable to handle kernel NULL pointer dereference in corrupted",
}},
@@ -634,6 +653,7 @@ When freeing a lockf struct that already is part of a linked list, make sure to
When freeing a lockf struct that already is part of a linked list, make sure to
`,
Command: CmdFix,
+ CommandStr: "fix:",
CommandArgs: "When freeing a lockf struct that already is part of a linked list, make sure to",
}},
}