diff options
author | Daniel Axtens <dja@axtens.net> | 2019-10-24 01:33:42 +1100 |
---|---|---|
committer | Stephen Finucane <stephen@that.guru> | 2019-11-30 16:40:08 +0000 |
commit | d380219e4dd5e963f7b2b3fb421cd033e70ac5a8 (patch) | |
tree | c392a73e1a5a3a9015f961430430f12fd66e64c9 | |
parent | 3ed6a1434dd90f073f5db5a6e85a80469aaaed40 (diff) | |
download | patchwork-d380219e4dd5e963f7b2b3fb421cd033e70ac5a8.tar patchwork-d380219e4dd5e963f7b2b3fb421cd033e70ac5a8.tar.gz |
api: support filtering patches by hash
This is a feature that the XML-RPC API has, and which is used in
the wild [1], so support it in the REST API.
I tried to version the new filter field, but it's not at all clear
how to do this with django-filters. The best way I could find
requires manually manipulating request.GET, which seems to defeat
the point of django-filters. So document it for 1.2, and have it
work on older versions as an undocumented feature.
[1] https://git.kernel.org/pub/scm/linux/kernel/git/mricon/korg-helpers.git/tree/git-patchwork-bot.py?id=104e7374e1be8458e6d2e82478625a7bf8c822ff
Cc: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Acked-by: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
-rw-r--r-- | docs/api/schemas/latest/patchwork.yaml | 7 | ||||
-rw-r--r-- | docs/api/schemas/patchwork.j2 | 9 | ||||
-rw-r--r-- | docs/api/schemas/v1.2/patchwork.yaml | 7 | ||||
-rw-r--r-- | notes/rest-filter-hash-e031bd3db42eb540.yaml | 5 | ||||
-rw-r--r-- | patchwork/api/filters.py | 8 | ||||
-rw-r--r-- | patchwork/tests/api/test_patch.py | 36 |
6 files changed, 71 insertions, 1 deletions
diff --git a/docs/api/schemas/latest/patchwork.yaml b/docs/api/schemas/latest/patchwork.yaml index 4696900..6c7564b 100644 --- a/docs/api/schemas/latest/patchwork.yaml +++ b/docs/api/schemas/latest/patchwork.yaml @@ -463,6 +463,13 @@ paths: enum: - 'true' - 'false' + - in: query + name: hash + description: > + The patch hash as a case-insensitive hexadecimal string, to filter by. + schema: + title: '' + type: string responses: '200': description: '' diff --git a/docs/api/schemas/patchwork.j2 b/docs/api/schemas/patchwork.j2 index 4fc100e..12a6f67 100644 --- a/docs/api/schemas/patchwork.j2 +++ b/docs/api/schemas/patchwork.j2 @@ -468,6 +468,15 @@ paths: enum: - 'true' - 'false' +{% if version >= (1, 2) %} + - in: query + name: hash + description: > + The patch hash as a case-insensitive hexadecimal string, to filter by. + schema: + title: '' + type: string +{% endif %} responses: '200': description: '' diff --git a/docs/api/schemas/v1.2/patchwork.yaml b/docs/api/schemas/v1.2/patchwork.yaml index 2ced470..7dc9579 100644 --- a/docs/api/schemas/v1.2/patchwork.yaml +++ b/docs/api/schemas/v1.2/patchwork.yaml @@ -463,6 +463,13 @@ paths: enum: - 'true' - 'false' + - in: query + name: hash + description: > + The patch hash as a case-insensitive hexadecimal string, to filter by. + schema: + title: '' + type: string responses: '200': description: '' diff --git a/notes/rest-filter-hash-e031bd3db42eb540.yaml b/notes/rest-filter-hash-e031bd3db42eb540.yaml new file mode 100644 index 0000000..b805931 --- /dev/null +++ b/notes/rest-filter-hash-e031bd3db42eb540.yaml @@ -0,0 +1,5 @@ +--- +api: + - | + The REST API now supports filtering patches by their hashes, using the + ``hash`` query parameter. diff --git a/patchwork/api/filters.py b/patchwork/api/filters.py index 37aca82..4184ee8 100644 --- a/patchwork/api/filters.py +++ b/patchwork/api/filters.py @@ -7,6 +7,7 @@ from django.contrib.auth.models import User from django.core.exceptions import ValidationError from django.db.models import Q from django_filters.rest_framework import FilterSet +from django_filters import CharFilter from django_filters import IsoDateTimeFilter from django_filters import ModelMultipleChoiceFilter from django.forms import ModelMultipleChoiceField as BaseMultipleChoiceField @@ -176,11 +177,16 @@ class PatchFilterSet(TimestampMixin, FilterSet): submitter = PersonFilter(queryset=Person.objects.all()) delegate = UserFilter(queryset=User.objects.all()) state = StateFilter(queryset=State.objects.all()) + hash = CharFilter(lookup_expr='iexact') class Meta: model = Patch + # NOTE(dja): ideally we want to version the hash field, but I cannot + # find a way to do that which is reliable and not extremely ugly. + # The best I can come up with is manually working with request.GET + # which seems to rather defeat the point of using django-filters. fields = ('project', 'series', 'submitter', 'delegate', - 'state', 'archived') + 'state', 'archived', 'hash') class CheckFilterSet(TimestampMixin, FilterSet): diff --git a/patchwork/tests/api/test_patch.py b/patchwork/tests/api/test_patch.py index edae985..4afc15a 100644 --- a/patchwork/tests/api/test_patch.py +++ b/patchwork/tests/api/test_patch.py @@ -22,6 +22,13 @@ from patchwork.tests.utils import create_user if settings.ENABLE_REST_API: from rest_framework import status +# a diff different from the default, required to test hash filtering +SAMPLE_DIFF = """--- /dev/null\t2019-01-01 00:00:00.000000000 +0800 ++++ a\t2019-01-01 00:00:00.000000000 +0800 +@@ -0,0 +1 @@ ++b +""" + @unittest.skipUnless(settings.ENABLE_REST_API, 'requires ENABLE_REST_API') class TestPatchAPI(utils.APITestCase): @@ -152,6 +159,35 @@ class TestPatchAPI(utils.APITestCase): 'submitter': 'test@example.org'}) self.assertEqual(0, len(resp.data)) + def test_list_filter_hash(self): + """Filter patches by hash.""" + patch = self._create_patch() + patch_new_diff = create_patch(state=patch.state, project=patch.project, + submitter=patch.submitter, + diff=SAMPLE_DIFF) + + # check regular filtering + resp = self.client.get(self.api_url(), {'hash': patch.hash}) + self.assertEqual([patch.id], [x['id'] for x in resp.data]) + + # 2 patches with identical diffs + patch_same_diff = create_patch(state=patch.state, + project=patch.project, + submitter=patch.submitter) + resp = self.client.get(self.api_url(), {'hash': patch.hash}) + self.assertEqual([patch.id, patch_same_diff.id], + [x['id'] for x in resp.data]) + + # case insensitive matching + resp = self.client.get(self.api_url(), + {'hash': patch_new_diff.hash.upper()}) + self.assertEqual([patch_new_diff.id], [x['id'] for x in resp.data]) + + # empty response if nothing matches + resp = self.client.get(self.api_url(), { + 'hash': 'da638d0746a115000bf890fada1f02679aa282e8'}) + self.assertEqual(0, len(resp.data)) + @utils.store_samples('patch-list-1-0') def test_list_version_1_0(self): """List patches using API v1.0.""" |