diff --git a/handlers/monthly_update/__init__.py b/handlers/monthly_update/__init__.py new file mode 100644 index 0000000..8b0d2ca --- /dev/null +++ b/handlers/monthly_update/__init__.py @@ -0,0 +1,46 @@ +from eventhandler import EventHandler + +import re + +REPLY = "monthly update" + +REACTION = "eyes" + +MSG = ('Someone thinks this change could be added to the monthly blog ' + 'post! To help with this, we need someone to answer the following ' + 'qurstions: :smile:\n\n' + '1. Who is most impacted by this change: users, ' + 'Servo developers, embedders, or some other group?\n' + '1. What observable difference does this change make?\n' + '1. What preferences (if any) need to be enabled to observe ' + 'this difference?\n' + '1. What (if any) specific URLs are affected?\n\n' + 'If this change is part of a broader feature/project please ' + 'make sure the PR description contains a `Fixes: #12345` or ' + '`Part of: #12345` issue reference.\n\n' + 'Please add `@%s %s` when answering these ' + 'questions so the bot notices your answer (or just quote this ' + 'comment).\n\n' + 'Thanks for helping us prepare the monthly blog post! :heart:') + + +class MonthlyUpdateHandler(EventHandler): + def on_issue_labeled(self, api, payload): + if payload['label']['name'].lower() == 'monthly update': + api.post_comment(MSG % (api.user, REPLY)) + + def on_new_comment(self, api, payload): + if payload['issue']['state'] != 'open': + return + + user = payload['comment']['user']['login'] + if user == api.user: # ignore comments from self + return # (since `MSG` already has `REPLY`) + + msg = payload['comment']['body'] + + if re.search(r'@%s[: ]*%s' % (api.user, REPLY), str(msg)): + api.add_reaction(payload['comment']['id'], REACTION) + + +handler_interface = MonthlyUpdateHandler diff --git a/handlers/monthly_update/tests/label_monthly_update.json b/handlers/monthly_update/tests/label_monthly_update.json new file mode 100644 index 0000000..03e0970 --- /dev/null +++ b/handlers/monthly_update/tests/label_monthly_update.json @@ -0,0 +1,21 @@ +{ + "initial": {}, + "expected": { + "comments": 1 + }, + "payload": { + "repository": { + "owner": { + "login": "servo" + }, + "name": "highfive" + }, + "label": { + "name": "monthly update" + }, + "action": "labeled", + "issue": { + "number": 130 + } + } +} diff --git a/handlers/monthly_update/tests/reply.json b/handlers/monthly_update/tests/reply.json new file mode 100644 index 0000000..325ded4 --- /dev/null +++ b/handlers/monthly_update/tests/reply.json @@ -0,0 +1,26 @@ +{ + "initial": {}, + "expected": { + "reactions": 1 + }, + "payload": { + "repository": { + "owner": { + "login": "servo" + }, + "name": "highfive" + }, + "action": "created", + "issue": { + "number": 130, + "state": "open" + }, + "comment": { + "user": { + "login": "someone" + }, + "body": "@highfive monthly update answers!", + "id": 12 + } + } +} diff --git a/newpr.py b/newpr.py index 98ca7b1..629e093 100755 --- a/newpr.py +++ b/newpr.py @@ -86,6 +86,7 @@ class GithubAPIProvider(APIProvider): BASE_URL = "https://api.github.com/repos/" contributors_url = BASE_URL + "%s/%s/contributors?per_page=400" post_comment_url = BASE_URL + "%s/%s/issues/%s/comments" + add_reaction_url = BASE_URL + "%s/%s/issues/comments/%s/reactions" collaborators_url = BASE_URL + "%s/%s/collaborators" issue_url = BASE_URL + "%s/%s/issues/%s" get_label_url = BASE_URL + "%s/%s/issues/%s/labels" @@ -170,6 +171,16 @@ def is_new_contributor(self, username): return True url = links['next'] + def add_reaction(self, comment_id, reaction): + url = self.add_reaction_url % (self.owner, self.repo, comment_id) + try: + self.api_req("POST", url, {"content": reaction}) + except error.HTTPError as e: + if e.code == 201: + pass + else: + raise e + def post_comment(self, body): url = self.post_comment_url % (self.owner, self.repo, self.issue) try: diff --git a/test.py b/test.py index 8658aa8..478d505 100644 --- a/test.py +++ b/test.py @@ -22,6 +22,7 @@ def __init__(self, payload, user, new_contributor, labels, assignee, self.diff = diff self.pull_request = pull_request self.repo = str(self.repo) # workaround for testing + self.reactions = [] def is_new_contributor(self, username): return self.new_contributor @@ -32,6 +33,9 @@ def post_comment(self, body): def add_label(self, label): self.labels += [label] + def add_reaction(self, comment_id, reaction): + self.reactions += [reaction] + def remove_label(self, label): self.labels.remove(label) @@ -107,6 +111,9 @@ def run_tests(tests, warn=True, overwrite=False): if 'assignee' in expected: assert api.assignee == expected['assignee'], \ "%s == %s" % (api.assignee, expected['assignee']) + if 'reactions' in expected: + assert len(api.reactions) == expected['reactions'], \ + "%s == %s" % (len(api.reactions), expected['reactions']) # If this is the last test in the file, then it's time for cleanup if test['clean']: