From ab1b8d5ae2f9316111bffb6c524ebc1efc598db4 Mon Sep 17 00:00:00 2001 From: Mikhail Goncharov Date: Thu, 8 Oct 2020 14:32:40 +0200 Subject: [PATCH] Use buildkite API instead of passing stat via files Previous approach had drawbacks: - every step had to implement exporting of results in fixed format - if step failed then failure will not be detected Now report step will fetch results directly from Buildkite. Agents have to be updated to have BUILDKITE_API_TOKEN env. --- docs/playbooks.md | 2 +- kubernetes/buildkite/linux-agents.yaml | 5 +++++ scripts/buildkite_utils.py | 17 ++++++++++++++++- scripts/pipeline_premerge.py | 4 +--- scripts/summary.py | 23 ++++++++++++----------- 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/docs/playbooks.md b/docs/playbooks.md index 05c14af..a7e4926 100644 --- a/docs/playbooks.md +++ b/docs/playbooks.md @@ -49,7 +49,7 @@ These are the steps to set up the build server on a clean infrastructure: ./local_setup.sh ``` If you not running docker under your user, you might need to - `sudo gcloud auth login --no-launch-browser && gcloud auth configure-docker` + `sudo gcloud auth login --no-launch-browser && sudo gcloud auth configure-docker` before running other commands under sudo. 1. Delete the old cluster, if it still exists: ```bash diff --git a/kubernetes/buildkite/linux-agents.yaml b/kubernetes/buildkite/linux-agents.yaml index a6624ad..51d2499 100644 --- a/kubernetes/buildkite/linux-agents.yaml +++ b/kubernetes/buildkite/linux-agents.yaml @@ -66,6 +66,11 @@ spec: secretKeyRef: name: conduit-api-token key: token + - name: BUILDKITE_API_TOKEN + valueFrom: + secretKeyRef: + name: buildkite-api-token-readonly + key: token volumes: - name: ssd hostPath: diff --git a/scripts/buildkite_utils.py b/scripts/buildkite_utils.py index d40ee1d..37e25b7 100644 --- a/scripts/buildkite_utils.py +++ b/scripts/buildkite_utils.py @@ -3,6 +3,7 @@ import os import re import subprocess from typing import Optional +import requests def upload_file(base_dir: str, file: str): @@ -22,8 +23,22 @@ def upload_file(base_dir: str, file: str): return None +class BuildkiteApi: + def __init__(self, token: str, organization: str): + self.token = token + self.organization = organization + + def get_build(self, pipeline: str, build_number: str): + authorization = f'Bearer {self.token}' + # https://buildkite.com/docs/apis/rest-api/builds#get-a-build + url = f'https://api.buildkite.com/v2/organizations/{self.organization}/pipelines/{pipeline}/builds/{build_number}' + response = requests.get(url, headers={'Authorization': authorization}) + if response.status_code != 200: + raise Exception(f'Builkite responded with non-OK status: {re.status_code}') + return response.json() + + def format_url(url: str, name: Optional[str] = None): if name is None: name = url return f"\033]1339;url='{url}';content='{name}'\a\n" - diff --git a/scripts/pipeline_premerge.py b/scripts/pipeline_premerge.py index 1294bdd..01cc8cc 100755 --- a/scripts/pipeline_premerge.py +++ b/scripts/pipeline_premerge.py @@ -81,9 +81,6 @@ if __name__ == '__main__': report_step = { 'label': ':spiral_note_pad: report', 'commands': [ - 'mkdir -p artifacts', - 'buildkite-agent artifact download "*_result.json" .', - # Clone scripts. 'export SRC=${BUILDKITE_BUILD_PATH}/llvm-premerge-checks', 'rm -rf ${SRC}', @@ -94,6 +91,7 @@ if __name__ == '__main__': 'echo "llvm-premerge-checks commit"', 'git rev-parse HEAD', 'cd "$BUILDKITE_BUILD_CHECKOUT_PATH"', + '${SRC}/scripts/summary.py', ], 'artifact_paths': ['artifacts/**/*'], diff --git a/scripts/summary.py b/scripts/summary.py index a74892e..7b9ba00 100755 --- a/scripts/summary.py +++ b/scripts/summary.py @@ -14,18 +14,15 @@ # limitations under the License. import argparse -import glob -import json import logging import os from phabtalk.phabtalk import PhabTalk -from buildkite_utils import format_url - +from buildkite_utils import format_url, BuildkiteApi if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument('--log-level', type=str, default='WARNING') + parser.add_argument('--log-level', type=str, default='INFO') args = parser.parse_args() logging.basicConfig(level=args.log_level, format='%(levelname)-7s %(message)s') @@ -43,13 +40,17 @@ if __name__ == '__main__': if ph_target_phid is None: logging.warning('ph_target_phid is not specified. Will not update the build status in Phabricator') exit(0) + + bk = BuildkiteApi(os.getenv("BUILDKITE_API_TOKEN"), os.getenv("BUILDKITE_ORGANIZATION_SLUG")) + build = bk.get_build(os.getenv("BUILDKITE_PIPELINE_SLUG"), os.getenv("BUILDKITE_BUILD_NUMBER")) success = True - for path in glob.glob("*_result.json"): - logging.info(f'analysing {path}') - with open(path, 'r') as f: - report = json.load(f) - logging.info(report) - success = success and report['success'] + build.setdefault('jobs', []) + for j in build['jobs']: + j.setdefault('state', '') + j.setdefault('id', '') + logging.info(f'{j["id"]} state {j["state"]}') + success = success and (j['state'] != 'failed') + phabtalk = PhabTalk(os.getenv('CONDUIT_TOKEN')) build_url = f'https://reviews.llvm.org/harbormaster/build/{os.getenv("ph_build_id")}' print(f'Reporting results to Phabricator build {format_url(build_url)}', flush=True)