Index: scripts/master/try_job_rietveld.py |
diff --git a/scripts/master/try_job_rietveld.py b/scripts/master/try_job_rietveld.py |
index a351ad38e4f57afbd620b163be61c139d926a251..983c2e5979670d8b26867ea7cf16b1fc2be1e19d 100644 |
--- a/scripts/master/try_job_rietveld.py |
+++ b/scripts/master/try_job_rietveld.py |
@@ -117,6 +117,100 @@ class _ValidUserPoller(internet.TimerService): |
self._valid = True |
+class _RietveldPoller(base.PollingChangeSource): |
+ """Polls Rietveld for any pending patch sets to build. |
+ |
+ Periodically polls Rietveld to see if any patch sets have been marked by |
+ users to be tried. If so, send them to the trybots. |
+ """ |
+ |
+ def __init__(self, get_pending_endpoint, interval, cachepath=None): |
+ """ |
+ Args: |
+ get_pending_endpoint: Rietveld URL string used to retrieve jobs to try. |
+ interval: Interval used to poll Rietveld, in seconds. |
+ cachepath: Path to file where state to persist between master restarts |
+ will be stored. |
+ """ |
+ # Set interval time in base class. |
+ self.pollInterval = interval |
+ |
+ # A string URL for the Rietveld endpoint to query for pending try jobs. |
+ self._get_pending_endpoint = get_pending_endpoint |
+ |
+ # Cursor used to keep track of next patchset(s) to try. If the cursor |
+ # is None, then try from the beginning. |
+ self._cursor = None |
+ |
+ # Try job parent of this poller. |
+ self._try_job_rietveld = None |
+ |
+ self._cachepath = cachepath |
+ |
+ if self._cachepath: |
+ if os.path.exists(self._cachepath): |
+ with open(self._cachepath) as f: |
+ # Using JSON allows us to be flexible and extend the format |
+ # in a compatible way. |
+ data = json.load(f) |
+ self._cursor = data.get('cursor').encode('utf-8') |
+ |
+ # base.PollingChangeSource overrides: |
+ def poll(self): |
+ """Polls Rietveld for any pending try jobs and submit them. |
+ |
+ Returns: |
+ A deferred objects to be called once the operation completes. |
+ """ |
+ log.msg('RietveldPoller.poll') |
+ d = defer.succeed(None) |
+ d.addCallback(self._OpenUrl) |
+ d.addCallback(self._ParseJson) |
+ d.addErrback(log.err, 'error in RietveldPoller') # eat errors |
+ return d |
+ |
+ def setServiceParent(self, parent): |
+ base.PollingChangeSource.setServiceParent(self, parent) |
+ self._try_job_rietveld = parent |
+ |
+ def _OpenUrl(self, _): |
+ """Downloads pending patch sets from Rietveld. |
+ |
+ Returns: A string containing the pending patchsets from Rietveld |
+ encoded as JSON. |
+ """ |
+ endpoint = self._get_pending_endpoint |
+ if self._cursor: |
+ sep = '&' if '?' in endpoint else '?' |
+ endpoint = endpoint + '%scursor=%s' % (sep, self._cursor) |
+ |
+ log.msg('RietveldPoller._OpenUrl: %s' % endpoint) |
+ return client.getPage(endpoint, agent='buildbot', timeout=2*60) |
+ |
+ def _ParseJson(self, json_string): |
+ """Parses the JSON pending patch set information. |
+ |
+ Args: |
+ json_string: A string containing the serialized JSON jobs. |
+ |
+ Returns: A list of pending try jobs. This is the list of all jobs returned |
+ by Rietveld, not simply the ones we tried this time. |
+ """ |
+ data = json.loads(json_string) |
+ d = self._try_job_rietveld.SubmitJobs(data['jobs']) |
+ def success_callback(value): |
+ self._cursor = str(data['cursor']) |
+ self._try_job_rietveld.processed_keys.clear() |
+ |
+ if self._cachepath: |
+ with open(self._cachepath, 'w') as f: |
+ json.dump({'cursor': self._cursor}, f) |
+ |
+ return value |
+ d.addCallback(success_callback) |
+ return d |
+ |
+ |
class _RietveldPollerWithCache(base.PollingChangeSource): |
"""Polls Rietveld for any pending patch sets to build. |