1
0
Fork 0

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.
This commit is contained in:
Mikhail Goncharov 2020-10-08 14:32:40 +02:00
parent 563d6ba723
commit ab1b8d5ae2
5 changed files with 35 additions and 16 deletions

View file

@ -49,7 +49,7 @@ These are the steps to set up the build server on a clean infrastructure:
./local_setup.sh ./local_setup.sh
``` ```
If you not running docker under your user, you might need to 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. before running other commands under sudo.
1. Delete the old cluster, if it still exists: 1. Delete the old cluster, if it still exists:
```bash ```bash

View file

@ -66,6 +66,11 @@ spec:
secretKeyRef: secretKeyRef:
name: conduit-api-token name: conduit-api-token
key: token key: token
- name: BUILDKITE_API_TOKEN
valueFrom:
secretKeyRef:
name: buildkite-api-token-readonly
key: token
volumes: volumes:
- name: ssd - name: ssd
hostPath: hostPath:

View file

@ -3,6 +3,7 @@ import os
import re import re
import subprocess import subprocess
from typing import Optional from typing import Optional
import requests
def upload_file(base_dir: str, file: str): def upload_file(base_dir: str, file: str):
@ -22,8 +23,22 @@ def upload_file(base_dir: str, file: str):
return None 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): def format_url(url: str, name: Optional[str] = None):
if name is None: if name is None:
name = url name = url
return f"\033]1339;url='{url}';content='{name}'\a\n" return f"\033]1339;url='{url}';content='{name}'\a\n"

View file

@ -81,9 +81,6 @@ if __name__ == '__main__':
report_step = { report_step = {
'label': ':spiral_note_pad: report', 'label': ':spiral_note_pad: report',
'commands': [ 'commands': [
'mkdir -p artifacts',
'buildkite-agent artifact download "*_result.json" .',
# Clone scripts. # Clone scripts.
'export SRC=${BUILDKITE_BUILD_PATH}/llvm-premerge-checks', 'export SRC=${BUILDKITE_BUILD_PATH}/llvm-premerge-checks',
'rm -rf ${SRC}', 'rm -rf ${SRC}',
@ -94,6 +91,7 @@ if __name__ == '__main__':
'echo "llvm-premerge-checks commit"', 'echo "llvm-premerge-checks commit"',
'git rev-parse HEAD', 'git rev-parse HEAD',
'cd "$BUILDKITE_BUILD_CHECKOUT_PATH"', 'cd "$BUILDKITE_BUILD_CHECKOUT_PATH"',
'${SRC}/scripts/summary.py', '${SRC}/scripts/summary.py',
], ],
'artifact_paths': ['artifacts/**/*'], 'artifact_paths': ['artifacts/**/*'],

View file

@ -14,18 +14,15 @@
# limitations under the License. # limitations under the License.
import argparse import argparse
import glob
import json
import logging import logging
import os import os
from phabtalk.phabtalk import PhabTalk from phabtalk.phabtalk import PhabTalk
from buildkite_utils import format_url from buildkite_utils import format_url, BuildkiteApi
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser() 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() args = parser.parse_args()
logging.basicConfig(level=args.log_level, format='%(levelname)-7s %(message)s') logging.basicConfig(level=args.log_level, format='%(levelname)-7s %(message)s')
@ -43,13 +40,17 @@ if __name__ == '__main__':
if ph_target_phid is None: if ph_target_phid is None:
logging.warning('ph_target_phid is not specified. Will not update the build status in Phabricator') logging.warning('ph_target_phid is not specified. Will not update the build status in Phabricator')
exit(0) 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 success = True
for path in glob.glob("*_result.json"): build.setdefault('jobs', [])
logging.info(f'analysing {path}') for j in build['jobs']:
with open(path, 'r') as f: j.setdefault('state', '')
report = json.load(f) j.setdefault('id', '')
logging.info(report) logging.info(f'{j["id"]} state {j["state"]}')
success = success and report['success'] success = success and (j['state'] != 'failed')
phabtalk = PhabTalk(os.getenv('CONDUIT_TOKEN')) phabtalk = PhabTalk(os.getenv('CONDUIT_TOKEN'))
build_url = f'https://reviews.llvm.org/harbormaster/build/{os.getenv("ph_build_id")}' 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) print(f'Reporting results to Phabricator build {format_url(build_url)}', flush=True)