Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Copyright (c) 2014 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 import json | |
| 6 import re | |
| 7 | |
| 8 from twisted.internet import defer | |
| 9 from twisted.python import log | |
| 10 | |
| 11 from buildbot.changes import filter | |
| 12 from buildbot.schedulers.basic import SingleBranchScheduler | |
| 13 | |
| 14 from master.gerrit_poller import GerritPoller | |
| 15 from master.builders_pools import BuildersPools | |
| 16 | |
| 17 | |
| 18 ALWAYS_TRUE_FILTER = filter.ChangeFilter(filter_fn=lambda x: True) | |
| 19 | |
| 20 | |
| 21 class JobDefinition(object): | |
| 22 """Describes a try job posted on Gerrit.""" | |
| 23 def __init__(self, builder_names=None): | |
| 24 # Force str type and remove empty builder names. | |
| 25 self.builder_names = [str(b) for b in builder_names or [] | |
| 26 if b] | |
| 27 | |
| 28 def __repr__(self): | |
| 29 return repr(self.__dict__) | |
| 30 | |
| 31 @staticmethod | |
| 32 def parse(text): | |
| 33 """Parses a try job definition.""" | |
| 34 text = text and text.strip() | |
| 35 if not text: | |
| 36 # Return an empty definition. | |
| 37 return JobDefinition() | |
| 38 | |
| 39 # Parse as json. | |
| 40 job = json.loads(text) | |
| 41 | |
| 42 # Convert to canonical form. | |
| 43 if isinstance(job, list): | |
| 44 # Treat a list as builder name list. | |
| 45 job = {'builderNames': job} | |
| 46 | |
| 47 return JobDefinition(job.get('builderNames')) | |
| 48 | |
| 49 | |
| 50 class _TryJobGerritPoller(GerritPoller): | |
| 51 """Polls issues, creates changes and calls scheduler.submitJob. | |
| 52 | |
| 53 This class is a part of TryJobGerritScheduler implementation and not designed | |
| 54 to be used otherwise. | |
| 55 """ | |
| 56 | |
| 57 MESSAGE_REGEX_TRYJOB = re.compile('Patch set \d+:\s+\!tryjob', re.I) | |
| 58 | |
| 59 def __init__(self, scheduler, gerrit_host, gerrit_projects=None, | |
| 60 pollInterval=None): | |
| 61 assert scheduler | |
| 62 GerritPoller.__init__(self, gerrit_host, gerrit_projects, pollInterval) | |
| 63 self.scheduler = scheduler | |
|
Dan Jacques
2014/04/26 00:38:51
I don't think the 'change source' / 'scheduler' se
nodir
2014/04/28 22:31:11
In general, yes, a poller and scheduler don't know
| |
| 64 | |
| 65 def _is_interesting_comment(self, comment): | |
| 66 return self.MESSAGE_REGEX_TRYJOB.match(comment['message']) | |
| 67 | |
| 68 def getChangeQuery(self): | |
| 69 query = GerritPoller.getChangeQuery(self) | |
| 70 # Request only issues with TryJob=+1 label. | |
| 71 query += '+label:TryJob=%2B1' | |
|
Dan Jacques
2014/04/26 00:38:51
While you're constraining the query, you might as
nodir
2014/04/28 22:31:11
I think I will wait for your GerritAgent
| |
| 72 return query | |
| 73 | |
| 74 def parseJob(self, comment): | |
| 75 """Parses a JobDefinition from a Gerrit comment.""" | |
| 76 msg = comment['message'] | |
| 77 tryjob_match = self.MESSAGE_REGEX_TRYJOB.match(msg) | |
| 78 assert tryjob_match | |
| 79 job_def_str = msg[tryjob_match.end():] | |
| 80 return JobDefinition.parse(job_def_str) | |
| 81 | |
| 82 @defer.inlineCallbacks | |
| 83 def addChange(self, (change, comment)): | |
| 84 """Parses a job, adds a change and calls self.scheduler.submitJob.""" | |
| 85 try: | |
| 86 job = self.parseJob(comment) | |
| 87 buildbotChange = yield self.addBuildbotChange(change, comment) | |
| 88 self.scheduler.submitJob(buildbotChange, job) | |
|
Dan Jacques
2014/04/26 00:38:51
This needs to be yielded, doesn't it?
nodir
2014/04/28 22:31:11
Done.
| |
| 89 except Exception as e: | |
| 90 log.err('TryJobGerritPoller failed: %s' % e) | |
| 91 | |
| 92 | |
| 93 class TryJobGerritScheduler(SingleBranchScheduler): | |
|
Dan Jacques
2014/04/26 00:38:51
It would be nice if you could use a less heavy-han
nodir
2014/04/28 22:31:11
This scheduler takes the builder names from the jo
| |
| 94 """Polls try jobs on Gerrit and creates buildsets.""" | |
| 95 def __init__(self, name, default_builder_names, gerrit_host, | |
| 96 gerrit_projects=None, pollInterval=None): | |
| 97 """Creates a new TryJobGerritScheduler. | |
| 98 | |
| 99 Args: | |
| 100 name: name of the scheduler. | |
| 101 default_builder_names: a list of builder names used in case a job didn't | |
| 102 specify any. | |
| 103 gerrit_host: URL to the Gerrit instance | |
| 104 gerrit_projects: Gerrit projects to filter issues. | |
| 105 pollInterval: frequency of polling. | |
| 106 """ | |
| 107 SingleBranchScheduler.__init__(self, name, | |
| 108 builderNames=default_builder_names, | |
|
Kevin Graney
2014/04/26 02:45:11
Are you somehow running PRESUBMIT.py for the jobs
nodir
2014/04/28 22:31:11
This code lives on server. The git-try will run PR
| |
| 109 change_filter=ALWAYS_TRUE_FILTER) | |
| 110 self.poller = _TryJobGerritPoller(self, gerrit_host, gerrit_projects, | |
| 111 pollInterval) | |
| 112 | |
| 113 def setServiceParent(self, parent): | |
| 114 SingleBranchScheduler.setServiceParent(self, parent) | |
| 115 self.poller.master = self.master | |
| 116 self.poller.setServiceParent(self) | |
| 117 | |
| 118 def gotChange(self, *args, **kwargs): | |
| 119 """Do nothing because changes are processed by submitJob.""" | |
| 120 | |
| 121 def addSourcestamp(self, change): | |
| 122 return self.master.db.sourcestamps.addSourceStamp( | |
| 123 project=change.project, | |
| 124 repository=change.repository, | |
| 125 branch=change.branch, | |
| 126 revision=change.revision) | |
| 127 | |
| 128 def addBuildset(self, change, ssid, job): | |
| 129 return self.addBuildsetForSourceStamp( | |
| 130 ssid=ssid, | |
| 131 reason='tryjob', | |
| 132 properties=change.properties, | |
| 133 builderNames=job.builder_names) | |
| 134 | |
| 135 @defer.inlineCallbacks | |
| 136 def submitJob(self, change, job): | |
| 137 ssid = yield self.addSourcestamp(change) | |
| 138 bsid = yield self.addBuildset(change, ssid, job) | |
| 139 log.msg('Successfully submitted a Gerrit try job for %s: %s.' % (change.who, | |
| 140 job)) | |
| 141 defer.returnValue(bsid) | |
| OLD | NEW |