From 8441eb82f3a1a4d03eb0e194e91bc86017ab4466 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 1 Oct 2020 13:34:16 +0200 Subject: dashboard/app: add unfix command Add "#syz unfix" command that undoes "#syz fix" effects and resets any existing fixing commits. --- dashboard/app/email_test.go | 29 +++++++++++++++++++++++ dashboard/app/reporting.go | 3 ++- dashboard/app/reporting_email.go | 3 +++ dashboard/dashapi/dashapi.go | 25 ++++++++++---------- docs/syzbot.md | 4 ++++ pkg/email/parser.go | 51 +++++++++++++++++++++++----------------- 6 files changed, 80 insertions(+), 35 deletions(-) diff --git a/dashboard/app/email_test.go b/dashboard/app/email_test.go index 5bd46c95e..2e73e61f3 100644 --- a/dashboard/app/email_test.go +++ b/dashboard/app/email_test.go @@ -619,3 +619,32 @@ syzbot will keep track of this issue. See: https://goo.gl/tpsmEJ#status for how to communicate with syzbot.`, extBugID, crashLogLink, kernelConfigLink)) } + +// Test for unfix command which should unmark a bug as fixed by any commits. +func TestEmailUnfix(t *testing.T) { + c := NewCtx(t) + defer c.Close() + + build := testBuild(1) + c.client2.UploadBuild(build) + + crash := testCrash(build, 1) + c.client2.ReportCrash(crash) + + c.expectOK(c.GET("/email_poll")) + msg := c.pollEmailBug() + + c.incomingEmail(msg.Sender, "#syz fix: some commit") + c.expectNoEmail() + c.incomingEmail(msg.Sender, "#syz unfix") + c.expectNoEmail() + + build2 := testBuild(2) + build2.Manager = build.Manager + build2.Commits = []string{"some commit"} + c.client2.UploadBuild(build2) + + // The bug should be still unfixed, since we unmarked it. + c.client2.ReportCrash(crash) + c.expectNoEmail() +} diff --git a/dashboard/app/reporting.go b/dashboard/app/reporting.go index 6f95c3235..775eaf759 100644 --- a/dashboard/app/reporting.go +++ b/dashboard/app/reporting.go @@ -831,7 +831,8 @@ func incomingCommandUpdate(c context.Context, now time.Time, cmd *dashapi.BugUpd if ok, reply, err := incomingCommandCmd(c, now, cmd, bug, dup, bugReporting, final, stateEnt); !ok { return false, reply, err } - if len(cmd.FixCommits) != 0 && (bug.Status == BugStatusOpen || bug.Status == BugStatusDup) { + if (len(cmd.FixCommits) != 0 || cmd.ResetFixCommits) && + (bug.Status == BugStatusOpen || bug.Status == BugStatusDup) { sort.Strings(cmd.FixCommits) if !reflect.DeepEqual(bug.Commits, cmd.FixCommits) { bug.updateCommits(cmd.FixCommits, now) diff --git a/dashboard/app/reporting_email.go b/dashboard/app/reporting_email.go index 140bee5a2..178a64c30 100644 --- a/dashboard/app/reporting_email.go +++ b/dashboard/app/reporting_email.go @@ -311,6 +311,8 @@ func incomingMail(c context.Context, r *http.Request) error { return replyTo(c, msg, "no commit title", nil) } cmd.FixCommits = []string{msg.CommandArgs} + case email.CmdUnFix: + cmd.ResetFixCommits = true case email.CmdDup: if msg.CommandArgs == "" { return replyTo(c, msg, "no dup title", nil) @@ -343,6 +345,7 @@ var emailCmdToStatus = map[email.Command]dashapi.BugStatus{ email.CmdInvalid: dashapi.BugStatusInvalid, email.CmdUnDup: dashapi.BugStatusOpen, email.CmdFix: dashapi.BugStatusOpen, + email.CmdUnFix: dashapi.BugStatusUpdate, email.CmdDup: dashapi.BugStatusDup, email.CmdUnCC: dashapi.BugStatusUnCC, } diff --git a/dashboard/dashapi/dashapi.go b/dashboard/dashapi/dashapi.go index a1c5c0f63..04e3058bf 100644 --- a/dashboard/dashapi/dashapi.go +++ b/dashboard/dashapi/dashapi.go @@ -365,18 +365,19 @@ type BisectResult struct { } type BugUpdate struct { - ID string // copied from BugReport - JobID string // copied from BugReport - ExtID string - Link string - Status BugStatus - ReproLevel ReproLevel - DupOf string - OnHold bool // If set for open bugs, don't upstream this bug. - Notification bool // Reply to a notification. - FixCommits []string // Titles of commits that fix this bug. - CC []string // Additional emails to add to CC list in future emails. - CrashID int64 + ID string // copied from BugReport + JobID string // copied from BugReport + ExtID string + Link string + Status BugStatus + ReproLevel ReproLevel + DupOf string + OnHold bool // If set for open bugs, don't upstream this bug. + Notification bool // Reply to a notification. + ResetFixCommits bool // Remove all commits (empty FixCommits means leave intact). + FixCommits []string // Titles of commits that fix this bug. + CC []string // Additional emails to add to CC list in future emails. + CrashID int64 } type BugUpdateReply struct { diff --git a/docs/syzbot.md b/docs/syzbot.md index 34f568c29..b947631cc 100644 --- a/docs/syzbot.md +++ b/docs/syzbot.md @@ -37,6 +37,10 @@ about its final title, in particular, you don't need to wait for the commit to be merged into upstream tree. `syzbot` only needs to know the title by which it will appear in tested trees. In case of an error or a title change, you can override the commit simply by sending another `#syz fix` command. +- to undo a previous fix command and remove any fixing commits: +``` +#syz unfix +```` - to mark the bug as a duplicate of another `syzbot` bug: ``` #syz dup: exact-subject-of-another-report diff --git a/pkg/email/parser.go b/pkg/email/parser.go index 589598ba2..df7cc4717 100644 --- a/pkg/email/parser.go +++ b/pkg/email/parser.go @@ -38,6 +38,7 @@ const ( CmdNone CmdUpstream CmdFix + CmdUnFix CmdDup CmdUnDup CmdTest @@ -223,28 +224,7 @@ func extractCommand(body string) (cmd Command, str, args string) { cmdEnd = cmdEnd1 } str = body[cmdPos : cmdPos+cmdEnd] - switch str { - default: - cmd = CmdUnknown - case "": - cmd = CmdNone - case "upstream": - cmd = CmdUpstream - case "fix", "fix:": - cmd = CmdFix - case "dup", "dup:": - cmd = CmdDup - case "undup": - cmd = CmdUnDup - case "test", "test:": - cmd = CmdTest - case "invalid": - cmd = CmdInvalid - case "uncc", "uncc:": - cmd = CmdUnCC - case "test_5_arg_cmd": - cmd = cmdTest5 - } + cmd = strToCmd(str) // Some email clients split text emails at 80 columns are the transformation is irrevesible. // We try hard to restore what was there before. // For "test:" command we know that there must be 2 tokens without spaces. @@ -260,6 +240,33 @@ func extractCommand(body string) (cmd Command, str, args string) { return } +func strToCmd(str string) Command { + switch str { + default: + return CmdUnknown + case "": + return CmdNone + case "upstream": + return CmdUpstream + case "fix", "fix:": + return CmdFix + case "unfix": + return CmdUnFix + case "dup", "dup:": + return CmdDup + case "undup": + return CmdUnDup + case "test", "test:": + return CmdTest + case "invalid": + return CmdInvalid + case "uncc", "uncc:": + return CmdUnCC + case "test_5_arg_cmd": + return cmdTest5 + } +} + func extractArgsTokens(body string, num int) string { var args []string for pos := 0; len(args) < num && pos < len(body); { -- cgit mrf-deployment