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:
parent
6b731dc4d5
commit
1c04f70eb9
3 changed files with 26 additions and 34 deletions
|
@ -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:
|
||||||
|
|
|
@ -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)
|
|
|
@ -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'))
|
||||||
|
|
Loading…
Reference in a new issue