| Index: dashboard/dashboard/post_bisect_results.py
|
| diff --git a/dashboard/dashboard/post_bisect_results.py b/dashboard/dashboard/post_bisect_results.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5d5bc1b18df25cae63815141ae0d91237cd9ec06
|
| --- /dev/null
|
| +++ b/dashboard/dashboard/post_bisect_results.py
|
| @@ -0,0 +1,111 @@
|
| +# Copyright 2016 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +"""URL endpoint to allow bisect bots to post results to the dashboard."""
|
| +
|
| +import json
|
| +import logging
|
| +
|
| +from google.appengine.api import app_identity
|
| +from google.appengine.ext import ndb
|
| +
|
| +from dashboard import datastore_hooks
|
| +from dashboard import post_data_handler
|
| +from dashboard import rietveld_service
|
| +from dashboard import update_bug_with_results
|
| +from dashboard import utils
|
| +from dashboard.models import try_job
|
| +
|
| +_EXPECTED_RESULT_PROPERTIES = {
|
| + 'status': ['completed', 'failed', 'pending', 'aborted'],
|
| +}
|
| +
|
| +
|
| +class BadRequestError(Exception):
|
| + """An error indicating that a 400 response status should be returned."""
|
| + pass
|
| +
|
| +
|
| +class PostBisectResultsHandler(post_data_handler.PostDataHandler):
|
| +
|
| + def post(self):
|
| + """Validates data parameter and saves to TryJob entity.
|
| +
|
| + Bisect results come from a "data" parameter, which is a JSON encoding of a
|
| + dictionary.
|
| +
|
| + The required fields are "master", "bot", "test".
|
| +
|
| + Request parameters:
|
| + data: JSON encoding of a dictionary.
|
| +
|
| + Outputs:
|
| + Empty 200 response with if successful,
|
| + 200 response with warning message if optional data is invalid,
|
| + 403 response with error message if sender IP is not white-listed,
|
| + 400 response with error message if required data is invalid.
|
| + 500 with error message otherwise.
|
| + """
|
| + datastore_hooks.SetPrivilegedRequest()
|
| + if not self._CheckIpAgainstWhitelist():
|
| + return
|
| +
|
| + data = self.request.get('data')
|
| + if not data:
|
| + self.ReportError('Missing "data" parameter.', status=400)
|
| + return
|
| +
|
| + try:
|
| + data = json.loads(self.request.get('data'))
|
| + except ValueError:
|
| + self.ReportError('Invalid JSON string.', status=400)
|
| + return
|
| +
|
| + logging.info('Received data: %s', data)
|
| +
|
| + try:
|
| + _ValidateResultsData(data)
|
| + job = _GetTryJob(data)
|
| + if not job:
|
| + self.ReportWarning('No try job found.')
|
| + return
|
| + _UpdateTryJob(job, data)
|
| + update_bug_with_results.UpdateQuickLog(job)
|
| + except BadRequestError as error:
|
| + self.ReportError(error.message, status=400)
|
| +
|
| +
|
| +def _ValidateResultsData(results_data):
|
| + utils.Validate(_EXPECTED_RESULT_PROPERTIES, results_data)
|
| + # TODO(chrisphan): Validate other values.
|
| +
|
| +
|
| +def _UpdateTryJob(job, results_data):
|
| + if not job.results_data:
|
| + job.results_data = {}
|
| + job.results_data.update(results_data)
|
| + job.results_data['issue_url'] = (job.results_data.get('issue_url') or
|
| + _IssueURL(job))
|
| + job.put()
|
| +
|
| +
|
| +def _GetTryJob(results_data):
|
| + try_job_id = results_data.get('try_job_id')
|
| + if not try_job_id:
|
| + return None
|
| + job = ndb.Key(try_job.TryJob, try_job_id).get()
|
| + return job
|
| +
|
| +
|
| +def _IssueURL(job):
|
| + """Returns a URL for information about a bisect try job."""
|
| + if job.use_buildbucket:
|
| + hostname = app_identity.get_default_version_hostname()
|
| + job_id = job.buildbucket_job_id
|
| + return 'https://%s/buildbucket_job_status/%s' % (hostname, job_id)
|
| + else:
|
| + config = rietveld_service.GetDefaultRietveldConfig()
|
| + host = (config.internal_server_url if job.internal_only else
|
| + config.server_url)
|
| + return '%s/%d' % (host, job.rietveld_issue_id)
|
|
|