Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2015 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2015 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Tool for interacting with Buildbucket. | 6 """Tool for interacting with Buildbucket. |
| 7 | 7 |
| 8 Usage: | 8 Usage: |
| 9 $ depot-tools-auth login https://cr-buildbucket.appspot.com | 9 $ depot-tools-auth login https://cr-buildbucket.appspot.com |
| 10 $ buildbucket.py \ | 10 $ buildbucket.py \ |
| 11 put \ | 11 put \ |
| 12 --bucket master.tryserver.chromium.linux \ | 12 --bucket master.tryserver.chromium.linux \ |
| 13 --builder my-builder \ | 13 --builder my-builder \ |
| 14 | 14 |
| 15 Puts a build into buildbucket for my-builder on tryserver.chromium.linux. | 15 Puts a build into buildbucket for my-builder on tryserver.chromium.linux. |
| 16 """ | 16 """ |
| 17 | 17 |
| 18 import argparse | 18 import argparse |
| 19 import json | 19 import json |
| 20 import urlparse | 20 import urlparse |
| 21 import os | 21 import os |
| 22 import sys | 22 import sys |
| 23 | 23 |
| 24 from third_party import httplib2 | 24 from third_party import httplib2 |
| 25 | 25 |
| 26 import auth | 26 import auth |
| 27 | 27 |
| 28 | 28 |
| 29 BUILDBUCKET_URL = 'https://cr-buildbucket.appspot.com' | 29 BUILDBUCKET_URL = 'https://cr-buildbucket.appspot.com' |
| 30 PUT_BUILD_URL = urlparse.urljoin( | 30 BUILDBUCKET_API_URL = urlparse.urljoin( |
| 31 BUILDBUCKET_URL, | 31 BUILDBUCKET_URL, |
| 32 '_ah/api/buildbucket/v1/builds', | 32 '_ah/api/buildbucket/v1/builds', |
| 33 ) | 33 ) |
| 34 | 34 |
| 35 | 35 |
| 36 def main(argv): | 36 def main(argv): |
| 37 parser = argparse.ArgumentParser() | 37 parser = argparse.ArgumentParser() |
| 38 parser.add_argument( | 38 parser.add_argument( |
| 39 '-v', | 39 '-v', |
| 40 '--verbose', | 40 '--verbose', |
| 41 action='store_true', | 41 action='store_true', |
| 42 ) | 42 ) |
| 43 subparsers = parser.add_subparsers(dest='command') | 43 subparsers = parser.add_subparsers(dest='command') |
| 44 get_parser = subparsers.add_parser('get') | |
| 45 get_parser.add_argument( | |
| 46 '-i', | |
|
nodir
2015/08/07 21:43:11
IMO: drop this. --id is short and descriptive
smut
2015/08/07 21:46:48
Done.
| |
| 47 '--id', | |
| 48 help='The ID of the build to get the status of.', | |
| 49 required=True, | |
| 50 ) | |
| 44 put_parser = subparsers.add_parser('put') | 51 put_parser = subparsers.add_parser('put') |
| 45 put_parser.add_argument( | 52 put_parser.add_argument( |
| 46 '-b', | 53 '-b', |
| 47 '--bucket', | 54 '--bucket', |
| 48 help=( | 55 help=( |
| 49 'The bucket to schedule the build on. Typically the master name, e.g.' | 56 'The bucket to schedule the build on. Typically the master name, e.g.' |
| 50 ' master.tryserver.chromium.linux.' | 57 ' master.tryserver.chromium.linux.' |
| 51 ), | 58 ), |
| 52 required=True, | 59 required=True, |
| 53 ) | 60 ) |
| 54 put_parser.add_argument( | 61 put_parser.add_argument( |
| 55 '-c', | 62 '-c', |
| 56 '--changes', | 63 '--changes', |
| 57 help='A flie to load a JSON list of changes dicts from.', | 64 help='A flie to load a JSON list of changes dicts from.', |
| 58 ) | 65 ) |
| 59 put_parser.add_argument( | 66 put_parser.add_argument( |
| 60 '-n', | 67 '-n', |
| 61 '--builder-name', | 68 '--builder-name', |
| 62 help='The builder to schedule the build on.', | 69 help='The builder to schedule the build on.', |
| 63 required=True, | 70 required=True, |
| 64 ) | 71 ) |
| 65 put_parser.add_argument( | 72 put_parser.add_argument( |
| 66 '-p', | 73 '-p', |
| 67 '--properties', | 74 '--properties', |
| 68 help='A file to load a JSON dict of properties from.', | 75 help='A file to load a JSON dict of properties from.', |
| 69 ) | 76 ) |
| 70 args = parser.parse_args() | 77 args = parser.parse_args() |
| 71 # TODO(smut): When more commands are implemented, refactor this. | |
| 72 assert args.command == 'put' | |
| 73 | 78 |
| 74 changes = [] | 79 body = None |
| 75 if args.changes: | |
| 76 try: | |
| 77 with open(args.changes) as fp: | |
| 78 changes.extend(json.load(fp)) | |
| 79 except (TypeError, ValueError): | |
| 80 sys.stderr.write('%s contained invalid JSON list.\n' % args.changes) | |
| 81 raise | |
| 82 | 80 |
| 83 properties = {} | 81 if args.command == 'get': |
| 84 if args.properties: | 82 method = 'GET' |
| 85 try: | 83 url = '%s/%s' % (BUILDBUCKET_API_URL, args.id) |
| 86 with open(args.properties) as fp: | 84 elif args.command == 'put': |
| 87 properties.update(json.load(fp)) | 85 changes = [] |
| 88 except (TypeError, ValueError): | 86 if args.changes: |
| 89 sys.stderr.write('%s contained invalid JSON dict.\n' % args.properties) | 87 try: |
| 90 raise | 88 with open(args.changes) as fp: |
| 89 changes.extend(json.load(fp)) | |
| 90 except (TypeError, ValueError): | |
| 91 sys.stderr.write('%s contained invalid JSON list.\n' % args.changes) | |
| 92 raise | |
| 93 | |
| 94 properties = {} | |
| 95 if args.properties: | |
| 96 try: | |
| 97 with open(args.properties) as fp: | |
| 98 properties.update(json.load(fp)) | |
| 99 except (TypeError, ValueError): | |
| 100 sys.stderr.write('%s contained invalid JSON dict.\n' % args.properties) | |
| 101 raise | |
| 102 | |
| 103 body = json.dumps({ | |
| 104 'bucket': args.bucket, | |
| 105 'parameters_json': json.dumps({ | |
| 106 'builder_name': args.builder_name, | |
| 107 'changes': changes, | |
| 108 'properties': properties, | |
| 109 }), | |
| 110 }) | |
| 111 method = 'PUT' | |
| 112 url = BUILDBUCKET_API_URL | |
| 91 | 113 |
| 92 authenticator = auth.get_authenticator_for_host( | 114 authenticator = auth.get_authenticator_for_host( |
| 93 BUILDBUCKET_URL, | 115 BUILDBUCKET_URL, |
| 94 auth.make_auth_config(use_oauth2=True), | 116 auth.make_auth_config(use_oauth2=True), |
| 95 ) | 117 ) |
| 96 http = authenticator.authorize(httplib2.Http()) | 118 http = authenticator.authorize(httplib2.Http()) |
| 97 http.force_exception_to_status_code = True | 119 http.force_exception_to_status_code = True |
| 98 response, content = http.request( | 120 response, content = http.request( |
| 99 PUT_BUILD_URL, | 121 url, |
| 100 'PUT', | 122 method, |
| 101 body=json.dumps({ | 123 body=body, |
| 102 'bucket': args.bucket, | |
| 103 'parameters_json': json.dumps({ | |
| 104 'builder_name': args.builder_name, | |
| 105 'changes': changes, | |
| 106 'properties': properties, | |
| 107 }), | |
| 108 }), | |
| 109 headers={'Content-Type': 'application/json'}, | 124 headers={'Content-Type': 'application/json'}, |
| 110 ) | 125 ) |
| 111 | 126 |
| 112 if args.verbose: | 127 if args.verbose: |
| 113 print content | 128 print content |
| 114 | 129 |
| 115 return response.status != 200 | 130 return response.status != 200 |
| 116 | 131 |
| 117 | 132 |
| 118 if __name__ == '__main__': | 133 if __name__ == '__main__': |
| 119 sys.exit(main(sys.argv)) | 134 sys.exit(main(sys.argv)) |
| OLD | NEW |