| 217 | |
| 218 | |
| 219 | class CommentBot: |
| 220 | |
| 221 | def __init__(self, name, handler, token=None): |
| 222 | # TODO(kszucs): validate |
| 223 | assert isinstance(name, str) |
| 224 | assert callable(handler) |
| 225 | self.name = name |
| 226 | self.handler = handler |
| 227 | kwargs = {} |
| 228 | if token is not None: |
| 229 | kwargs["auth"] = github.Auth.Token(token) |
| 230 | self.github = github.Github(**kwargs) |
| 231 | |
| 232 | def parse_command(self, payload): |
| 233 | mention = f'@{self.name}' |
| 234 | comment = payload['comment'] |
| 235 | |
| 236 | if payload['sender']['login'] == self.name: |
| 237 | raise EventError("Don't respond to itself") |
| 238 | elif payload['action'] not in {'created', 'edited'}: |
| 239 | raise EventError("Don't respond to comment deletion") |
| 240 | elif not comment['body'].lstrip().startswith(mention): |
| 241 | raise EventError("The bot is not mentioned") |
| 242 | |
| 243 | # Parse the comment, removing the bot mentioned (and everything |
| 244 | # before it) |
| 245 | command = payload['comment']['body'].split(mention)[-1] |
| 246 | |
| 247 | # then split on newlines and keep only the first line |
| 248 | # (ignoring all other lines) |
| 249 | return command.split("\n")[0].strip() |
| 250 | |
| 251 | def handle(self, event, payload): |
| 252 | try: |
| 253 | command = self.parse_command(payload) |
| 254 | except EventError as e: |
| 255 | logger.error(e) |
| 256 | # see the possible reasons in the validate method |
| 257 | return |
| 258 | |
| 259 | if event == 'issue_comment': |
| 260 | return self.handle_issue_comment(command, payload) |
| 261 | elif event == 'pull_request_review_comment': |
| 262 | return self.handle_review_comment(command, payload) |
| 263 | else: |
| 264 | raise ValueError(f"Unexpected event type {event}") |
| 265 | |
| 266 | def handle_issue_comment(self, command, payload): |
| 267 | repo = self.github.get_repo(payload['repository']['id'], lazy=True) |
| 268 | issue = repo.get_issue(payload['issue']['number']) |
| 269 | |
| 270 | try: |
| 271 | pull = issue.as_pull_request() |
| 272 | except github.GithubException: |
| 273 | return issue.create_comment( |
| 274 | "The comment bot only listens to pull request comments!" |
| 275 | ) |
| 276 |
no outgoing calls