blob: bbb899730d3ac0d89fd5107bc405b5543aae4d70 [file] [log] [blame]
smut@google.com5f0788b2015-06-09 00:04:51 +00001#!/usr/bin/env python
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
4# found in the LICENSE file.
5
6"""Tool for interacting with Buildbucket.
7
8Usage:
9 $ depot-tools-auth login https://cr-buildbucket.appspot.com
10 $ buildbucket.py \
11 put \
12 --bucket master.tryserver.chromium.linux \
13 --builder my-builder \
14
15 Puts a build into buildbucket for my-builder on tryserver.chromium.linux.
16"""
17
18import argparse
19import json
20import urlparse
21import os
22import sys
Sergiy Belozorov64a001e2018-12-03 23:19:51 +000023import time
smut@google.com5f0788b2015-06-09 00:04:51 +000024
25from third_party import httplib2
26
27import auth
28
29
30BUILDBUCKET_URL = 'https://cr-buildbucket.appspot.com'
smut@google.com8e6e1e62015-08-07 21:52:18 +000031BUILDBUCKET_API_URL = urlparse.urljoin(
smut@google.com5f0788b2015-06-09 00:04:51 +000032 BUILDBUCKET_URL,
33 '_ah/api/buildbucket/v1/builds',
34)
35
36
John Budorickec40d022018-12-10 17:59:09 +000037def add_common_arguments(parser):
38 parser.add_argument(
39 '--response-json',
40 help=(
41 'A path to which the response JSON will be written. '
42 'If no valid JSON is received, nothing will be written.'
43 )
44 )
45
46
smut@google.com5f0788b2015-06-09 00:04:51 +000047def main(argv):
48 parser = argparse.ArgumentParser()
49 parser.add_argument(
50 '-v',
51 '--verbose',
52 action='store_true',
53 )
54 subparsers = parser.add_subparsers(dest='command')
John Budorickec40d022018-12-10 17:59:09 +000055
smut@google.com8e6e1e62015-08-07 21:52:18 +000056 get_parser = subparsers.add_parser('get')
John Budorickec40d022018-12-10 17:59:09 +000057 add_common_arguments(get_parser)
smut@google.com8e6e1e62015-08-07 21:52:18 +000058 get_parser.add_argument(
59 '--id',
60 help='The ID of the build to get the status of.',
61 required=True,
62 )
John Budorickec40d022018-12-10 17:59:09 +000063
smut@google.com5f0788b2015-06-09 00:04:51 +000064 put_parser = subparsers.add_parser('put')
John Budorickec40d022018-12-10 17:59:09 +000065 add_common_arguments(put_parser)
smut@google.com5f0788b2015-06-09 00:04:51 +000066 put_parser.add_argument(
smut@google.com1da6b032015-06-09 00:16:03 +000067 '-b',
smut@google.com5f0788b2015-06-09 00:04:51 +000068 '--bucket',
69 help=(
70 'The bucket to schedule the build on. Typically the master name, e.g.'
71 ' master.tryserver.chromium.linux.'
72 ),
73 required=True,
74 )
75 put_parser.add_argument(
smut@google.comc1ae89e2015-06-22 23:06:44 +000076 '-c',
77 '--changes',
78 help='A flie to load a JSON list of changes dicts from.',
79 )
80 put_parser.add_argument(
smut@google.com5f0788b2015-06-09 00:04:51 +000081 '-n',
82 '--builder-name',
83 help='The builder to schedule the build on.',
84 required=True,
85 )
86 put_parser.add_argument(
87 '-p',
88 '--properties',
Sergiy Byelozyorovc3975e52018-07-09 22:30:09 +000089 help=(
90 'A file to load a JSON dict of properties from. Use "-" to pipe JSON '
91 'from another command.'
92 ),
smut@google.com5f0788b2015-06-09 00:04:51 +000093 )
John Budorickec40d022018-12-10 17:59:09 +000094
Sergiy Belozorov64a001e2018-12-03 23:19:51 +000095 retry_parser = subparsers.add_parser('retry')
John Budorickec40d022018-12-10 17:59:09 +000096 add_common_arguments(retry_parser)
Sergiy Belozorov64a001e2018-12-03 23:19:51 +000097 retry_parser.add_argument(
98 '--id',
99 help='The ID of the build to retry.',
100 required=True,
101 )
102
smut@google.com5f0788b2015-06-09 00:04:51 +0000103 args = parser.parse_args()
smut@google.com5f0788b2015-06-09 00:04:51 +0000104
smut@google.com8e6e1e62015-08-07 21:52:18 +0000105 body = None
smut@google.comc1ae89e2015-06-22 23:06:44 +0000106
smut@google.com8e6e1e62015-08-07 21:52:18 +0000107 if args.command == 'get':
108 method = 'GET'
109 url = '%s/%s' % (BUILDBUCKET_API_URL, args.id)
110 elif args.command == 'put':
111 changes = []
112 if args.changes:
113 try:
114 with open(args.changes) as fp:
115 changes.extend(json.load(fp))
116 except (TypeError, ValueError):
117 sys.stderr.write('%s contained invalid JSON list.\n' % args.changes)
118 raise
119
120 properties = {}
121 if args.properties:
122 try:
Sergiy Byelozyorovc3975e52018-07-09 22:30:09 +0000123 # Allow using pipes to stream properties from another command, e.g.
124 # echo '{"foo": "bar", "baz": 42}' | buildbucket.py -p -
125 if args.properties == '-':
126 properties.update(json.load(sys.stdin))
127 else:
128 with open(args.properties) as fp:
129 properties.update(json.load(fp))
smut@google.com8e6e1e62015-08-07 21:52:18 +0000130 except (TypeError, ValueError):
131 sys.stderr.write('%s contained invalid JSON dict.\n' % args.properties)
132 raise
133
134 body = json.dumps({
135 'bucket': args.bucket,
136 'parameters_json': json.dumps({
137 'builder_name': args.builder_name,
138 'changes': changes,
139 'properties': properties,
140 }),
141 })
142 method = 'PUT'
143 url = BUILDBUCKET_API_URL
Sergiy Belozorov64a001e2018-12-03 23:19:51 +0000144 elif args.command == 'retry':
145 method = 'PUT'
146 url = '%s/%s/retry' % (BUILDBUCKET_API_URL, args.id)
smut@google.com5f0788b2015-06-09 00:04:51 +0000147
148 authenticator = auth.get_authenticator_for_host(
149 BUILDBUCKET_URL,
150 auth.make_auth_config(use_oauth2=True),
151 )
152 http = authenticator.authorize(httplib2.Http())
153 http.force_exception_to_status_code = True
Sergiy Belozorov64a001e2018-12-03 23:19:51 +0000154
155 if args.verbose:
156 print 'Request URL:', url
157 print 'Request method:', method
158 print 'Request body:', body
159
smut@google.com5f0788b2015-06-09 00:04:51 +0000160 response, content = http.request(
smut@google.com8e6e1e62015-08-07 21:52:18 +0000161 url,
162 method,
163 body=body,
smut@google.com5f0788b2015-06-09 00:04:51 +0000164 headers={'Content-Type': 'application/json'},
165 )
166
167 if args.verbose:
Sergiy Belozorov64a001e2018-12-03 23:19:51 +0000168 print 'Response:', response
169 print 'Content:', content
smut@google.com5f0788b2015-06-09 00:04:51 +0000170
Sergiy Belozorov64a001e2018-12-03 23:19:51 +0000171 try:
John Budorickec40d022018-12-10 17:59:09 +0000172 content_json = json.loads(content)
173 if args.response_json:
174 with open(args.response_json, 'w') as response_json_file:
175 response_json_file.write(content)
176 build_url = content_json['build']['url']
Sergiy Belozorov64a001e2018-12-03 23:19:51 +0000177 except (ValueError, TypeError, KeyError):
178 pass
179 else:
John Budorickec40d022018-12-10 17:59:09 +0000180 print 'Build: %s' % build_url
Michael Achenbach0639cbc2018-09-18 11:33:14 +0000181
smut@google.com5f0788b2015-06-09 00:04:51 +0000182 return response.status != 200
183
184
185if __name__ == '__main__':
186 sys.exit(main(sys.argv))