#!/usr/bin/env python3
#===----------------------------------------------------------------------===##
#
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
#===----------------------------------------------------------------------===##

import argparse
import io
import os
import phabricator
import re
import subprocess
import sys
import time

LLVM_REVIEWS_API = "https://reviews.llvm.org/api/"

def main(argv):
    parser = argparse.ArgumentParser(
        description="""
This script gathers information about a Buildkite build and updates the
Phabricator review associated to the HEAD commit with those results.

The intended usage of this script is to pipe the output of a command defined
in a Buildkite pipeline into it. The script will echo everything to stdout,
like tee, but will also update the Phabricator review associated to HEAD
with the results of the build.

The script is assumed to be running inside a Buildkite agent, and as such,
it assumes the existence of several environment variables that are specific
to Buildkite. It also assumes that it is running in a context where the HEAD
commit contains the Phabricator ID of the review to update.
""")
    args = parser.parse_args(argv)

    for var in ('BUILDKITE_LABEL', 'BUILDKITE_JOB_ID', 'BUILDKITE_BUILD_URL', 'CONDUIT_TOKEN'):
        if var not in os.environ:
            raise RuntimeError(
                'The {} environment variable must exist -- are you running '
                'this script from a Buildkite agent?'.format(var))

    # First, read all the log input and write it line-by-line to stdout.
    # This is important so that we can follow progress in the Buildkite
    # console. Since we're being piped into in real time, it's also the
    # moment to time the duration of the job.
    start = time.time()
    log = io.StringIO()
    while True:
        line = sys.stdin.readline()
        if line == '':
            break
        sys.stdout.write(line)
        sys.stdout.flush() # flush every line to avoid buffering
        log.write(line)
    end = time.time()

    # Then, extract information from the environment and post-process the logs.
    log.seek(0)
    log = log.read()
    result = 'fail' if 'FAILED:' in log else 'pass'
    resultObject = {
        'name': '{BUILDKITE_LABEL} ({BUILDKITE_BUILD_URL}#{BUILDKITE_JOB_ID})'.format(**os.environ),
        'result': result,
        'duration': end - start,
        'details': log
    }

    commitMessage = subprocess.check_output(['git', 'log', '--format=%B' , '-n', '1']).decode()
    phabricatorID = re.search(r'^Phabricator-ID:\s+(.+)$', commitMessage, flags=re.MULTILINE)
    if not phabricatorID:
        raise RuntimeError('Could not find the Phabricator ID in the commit message. '
                           'The commit message was:\n{}'.format(commitMessage))
    else:
        phabricatorID = phabricatorID.group(1)

    token = os.environ['CONDUIT_TOKEN']
    phab = phabricator.Phabricator(token=token, host=LLVM_REVIEWS_API)
    phab.harbormaster.sendmessage(buildTargetPHID=phabricatorID, type=result, unit=[resultObject])

if __name__ == '__main__':
    main(sys.argv[1:])
