#!/usr/bin/env python

import argparse
import sys

sys.dont_write_bytecode = True

from common import testinfra

def trigger_image(github, opts):
    title = testinfra.ISSUE_TITLE_IMAGE_REFRESH.format(opts.image)
    if opts.pull:
        # Add a comment to the pull request with the right text and set the right label
        issue = github.get("issues/" + opts.pull)
        github.post("issues/" + opts.pull + "/comments", { "body": "bot: " + title })
        github.patch("issues/" + opts.pull, { "labels": issue['labels'] + [ "bot" ] })
    else:
        # Make a new issue with the right content.
        github.post("issues", { "title": title,
                                "labels": [ "bot" ],
                                "body": "bot: " + title })
    return 0

def trigger_pull(github, opts):
    pull = github.get("pulls/" + opts.pull)

    if not pull:
        sys.stderr.write("{0} is not a pull request.\n".format(opts.pull))
        return 1

    # triggering is manual, so don't prevent triggering a user that isn't on the whitelist
    # but issue a warning in case of an oversight
    login = pull["head"]["user"]["login"]
    if login not in github.whitelist:
        sys.stderr.write("warning: pull request author '{0}' isn't in github-whitelist.\n".format(login))

    revision = pull['head']['sha']
    statuses = github.statuses(revision)
    if opts.context:
        contexts = [ opts.context ]
        all = False
    else:
        contexts = list(set(statuses.keys()) & set(testinfra.DEFAULT_VERIFY.keys()))
        all = True

    ret = 0
    for context in contexts:
        status = statuses.get(context, { })
        if status.get("state", all and "unknown" or "empty") not in ["empty", "error", "failure"]:
            if not opts.force:
                if not all:
                    sys.stderr.write("{0}: isn't in triggerable state: {1}\n".format(context, status["state"]))
                    ret = 1
                continue
        sys.stderr.write("{0}: triggering on pull request {1}\n".format(context, opts.pull))
        changes = { "state": "pending", "description": testinfra.NOT_TESTED, "context": context }
        github.post("statuses/" + revision, changes)

    return ret

def main():
    parser = argparse.ArgumentParser(description='Manually trigger CI Robots')
    parser.add_argument('-f', '--force', action="store_true",
                        help='Force setting the status even if the program logic thinks it shouldn''t be done')
    parser.add_argument('--image', help='Trigger a image refresh instead of a testsuite run')
    parser.add_argument('pull', nargs='?', help='The pull request to trigger')
    parser.add_argument('context', nargs='?', help='The github task context to trigger')
    opts = parser.parse_args()

    github = testinfra.GitHub()

    if opts.image:
        return trigger_image(github, opts)
    elif opts.pull and not opts.image:
        return trigger_pull(github, opts)
    else:
        sys.stderr.write("Please specify either --image or a pull request.\n")
        return 1

if __name__ == '__main__':
    sys.exit(main())
