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 '--id', |
| 47 help='The ID of the build to get the status of.', |
| 48 required=True, |
| 49 ) |
44 put_parser = subparsers.add_parser('put') | 50 put_parser = subparsers.add_parser('put') |
45 put_parser.add_argument( | 51 put_parser.add_argument( |
46 '-b', | 52 '-b', |
47 '--bucket', | 53 '--bucket', |
48 help=( | 54 help=( |
49 'The bucket to schedule the build on. Typically the master name, e.g.' | 55 'The bucket to schedule the build on. Typically the master name, e.g.' |
50 ' master.tryserver.chromium.linux.' | 56 ' master.tryserver.chromium.linux.' |
51 ), | 57 ), |
52 required=True, | 58 required=True, |
53 ) | 59 ) |
54 put_parser.add_argument( | 60 put_parser.add_argument( |
55 '-c', | 61 '-c', |
56 '--changes', | 62 '--changes', |
57 help='A flie to load a JSON list of changes dicts from.', | 63 help='A flie to load a JSON list of changes dicts from.', |
58 ) | 64 ) |
59 put_parser.add_argument( | 65 put_parser.add_argument( |
60 '-n', | 66 '-n', |
61 '--builder-name', | 67 '--builder-name', |
62 help='The builder to schedule the build on.', | 68 help='The builder to schedule the build on.', |
63 required=True, | 69 required=True, |
64 ) | 70 ) |
65 put_parser.add_argument( | 71 put_parser.add_argument( |
66 '-p', | 72 '-p', |
67 '--properties', | 73 '--properties', |
68 help='A file to load a JSON dict of properties from.', | 74 help='A file to load a JSON dict of properties from.', |
69 ) | 75 ) |
70 args = parser.parse_args() | 76 args = parser.parse_args() |
71 # TODO(smut): When more commands are implemented, refactor this. | |
72 assert args.command == 'put' | |
73 | 77 |
74 changes = [] | 78 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 | 79 |
83 properties = {} | 80 if args.command == 'get': |
84 if args.properties: | 81 method = 'GET' |
85 try: | 82 url = '%s/%s' % (BUILDBUCKET_API_URL, args.id) |
86 with open(args.properties) as fp: | 83 elif args.command == 'put': |
87 properties.update(json.load(fp)) | 84 changes = [] |
88 except (TypeError, ValueError): | 85 if args.changes: |
89 sys.stderr.write('%s contained invalid JSON dict.\n' % args.properties) | 86 try: |
90 raise | 87 with open(args.changes) as fp: |
| 88 changes.extend(json.load(fp)) |
| 89 except (TypeError, ValueError): |
| 90 sys.stderr.write('%s contained invalid JSON list.\n' % args.changes) |
| 91 raise |
| 92 |
| 93 properties = {} |
| 94 if args.properties: |
| 95 try: |
| 96 with open(args.properties) as fp: |
| 97 properties.update(json.load(fp)) |
| 98 except (TypeError, ValueError): |
| 99 sys.stderr.write('%s contained invalid JSON dict.\n' % args.properties) |
| 100 raise |
| 101 |
| 102 body = json.dumps({ |
| 103 'bucket': args.bucket, |
| 104 'parameters_json': json.dumps({ |
| 105 'builder_name': args.builder_name, |
| 106 'changes': changes, |
| 107 'properties': properties, |
| 108 }), |
| 109 }) |
| 110 method = 'PUT' |
| 111 url = BUILDBUCKET_API_URL |
91 | 112 |
92 authenticator = auth.get_authenticator_for_host( | 113 authenticator = auth.get_authenticator_for_host( |
93 BUILDBUCKET_URL, | 114 BUILDBUCKET_URL, |
94 auth.make_auth_config(use_oauth2=True), | 115 auth.make_auth_config(use_oauth2=True), |
95 ) | 116 ) |
96 http = authenticator.authorize(httplib2.Http()) | 117 http = authenticator.authorize(httplib2.Http()) |
97 http.force_exception_to_status_code = True | 118 http.force_exception_to_status_code = True |
98 response, content = http.request( | 119 response, content = http.request( |
99 PUT_BUILD_URL, | 120 url, |
100 'PUT', | 121 method, |
101 body=json.dumps({ | 122 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'}, | 123 headers={'Content-Type': 'application/json'}, |
110 ) | 124 ) |
111 | 125 |
112 if args.verbose: | 126 if args.verbose: |
113 print content | 127 print content |
114 | 128 |
115 return response.status != 200 | 129 return response.status != 200 |
116 | 130 |
117 | 131 |
118 if __name__ == '__main__': | 132 if __name__ == '__main__': |
119 sys.exit(main(sys.argv)) | 133 sys.exit(main(sys.argv)) |
OLD | NEW |