Skip to content

Instantly share code, notes, and snippets.

@arunsathiya
Forked from sophiebits-humu/automerge.py
Created April 15, 2020 19:56
Show Gist options
  • Save arunsathiya/3aa25480319df50566bf95b4629baef8 to your computer and use it in GitHub Desktop.
Save arunsathiya/3aa25480319df50566bf95b4629baef8 to your computer and use it in GitHub Desktop.
# (c) 2020 Humu
# MIT License
from typing import Any
import github
AUTOMERGE_LABEL_NAME = 'automerge'
class Automerge:
def __init__(self, githubClient: github.Github) -> None:
self._github = githubClient
def _hasAutomergeLabel(self, pr: github.PullRequest.PullRequest) -> bool:
return any(label.name == AUTOMERGE_LABEL_NAME for label in pr.labels)
def processWebhookEvent(self, eventType: str, eventJson: Any) -> None:
# If a PR becomes green, merge it.
# If new commits are pushed, a PR check fails, or the PR is closed, remove the label.
if eventType == 'status':
# https://developer.github.com/v3/activity/events/types/#statusevent
repo = self._github.create_from_raw_data(
github.Repository.Repository, eventJson['repository']
)
commit = self._github.create_from_raw_data(github.Commit.Commit, eventJson['commit'])
# Shockingly, GitHub gives no way to get the PR associated with a 'status' event. You
# need to search the list of PRs.
matchingPr = next(
(pr for pr in repo.get_pulls(sort='updated') if pr.head.sha == commit.sha), None
)
if matchingPr and self._hasAutomergeLabel(matchingPr):
# Clean means green, unstable means yellow, which happens often with Reviewable,
# for whatever reason. (If the PR is not accepted or one of our required checks is
# failing, it'll be 'blocked'.)
# https://developer.github.com/v4/enum/mergestatestatus/
if matchingPr.mergeable_state in ('clean', 'unstable'):
matchingPr.merge(merge_method='squash')
# If a check fails, we leave the label so that if it's a flaky test it can be rerun.
# (If a test fails due to a code issue and new commits are pushed as a fix, the
# label will be removed due to the 'synchronize' below.)
elif eventType == 'pull_request':
# https://developer.github.com/v3/activity/events/types/#pullrequestevent
pr = self._github.create_from_raw_data(
github.PullRequest.PullRequest, eventJson['pull_request']
)
if self._hasAutomergeLabel(pr):
# 'synchonize' means new commits were pushed
if eventJson['action'] == 'synchronize' or (
eventJson['action'] == 'closed' and not pr.merged
):
pr.remove_from_labels(AUTOMERGE_LABEL_NAME)
elif eventType == 'pull_request_review':
# https://developer.github.com/v3/activity/events/types/#pullrequestreviewevent
pr = self._github.create_from_raw_data(
github.PullRequest.PullRequest, eventJson['pull_request']
)
review = self._github.create_from_raw_data(
github.PullRequestReview.PullRequestReview, eventJson['review']
)
# Some API docs have 'state' values capitalized, some lowercase. Why? Don't know.
if eventJson['action'] == 'submitted' and review.state.lower() == 'changes_requested':
if self._hasAutomergeLabel(pr):
pr.remove_from_labels(AUTOMERGE_LABEL_NAME)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment