#!/usr/bin/python

#Script to create, delete, or upload an asset to, a GitHub Release of ice-frontend-react-mobx project.

import os, sys, getopt
import requests
import json

API_ACCESS_TOKEN =  "token " + "7250c09437a0d207d451ba5390341a2e167a3327" #GitHub Personal Access Token of the account 'vps-jenkins'
headers = {"Authorization" : API_ACCESS_TOKEN}
base_url = "https://api.github.com/repos/vpsinc/ice-console2/releases"

def main():
    name, desc, branch, tag, asset = "", "", "", "", ""
    create, upload = False, False

    opts = get_all_options()
    for opt, arg in opts:
        if opt in ("-n", "--name"):
            name = arg
        elif opt in ("-D", "--desc"):
            desc = arg
        elif opt in ("-b", "--branch"):
            branch = arg
        elif opt in ("-g", "--get"):
            print (get_release_by_tag(arg))
        elif opt in ("-c", "--create"):
            create = True
            tag = arg
        elif opt in ("-u", "--upload"):
            upload = True
            tag = arg
        elif opt in ("-f", "--file"):
            asset = arg
        elif opt in ("-d", "--delete"):
            delete_release(get_release_id_by_tag(arg))
        elif opt in ("-h", "--help"):
            usage()
        else:
            assert False, "Unhandled option"

    if upload:
        create = False    #Required, if both -u and -c options are mentioned(by an idiot)
        print(tag, name, desc, branch, asset)
        release = safe_upload_asset(tag=tag, name=name, desc=desc, branch=branch, asset=asset)

    if create:
        release = safe_create_release(tag=tag, name=name, desc=desc, branch=branch)


def get_all_options():
    """Return all the command line options"""

    opts, args = None, None
    try:
        opts, args = getopt.getopt(sys.argv[1:], "hg:c:d:n:b:D:u:f:", ["help", "get=", "create=", "delete=", "name=", "branch=", "desc=", "upload=", "file="])
        if not opts and not args:
            usage()
            sys.exit(-1)

    except getopt.GetoptError as err:
        print str(err)  # will print something like "option -a not recognized"
        usage()
        sys.exit(-1)

    return opts


def usage():
    print """GitHub Release \n\t-h    --help
        \n\t-g tag    --get=tag \n\t\t\tPrints release details. Fails with exit value -1 if release doesn't exist.
        \n\t-c tag    --create=tag \n\t\t\tCreates a Release with the tag. Fails with exit value -1 if release already exists
        \n\t-d tag    --delete=tag \n\t\t\tDeletes a release. Fails with exit value -1 if release doesn't exist.
        \n\t-n name    --name=name \n\t\t\tName of the release. Must be used with -c or -u option.
        \n\t-b branch    --branch=branch \n\t\t\tCommitish branch of the release tag. Must be used with -c or -u option.
        \n\t-D description    --desc=description \n\t\t\tDescription of the Release. Must be used with -c or -u option.
        \n\t-u tag    --upload=tag \n\t\t\tUploads an asset to a release. Creates release if it doesn't exist(doesn't need to add -c option explicitly).
                           File path of asset must be mention using -f option.
        \n\t-f path    --file=path \n\t\t\tUsed to mention file path of the asset to be uploaded to a release. Must be used with -u option.
        \n\t-D description    --desc=description \n\t\t\tDescription of the Release. Must be used with -c or -u option."""


def safe_create_release(**kwargs):
    """Creates a GitHub release.
       Safe because, checks if release exists before creating one.

       Args:
           **kwargs: Keyword arguments(tag is mandatory)
                      {
                        "tag" Tag Name,
                        "branch": git branch,
                        "name": Name of the release,
                        "desc": Description
                      }
       Returns:
           JSON: Release details, if created successfully, empty otherwise.

       Exits process with -1 if fails to create release.
    """

    if not kwargs:
        print ("No Release details mentioned!")
        sys.exit(-1)

    if "tag" not in kwargs or not kwargs["tag"]:
        print ("Release Tag missing!")
        sys.exit(-1)

    if get_release_by_tag(kwargs["tag"]):
        print ("%s is already released"%kwargs["tag"])
        sys.exit(-1)

    release = create_release(**kwargs)
    if not release:
        print ("Something went wrong, could not create Release for %s!"%kwargs["tag"])
        sys.exit(-1)


def safe_upload_asset(**kwargs):
    """Create a release and upload asset to the release.
       Safe because, checks if release exists before creating one.

       Args:
           **kwargs: Keyword arguments(tag and asset are mandatory)
                      {
                        "tag" Tag Name,
                        "asset": Path of asset file,
                        "branch": git branch,
                        "name": Name of the release,
                        "desc": Description
                      }
       Returns:
           JSON: Release details, if uploaded successfully, empty otherwise.

       Exits process with -1 if fails to create/upload to, release.
    """

    if not kwargs:
        print ("No Release details mentioned!")
        sys.exit(-1)

    if not all(((key in kwargs) and kwargs[key]) for key in ("tag", "asset")):   #Check if tag and asset path are mentioned and are valid
        print ("Release tag or asset path missing!")
        sys.exit(-1)

    if not os.path.exists(kwargs["asset"]):
        print ("File missing!")
        sys.exit(-1)

    details = get_release_by_tag(kwargs["tag"])
    if not details:
        details = create_release(**kwargs)

    if not details:
        print ("Could not get/create release %s"%kwargs["tag"])
        sys.exit(-1)

    if upload_asset(details["upload_url"], kwargs["asset"]):
        return get_release_by_tag(kwargs["tag"])

    #Created release but could not upload asset? That's crazy!
    sys.exit(-1)


def get_release_by_tag(tag):
    """Returns a JSON with release details."""

    if not tag:
        print ("Can't get release details, tag missing!")
        return {}

    url = base_url + "/tags/" + tag
    res = requests.get(url, headers=headers)

    if res.status_code != requests.codes.ok:
        #print ("Something went wrong, could not get %s release details!"%tag)
        return {}

    return json.loads(res.content)


def get_release_id_by_tag(tag):
    """Returns Release ID of the release with @tag"""

    release = get_release_by_tag(tag)
    if not release:
        print ("Could not get release details!")
        return None

    return release["id"]


def create_release(**kwargs):
    """Creates a GitHub Release.
       Args:
            **kwargs: Keyword arguments(tag is mandatory)
                      {
                        "tag" Tag Name,
                        "branch": git branch,
                        "name": Name of the release,
                        "desc": Description
                      }
       Returns:
           JSON: Release details, if created successfully, empty otherwise.
    """

    release = {
        "tag_name": kwargs["tag"],
        "target_commitish": kwargs.get("branch", "master"),
        "name": kwargs.get("name", ""),
        "body": kwargs.get("desc", "")
    }
    print(release)

    res = requests.post(base_url, data=json.dumps(release), headers=headers)
    print(res)
    if res.status_code != requests.codes.created:
        return {}

    return json.loads(res.content)


def upload_asset(upload_url, asset):
    """Uploads an asset to a release.
       Args:
            upload_url : The GitHub upload url of the release
            asset      : Path to the asset file

       Returns:
           JSON: Details of the uploaded asset, if successful, empty otherwise.
    """

    url = upload_url.replace("{?name,label}", "?name=")
    url += asset
    url += "&label=" + os.path.basename(asset)
    print(url)
    headers["Content-Type"] = "application/gzip"
    # files = {'file': open(asset, 'rb')}
    # files = {'package': (asset, open(asset, 'rb'), 'application/x-gzip')}
    data = open(asset, 'rb').read()
    res = requests.post(url, headers=headers, data=data)
    print(res.content)
    del headers["Content-Type"]
    if res.status_code != requests.codes.created:
        return {}

    return json.loads(res.content)


def delete_release(release_id):
    """Deletes a GitHub Release. Exits process with -1 if fails to delete.
       Returns nothing.
    """

    if not release_id:
        print ("Release ID missing!")
        sys.exit(-1)

    url = base_url + "/" + str(release_id)
    res = requests.delete(url,  headers=headers)

    if res.status_code != requests.codes.no_content:
        sys.exit(-1)


if __name__ == "__main__":
    main()
