#!/usr/bin/env python

"""
Determine whether we allow a GitHub PR to be
built automatically.  Checks a whitelist
of repo owners and compares to the HEAD
repo of the pull request.

Uses an environment variable `GITHUB_OWNER_WHITELIST`
to check whether the owner of the PR repo is whitelisted.
This is a comma-separated list of organizations and
users.  For example, a bash script might define:

    export GITHUB_OWNER_WHITELIST="edx,a_user,another_user"

to allow PRs from repos owned by "edx", "a_usr", and "another_user"
"""

import sys
import os
import requests
from textwrap import dedent

# The Ansible script will fill in the GitHub OAuth token.
# That way, we can give the jenkins user on the worker
# execute-only access to this script, ensuring that
# the jenkins user cannot retrieve the token.
GITHUB_OAUTH_TOKEN = "{{ github_oauth_token }}"

USAGE = "Usage: {0} ORG REPO PULL_REQUEST_NUM"


def parse_args(arg_list):
    """
    Parse the list of arguments, returning a dict of the form

        {
            'org': GITHUB_ORG,
            'repo': GITHUB_REPO,
            'pr_num': GITHUB_PR_NUM
        }

    Prints an error message and exits if the arguments are invalid.
    """
    if len(arg_list) != 4:
        print USAGE.format(arg_list[0])
        exit(1)

    # Retrieve the PR number and check that it's an integer
    try:
        pr_num = int(arg_list[3])
    except TypeError:
        print "'{0}' is not a number".format(arg_list[3])

    return {
        'org': arg_list[1],
        'repo': arg_list[2],
        'pr_num': pr_num
    }


def pr_repo_owner(org, repo, pr_num):
    """
    Return the name of the owner of the repo from the
    HEAD of the PR.
    """
    # Query GitHub for information about the pull request
    url = "https://api.github.com/repos/{0}/{1}/pulls/{2}?access_token={3}".format(
        org, repo, pr_num, GITHUB_OAUTH_TOKEN
    )
    response = requests.get(url)

    if response.status_code != 200:
        print dedent("""
        Could not retrieve info for pull request #{0}.
        HTTP status code: {1}
        """.format(pr_num, response.status_code)).strip()
        exit(1)

    # Parse the response as json
    try:
        pr_data = response.json()
    except TypeError:
        print "Could not parse info for pull request #{0}".format(pr_num)
        exit(1)

    # Retrieve the owner of the repo
    try:
        return pr_data['head']['repo']['owner']['login']

    except KeyError:
        print "Could not get repo owner from PR info"
        exit(1)


def main():
    """
    Exits with code 0 (success) if the PR is from a whitelisted
    repo; otherwise, exits with status 1 (failure).
    """
    if not GITHUB_OAUTH_TOKEN:
        print "No GitHub Oauth token configured."
        exit(1)

    arg_dict = parse_args(sys.argv)
    owner = pr_repo_owner(arg_dict['org'], arg_dict['repo'], arg_dict['pr_num'])

    # Check that the owner is whitelisted
    whitelist_owners = os.environ.get('GITHUB_OWNER_WHITELIST', '').split(',')
    if owner not in whitelist_owners:
        print dedent("""
            Owner '{0}' is not in the whitelist.
            You can update the whitelist by setting the environment variable
            `GITHUB_OWNER_WHITELIST` to a comma-separated list of organizations
            and users.
        """.format(owner)).strip()
        exit(1)

    else:
        print "Owner '{0}' is authorized".format(owner)
        exit(0)


if __name__ == "__main__":
    main()
