| OLD | NEW |
| (Empty) | |
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 |
| 5 """Build triggering via buildbucket.""" |
| 6 |
| 7 import json |
| 8 |
| 9 from twisted.internet import defer |
| 10 |
| 11 from . import client |
| 12 from . import common |
| 13 |
| 14 |
| 15 class TriggeringService(object): |
| 16 """Schedules new builds on buildbucket.""" |
| 17 |
| 18 def __init__(self, active_master, buildbucket_service): |
| 19 self.active_master = active_master |
| 20 self.buildbucket_service = buildbucket_service |
| 21 |
| 22 @classmethod |
| 23 @defer.inlineCallbacks |
| 24 def create(cls, active_master): |
| 25 buildbucket_service = yield client.create_buildbucket_service(active_master) |
| 26 defer.returnValue(cls(active_master, buildbucket_service)) |
| 27 |
| 28 def start(self): |
| 29 self.buildbucket_service.start() |
| 30 |
| 31 def stop(self): |
| 32 self.buildbucket_service.stop() |
| 33 |
| 34 @staticmethod |
| 35 def get_buildset(build_def): |
| 36 tags = build_def.get('tags', []) |
| 37 PREFIX = 'buildset:' |
| 38 for t in tags: |
| 39 if t.startswith(PREFIX): |
| 40 return t[len(PREFIX):] |
| 41 return None |
| 42 |
| 43 def get_build_url(self, build_id): |
| 44 return 'https://%s/b/%s' % ( |
| 45 client.get_default_buildbucket_hostname(self.active_master), build_id) |
| 46 |
| 47 @defer.inlineCallbacks |
| 48 def trigger( |
| 49 self, source_build, bucket_name, builder_name, properties, changes=None): |
| 50 """Schedules a build on buildbucket.""" |
| 51 info = source_build.getProperties().getProperty(common.INFO_PROPERTY) or {} |
| 52 build_def = info.get(common.BUILD_PROPERTY) or {} |
| 53 bucket_name = bucket_name or build_def.get('bucket') |
| 54 if not bucket_name: |
| 55 # This function should not be called in this case. |
| 56 raise common.Error( |
| 57 'Neither bucket_name is specified, nor the build is from buildbucket') |
| 58 |
| 59 tags = [] |
| 60 if build_def: |
| 61 tags.append('parent_build_id:%s' % build_def['id']) |
| 62 buildset = self.get_buildset(build_def) |
| 63 if buildset: |
| 64 tags.append('buildset:%s' % buildset) |
| 65 |
| 66 response = yield self.buildbucket_service.api.put(body={ |
| 67 'bucket': bucket_name, |
| 68 'tags': tags, |
| 69 'parameters_json': json.dumps({ |
| 70 'builder_name': builder_name, |
| 71 'properties': properties, |
| 72 'changes': changes or [], |
| 73 }), |
| 74 }) |
| 75 result = { |
| 76 'response': response, |
| 77 } |
| 78 build_id = response.get('build', {}).get('id', {}) |
| 79 if build_id: |
| 80 result['build_url'] = self.get_build_url(build_id) |
| 81 defer.returnValue(result) |
| 82 |
| 83 |
| 84 _master_triggering_service_map = {} |
| 85 |
| 86 |
| 87 def get_triggering_service(active_master): |
| 88 """Returns a TriggeringService instance for active_master as Deferred.""" |
| 89 d = _master_triggering_service_map.get(active_master) |
| 90 if not d: |
| 91 d = TriggeringService.create(active_master) |
| 92 def start(service): |
| 93 service.start() |
| 94 return service |
| 95 d.addCallback(start) |
| 96 _master_triggering_service_map[active_master] = d |
| 97 return d |
| 98 |
| 99 |
| 100 def change_from_change_spec(self, change): |
| 101 """Converts a change in change_spec format to buildbucket format. |
| 102 |
| 103 For more info on change_spec format, see |
| 104 master.chromium_step.AnnotationObserver.insertSourceStamp. |
| 105 |
| 106 Buildbucket change format is described in README.md. |
| 107 """ |
| 108 create_ts = None |
| 109 if 'when_timestamp' in change: |
| 110 # Convert from seconds to milliseconds since Unix Epoch. |
| 111 assert isinstance(change['when_timestamp'], (int, float)) |
| 112 create_ts = change['when_timestamp'] * 1000 |
| 113 |
| 114 return { |
| 115 'revision': change.get('revision'), |
| 116 'author': { |
| 117 # Assuming author is email. |
| 118 'email': change.get('author'), |
| 119 }, |
| 120 'create_ts': create_ts, |
| 121 'files': [{'path': f} for f in change.get('files', [])], |
| 122 'message': change.get('comments'), |
| 123 'branch': change.get('branch'), |
| 124 'url': change.get('revlink'), |
| 125 'project': change.get('project'), |
| 126 } |
| 127 |
| OLD | NEW |