def from_github(repo: GithubRepository, pull_id: int) -> 'PullRequestDetails': """Retrieves a single pull request. References: https://developer.github.com/v3/pulls/#get-a-single-pull-request Args: repo: The github repo to get the pull request from. pull_id: The id of the pull request. Raises: RuntimeError: If the request does not return status 200 (success). """ url = "https://api.github.com/repos/{}/{}/pulls/{}".format( repo.organization, repo.name, pull_id) response = repo.get(url) if response.status_code != 200: raise RuntimeError( 'Pull check failed. Code: {}. Content: {!r}.'.format( response.status_code, response.content)) payload = json.JSONDecoder().decode(response.content.decode()) return PullRequestDetails(payload, repo)
def get_branch_details(repo: GithubRepository, branch: str) -> Any: """Get details about a github branch. References: https://developer.github.com/v3/repos/branches/#get-branch Args: repo: The github repo that has the branch. branch: The name of the branch. Returns: The raw response to the query to get details. Raises: RuntimeError: If the request does not return status 200 (success). """ url = "https://api.github.com/repos/{}/{}/branches/{}".format( repo.organization, repo.name, branch) response = repo.get(url) if response.status_code != 200: raise RuntimeError( 'Failed to get branch details. Code: {}. Content: {!r}.'.format( response.status_code, response.content)) return json.JSONDecoder().decode(response.content.decode())
def list_pr_comments(repo: GithubRepository, pull_id: int) -> List[Dict[str, Any]]: """List comments for a given pull request. References: https://developer.github.com/v3/issues/comments/#list-comments-on-an-issue Args: repo: The github repo for the pull request. pull_id: The id of the pull request. Returns: A list of the raw responses for the pull requests. Raises: RuntimeError: If the request does not return status 200 (success). """ url = "https://api.github.com/repos/{}/{}/issues/{}/comments".format( repo.organization, repo.name, pull_id) response = repo.get(url) if response.status_code != 200: raise RuntimeError( 'Comments get failed. Code: {}. Content: {!r}.'.format( response.status_code, response.content)) payload = json.JSONDecoder().decode(response.content.decode()) return payload
def check_collaborator_has_write( repo: GithubRepository, username: str) -> Optional[CannotAutomergeError]: """Checks whether the given user is a collaborator (admin and write access). References: https://developer.github.com/v3/issues/events/#list-events-for-an-issue Args: repo: The github repo to check. username: The github username to check whether the user is a collaborator. Returns: CannotAutomergeError if the user does not have admin and write permissions and so cannot use automerge, None otherwise. Raises: RuntimeError: If the request does not return status 200 (success). """ url = "https://api.github.com/repos/{}/{}/collaborators/{}/permission" "".format( repo.organization, repo.name, username) response = repo.get(url) if response.status_code != 200: raise RuntimeError( 'Collaborator check failed. Code: {}. Content: {!r}.'.format( response.status_code, response.content)) payload = json.JSONDecoder().decode(response.content.decode()) if payload['permission'] not in ['admin', 'write']: return CannotAutomergeError( 'Only collaborators with write permission can use automerge.') return None
def get_all(repo: GithubRepository, url_func: Callable[[int], str]) -> List[Any]: """Get all results, accounting for pagination. Args: repo: The github repo to call GET on. url_func: A function from an integer page number to the url to get the result for that page. Returns: A list of the results by page. Raises: RuntimeError: If the request does not return status 200 (success). """ results: List[Any] = [] page = 0 has_next = True while has_next: url = url_func(page) response = repo.get(url) if response.status_code != 200: raise RuntimeError( f'Request failed to {url}. Code: {response.status_code}.' f' Content: {response.content!r}.') payload = json.JSONDecoder().decode(response.content.decode()) results += payload has_next = 'link' in response.headers and 'rel="next"' in response.headers[ 'link'] page += 1 return results
def get_repo_ref(repo: GithubRepository, ref: str) -> Dict[str, Any]: """Get a given github reference. References: https://developer.github.com/v3/git/refs/#get-a-reference Args: repo: The github repo to get the reference from. ref: The id of the reference. Returns: The raw response of the request for the reference.. Raises: RuntimeError: If the request does not return status 200 (success). """ url = f"https://api.github.com/repos/{repo.organization}/{repo.name}/git/refs/{ref}" response = repo.get(url) if response.status_code != 200: raise RuntimeError( 'Refs get failed. Code: {}. Content: {!r}.'.format( response.status_code, response.content ) ) payload = json.JSONDecoder().decode(response.content.decode()) return payload
def list_open_pull_requests(repo: GithubRepository, base_branch: Optional[str] = None, per_page: int = 100) -> List[PullRequestDetails]: url = ( f"https://api.github.com/repos/{repo.organization}/{repo.name}/pulls" f"?per_page={per_page}") data = { 'state': 'open', } if base_branch is not None: data['base'] = base_branch response = repo.get(url, json=data) if response.status_code != 200: raise RuntimeError( 'List pulls failed. Code: {}. Content: {!r}.'.format( response.status_code, response.content)) pulls = json.JSONDecoder().decode(response.content.decode()) results = [PullRequestDetails(pull, repo) for pull in pulls] # Filtering via the API doesn't seem to work, so we do it ourselves. if base_branch is not None: results = [ result for result in results if result.base_branch_name == base_branch ] return results
def get_repo_ref(repo: GithubRepository, ref: str) -> Dict[str, Any]: """ References: https://developer.github.com/v3/git/refs/#get-a-reference """ url = f"https://api.github.com/repos/{repo.organization}/{repo.name}/git/refs/{ref}" response = repo.get(url) if response.status_code != 200: raise RuntimeError('Refs get failed. Code: {}. Content: {!r}.'.format( response.status_code, response.content)) payload = json.JSONDecoder().decode(response.content.decode()) return payload
def list_pr_comments(repo: GithubRepository, pull_id: int) -> List[Dict[str, Any]]: """ References: https://developer.github.com/v3/issues/comments/#list-comments-on-an-issue """ url = "https://api.github.com/repos/{}/{}/issues/{}/comments".format( repo.organization, repo.name, pull_id) response = repo.get(url) if response.status_code != 200: raise RuntimeError( 'Comments get failed. Code: {}. Content: {!r}.'.format( response.status_code, response.content)) payload = json.JSONDecoder().decode(response.content.decode()) return payload
def get_branch_details(repo: GithubRepository, branch: str) -> Any: """ References: https://developer.github.com/v3/repos/branches/#get-branch """ url = "https://api.github.com/repos/{}/{}/branches/{}".format( repo.organization, repo.name, branch) response = repo.get(url) if response.status_code != 200: raise RuntimeError( 'Failed to get branch details. Code: {}. Content: {!r}.'.format( response.status_code, response.content)) return json.JSONDecoder().decode(response.content.decode())
def from_github(repo: GithubRepository, pull_id: int) -> 'PullRequestDetails': """ References: https://developer.github.com/v3/pulls/#get-a-single-pull-request """ url = "https://api.github.com/repos/{}/{}/pulls/{}".format( repo.organization, repo.name, pull_id) response = repo.get(url) if response.status_code != 200: raise RuntimeError( 'Pull check failed. Code: {}. Content: {!r}.'.format( response.status_code, response.content)) payload = json.JSONDecoder().decode(response.content.decode()) return PullRequestDetails(payload, repo)
def get_all(repo: GithubRepository, url_func: Callable[[int], str]) -> List[Any]: results: List[Any] = [] page = 0 has_next = True while has_next: url = url_func(page) response = repo.get(url) if response.status_code != 200: raise RuntimeError( f'Request failed to {url}. Code: {response.status_code}.' f' Content: {response.content!r}.') payload = json.JSONDecoder().decode(response.content.decode()) results += payload has_next = 'link' in response.headers and 'rel="next"' in response.headers[ 'link'] page += 1 return results
def list_open_pull_requests( repo: GithubRepository, base_branch: Optional[str] = None, per_page: int = 100 ) -> List[PullRequestDetails]: """List open pull requests. Args: repo: The github repo for the pull requests. base_branch: The branch for which to request pull requests. per_page: The number of results to obtain per page. Returns: A list of the pull requests. Raises: RuntimeError: If the request does not return status 200 (success). """ url = ( f"https://api.github.com/repos/{repo.organization}/{repo.name}/pulls" f"?per_page={per_page}" ) data = {'state': 'open'} if base_branch is not None: data['base'] = base_branch response = repo.get(url, json=data) if response.status_code != 200: raise RuntimeError( 'List pulls failed. Code: {}. Content: {!r}.'.format( response.status_code, response.content ) ) pulls = json.JSONDecoder().decode(response.content.decode()) results = [PullRequestDetails(pull, repo) for pull in pulls] # Filtering via the API doesn't seem to work, so we do it ourselves. if base_branch is not None: results = [result for result in results if result.base_branch_name == base_branch] return results
def check_collaborator_has_write( repo: GithubRepository, username: str) -> Optional[CannotAutomergeError]: """ References: https://developer.github.com/v3/issues/events/#list-events-for-an-issue """ url = "https://api.github.com/repos/{}/{}/collaborators/{}/permission" "".format( repo.organization, repo.name, username) response = repo.get(url) if response.status_code != 200: raise RuntimeError( 'Collaborator check failed. Code: {}. Content: {!r}.'.format( response.status_code, response.content)) payload = json.JSONDecoder().decode(response.content.decode()) if payload['permission'] not in ['admin', 'write']: return CannotAutomergeError( 'Only collaborators with write permission can use automerge.') return None