1
0
Fork 0

cancel previous builds for the same revisions

using metadata tags set in #298 finds and cancels existing builds before
starting a new one.

One caveat is that no result is reported back to Phabricator for the
cancelled build. That should not be an issue in the normal usecase.

For #278
This commit is contained in:
Mikhail Goncharov 2021-05-04 11:24:08 +02:00
parent 6b731dc4d5
commit 1c04f70eb9
3 changed files with 26 additions and 34 deletions

View file

@ -78,6 +78,9 @@ class BuildkiteApi:
# https://buildkite.com/docs/apis/rest-api/builds#get-a-build # https://buildkite.com/docs/apis/rest-api/builds#get-a-build
return benedict(self.get(f'https://api.buildkite.com/v2/organizations/{self.organization}/pipelines/{pipeline}/builds/{build_number}').json()) return benedict(self.get(f'https://api.buildkite.com/v2/organizations/{self.organization}/pipelines/{pipeline}/builds/{build_number}').json())
def list_running_revision_builds(self, pipeline: str, rev: str):
return self.get(f'https://api.buildkite.com/v2/organizations/{self.organization}/pipelines/{pipeline}/builds?state[]=scheduled&state[]=running&meta_data[ph_buildable_revision]={rev}').json()
@backoff.on_exception(backoff.expo, Exception, max_tries=3, logger='', factor=3) @backoff.on_exception(backoff.expo, Exception, max_tries=3, logger='', factor=3)
def get(self, url: str): def get(self, url: str):
authorization = f'Bearer {self.token}' authorization = f'Bearer {self.token}'
@ -86,6 +89,15 @@ class BuildkiteApi:
raise Exception(f'Buildkite responded with non-OK status: {response.status_code}') raise Exception(f'Buildkite responded with non-OK status: {response.status_code}')
return response return response
# cancel a build. 'build' is a json object returned by API.
def cancel_build(self, build):
build = benedict(build)
url = f'https://api.buildkite.com/v2/organizations/{self.organization}/pipelines/{build.get("pipeline.slug")}/builds/{build.get("number")}/cancel'
authorization = f'Bearer {self.token}'
response = requests.put(url, headers={'Authorization': authorization})
if response.status_code != 200:
raise Exception(f'Buildkite responded with non-OK status: {response.status_code}')
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:

View file

@ -1,33 +0,0 @@
#!/usr/bin/env python3
# Copyright 2020 Google LLC
#
# Licensed under the the Apache License v2.0 with LLVM Exceptions (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://llvm.org/LICENSE.txt
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import requests
def main(review_number, api_key):
buildkite = requests.Session()
buildkite.headers.update({'Authorization': 'Bearer {}'.format(api_key)})
api = lambda query: 'https://api.buildkite.com/v2' + query
builds = buildkite.get(api('/organizations/llvm-project/builds?state[]=scheduled&state[]=running')).json()
for build in builds:
if build['message'] == review_number:
pipeline = build['pipeline']['slug']
buildkite.put(api('/organizations/llvm-project/pipelines/{}/builds/{}/cancel'.format(pipeline, build['number'])))
if __name__ == '__main__':
review_number = 'D{}'.format(os.getenv('ph_buildable_revision'))
api_key = # TODO where do we get that? The agents on the service queue need to have the proper access (read_builds and write_builds)
main(review_number, api_key)

View file

@ -15,7 +15,9 @@
import os import os
import yaml import yaml
from buildkite_utils import annotate, feedback_url, set_metadata import logging
from buildkite_utils import set_metadata, BuildkiteApi
if __name__ == '__main__': if __name__ == '__main__':
diff_id = os.getenv("ph_buildable_diff") diff_id = os.getenv("ph_buildable_diff")
@ -23,6 +25,17 @@ if __name__ == '__main__':
base_commit = os.getenv('ph_base_commit', 'auto') base_commit = os.getenv('ph_base_commit', 'auto')
run_build = os.getenv('ph_skip_build') is None run_build = os.getenv('ph_skip_build') is None
trigger = os.getenv('ph_trigger_pipeline') trigger = os.getenv('ph_trigger_pipeline')
logging.basicConfig(level=log_level, format='%(levelname)-7s %(message)s')
# Cancel any existing builds.
# Do this before setting own 'ph_buildable_revision'.
try:
bk = BuildkiteApi(os.getenv("BUILDKITE_API_TOKEN"), os.getenv("BUILDKITE_ORGANIZATION_SLUG"))
for b in bk.list_running_revision_builds(os.getenv("BUILDKITE_PIPELINE_SLUG"), os.getenv('ph_buildable_revision')):
logging.info(f'cancelling build {b.get("web_url")}')
bk.cancel_build(b)
except Exception as e:
logging.error(e)
set_metadata('ph_buildable_diff', os.getenv("ph_buildable_diff")) set_metadata('ph_buildable_diff', os.getenv("ph_buildable_diff"))
set_metadata('ph_buildable_revision', os.getenv('ph_buildable_revision')) set_metadata('ph_buildable_revision', os.getenv('ph_buildable_revision'))