Skip to content

Commit 6d825b1

Browse files
stephenfinfstachura
authored andcommitted
REST: Expose Patch.labels
1 parent 8f799cb commit 6d825b1

8 files changed

Lines changed: 105 additions & 1 deletion

File tree

‎docs/api/schemas/latest/patchwork.yaml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2312,6 +2312,11 @@ components:
23122312
type: array
23132313
items:
23142314
$ref: '#/components/schemas/PatchEmbedded'
2315+
labels:
2316+
title: Labels
2317+
type: array
2318+
items:
2319+
type: string
23152320
PatchDetail:
23162321
type: object
23172322
title: Patches

‎docs/api/schemas/patchwork.j2‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2397,6 +2397,13 @@ components:
23972397
type: array
23982398
items:
23992399
$ref: '#/components/schemas/PatchEmbedded'
2400+
{% endif %}
2401+
{% if version >= (1, 4) %}
2402+
labels:
2403+
title: Labels
2404+
type: array
2405+
items:
2406+
type: string
24002407
{% endif %}
24012408
PatchDetail:
24022409
type: object

‎docs/api/schemas/v1.4/patchwork.yaml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2312,6 +2312,11 @@ components:
23122312
type: array
23132313
items:
23142314
$ref: '#/components/schemas/PatchEmbedded'
2315+
labels:
2316+
title: Labels
2317+
type: array
2318+
items:
2319+
type: string
23152320
PatchDetail:
23162321
type: object
23172322
title: Patches

‎patchwork/api/cover.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from rest_framework.generics import RetrieveAPIView
1010
from rest_framework.reverse import reverse
1111
from rest_framework.serializers import SerializerMethodField
12+
from rest_framework.serializers import StringRelatedField
1213

1314
from patchwork.api.base import BaseHyperlinkedModelSerializer
1415
from patchwork.api.filters import CoverFilterSet
@@ -25,6 +26,7 @@ class CoverListSerializer(BaseHyperlinkedModelSerializer):
2526
mbox = SerializerMethodField()
2627
series = SeriesSerializer(read_only=True)
2728
comments = SerializerMethodField()
29+
labels = StringRelatedField(many=True)
2830

2931
def get_web_url(self, instance):
3032
request = self.context.get('request')
@@ -62,11 +64,13 @@ class Meta:
6264
'mbox',
6365
'series',
6466
'comments',
67+
'labels',
6568
)
6669
read_only_fields = fields
6770
versioned_fields = {
6871
'1.1': ('web_url', 'mbox', 'comments'),
6972
'1.2': ('list_archive_url',),
73+
'1.4': ('labels',),
7074
}
7175
extra_kwargs = {
7276
'url': {'view_name': 'api-cover-detail'},

‎patchwork/api/patch.py‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from rest_framework.reverse import reverse
1919
from rest_framework.serializers import SerializerMethodField
2020
from rest_framework import status
21+
from rest_framework.serializers import StringRelatedField
2122

2223
from patchwork.api.base import BaseHyperlinkedModelSerializer
2324
from patchwork.api.base import PatchworkPermission
@@ -94,6 +95,7 @@ class PatchListSerializer(BaseHyperlinkedModelSerializer):
9495
default=[],
9596
style={'base_template': 'input.html'},
9697
)
98+
labels = StringRelatedField(many=True)
9799

98100
def get_web_url(self, instance):
99101
request = self.context.get('request')
@@ -177,6 +179,7 @@ class Meta:
177179
'checks',
178180
'tags',
179181
'related',
182+
'labels',
180183
)
181184
read_only_fields = (
182185
'url',
@@ -194,13 +197,15 @@ class Meta:
194197
'check',
195198
'checks',
196199
'tags',
200+
'labels',
197201
)
198202
versioned_fields = {
199203
'1.1': ('comments', 'web_url'),
200204
'1.2': (
201205
'list_archive_url',
202206
'related',
203207
),
208+
'1.4': ('labels',),
204209
}
205210
extra_kwargs = {
206211
'url': {'view_name': 'api-patch-detail'},
@@ -367,6 +372,7 @@ def get_queryset(self):
367372
'project',
368373
'series__project',
369374
'related__patches__project',
375+
'labels',
370376
)
371377
.select_related('state', 'submitter', 'series')
372378
.defer('content', 'diff', 'headers')
@@ -391,7 +397,9 @@ class PatchDetail(RetrieveUpdateAPIView):
391397
def get_queryset(self):
392398
return (
393399
Patch.objects.all()
394-
.prefetch_related('check_set', 'related__patches__project')
400+
.prefetch_related(
401+
'check_set', 'related__patches__project', 'labels'
402+
)
395403
.select_related(
396404
'project', 'state', 'submitter', 'delegate', 'series'
397405
)

‎patchwork/tests/unit/api/test_cover.py‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ def assertSerialized(self, cover_obj, cover_json):
4040
self.assertIn(cover_obj.get_absolute_url(), cover_json['web_url'])
4141
self.assertIn('comments', cover_json)
4242

43+
# list fields
44+
45+
for label in cover_obj.labels.all():
46+
self.assertIn(label.name, cover_json['labels'])
47+
4348
# nested fields
4449

4550
self.assertEqual(cover_obj.submitter.id, cover_json['submitter']['id'])
@@ -130,6 +135,18 @@ def test_list_version_1_0(self):
130135
self.assertIn('url', resp.data[0])
131136
self.assertNotIn('mbox', resp.data[0])
132137
self.assertNotIn('web_url', resp.data[0])
138+
self.assertNotIn('labels', resp.data[0])
139+
140+
def test_list_version_1_1(self):
141+
create_cover()
142+
143+
resp = self.client.get(self.api_url(version='1.1'))
144+
self.assertEqual(status.HTTP_200_OK, resp.status_code)
145+
self.assertEqual(1, len(resp.data))
146+
self.assertIn('url', resp.data[0])
147+
self.assertIn('mbox', resp.data[0])
148+
self.assertIn('web_url', resp.data[0])
149+
self.assertNotIn('labels', resp.data[0])
133150

134151
def test_list_bug_335(self):
135152
"""Ensure we retrieve the embedded series project once."""
@@ -177,6 +194,15 @@ def test_detail_invalid(self):
177194
with self.assertRaises(NoReverseMatch):
178195
self.client.get(self.api_url('foo'))
179196

197+
def test_detail_version_1_1(self):
198+
cover = create_cover()
199+
200+
resp = self.client.get(self.api_url(cover.id, version='1.1'))
201+
self.assertIn('url', resp.data)
202+
self.assertIn('web_url', resp.data)
203+
self.assertIn('comments', resp.data)
204+
self.assertNotIn('labels', resp.data)
205+
180206
def test_create_update_delete(self):
181207
user = create_maintainer()
182208
user.is_superuser = True

‎patchwork/tests/unit/api/test_patch.py‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
from patchwork.models import Patch
1515
from patchwork.tests.unit.api import utils
16+
from patchwork.tests.utils import create_label
1617
from patchwork.tests.utils import create_maintainer
1718
from patchwork.tests.utils import create_patch
1819
from patchwork.tests.utils import create_patches
@@ -54,6 +55,11 @@ def assertSerialized(self, patch_obj, patch_json):
5455
self.assertIn(patch_obj.get_absolute_url(), patch_json['web_url'])
5556
self.assertIn('comments', patch_json)
5657

58+
# list fields
59+
60+
for label in patch_obj.labels.all():
61+
self.assertIn(label.name, patch_json['labels'])
62+
5763
# nested fields
5864

5965
self.assertEqual(patch_obj.submitter.id, patch_json['submitter']['id'])
@@ -232,6 +238,16 @@ def test_list_version_1_0(self):
232238
self.assertEqual(1, len(resp.data))
233239
self.assertIn('url', resp.data[0])
234240
self.assertNotIn('web_url', resp.data[0])
241+
self.assertNotIn('labels', resp.data[0])
242+
243+
def test_list_version_1_1(self):
244+
create_patch()
245+
246+
resp = self.client.get(self.api_url(version='1.1'))
247+
self.assertEqual(status.HTTP_200_OK, resp.status_code)
248+
self.assertEqual(1, len(resp.data))
249+
self.assertIn('web_url', resp.data[0])
250+
self.assertNotIn('labels', resp.data[0])
235251

236252
def test_list_bug_335(self):
237253
"""Ensure we retrieve the embedded series project in O(1)."""
@@ -271,6 +287,23 @@ def test_detail_version_1_0(self):
271287
self.assertIn('url', resp.data)
272288
self.assertNotIn('web_url', resp.data)
273289
self.assertNotIn('comments', resp.data)
290+
self.assertNotIn('labels', resp.data)
291+
292+
def test_detail_version_1_1(self):
293+
patch = create_patch()
294+
295+
resp = self.client.get(self.api_url(item=patch.id, version='1.1'))
296+
self.assertIn('url', resp.data)
297+
self.assertIn('web_url', resp.data)
298+
self.assertIn('comments', resp.data)
299+
self.assertNotIn('labels', resp.data)
300+
301+
def test_detail_version_1_4(self):
302+
label = create_label()
303+
patch = create_patch(labels=[label])
304+
305+
resp = self.client.get(self.api_url(item=patch.id, version='1.4'))
306+
self.assertEqual(resp.data['labels'], [label.name])
274307

275308
def test_detail_non_existent(self):
276309
"""Ensure we get a 404 for a non-existent patch."""
@@ -282,6 +315,15 @@ def test_detail_invalid(self):
282315
with self.assertRaises(NoReverseMatch):
283316
self.client.get(self.api_url('foo'))
284317

318+
def test_detail_labels(self):
319+
patch = create_patch()
320+
321+
resp = self.client.get(self.api_url(item=patch.id, version='1.4'))
322+
self.assertIn('url', resp.data)
323+
self.assertIn('web_url', resp.data)
324+
self.assertIn('comments', resp.data)
325+
self.assertIn('labels', resp.data)
326+
285327
def test_create(self):
286328
"""Ensure creations are rejected."""
287329
project = create_project()

‎releasenotes/notes/labels-6d0096c7d8505627.yaml‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,10 @@ features:
99
Labels can have an optional description attached, which will provide a
1010
little insight into the purpose of the label. Labels are completely
1111
customizable and the labels available will vary by instance.
12+
api:
13+
- |
14+
The ``/patches`` endpoint now exposes a ``labels`` attribute for each
15+
patch.
16+
- |
17+
The ``/covers`` endpoint now exposes a ``labels`` attribute for each cover
18+
letter.

0 commit comments

Comments
 (0)