OLD | NEW |
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...) Loading... |
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...) Loading... |
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...) Loading... |
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...) Loading... |
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) |
OLD | NEW |