Skip to content

Commit d4d13cd

Browse files
author
Mike Taylor
committed
Issue #3445 - Part 2. Add machinery for "accepted: invalid" milestone
1 parent 859acb3 commit d4d13cd

File tree

6 files changed

+132
-7
lines changed

6 files changed

+132
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"action": "milestoned",
3+
"issue": {
4+
"title": "www.netflix.com - test private issue accepted",
5+
"repository_url": "https://api.github.com/repos/webcompat/webcompat-tests-private",
6+
"number": 600,
7+
"body": "<!-- @browser: Firefox 55.0 -->\n<!-- @ua_header: Mozilla/5.0 (X11; Linux x86_64; rv:55.0) Gecko/20100101 Firefox/55.0 -->\n<!-- @reported_with: web -->\n<!-- @public_url: https://github.com/webcompat/webcompat-tests/issues/1 -->\n\n**URL**: https://www.netflix.com/",
8+
"labels": [
9+
{
10+
"id": 1788251357,
11+
"node_id": "MDU6TGFiZWwxNzg4MjUxMzU3",
12+
"url": "https://api.github.com/repos/webcompat/webcompat-tests/labels/action-needsmoderation",
13+
"name": "action-needsmoderation",
14+
"color": "d36200",
15+
"default": false,
16+
"description": "issue in the process of being moderated"
17+
}
18+
],
19+
"state": "open",
20+
"milestone": {
21+
"url": "https://api.github.com/repos/webcompat/webcompat-tests-private/milestones/2",
22+
"html_url": "https://github.com/webcompat/webcompat-tests-private/milestone/2",
23+
"labels_url": "https://api.github.com/repos/webcompat/webcompat-tests-private/milestones/2/labels",
24+
"id": 5092463,
25+
"node_id": "MDk6TWlsZXN0b25lNTA5MjQ2Mw==",
26+
"number": 2,
27+
"title": "accepted: invalid",
28+
"description": "This is when a bug has been accepted for moderation",
29+
"open_issues": 0,
30+
"closed_issues": 2,
31+
"state": "open",
32+
"created_at": "2020-02-11T00:37:18Z",
33+
"updated_at": "2020-02-11T18:34:04Z",
34+
"due_on": null,
35+
"closed_at": null
36+
}
37+
},
38+
"milestone": {
39+
"title": "accepted: invalid"
40+
}
41+
}

tests/unit/test_webhook.py

+15
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,21 @@ def test_repo_scope_unknown(self):
411411
actual = helpers.repo_scope(url)
412412
self.assertEqual(expected, actual)
413413

414+
def test_prepare_invalid_issue(self):
415+
"""Test we prepare the right payload for the invalid issue."""
416+
expected = {'body': '<p>Thanks for the report, but this is not a Compatibility\nissue.</p><p>For this project we try to focus our effort on layouts, features\nor content that works as expected in one browser but not in another.\nClosing the issue as Invalid.</p>', # noqa
417+
'milestone': 8,
418+
'state': 'closed',
419+
'title': 'Test title!'}
420+
actual = helpers.prepare_invalid_issue('Test title!')
421+
self.assertEqual(type(actual), dict)
422+
self.assertEqual(actual, expected)
423+
424+
def test_prepare_invalid_issue_no_title(self):
425+
"""Test we raise for a missing title arguement."""
426+
with pytest.raises(ValueError) as excinfo:
427+
helpers.prepare_invalid_issue()
428+
414429
def test_prepare_rejected_issue(self):
415430
"""Test we prepare the right payload for the rejected issue."""
416431
expected = {'body': "<p>The content of this issue doesn't meet our\n"

tests/unit/test_webhook_model.py

+19-1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,21 @@ def test_reject_private_issue(mock_mr):
142142
assert issue.get_public_issue_number() in uri
143143

144144

145+
@patch('webcompat.webhooks.model.make_request')
146+
def test_reject_invalid_issue(mock_mr):
147+
"""Test issue state and API request that is sent to GitHub."""
148+
mock_mr.return_value.status_code == 200
149+
json_event, signature = event_data('private_issue_opened.json')
150+
payload = json.loads(json_event)
151+
issue = WebHookIssue.from_dict(payload)
152+
issue.reject_invalid_issue()
153+
method, uri, data = mock_mr.call_args[0]
154+
# make sure we sent a patch with the right data to GitHub
155+
assert method == 'patch'
156+
assert type(data) == dict
157+
assert issue.get_public_issue_number() in uri
158+
159+
145160
def test_prepare_public_comment():
146161
"""Test we prepare the right comment body."""
147162
expected_payload = '{"body": "[Original issue 1](https://github.com/webcompat/webcompat-tests/issues/1)"}' # noqa
@@ -319,7 +334,10 @@ def test_process_issue_action_github_api_exception(mock_mr, caplog):
319334
('new_event_valid.json', 'public:opened labels failed',
320335
'tag_as_public'),
321336
('private_milestone_closed.json',
322-
'public rejection failed', 'reject_private_issue')
337+
'public rejection failed', 'reject_private_issue'),
338+
('private_milestone_accepted_invalid.json',
339+
'private:closing public issue as invalid failed',
340+
'reject_invalid_issue')
323341
]
324342
for scenario in scenarios:
325343
issue_payload, expected_log, method = scenario

webcompat/issues.py

+16-6
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@
2323
PRIVATE_REPO_URI = app.config['PRIVATE_REPO_URI']
2424
PRIVATE_REPO_MILESTONE = app.config['PRIVATE_REPO_MILESTONE']
2525

26-
REJECTED_TITLE = 'Issue rejected.'
27-
REJECTED_BODY = '''<p>The content of this issue doesn't meet our
28-
<a href="https://webcompat.com/terms#acceptable-use">acceptable use</a>
29-
guidelines. Its original content has been deleted.</p>'''
26+
INVALID_BODY = '''<p>Thanks for the report, but this is not a Compatibility
27+
issue.</p><p>For this project we try to focus our effort on layouts, features
28+
or content that works as expected in one browser but not in another.
29+
Closing the issue as Invalid.</p>'''
3030
ONGOING_TITLE = 'In the moderation queue.'
3131
ONGOING_BODY = '''<p>This issue has been put in the moderation queue. A human
3232
will review if the message meets our current
@@ -35,20 +35,30 @@
3535
It will probably take a couple of days depending on the backlog.
3636
Once it has been reviewed, the content will be either made public
3737
or deleted.</p>'''
38+
REJECTED_TITLE = 'Issue rejected.'
39+
REJECTED_BODY = '''<p>The content of this issue doesn't meet our
40+
<a href="https://webcompat.com/terms#acceptable-use">acceptable use</a>
41+
guidelines. Its original content has been deleted.</p>'''
3842

3943

40-
def moderation_template(choice='ongoing'):
44+
def moderation_template(choice='ongoing', title=None):
4145
"""Gets the placeholder data to send for unmoderated issues.
4246
43-
The moderation is for now two types:
47+
The moderation is for now these types:
4448
- ongoing: the issue is in the moderation queue.
4549
- rejected: the issue has been rejected.
50+
- invalid: the issue is invalid (but not rejected)
4651
4752
The default is 'ongoing' even with unknown keywords.
4853
"""
4954
if choice == 'rejected':
5055
title = REJECTED_TITLE
5156
body = REJECTED_BODY
57+
elif choice == 'invalid':
58+
if not title:
59+
raise ValueError("A title must be passed in for invalid issues")
60+
title = title
61+
body = INVALID_BODY
5262
else:
5363
title = ONGOING_TITLE
5464
body = ONGOING_BODY

webcompat/webhooks/helpers.py

+19
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,25 @@ def msg_log(msg, issue_number):
209209
log.info(msg)
210210

211211

212+
def prepare_invalid_issue(title=None):
213+
"""Create the payload for the invalid moderated issue.
214+
215+
When the issue has been moderated as "accepted:invalid",
216+
we need to change a couple of things in the public space
217+
218+
- change body
219+
- close the issue
220+
- remove the action-needsmoderation label
221+
- change the milestone to invalid
222+
"""
223+
# Extract the relevant information
224+
invalid_id = app.config['STATUSES']['invalid']['id']
225+
payload_request = moderation_template('invalid', title)
226+
payload_request['state'] = 'closed'
227+
payload_request['milestone'] = invalid_id
228+
return payload_request
229+
230+
212231
def prepare_rejected_issue():
213232
"""Create the payload for the rejected moderated issue.
214233

webcompat/webhooks/model.py

+22
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from webcompat.webhooks.helpers import make_request
2222
from webcompat.webhooks.helpers import msg_log
2323
from webcompat.webhooks.helpers import oops
24+
from webcompat.webhooks.helpers import prepare_invalid_issue
2425
from webcompat.webhooks.helpers import prepare_rejected_issue
2526
from webcompat.webhooks.helpers import repo_scope
2627

@@ -143,6 +144,14 @@ def prepare_public_comment(self):
143144
# prepare the payload
144145
return f'[Original issue {public_number}]({self.public_url})'
145146

147+
def reject_invalid_issue(self):
148+
"""Send a passed-moderation-yet-invalid PATCH to the public issue."""
149+
payload_request = prepare_invalid_issue(self.title)
150+
public_number = self.get_public_issue_number()
151+
# Preparing the proxy request
152+
path = f'repos/{PUBLIC_REPO}/{public_number}'
153+
make_request('patch', path, payload_request)
154+
146155
def reject_private_issue(self):
147156
"""Send a rejected moderation PATCH on the public issue."""
148157
payload_request = prepare_rejected_issue()
@@ -237,6 +246,19 @@ def process_issue_action(self):
237246
# we didn't get exceptions, so it's safe to close it
238247
self.close_private_issue()
239248
return make_response('Moderated issue accepted', 200)
249+
elif (self.action == 'milestoned' and scope == 'private' and
250+
self.milestoned_with == 'accepted: invalid'):
251+
try:
252+
self.reject_invalid_issue()
253+
except HTTPError as e:
254+
msg_log(
255+
'private:closing public issue as invalid failed',
256+
self.number)
257+
return oops()
258+
else:
259+
# we didn't get exceptions, so it's safe to close it
260+
self.close_private_issue()
261+
return make_response('Moderated issue closed as invalid', 200)
240262
elif (scope == 'private' and self.state == 'closed' and
241263
not self.milestone == 'accepted'):
242264
# private issue has been closed. It is rejected

0 commit comments

Comments
 (0)