blob: bbb899730d3ac0d89fd5107bc405b5543aae4d70 [file] [log] [blame]
#!/usr/bin/env python
# Copyright (c) 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Tool for interacting with Buildbucket.
Usage:
$ depot-tools-auth login https://cr-buildbucket.appspot.com
$ buildbucket.py \
put \
--bucket master.tryserver.chromium.linux \
--builder my-builder \
Puts a build into buildbucket for my-builder on tryserver.chromium.linux.
"""
import argparse
import json
import urlparse
import os
import sys
import time
from third_party import httplib2
import auth
BUILDBUCKET_URL = 'https://cr-buildbucket.appspot.com'
BUILDBUCKET_API_URL = urlparse.urljoin(
BUILDBUCKET_URL,
'_ah/api/buildbucket/v1/builds',
)
def add_common_arguments(parser):
parser.add_argument(
'--response-json',
help=(
'A path to which the response JSON will be written. '
'If no valid JSON is received, nothing will be written.'
)
)
def main(argv):
parser = argparse.ArgumentParser()
parser.add_argument(
'-v',
'--verbose',
action='store_true',
)
subparsers = parser.add_subparsers(dest='command')
get_parser = subparsers.add_parser('get')
add_common_arguments(get_parser)
get_parser.add_argument(
'--id',
help='The ID of the build to get the status of.',
required=True,
)
put_parser = subparsers.add_parser('put')
add_common_arguments(put_parser)
put_parser.add_argument(
'-b',
'--bucket',
help=(
'The bucket to schedule the build on. Typically the master name, e.g.'
' master.tryserver.chromium.linux.'
),
required=True,
)
put_parser.add_argument(
'-c',
'--changes',
help='A flie to load a JSON list of changes dicts from.',
)
put_parser.add_argument(
'-n',
'--builder-name',
help='The builder to schedule the build on.',
required=True,
)
put_parser.add_argument(
'-p',
'--properties',
help=(
'A file to load a JSON dict of properties from. Use "-" to pipe JSON '
'from another command.'
),
)
retry_parser = subparsers.add_parser('retry')
add_common_arguments(retry_parser)
retry_parser.add_argument(
'--id',
help='The ID of the build to retry.',
required=True,
)
args = parser.parse_args()
body = None
if args.command == 'get':
method = 'GET'
url = '%s/%s' % (BUILDBUCKET_API_URL, args.id)
elif args.command == 'put':
changes = []
if args.changes:
try:
with open(args.changes) as fp:
changes.extend(json.load(fp))
except (TypeError, ValueError):
sys.stderr.write('%s contained invalid JSON list.\n' % args.changes)
raise
properties = {}
if args.properties:
try:
# Allow using pipes to stream properties from another command, e.g.
# echo '{"foo": "bar", "baz": 42}' | buildbucket.py -p -
if args.properties == '-':
properties.update(json.load(sys.stdin))
else:
with open(args.properties) as fp:
properties.update(json.load(fp))
except (TypeError, ValueError):
sys.stderr.write('%s contained invalid JSON dict.\n' % args.properties)
raise
body = json.dumps({
'bucket': args.bucket,
'parameters_json': json.dumps({
'builder_name': args.builder_name,
'changes': changes,
'properties': properties,
}),
})
method = 'PUT'
url = BUILDBUCKET_API_URL
elif args.command == 'retry':
method = 'PUT'
url = '%s/%s/retry' % (BUILDBUCKET_API_URL, args.id)
authenticator = auth.get_authenticator_for_host(
BUILDBUCKET_URL,
auth.make_auth_config(use_oauth2=True),
)
http = authenticator.authorize(httplib2.Http())
http.force_exception_to_status_code = True
if args.verbose:
print 'Request URL:', url
print 'Request method:', method
print 'Request body:', body
response, content = http.request(
url,
method,
body=body,
headers={'Content-Type': 'application/json'},
)
if args.verbose:
print 'Response:', response
print 'Content:', content
try:
content_json = json.loads(content)
if args.response_json:
with open(args.response_json, 'w') as response_json_file:
response_json_file.write(content)
build_url = content_json['build']['url']
except (ValueError, TypeError, KeyError):
pass
else:
print 'Build: %s' % build_url
return response.status != 200
if __name__ == '__main__':
sys.exit(main(sys.argv))