Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Side by Side Diff: appengine/cr-buildbucket/api.py

Issue 1082303002: buildbucket: put_batch endpoint (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: removed memcache import Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | appengine/cr-buildbucket/errors.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import datetime 5 import datetime
6 import functools 6 import functools
7 import json 7 import json
8 import logging 8 import logging
9 9
10 from components import auth 10 from components import auth
(...skipping 25 matching lines...) Expand all
36 errors.InvalidBuildStateError: ErrorReason.INVALID_BUILD_STATE, 36 errors.InvalidBuildStateError: ErrorReason.INVALID_BUILD_STATE,
37 errors.BuildIsCompletedError: ErrorReason.BUILD_IS_COMPLETED, 37 errors.BuildIsCompletedError: ErrorReason.BUILD_IS_COMPLETED,
38 } 38 }
39 39
40 40
41 class ErrorMessage(messages.Message): 41 class ErrorMessage(messages.Message):
42 reason = messages.EnumField(ErrorReason, 1, required=True) 42 reason = messages.EnumField(ErrorReason, 1, required=True)
43 message = messages.StringField(2, required=True) 43 message = messages.StringField(2, required=True)
44 44
45 45
46 def exception_to_error_message(ex):
47 assert isinstance(ex, errors.Error)
48 return ErrorMessage(
49 reason=ERROR_REASON_MAP[type(ex)],
50 message=ex.message,
51 )
52
53
54 class PutRequestMessage(messages.Message):
55 client_operation_id = messages.StringField(1)
56 bucket = messages.StringField(2, required=True)
57 tags = messages.StringField(3, repeated=True)
58 parameters_json = messages.StringField(4)
59 lease_expiration_ts = messages.IntegerField(5)
60
61
46 class BuildMessage(messages.Message): 62 class BuildMessage(messages.Message):
47 """Describes model.Build, see its docstring.""" 63 """Describes model.Build, see its docstring."""
48 id = messages.IntegerField(1, required=True) 64 id = messages.IntegerField(1, required=True)
49 bucket = messages.StringField(2, required=True) 65 bucket = messages.StringField(2, required=True)
50 tags = messages.StringField(3, repeated=True) 66 tags = messages.StringField(3, repeated=True)
51 parameters_json = messages.StringField(4) 67 parameters_json = messages.StringField(4)
52 status = messages.EnumField(model.BuildStatus, 5) 68 status = messages.EnumField(model.BuildStatus, 5)
53 result = messages.EnumField(model.BuildResult, 6) 69 result = messages.EnumField(model.BuildResult, 6)
54 result_details_json = messages.StringField(7) 70 result_details_json = messages.StringField(7)
55 failure_reason = messages.EnumField(model.FailureReason, 8) 71 failure_reason = messages.EnumField(model.FailureReason, 8)
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 endpoints_decorator = auth.endpoints_method( 165 endpoints_decorator = auth.endpoints_method(
150 request_message_class, response_message_class, **kwargs) 166 request_message_class, response_message_class, **kwargs)
151 167
152 def decorator(fn): 168 def decorator(fn):
153 @functools.wraps(fn) 169 @functools.wraps(fn)
154 def decorated(*args, **kwargs): 170 def decorated(*args, **kwargs):
155 try: 171 try:
156 return fn(*args, **kwargs) 172 return fn(*args, **kwargs)
157 except errors.Error as ex: 173 except errors.Error as ex:
158 assert hasattr(response_message_class, 'error') 174 assert hasattr(response_message_class, 'error')
159 return response_message_class(error=ErrorMessage( 175 return response_message_class(error=exception_to_error_message(ex))
160 reason=ERROR_REASON_MAP[type(ex)],
161 message=ex.message,
162 ))
163 return endpoints_decorator(decorated) 176 return endpoints_decorator(decorated)
164 return decorator 177 return decorator
165 178
166 179
167 def parse_json(json_data, param_name): 180 def parse_json(json_data, param_name):
168 if not json_data: 181 if not json_data:
169 return None 182 return None
170 try: 183 try:
171 return json.loads(json_data) 184 return json.loads(json_data)
172 except ValueError as ex: 185 except ValueError as ex:
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 path='builds/{id}', http_method='GET') 224 path='builds/{id}', http_method='GET')
212 def get(self, request): 225 def get(self, request):
213 """Returns a build by id.""" 226 """Returns a build by id."""
214 build = self.service.get(request.id) 227 build = self.service.get(request.id)
215 if build is None: 228 if build is None:
216 raise errors.BuildNotFoundError() 229 raise errors.BuildNotFoundError()
217 return build_to_response_message(build) 230 return build_to_response_message(build)
218 231
219 ################################### PUT #################################### 232 ################################### PUT ####################################
220 233
221 class PutRequestMessage(messages.Message):
222 bucket = messages.StringField(1, required=True)
223 tags = messages.StringField(2, repeated=True)
224 parameters_json = messages.StringField(3)
225 lease_expiration_ts = messages.IntegerField(4)
226
227 @buildbucket_api_method( 234 @buildbucket_api_method(
228 PutRequestMessage, BuildResponseMessage, 235 PutRequestMessage, BuildResponseMessage,
229 path='builds', http_method='PUT') 236 path='builds', http_method='PUT')
230 def put(self, request): 237 def put(self, request):
231 """Creates a new build.""" 238 """Creates a new build."""
232 if not request.bucket:
233 raise errors.InvalidInputError('Bucket not specified')
234
235 build = self.service.add( 239 build = self.service.add(
236 bucket=request.bucket, 240 bucket=request.bucket,
237 tags=request.tags, 241 tags=request.tags,
238 parameters=parse_json(request.parameters_json, 'parameters_json'), 242 parameters=parse_json(request.parameters_json, 'parameters_json'),
239 lease_expiration_date=parse_datetime(request.lease_expiration_ts), 243 lease_expiration_date=parse_datetime(request.lease_expiration_ts),
244 client_operation_id=request.client_operation_id,
240 ) 245 )
241 return build_to_response_message(build, include_lease_key=True) 246 return build_to_response_message(build, include_lease_key=True)
242 247
248 ################################ PUT_BATCH #################################
249
250 class PutBatchRequestMessage(messages.Message):
251 builds = messages.MessageField(PutRequestMessage, 1, repeated=True)
252
253 class PutBatchResponseMessage(messages.Message):
254 class OneResult(messages.Message):
255 client_operation_id = messages.StringField(1)
256 build = messages.MessageField(BuildMessage, 2)
257 error = messages.MessageField(ErrorMessage, 3)
258 results = messages.MessageField(OneResult, 1, repeated=True)
259
260 @buildbucket_api_method(
261 PutBatchRequestMessage, PutBatchResponseMessage,
262 path='builds/batch', http_method='PUT')
263 def put_batch(self, request):
264 """Creates builds."""
265 build_futures = [
266 self.service.add_async(
267 bucket=put_req.bucket,
268 tags=put_req.tags,
269 parameters=parse_json(put_req.parameters_json, 'parameters_json'),
270 lease_expiration_date=parse_datetime(put_req.lease_expiration_ts),
271 client_operation_id=put_req.client_operation_id,
272 )
273 for put_req in request.builds
274 ]
275
276 res = self.PutBatchResponseMessage()
277
278 def to_msg(req, build_future):
279 one_res = res.OneResult(client_operation_id=req.client_operation_id)
280 try:
281 build = build_future.get_result()
282 one_res.build = build_to_message(build, include_lease_key=True)
283 except errors.Error as ex:
284 one_res.error = exception_to_error_message(ex)
285 return one_res
286
287 res.results = [
288 to_msg(req, build)
289 for req, build in zip(request.builds, build_futures)]
290 return res
291
243 ################################## SEARCH ################################# 292 ################################## SEARCH #################################
244 293
245 SEARCH_REQUEST_RESOURCE_CONTAINER = endpoints.ResourceContainer( 294 SEARCH_REQUEST_RESOURCE_CONTAINER = endpoints.ResourceContainer(
246 message_types.VoidMessage, 295 message_types.VoidMessage,
247 start_cursor=messages.StringField(1), 296 start_cursor=messages.StringField(1),
248 # All specified tags must be present in a build. 297 # All specified tags must be present in a build.
249 bucket=messages.StringField(2, repeated=True), 298 bucket=messages.StringField(2, repeated=True),
250 tag=messages.StringField(3, repeated=True), 299 tag=messages.StringField(3, repeated=True),
251 status=messages.EnumField(model.BuildStatus, 4), 300 status=messages.EnumField(model.BuildStatus, 4),
252 result=messages.EnumField(model.BuildResult, 5), 301 result=messages.EnumField(model.BuildResult, 5),
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after
512 rules=[ 561 rules=[
513 acl.Rule( 562 acl.Rule(
514 role=rule.role, 563 role=rule.role,
515 group=rule.group, 564 group=rule.group,
516 ) 565 )
517 for rule in request.rules 566 for rule in request.rules
518 ], 567 ],
519 ) 568 )
520 bucket_acl = acl.set_acl(request.bucket, bucket_acl) 569 bucket_acl = acl.set_acl(request.bucket, bucket_acl)
521 return bucket_acl_to_response_message(bucket_acl) 570 return bucket_acl_to_response_message(bucket_acl)
OLDNEW
« no previous file with comments | « no previous file | appengine/cr-buildbucket/errors.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698