| 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...) Expand all 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...) Expand 10 before | Expand all | Expand 10 after 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...) Expand 10 before | Expand all | Expand 10 after 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...) Expand 10 before | Expand all | Expand 10 after 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 |