Skip to content

Commit 79930e1

Browse files
committed
Add pull request functionality
1 parent 6416606 commit 79930e1

4 files changed

Lines changed: 104 additions & 12 deletions

File tree

bot/github.py

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,35 +81,100 @@ def issues(self, update, _):
8181
self._send(repo, text)
8282

8383
def issue_comment(self, update, context):
84-
# Any time a comment on an issue is created, edited, or deleted.
84+
# Any time a comment on an issue or pull request is created, edited, or deleted.
8585
# TODO: Possibly support editing and closing of comments?
8686
if update.payload['action'] == 'created':
8787
issue = update.payload['issue']
8888
comment = update.payload['comment']
8989
author = comment['user']
9090
repo = update.payload['repository']
91+
is_pull_request = 'pull_request' in issue
9192

9293
text = render_github_markdown(comment['body'], repo['full_name'])
9394

9495
issue_link = link(issue['html_url'], f'{repo["full_name"]}#{issue["number"]} {issue["title"]}')
9596
author_link = link(author['html_url'], '@' + author['login'])
96-
data_link = encode_data_link(('issue', repo['full_name'], issue['number'], author['login']))
97+
data_link = encode_data_link(('pull request' if is_pull_request else 'issue',
98+
repo['full_name'], issue['number'], author['login']))
9799
text = f'{data_link}💬 New comment on {issue_link}\nby {author_link}\n\n{text}'
98100

99101
self._send(repo, text)
100102

101103
def pull_request(self, update, context):
102104
# Pull request opened, closed, reopened, edited, assigned, unassigned, review requested,
103105
# review request removed, labeled, unlabeled, or synchronized.
104-
pass
106+
# TODO: Possibly support closed, reopened, edited, assigned etc.
107+
if update.payload['action'] == 'opened':
108+
pull_request = update.payload['pull_request']
109+
author = pull_request['user']
110+
repo = update.payload['repository']
111+
112+
text = render_github_markdown(pull_request['body'], repo['full_name'])
113+
114+
pull_request_link = link(pull_request['html_url'],
115+
f'{repo["full_name"]}#{pull_request["number"]} {pull_request["title"]}')
116+
author_link = link(author['html_url'], '@' + author['login'])
117+
data_link = encode_data_link(('pull request', repo['full_name'], pull_request['number'], author['login']))
118+
text = f'{data_link}🔌 New pull request {pull_request_link}\nby {author_link}\n\n{text}'
119+
120+
self._send(repo, text)
105121

106122
def pull_request_review(self, update, context):
107123
# Pull request review submitted, edited, or dismissed.
108-
pass
124+
# TODO: Possibly support edited and dismissed?
125+
if update.payload['action'] == 'submitted':
126+
review = update.payload['review']
127+
pull_request = update.payload['pull_request']
128+
author = review['user']
129+
repo = update.payload['repository']
130+
131+
if not review['body']:
132+
return
133+
134+
text = render_github_markdown(review['body'], repo['full_name'])
135+
136+
review_link = link(review['html_url'],
137+
f'{repo["full_name"]}#{pull_request["number"]} {pull_request["title"]}')
138+
author_link = link(author['html_url'], '@' + author['login'])
139+
data_link = encode_data_link(('pull request', repo['full_name'], pull_request['number'], author['login']))
140+
141+
if review['state'] in ('commented', 'approved', 'request_changes'):
142+
if review['state'] == 'commented':
143+
state = 'Commented'
144+
emoji = '💬'
145+
elif review['state'] == 'approved':
146+
state = 'Approved'
147+
emoji = '✅'
148+
elif review['state'] == 'request_changes':
149+
state = 'Changes requested'
150+
emoji = '‼️'
151+
152+
text = f'{data_link}{emoji} New pull request review {review_link}\n{state} by {author_link}\n\n{text}'
153+
self._send(repo, text)
109154

110155
def pull_request_review_comment(self, update, context):
111156
# Pull request diff comment created, edited, or deleted.
112-
pass
157+
if update.payload['action'] == 'created':
158+
pull_request = update.payload['pull_request']
159+
comment = update.payload['comment']
160+
author = comment['user']
161+
repo = update.payload['repository']
162+
163+
diff_hunk = f'<pre>{comment["path"]}\n{comment["diff_hunk"]}</pre>'
164+
165+
text = render_github_markdown(comment['body'], repo['full_name'])
166+
167+
issue_link = link(comment['html_url'],
168+
f'{repo["full_name"]}#{pull_request["number"]} {pull_request["title"]}')
169+
author_link = link(author['html_url'], '@' + author['login'])
170+
data_link = encode_data_link(('pull request review comment',
171+
repo['full_name'],
172+
pull_request['number'],
173+
comment['in_reply_to_id'] if 'in_reply_to_id' in comment else comment['id'],
174+
author['login'],))
175+
text = f'{data_link}💬 New pull request review comment {issue_link}\nby {author_link}\n{diff_hunk}\n\n{text}'
176+
177+
self._send(repo, text)
113178

114179
# def integration_installation_repositories(self, update, context):
115180
# new_repos = [{'id': repo['id'], 'full_name': repo['full_name']} for repo in

bot/githubapi.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,24 @@ def markdown(self, markdown, context):
152152

153153
return r.text
154154

155-
def add_issue_comment(self, repo, issue_number, body, access_token):
156-
r = self.post(f'https://api.github.com/repos/{repo}/issues/{issue_number}/comments', json={
155+
def add_issue_comment(self, repo, number, body, access_token):
156+
r = self.post(f'https://api.github.com/repos/{repo}/issues/{number}/comments', json={
157157
'body': body
158158
}, access_token=access_token)
159159

160160
r.raise_for_status()
161161

162162
return r.text
163163

164+
def add_review_comment(self, repo, number, in_reply_to, body, access_token):
165+
r = self.post(f'https://api.github.com/repos/{repo}/pulls/{number}/comments', json={
166+
'body': body,
167+
'in_reply_to': in_reply_to
168+
}, access_token=access_token)
169+
170+
r.raise_for_status()
171+
172+
return r.text
173+
164174

165175
github_api = GithubAPI()

bot/main.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,12 @@ def reply_handler(update: Update, context: CallbackContext):
7878
if not data:
7979
return
8080

81-
issue_type, repo, number, author = data
81+
comment_type, *data = data
8282

8383
access_token = context.user_data.get('access_token')
8484

8585
if not access_token:
86-
sent_msg = msg.reply_text(f'Cannot reply to {issue_type}, since you are not logged in. '
86+
sent_msg = msg.reply_text(f'Cannot reply to {comment_type}, since you are not logged in. '
8787
f'Press button below to go to a private chat with me and login.\n\n'
8888
f'<i>This message will self destruct in 30 sec.</i>',
8989
reply_markup=InlineKeyboardMarkup([[
@@ -93,10 +93,18 @@ def reply_handler(update: Update, context: CallbackContext):
9393
context.job_queue.run_once(delete_job, 30, sent_msg)
9494
return
9595

96-
if issue_type == 'issue':
96+
if comment_type in ('issue', 'pull request'):
97+
repo, number, author = data
98+
9799
text = f'@{author} {msg.text_markdown}'
98100

99101
github_api.add_issue_comment(repo, number, text, access_token=access_token)
102+
elif comment_type == 'pull request review comment':
103+
repo, number, comment_id, author = data
104+
105+
text = f'@{author} {msg.text_markdown}'
106+
107+
github_api.add_review_comment(repo, number, comment_id, text, access_token=access_token)
100108

101109

102110
if __name__ == '__main__':

bot/utils.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ def __iter__(self):
9696
in_quote = False
9797
in_tag = 0
9898
for token in super().__iter__():
99+
if token['type'] == 'StartTag' and token['name'] == 'pre':
100+
if not in_tag:
101+
token['data'] = {}
102+
yield {
103+
'data': 'Suggestion:\n',
104+
'type': 'Characters'
105+
}
106+
99107
if token['type'] == 'StartTag' and token['name'] == 'li':
100108
if not (token['data'] and token['data'].get('class') != 'task-list-item'):
101109
yield {
@@ -153,8 +161,9 @@ def __iter__(self):
153161
],
154162
attributes={
155163
'a': ['href'],
156-
'li': ['class'],
157-
'input': ['checked']
164+
'li': ['class'], # Stripped in _GithubFilter
165+
'input': ['checked'], # Stripped in _GithubFilter
166+
'pre': ['lang'], # Stripped in _GithubFilter
158167
},
159168
strip=True,
160169
filters=[_GithubFilter]

0 commit comments

Comments
 (0)