async def get_channels_info(slack_access_token): """ Get channel information from slack Args: slack_access_token (str): Used to authenticate with slack Returns: dict: A map of channel names to channel ids """ client = ClientWrapper() # public channels resp = await client.post("https://slack.com/api/channels.list", data={"token": slack_access_token}) resp.raise_for_status() channels = resp.json()['channels'] channels_map = {channel['name']: channel['id'] for channel in channels} # private channels resp = await client.post("https://slack.com/api/groups.list", data={"token": slack_access_token}) resp.raise_for_status() groups = resp.json()['groups'] groups_map = {group['name']: group['id'] for group in groups} return {**channels_map, **groups_map}
async def get_pull_request(*, github_access_token, org, repo, branch): """ Look up the pull request for a branch Args: github_access_token (str): The github access token org (str): The github organization (eg mitodl) repo (str): The github repository (eg micromasters) branch (str): The name of the associated branch Returns: dict: The information about the pull request """ endpoint = "https://api.github.com/repos/{org}/{repo}/pulls".format( org=org, repo=repo, ) client = ClientWrapper() response = await client.get( endpoint, headers=github_auth_headers(github_access_token), ) response.raise_for_status() pulls = response.json() pulls = [pull for pull in pulls if pull['head']['ref'] == branch] if not pulls: return None elif len(pulls) > 1: # Shouldn't happen since we look up by branch raise Exception( "More than one pull request for the branch {}".format(branch)) return pulls[0]
async def create_pr(*, github_access_token, repo_url, title, body, head, base): # pylint: disable=too-many-arguments """ Create a pull request Args: github_access_token (str): A github access token repo_url (str): The URL of the repository to create the PR in title (str): The title of the PR body (str): The body of the PR head (str): The head branch for the PR base (str): The base branch for the PR """ org, repo = get_org_and_repo(repo_url) endpoint = "https://api.github.com/repos/{org}/{repo}/pulls".format( org=org, repo=repo, ) client = ClientWrapper() resp = await client.post(endpoint, headers=github_auth_headers(github_access_token), data=json.dumps({ 'title': title, 'body': body, 'head': head, 'base': base, })) resp.raise_for_status()
async def get_issue(*, github_access_token, org, repo, issue_number): """ Look up information about an issue Args: github_access_token (str): The github access token org (str): An organization repo (str): A repository issue_number (int): The github issue number Returns: Issue: Information about the issue """ endpoint = f"https://api.github.com/repos/{org}/{repo}/issues/{issue_number}" client = ClientWrapper() response = await client.get( endpoint, headers=github_auth_headers(github_access_token)) response.raise_for_status() response_json = response.json() if 'pull_request' in response_json: return return Issue( title=response_json['title'], number=response_json['number'], org=org, repo=repo, status=response_json['state'], updatedAt=parse(response_json['updated_at']), url=response_json['html_url'], )
async def create_pr(*, github_access_token, repo_url, title, body, head, base): # pylint: disable=too-many-arguments """ Create a pull request Args: github_access_token (str): A github access token repo_url (str): The URL of the repository to create the PR in title (str): The title of the PR body (str): The body of the PR head (str): The head branch for the PR base (str): The base branch for the PR Returns: PullRequest: Info about the new pull request """ org, repo = get_org_and_repo(repo_url) endpoint = f"https://api.github.com/repos/{org}/{repo}/pulls" client = ClientWrapper() resp = await client.post( endpoint, headers=github_auth_headers(github_access_token), data=json.dumps({ "title": title, "body": body, "head": head, "base": base, }), ) resp.raise_for_status()
async def get_channels_info(slack_access_token): """ Get channel information from slack Args: slack_access_token (str): Used to authenticate with slack Returns: dict: A map of channel names to channel ids """ client = ClientWrapper() # public channels channels = {} async for channel in iterate_cursor( client.post, "channels", "https://slack.com/api/conversations.list", data={ "token": slack_access_token, "types": "public_channel,private_channel", }): channels[channel['name']] = channel['id'] return channels
async def get_pull_request(*, github_access_token, org, repo, branch, all_prs): """ Look up the most recently created pull request for a branch Args: github_access_token (str): The github access token org (str): The github organization (eg mitodl) repo (str): The github repository (eg micromasters) branch (str): The name of the associated branch all_prs (bool): If True, look through open and closed PRs. The most recent PR for that branch will be returned. If False, look only through open PRs. Returns: dict: The information about the pull request """ state = "all" if all_prs else "open" endpoint = f"https://api.github.com/repos/{org}/{repo}/pulls?state={state}&head={org}:{branch}&per_page=1" client = ClientWrapper() response = await client.get( endpoint, headers=github_auth_headers(github_access_token), ) response.raise_for_status() pulls = response.json() return pulls[0] if pulls else None
async def get_channels_info(slack_access_token): """ Get channel information from slack Args: slack_access_token (str): Used to authenticate with slack Returns: dict: A map of channel names to channel ids """ client = ClientWrapper() # public channels channels = {} async for channel in iterate_cursor( client.post, "channels", # see https://api.slack.com/methods/conversations.list "https://slack.com/api/conversations.list", data={ "token": slack_access_token, "types": "public_channel,private_channel", "limit": 200, # increase from default of 100 "exclude_archived": "true", }, ): channels[channel["name"]] = channel["id"] return channels
async def fetch_release_hash(hash_url): """Fetch the hash from the release""" client = ClientWrapper() response = await client.get(hash_url) response.raise_for_status() release_hash = response.content.decode().strip() if len(release_hash) != 40: raise Exception( f"Expected release hash from {hash_url} but got: {release_hash}" ) return release_hash
async def get_doofs_id(slack_access_token): """ Ask Slack for Doof's id Args: slack_access_token (str): The slack access token """ client = ClientWrapper() async for member in iterate_cursor(client.post, "members", "https://slack.com/api/users.list", data={"token": slack_access_token}): if member['name'] == 'doof': return member['id'] raise Exception("Unable to find Doof's user id")
async def delete_label(*, github_access_token, repo_url, pr_number, label): """ Set labels on a pull request, replacing other labels currently on that pull request. Args: github_access_token (str): A Github access token repo_url (str): The repository git URL pr_number (int): A pull request number label (str): The label text """ org, repo = get_org_and_repo(repo_url) endpoint = f"https://api.github.com/repos/{org}/{repo}/issues/{pr_number}/labels/{quote(label)}" client = ClientWrapper() response = await client.delete( endpoint, headers=github_auth_headers(github_access_token)) if response.status_code != 404: response.raise_for_status()
async def add_label(*, github_access_token, repo_url, pr_number, label): """ Add a label to a pull request, replacing other labels currently on that pull request. Args: github_access_token (str): A Github access token repo_url (str): The repository git URL pr_number (int): A pull request number label (str): The label text """ org, repo = get_org_and_repo(repo_url) endpoint = f"https://api.github.com/repos/{org}/{repo}/issues/{pr_number}/labels" client = ClientWrapper() payload = {"labels": [label]} response = await client.post( endpoint, json=payload, headers=github_auth_headers(github_access_token)) response.raise_for_status()
async def get_labels(*, github_access_token, repo_url, pr_number): """ Get a list of labels for a pull request Args: github_access_token (str): A Github access token repo_url (str): The repository git URL pr_number (int): A pull request number Returns: list of str: A list of labels """ org, repo = get_org_and_repo(repo_url) endpoint = f"https://api.github.com/repos/{org}/{repo}/issues/{pr_number}/labels" client = ClientWrapper() response = await client.get( endpoint, headers=github_auth_headers(github_access_token)) response.raise_for_status() return [item["name"] for item in response.json()]
async def run_query(*, github_access_token, query): """ Run a query using Github graphql API Args: github_access_token (str): A github access token query (str): A graphql query to run Returns: dict: The results of the query """ endpoint = "https://api.github.com/graphql" query = json.dumps({"query": query}) client = ClientWrapper() resp = await client.post( endpoint, data=query, headers={"Authorization": "Bearer {}".format(github_access_token)}) resp.raise_for_status() return resp.json()
async def get_status_of_pr(*, github_access_token, org, repo, branch): """ Get the status of the PR for a given branch Args: github_access_token (str): The github access token org (str): The github organization (eg mitodl) repo (str): The github repository (eg micromasters) branch (str): The name of the associated branch Returns: str: The status of the PR. If any status is failed this is failed, if any is pending this is pending. Else it's good. """ endpoint = "https://api.github.com/repos/{org}/{repo}/commits/{ref}/statuses".format( org=org, repo=repo, ref=branch, ) client = ClientWrapper() resp = await client.get( endpoint, headers=github_auth_headers(github_access_token), ) if resp.status_code == 404: statuses = [] else: resp.raise_for_status() statuses = resp.json() # Only look at PR builds statuses = [ status for status in statuses if status['context'] == 'continuous-integration/travis-ci/pr' ] if len(statuses) == 0: # This may be due to the PR not being available yet return NO_PR_BUILD return statuses[0]['state']