Bug 1306844 - Remove support for submitting pushes via the REST API

This endpoint is deprecated in favour of Pulse submissions, and is no
longer being used.
This commit is contained in:
Ed Morley 2017-04-20 16:18:17 +01:00
Родитель f3a286709d
Коммит 55650d582d
6 изменённых файлов: 3 добавлений и 550 удалений

Просмотреть файл

@ -139,41 +139,6 @@ which Treeherder instance will be accessed by the client.
Authentication is covered :ref:`here <authentication>`.
Resultset Collections
^^^^^^^^^^^^^^^^^^^^^
Resultset collections contain meta data associated with a GitHub pull request
or a push to mercurial or any event that requires tests to be run on a
repository. The most critical part of each resultset is the `revision`.
This is used as an identifier to associate test job data with. This is the
commit SHA of the top commit for the push. It should be 40 characters, but
can be a 12 character revision in some cases. A resultset collection has the
following data structure:
.. code-block:: python
[
{
# The top-most revision in the list of commits for a push.
'revision': '45f8637cb9f78f19cb8463ff174e81756805d8cf',
'author': 'somebody@somewhere.com',
'push_timestamp': 1384353511,
'type': 'push',
# a list of revisions associated with the resultset. There should be at least
# one.
'revisions': [
{
'comment': 'Bug 936711 - Fix crash which happened at disabling Bluetooth...',
'revision': 'cdfe03e77e66',
'repository': 'test_treeherder',
'author': 'Some Person <sperson@someplace.com>'
},
...
]
}
]
Job Collections
^^^^^^^^^^^^^^^
@ -265,58 +230,6 @@ see :ref:`custom-log-name` for more info.
Usage
^^^^^
If you want to use `TreeherderResultSetCollection` to build up the resultset
data structures to send, do something like this.
.. code-block:: python
from thclient import (TreeherderClient, TreeherderClientError,
TreeherderResultSetCollection)
trsc = TreeherderResultSetCollection()
for data in dataset:
trs = trsc.get_resultset()
trs.add_push_timestamp( data['push_timestamp'] )
trs.add_revision( data['revision'] )
trs.add_type( data['type'] )
trs.add_artifact( 'push_data', 'push', { 'stuff':[1,2,3,4,5] } )
for revision in data['revisions']:
tr = trs.get_revision()
tr.add_revision( revision['revision'] )
tr.add_author( revision['author'] )
tr.add_comment( revision['comment'] )
tr.add_repository( revision['repository'] )
trs.add_revision(tr)
trsc.add(trs)
# Send the collection to treeherder
# See the authentication section below for details on how to get a
# hawk id and secret
client = TreeherderClient(client_id='hawk_id', secret='hawk_secret')
# Post the result collection to a project
#
# data structure validation is automatically performed here, if validation
# fails a TreeherderClientError is raised
client.post_collection('mozilla-central', trsc)
At any time in building a data structure, you can examine what has been
created by looking at the `data` property. You can also call the `validate`
method at any time before sending a collection. All treeherder data classes
have `validate` methods that can be used for testing. The `validate` method
is called on every structure in a collection when `post_collection` is
called. If validation fails a `TreeherderClientError` is raised.
If you want to use `TreeherderJobCollection` to build up the job data
structures to send, do something like this:
@ -373,26 +286,8 @@ structures to send, do something like this:
client = TreeherderClient(client_id='hawk_id', secret='hawk_secret')
client.post_collection('mozilla-central', tjc)
If you don't want to use `TreeherderResultCollection` or
`TreeherderJobCollection` to build up the data structure to send, build the
data structures directly and add them to the collection.
.. code-block:: python
from thclient import TreeherderClient, TreeherderResultSetCollection
trc = TreeherderResultSetCollection()
for resultset in resultset_data:
trs = trc.get_resultset(resultset)
# Add any additional data to trs.data here
# add resultset to collection
trc.add(trs)
client = TreeherderClient(client_id='hawk_id', secret='hawk_secret')
client.post_collection('mozilla-central', trc)
If you don't want to use `TreeherderJobCollection` to build up the data structure
to send, build the data structures directly and add them to the collection.
.. code-block:: python

Просмотреть файл

@ -1,157 +0,0 @@
[
{
"revision": "45f8637cb9f78f19cb8463ff174e81756805d8cf",
"push_timestamp": 1384353511,
"revisions": [
{
"comment": "Bug 936711 - Fix crash which happened at disabling Bluetooth during reconnection. r=gyeh, a=koi+",
"author": "Some Person <sperson@someplace.com>",
"revision": "45f8637cb9f78f19cb8463ff174e81756805d8cf"
}
]
},
{
"revision": "b11529c9865a4dee3a93d63d119ebb89fcbbdf69",
"push_timestamp": 1384347643,
"revisions": [
{
"comment": "Bumping gaia.json for 1 gaia-1_2 revision(s) a=gaia-bump\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/b946d5776d33\nDesc: Merge pull request #13593 from wanderview/contacts-group-overflow\n\nBug 937291: Limit overflow of each group list. r=jmcf",
"author": "Gaia Pushbot <release+gaiajson@mozilla.com>",
"revision": "b11529c9865a4dee3a93d63d119ebb89fcbbdf69"
}
]
},
{
"revision": "130965d3df6c9a1093b4725f3b877eaef80d72bc",
"push_timestamp": 1384363842,
"revisions": [
{
"comment": "Bumping gaia.json for 1 gaia-1_2 revision(s) a=gaia-bump\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/b5b1d9aa0cc4\nDesc: Bug 934402 - Write an atom to send SMS using 'MozSMS' API",
"author": "Gaia Pushbot <release+gaiajson@mozilla.com>",
"revision": "130965d3df6c9a1093b4725f3b877eaef80d72bc"
}
]
},
{
"revision": "9d54ce168c996edaf211bf0edb20462675ad6ea1",
"push_timestamp": 1384358742,
"revisions": [
{
"comment": "Bumping gaia.json for 2 gaia-1_2 revision(s) a=gaia-bump\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/39145004f7c6\nDesc: Merge pull request #13659 from AndreiH/bug925851_v1.2\n\nBug 925851 - Re-enable test_capture_multiple_shots\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/b8010ab0e121\nDesc: Bug 925851 - Re-enable test_capture_multiple_shots",
"author": "Gaia Pushbot <release+gaiajson@mozilla.com>",
"revision": "9d54ce168c996edaf211bf0edb20462675ad6ea1"
}
]
},
{
"revision": "a69390334818373e2d7e6e9c8d626a328ed37d47",
"push_timestamp": 1384365342,
"revisions": [
{
"comment": "Bumping gaia.json for 8 gaia-1_2 revision(s) a=gaia-bump\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/3b19a90a8cec\ndelvalle@gmail.com>\nDesc: Merge pull request #13628 from gtorodelvalle/contacts-bug-936283-search-bar-plus-Gmail-or-Outlook\n\nBug 936283 - [B2G][Contacts] Search bar stops functioning when searching contacts in Gmail or Outlook more than once(cherry picked from commit 351f9ad4b8f5e427cd90ae6bdfbafb9a4c9639c7)\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/aa52963f4c22\nDesc: Merge pull request #13604 from snowmantw/issue937023\n\nBug 937023 - [v1.2] Remove transparent to blue transition of lock screen handle and animation after unlock, r=timdream(cherry picked from commit 002578cc3cd0ca31e1333aafd8d019d9dd83e408)\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/05617615ced6\nDesc: Merge pull request #13570 from timdream/keyboard-settings-back\n\nBug 914093 - Back button for Gaia Keyboard settings page, r=rudyl(cherry picked from commit 9abc79e45a7283a557f177a3f9b54bec2668a2b8)\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/13af00ed5c50\nDesc: Merge pull request #13540 from asutherland/makefile-fix\n\nBug 931550 - Clock and Mail app only have rocket icon on homescreen, can't launch/broken. r=:yurenju(cherry picked from commit 513bafaceb391b5fb102ae3ac5a2a753f91ce164)\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/d0df3d96ac80\nDesc: Merge pull request #13516 from fcampo/sim-import-FTE-933381\n\nBug 933381 - [FTE] No message when importing from empty SIM (r=jmcf)(cherry picked from commit c560ddbda27b4c3cc129acad2fa8a6ec0d148308)\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/3521ebd132ea\nDesc: Merge pull request #13531 from fcampo/retry-import-Contacts-935301\n\nBug 935301 - [Contacts] Clicking retry on error while importing from SD doesn't retry(cherry picked from commit 164bed00446439e2aabb6e58587c379ff8850800)\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/303169692648\nDesc: Merge pull request #13568 from comoyo/hu_gone\n\nBug 936579 - Bring back Hungarian autocorrect. r=RudyL(cherry picked from commit fecd21241feb20df0e9bbed2f279c42112cd283c)\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/70d7967a35e7\nDesc: Bug 936418 - [keyboard] 'Layout selection' in keyboard style switcher dialog isn't localized\n(cherry picked from commit ff35da1e70028276510c39f7ebaa421a7acb3ade)",
"author": "Gaia Pushbot <release+gaiajson@mozilla.com>",
"revision": "a69390334818373e2d7e6e9c8d626a328ed37d47"
}
]
},
{
"revision": "7f417c3505e3d2599ac9540f02e3dbee307a3963",
"push_timestamp": 1384364465,
"revisions": [
{
"comment": "Bumping gaia.json for 1 gaia-1_2 revision(s) a=gaia-bump\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/c7e53e332dcb\nDesc: Revert \"Merge pull request #13504 from jaoo/927486\"\n\nThis reverts commit c624b65c1333d2f951533ff5f5d3094681cb1916.",
"author": "Gaia Pushbot <release+gaiajson@mozilla.com>",
"revision": "7f417c3505e3d2599ac9540f02e3dbee307a3963"
}
]
},
{
"revision": "f361dcb60bbedaa01257fbca211452972f7a74b2",
"push_timestamp": 1384365942,
"revisions": [
{
"comment": "Bumping gaia.json for 2 gaia-1_2 revision(s) a=gaia-bump\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/33a44ec49b53\nDesc: Merge pull request #13662 from AndreiH/bug934446_v1.2\n\nBug 934446 - Test Messages contact input validation\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/c6fdfdccfb2e\nDesc: Bug 934446 - Test Messages contact input validation",
"author": "Gaia Pushbot <release+gaiajson@mozilla.com>",
"revision": "f361dcb60bbedaa01257fbca211452972f7a74b2"
}
]
},
{
"revision": "ce17cad5d554cfffddee13d1d8421ae9ec5aad82",
"push_timestamp": 1384366574,
"revisions": [
{
"comment": "Bumping gaia.json for 2 gaia-1_2 revision(s) a=gaia-bump\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/2ba51c7eadb0\nDesc: Merge pull request #13624 from teodosia/aurora-contact-photo-wait\n\nBug 937068 - Unxfail and enhance wait in test_contact_add_photo\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/d195214d4708\nDesc: Bug 937068 - Unxfail and enhance wait in test_contact_add_photo",
"author": "Gaia Pushbot <release+gaiajson@mozilla.com>",
"revision": "ce17cad5d554cfffddee13d1d8421ae9ec5aad82"
}
]
},
{
"revision": "ccc02c89ecc109844707eac9203d377a9dca7c0c",
"push_timestamp": 1384367498,
"revisions": [
{
"comment": "Bug 930281 - Use nsINode instead of nsIContent. r=smaug, a=lsblakk.",
"author": "Some Person <sperson@someplace.com>",
"revision": "ccc02c89ecc109844707eac9203d377a9dca7c0c"
},
{
"comment": "Bug 929261 - Fix for GetElementIC. r=shu, a=abillings",
"author": "Some Person <sperson@someplace.com>",
"revision": "80d76b93040f"
},
{
"comment": "Bug 919021 - Convert ctypes over to use JS::AutoValueVector instead of its own array class. r=terrence, a=lsblakk",
"author": "Some Person <sperson@someplace.com>",
"revision": "949dbbda2cfc"
},
{
"comment": "Bug 927073 - Binary compatibility broken for maintenance releases due to strict version-script - regression fix. r=glandium, a=lsblakk",
"author": "Some Person <sperson@someplace.com>",
"revision": "344b9cd8dc62"
},
{
"comment": "Bug 934062 - Add waitForExplicitFinish to stop intermittent CSP test errors. r=sstamm, a=test-only",
"author": "Some Person <sperson@someplace.com>",
"revision": "1ba2f441a418"
},
{
"comment": "Bug 913160 - Back out Bug 894331 to solve browser hangs when deleting history. a=lsblakk",
"author": "Some Person <sperson@someplace.com>",
"revision": "1008d7007411"
},
{
"comment": "Bug 921816 - Handle idls in --with-libxul-sdk builds. r=gps, a=lsblakk",
"author": "Some Person <sperson@someplace.com>",
"revision": "77e95b4af9f0"
},
{
"comment": "Bug 921776 - Notification completed not showing when download was started from a private tab. r=wesj, a=lsblakk",
"author": "Some Person <sperson@someplace.com>",
"revision": "a39f4c0f075d"
},
{
"comment": "Bug 934900 - Ensure back/forward are not re-enabled while in editing mode. r=sriram, a=lsblakk",
"author": "Some Person <sperson@someplace.com>",
"revision": "9ba6a44a6dfa"
},
{
"comment": "Merge m-b to b2g26. a=merge",
"author": "Some Person <sperson@someplace.com>",
"revision": "997b28cb8737"
}
]
},
{
"revision": "26b1b814be96c1902561872049de1579549e0c29",
"push_timestamp": 1384377343,
"revisions": [
{
"comment": "Bumping gaia.json for 2 gaia-1_2 revision(s) a=gaia-bump\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/9cde9c357524\nDesc: Merge pull request #13618 from viorelaioia/bug_937344_v1.2\n\n[v1.2] Bug 937344 - Replace get_all_video files in test_camera_capture_video with video_files property\n\n========\n\nhttps://hg.mozilla.org/integration/gaia-1_2/rev/d7f28b459e97\nDesc: [v1.2] Bug 937344 - Replace get_all_video files in test_camera_capture_video with video_files property",
"author": "Gaia Pushbot <release+gaiajson@mozilla.com>",
"revision": "26b1b814be96c1902561872049de1579549e0c29"
}
]
}
]

Просмотреть файл

@ -10,10 +10,7 @@ from requests_hawk import HawkAuth
from treeherder.client.thclient import (TreeherderClient,
TreeherderClientError,
TreeherderJob,
TreeherderJobCollection,
TreeherderResultSet,
TreeherderResultSetCollection,
TreeherderRevision)
TreeherderJobCollection)
class DataSetup(unittest.TestCase):
@ -34,23 +31,6 @@ class DataSetup(unittest.TestCase):
with open(self.job_data_file_path) as f:
self.job_data = json.load(f)
# Load sample resultsets
self.resultset_data = []
resultset_file = 'resultset_data.json'
self.resultset_data_file_path = os.path.join(
os.path.dirname(__file__),
'data',
resultset_file
)
with open(self.resultset_data_file_path) as f:
self.resultset_data = json.load(f)
for resultset in self.resultset_data:
resultset['type'] = 'push'
resultset['author'] = 'somebody@somewhere.com'
def compare_structs(self, struct1, struct2):
"""Compare two dictionary structures"""
@ -90,72 +70,6 @@ class DataSetup(unittest.TestCase):
)
class TreeherderResultsetTest(DataSetup, unittest.TestCase):
def test_sample_data_validation(self):
"""Confirm that the sample data validates"""
for resultset in self.resultset_data:
rs = TreeherderResultSet(resultset)
rs.validate()
for revision in resultset['revisions']:
tr = TreeherderRevision(revision)
tr.validate()
def test_resultset_sample_data(self):
"""Test all add methods for building result sets"""
trsc = TreeherderResultSetCollection()
for resultset in self.resultset_data:
trs = TreeherderResultSet()
trs.add_push_timestamp(resultset['push_timestamp'])
trs.add_revision(resultset['revision'])
trs.add_author(resultset['author'])
trs.add_type('push')
revisions = []
for revision in resultset['revisions']:
tr = TreeherderRevision()
tr.add_revision(revision['revision'])
tr.add_author(revision['author'])
tr.add_comment(revision['comment'])
tr.add_repository(revision['repository'])
revisions.append(tr)
trs.add_revisions(revisions)
self.compare_structs(trs.data, resultset)
trsc.add(trs)
# confirm we get the same thing if we initialize from
# a resultset dict
trs_struct = TreeherderResultSet(resultset)
self.compare_structs(trs_struct.data, resultset)
class TreeherderResultSetCollectionTest(DataSetup, unittest.TestCase):
def test_resultset_collection(self):
"""Confirm the collection matches the sample data"""
trc = TreeherderResultSetCollection()
for resultset in self.resultset_data:
trs = TreeherderResultSet(resultset)
trc.add(trs)
self.assertTrue(len(self.resultset_data) == len(trc.data))
class TreeherderJobCollectionTest(DataSetup, unittest.TestCase):
def test_job_collection(self):
@ -311,32 +225,6 @@ class TreeherderClientTest(DataSetup, unittest.TestCase):
client.post_collection('project', tjc)
@responses.activate
def test_send_result_collection(self):
"""Can add a treeherder collections to a TreeherderRequest."""
trc = TreeherderResultSetCollection()
for resultset in self.resultset_data:
trc.add(trc.get_resultset(resultset))
client = TreeherderClient(
server_url='http://host',
client_id='client-abc',
secret='secret123',
)
def request_callback(request):
# Check that the expected content was POSTed.
posted_json = json.loads(request.body)
self.assertEqual(posted_json, trc.get_collection_data())
return (200, {}, '{"message": "well-formed JSON stored", "resultsets": [123, 456]}')
url = client._get_endpoint_url(trc.endpoint_base, project='project')
responses.add_callback(responses.POST, url, match_querystring=True,
callback=request_callback, content_type='application/json')
client.post_collection('project', trc)
def test_hawkauth_setup(self):
"""Test that HawkAuth is correctly set up from the `client_id` and `secret` params."""
client = TreeherderClient(

Просмотреть файл

@ -5,8 +5,6 @@ import pytest
from django.core.urlresolvers import reverse
from rest_framework.test import APIClient
from tests import test_utils
from treeherder.client.thclient import TreeherderResultSetCollection
from treeherder.etl.resultset import store_result_set_data
from treeherder.model.models import (FailureClassification,
Job,
@ -400,38 +398,6 @@ def test_resultset_detail_bad_project(webapp, test_repository):
assert resp.status_int == 404
def test_resultset_create(test_repository, sample_resultset,
mock_post_json):
"""
test posting data to the resultset endpoint via webtest.
extected result are:
- return code 200
- return message successful
- 1 resultset stored in the jobs schema
"""
assert Push.objects.count() == 0
# store the first two, so we submit all, but should properly not re-
# add the others.
store_result_set_data(test_repository, sample_resultset[:2])
assert Push.objects.count() == 2
trsc = TreeherderResultSetCollection()
exp_revision_hashes = set()
for rs in sample_resultset:
rs.update({'author': 'John Doe'})
result_set = trsc.get_resultset(rs)
trsc.add(result_set)
exp_revision_hashes.add(rs["revision"])
test_utils.post_collection(test_repository.name, trsc)
assert Push.objects.count() == len(sample_resultset)
assert set(Push.objects.values_list('revision', flat=True)) == set(
[rs['revision'] for rs in sample_resultset])
def test_resultset_cancel_all(failure_classifications,
push_with_three_jobs, pulse_action_consumer,
test_repository, test_user):

Просмотреть файл

@ -352,98 +352,6 @@ class TreeherderJob(TreeherderData, ValidatorMixin):
}
class TreeherderRevision(TreeherderData, ValidatorMixin):
"""
Supports building a revision structure that is contained in
TreeherderResultSet.
"""
def __init__(self, data={}):
super(TreeherderRevision, self).__init__(data)
# Provide minimal json structure validation
self.required_properties = {
'revision': {'len': 50, 'cb': self.validate_existence},
'repository': {'cb': self.validate_existence},
}
def init_data(self):
self.data = {
# Stored in project_jobs_1.revision.author
'author': '',
# Stored in project_jobs_1.revision.comments
'comment': '',
# Stored in treeherder_reference_1.repository.name
'repository': '',
# Stored in project_jobs_1.revision.revision
'revision': '',
}
def add_author(self, author):
self.data['author'] = author
def add_comment(self, comment):
self.data['comment'] = comment
def add_repository(self, repository):
self.data['repository'] = repository
def add_revision(self, revision):
self.data['revision'] = revision
class TreeherderResultSet(TreeherderData, ValidatorMixin):
"""
Supports building a treeherder result set
"""
def __init__(self, data={}):
super(TreeherderResultSet, self).__init__(data)
self.required_properties = {
'revision': {'len': 40, 'cb': self.validate_existence},
'revisions': {'type': list, 'cb': self.validate_existence},
'author': {'len': 150, 'cb': self.validate_existence}
}
def init_data(self):
self.data = {
# Stored in project_jobs_1.result_set.push_timestamp
'push_timestamp': None,
# Stored in project_jobs_1.result_set.long_revision
'revision': '',
# Stored in project_jobs_1.result_set.author
'author': '',
# Stored in project_jobs_1.revision, new row per revision
'revisions': [],
# TODO: add type column to resultset in treeherder-service
'type': '',
}
def add_push_timestamp(self, push_timestamp):
self.data['push_timestamp'] = push_timestamp
def add_author(self, author):
self.data['author'] = author
def add_revisions(self, revisions):
for revision in revisions:
self.data['revisions'].append(revision.data)
def add_revision(self, revision):
self.data['revision'] = revision
def add_type(self, resultset_type):
self.data['type'] = resultset_type
def get_revision(self, data={}):
return TreeherderRevision(data)
class TreeherderCollection(object):
"""
Base class for treeherder data collections
@ -521,20 +429,6 @@ class TreeherderJobCollection(TreeherderCollection):
return TreeherderJob(data)
class TreeherderResultSetCollection(TreeherderCollection):
"""
Collection of result set objects
"""
def __init__(self, data=[]):
super(TreeherderResultSetCollection, self).__init__('resultset', data)
def get_resultset(self, data={}):
return TreeherderResultSet(data)
class TreeherderClient(object):
"""
Treeherder client class

Просмотреть файл

@ -1,6 +1,5 @@
import datetime
import newrelic.agent
from rest_framework import viewsets
from rest_framework.decorators import detail_route
from rest_framework.exceptions import ParseError
@ -11,7 +10,6 @@ from rest_framework.status import (HTTP_400_BAD_REQUEST,
from serializers import (CommitSerializer,
PushSerializer)
from treeherder.etl.resultset import store_result_set_data
from treeherder.model.models import (Commit,
Job,
Push,
@ -287,37 +285,6 @@ class ResultSetViewSet(viewsets.ViewSet):
return Response({"message": "New jobs added for push '{0}'".format(pk)})
def create(self, request, project):
"""
POST method implementation
"""
try:
repository = Repository.objects.get(name=project)
except Repository.DoesNotExist:
return Response({
"detail": "No project with name {}".format(project)
}, status=HTTP_404_NOT_FOUND)
# check if any revisions are shorter than the expected 40 characters
# The volume of resultsets is fairly low, so this loop won't be
# onerous.
for resultset in request.data:
for revision in resultset['revisions']:
try:
if len(revision['revision']) < 40:
raise ValueError("Revision < 40 characters")
except ValueError:
# The id of the submitter will be automatically included
# in the params via the ``hawk_lookup`` call
params = {
"revision": revision["revision"]
}
newrelic.agent.record_exception(params=params)
store_result_set_data(repository, request.data)
return Response({"message": "well-formed JSON stored"})
@detail_route()
def status(self, request, project, pk=None):
"""