blob: 9017753836802e9e7229f49913706a037a070141 [file] [log] [blame]
import argparse
import json
import os.path
import shutil
import subprocess
import sys
from common import fetch_configs
from common import OUTPUT_DIRECTORY
from common import BEP_OUTPUT_FILENAME
from shutil import copyfile
from urllib.parse import urlparse
def run(config, platform, bazel_binary, git_repository):
try:
if git_repository:
clone_repository(git_repository)
cleanup(bazel_binary)
else:
cleanup(bazel_binary)
os.mkdir(OUTPUT_DIRECTORY)
shell_commands(config.get("shell_commands", None))
bazel_run(bazel_binary, config.get("run_targets", None))
bazel_build(bazel_binary, config.get("build_flags", []), config.get("build_targets", None))
exit_code = bazel_test(bazel_binary, config.get("test_flags", []), config.get("test_targets", None))
upload_failed_test_logs(BEP_OUTPUT_FILENAME)
if git_repository:
delete_repository(git_repository)
exit(exit_code)
finally:
cleanup(bazel_binary)
def clone_repository(git_repository):
run_command(["git", "clone", git_repository, "downstream-repo"])
os.chdir("downstream-repo")
def delete_repository(git_repository):
os.chdir("..")
shutil.rmtree("downstream-repo")
def shell_commands(commands):
if not commands:
return
print("--- Shell Commands")
shell_command = "\n".join(commands)
run_command(shell_command, shell=True)
def bazel_run(bazel_binary, targets):
if not targets:
return
print("--- Run Targets")
for target in targets:
run_command([bazel_binary, "run", target])
def bazel_build(bazel_binary, flags, targets):
if not targets:
return
print("+++ Build")
run_command([bazel_binary, "build", "--color=yes"] + flags + targets)
def bazel_test(bazel_binary, flags, targets):
if not targets:
return
print("+++ Test")
res = subprocess.run([bazel_binary, "test", "--color=yes", "--build_event_json_file=" + BEP_OUTPUT_FILENAME] + flags + targets)
return res.returncode
def upload_failed_test_logs(bep_path):
for logfile in failed_test_logs(bep_path):
run_command(["buildkite-agent", "artifact", "upload", logfile])
def failed_test_logs(bep_path):
test_logs = []
raw_data = ""
with open(bep_path) as f:
raw_data = f.read()
decoder = json.JSONDecoder()
pos = 0
while pos < len(raw_data):
json_dict, size = decoder.raw_decode(raw_data[pos:])
if "testResult" in json_dict:
test_result = json_dict["testResult"]
if test_result["status"] != "PASSED":
outputs = test_result["testActionOutput"]
for output in outputs:
if output["name"] == "test.log":
new_path = label_to_path(json_dict["id"]["testResult"]["label"])
os.makedirs(os.path.dirname(new_path), exist_ok=True)
copyfile(urlparse(output["uri"]).path, new_path)
test_logs.append(new_path)
pos += size + 1
return test_logs
def label_to_path(label):
# remove leading //
path = label[2:]
path = path.replace(":", "/")
return OUTPUT_DIRECTORY + path + ".log"
def cleanup(bazel_binary):
print("--- Cleanup")
if os.path.exists("WORKSPACE"):
run_command([bazel_binary, "clean", "--expunge"])
if os.path.exists(OUTPUT_DIRECTORY):
shutil.rmtree(OUTPUT_DIRECTORY)
if os.path.exists("downstream-repo"):
shutil.rmtree("downstream-repo")
def run_command(args, shell=False):
print(" ".join(args))
res = subprocess.run(args, shell)
if res.returncode != 0:
exit(res.returncode)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Bazel Continous Integration Runner')
parser.add_argument("--platform", type=str, required=True, help="The platform the script is running on. Required.")
parser.add_argument("--bazel_binary", type=str, help="The path to the Bazel binary. Optional.")
parser.add_argument("--http_config", type=str, help="The URL of the config file. Optional.")
args = parser.parse_args()
configs = fetch_configs(args.http_config)
bazel_binary = "bazel"
if args.bazel_binary is not None:
bazel_binary = args.bazel_binary
git_repository = configs.get("git_repository", None)
if args.platform not in configs["platforms"]:
print("No configuration exists for '{0}'".format(args.platform))
run(configs["platforms"][args.platform], args.platform, bazel_binary, git_repository)