diff --git a/tests/webapp/api/test_bugzilla.py b/tests/webapp/api/test_bugzilla.py index 7f6d09f5508..4d6c934aa7f 100644 --- a/tests/webapp/api/test_bugzilla.py +++ b/tests/webapp/api/test_bugzilla.py @@ -209,6 +209,78 @@ def request_callback(request): assert resp.json()["detail"] == "Authentication credentials were not provided." +def test_post_comment(client, activate_responses, test_user): + """ + test successfully posting a comment to a Bugzilla bug + """ + + def request_callback(request): + headers = {} + requestdata = json.loads(request.body) + requestheaders = request.headers + assert requestheaders["x-bugzilla-api-key"] == "12345helloworld" + assert requestdata["comment"] == "Performance improvement detected." + assert requestdata["comment_tags"] == ["perf-alert"] + resp_body = {"id": 101} + return (200, headers, json.dumps(resp_body)) + + responses.add_callback( + responses.POST, + "https://thisisnotbugzilla.org/rest/bug/323/comment", + callback=request_callback, + content_type="application/json", + ) + + client.force_authenticate(user=test_user) + + resp = client.post( + reverse("bugzilla-post-comment"), + {"bug_id": 323, "comment": "Performance improvement detected."}, + ) + assert resp.status_code == 200 + assert resp.json()["id"] == 101 + + +def test_post_comment_missing_bug_id(client, activate_responses, test_user): + """ + test that post_comment returns 400 when bug_id is missing + """ + client.force_authenticate(user=test_user) + + resp = client.post( + reverse("bugzilla-post-comment"), + {"comment": "Performance improvement detected."}, + ) + assert resp.status_code == 400 + assert resp.json()["failure"] == "bug_id is required" + + +def test_post_comment_missing_comment(client, activate_responses, test_user): + """ + test that post_comment returns 400 when comment is missing + """ + client.force_authenticate(user=test_user) + + resp = client.post( + reverse("bugzilla-post-comment"), + {"bug_id": 323}, + ) + assert resp.status_code == 400 + assert resp.json()["failure"] == "comment is required" + + +def test_post_comment_unauthenticated(client, activate_responses): + """ + test that post_comment requires authentication + """ + resp = client.post( + reverse("bugzilla-post-comment"), + {"bug_id": 323, "comment": "Performance improvement detected."}, + ) + assert resp.status_code == 403 + assert resp.json()["detail"] == "Authentication credentials were not provided." + + def test_create_bug_with_long_crash_signature( client, eleven_jobs_stored, activate_responses, test_user ): diff --git a/treeherder/webapp/api/bugzilla.py b/treeherder/webapp/api/bugzilla.py index d4e10015ef0..51544c67208 100644 --- a/treeherder/webapp/api/bugzilla.py +++ b/treeherder/webapp/api/bugzilla.py @@ -121,3 +121,41 @@ def create_bug(self, request): "url": get_bug_url(bug_id, settings.BUGFILER_API_URL), } ) + + @action(detail=False, methods=["post"]) + def post_comment(self, request): + """ + Post a comment to an existing Bugzilla bug + """ + if settings.BUGFILER_API_KEY is None: + return Response({"failure": "Bugzilla API key not set!"}, status=HTTP_400_BAD_REQUEST) + + params = request.data + bug_id = params.get("bug_id") + comment = params.get("comment") + + if not bug_id: + return Response({"failure": "bug_id is required"}, status=HTTP_400_BAD_REQUEST) + if not comment: + return Response({"failure": "comment is required"}, status=HTTP_400_BAD_REQUEST) + + url = f"{settings.BUGFILER_API_URL}/rest/bug/{bug_id}/comment" + headers = { + "x-bugzilla-api-key": settings.BUGFILER_API_KEY, + "Accept": "application/json", + } + data = { + "comment": comment, + "comment_tags": ["perf-alert"], + } + + try: + response = make_request(url, method="POST", headers=headers, json=data) + except requests.exceptions.HTTPError as e: + try: + message = e.response.json()["message"] + except (ValueError, KeyError): + message = e.response.text + return Response({"failure": message}, status=HTTP_400_BAD_REQUEST) + + return Response({"id": response.json().get("id")}) diff --git a/ui/perfherder/alerts/FileBugModal.jsx b/ui/perfherder/alerts/FileBugModal.jsx index 4b53a47eb33..3963562d4b3 100644 --- a/ui/perfherder/alerts/FileBugModal.jsx +++ b/ui/perfherder/alerts/FileBugModal.jsx @@ -56,6 +56,7 @@ export default class FileBugModal extends React.Component { submitButtonText, user, errorMessage, + requireInput, } = this.props; const { inputValue, invalidInput, validated, disableButton } = this.state; @@ -80,7 +81,7 @@ export default class FileBugModal extends React.Component { - {title} (optional): + {title}{requireInput ? ':' : (optional): } @@ -114,7 +115,7 @@ export default class FileBugModal extends React.Component {