From 254d42956a405bcef4cbafbc812815d94458e261 Mon Sep 17 00:00:00 2001 From: Eric Rahm Date: Fri, 26 Apr 2019 14:07:31 -0700 Subject: [PATCH] Bug 1544149 - Use markdown in the bug filer (#4888) This updates the bug filer to use markdown in the bugzilla bug description. It adds bolded labels to the `Filed by` entry and any URLs specified. Addtionally the comment is surrounded in a code fence so that long lines aren't wrapped and lines that also happen to have markdown formatting in them are ignored. Example output: **Filed by:** foo [@] bar.com **Parsed log:** http://.../parsed.log.html **Full log:** http://.../full.log.html --- ``` [task 2019-03-06T03:54:26.459Z] 03:54:26 INFO - TEST-FAIL... [task 2019-03-06T03:54:26.460Z] 03:54:26 INFO - INFO | LeakSanitize ... ``` --- tests/webapp/api/test_bugzilla.py | 10 +++--- treeherder/webapp/api/bugzilla.py | 2 +- ui/job-view/details/BugFiler.jsx | 51 +++++++++++++++++++++++-------- 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/tests/webapp/api/test_bugzilla.py b/tests/webapp/api/test_bugzilla.py index 4f2b690a7..106ed6c17 100644 --- a/tests/webapp/api/test_bugzilla.py +++ b/tests/webapp/api/test_bugzilla.py @@ -17,7 +17,7 @@ def test_create_bug(client, eleven_jobs_stored, activate_responses, test_user): requestheaders = request.headers assert requestheaders['x-bugzilla-api-key'] == "12345helloworld" assert requestdata['product'] == "Bugzilla" - assert requestdata['description'] == u"#[markdown(off)]\nFiled by: {}\n\nIntermittent Description".format(test_user.email.replace('@', " [at] ")) + assert requestdata['description'] == u"**Filed by:** {}\nIntermittent Description".format(test_user.email.replace('@', " [at] ")) assert requestdata['component'] == "Administration" assert requestdata['summary'] == u"Intermittent summary" assert requestdata['comment_tags'] == "treeherder" @@ -61,7 +61,7 @@ def test_create_bug_with_unicode(client, eleven_jobs_stored, activate_responses, requestheaders = request.headers assert requestheaders['x-bugzilla-api-key'] == "12345helloworld" assert requestdata['product'] == "Bugzilla" - assert requestdata['description'] == u"#[markdown(off)]\nFiled by: {}\n\nIntermittent “description” string".format(test_user.email.replace('@', " [at] ")) + assert requestdata['description'] == u"**Filed by:** {}\nIntermittent “description” string".format(test_user.email.replace('@', " [at] ")) assert requestdata['component'] == "Administration" assert requestdata['summary'] == u"Intermittent “summary”" assert requestdata['comment_tags'] == "treeherder" @@ -105,7 +105,7 @@ def test_create_crash_bug(client, eleven_jobs_stored, activate_responses, test_u requestheaders = request.headers assert requestheaders['x-bugzilla-api-key'] == "12345helloworld" assert requestdata['product'] == "Bugzilla" - assert requestdata['description'] == u"#[markdown(off)]\nFiled by: {}\n\nIntermittent Description".format(test_user.email.replace('@', " [at] ")) + assert requestdata['description'] == u"**Filed by:** {}\nIntermittent Description".format(test_user.email.replace('@', " [at] ")) assert requestdata['component'] == "Administration" assert requestdata['summary'] == u"Intermittent summary" assert requestdata['comment_tags'] == "treeherder" @@ -155,7 +155,7 @@ def test_create_unauthenticated_bug(client, eleven_jobs_stored, activate_respons requestheaders = request.headers assert requestheaders['x-bugzilla-api-key'] == "12345helloworld" assert requestdata['product'] == "Bugzilla" - assert requestdata['description'] == u"#[markdown(off)]\nFiled by: MyName\n\nIntermittent Description" + assert requestdata['description'] == u"**Filed by:** MyName\nIntermittent Description" assert requestdata['component'] == "Administration" assert requestdata['summary'] == u"Intermittent summary" assert requestdata['comment_tags'] == "treeherder" @@ -203,7 +203,7 @@ def test_create_bug_with_long_crash_signature(client, eleven_jobs_stored, activa requestheaders = request.headers assert requestheaders['x-bugzilla-api-key'] == "12345helloworld" assert requestdata['product'] == "Bugzilla" - assert requestdata['description'] == u"#[markdown(off)]\nFiled by: MyName\n\nIntermittent Description" + assert requestdata['description'] == u"**Filed by:** MyName\nIntermittent Description" assert requestdata['component'] == "Administration" assert requestdata['summary'] == u"Intermittent summary" assert requestdata['comment_tags'] == "treeherder" diff --git a/treeherder/webapp/api/bugzilla.py b/treeherder/webapp/api/bugzilla.py index 81b3666e0..f37a0d4d9 100644 --- a/treeherder/webapp/api/bugzilla.py +++ b/treeherder/webapp/api/bugzilla.py @@ -29,7 +29,7 @@ class BugzillaViewSet(viewsets.ViewSet): return Response({"failure": "Crash signature can't be more than 2048 characters."}, status=HTTP_400_BAD_REQUEST) - description = u"#[markdown(off)]\nFiled by: {}\n\n{}".format( + description = u"**Filed by:** {}\n{}".format( request.user.email.replace('@', " [at] "), params.get("comment", "") ).encode("utf-8") diff --git a/ui/job-view/details/BugFiler.jsx b/ui/job-view/details/BugFiler.jsx index 03276c4a4..596a4469e 100644 --- a/ui/job-view/details/BugFiler.jsx +++ b/ui/job-view/details/BugFiler.jsx @@ -143,9 +143,13 @@ export class BugFilerClass extends React.Component { summaryString = summaryString.replace(re, ''); } - const checkedLogLinks = [parsedLog, fullLog]; + const checkedLogLinks = new Map([ + ['Parsed log', parsedLog], + ['Full log', fullLog], + ]); + if (reftestUrl) { - checkedLogLinks.push(reftestUrl); + checkedLogLinks.set('Reftest URL', reftestUrl); } this.state = { @@ -352,11 +356,14 @@ export class BugFilerClass extends React.Component { }); }; - toggleCheckedLogLink = link => { + toggleCheckedLogLink = (name, link) => { const { checkedLogLinks } = this.state; - const newCheckedLogLinks = checkedLogLinks.includes(link) - ? checkedLogLinks.filter(item => item !== link) - : [...checkedLogLinks, link]; + const newCheckedLogLinks = new Map(checkedLogLinks); + if (newCheckedLogLinks.has(name)) { + newCheckedLogLinks.delete(name); + } else { + newCheckedLogLinks.set(name, link); + } this.setState({ checkedLogLinks: newCheckedLogLinks }); }; @@ -395,7 +402,19 @@ export class BugFilerClass extends React.Component { return; } - const descriptionStrings = [...checkedLogLinks, comment].join('\n\n'); + // Format links in bugzilla markdown: + // **Parsed log:** http://... + // **Full log:** http://.... + const logLinks = [...checkedLogLinks] + .map(e => { + const [name, url] = e; + return `**${name}:** ${url}`; + }) + .join('\n'); + + // Join that with the comment separated with a hard rule. + const descriptionStrings = `${logLinks}\n\n---\n\n${comment}`; + const keywords = isIntermittent ? ['intermittent-failure'] : []; keywords.push('regression'); let severity = 'normal'; @@ -672,8 +691,10 @@ export class BugFilerClass extends React.Component {