Skip to content
This repository was archived by the owner on Jun 13, 2025. It is now read-only.

Commit 600f529

Browse files
Update
1 parent a3bb99c commit 600f529

File tree

4 files changed

+45
-34
lines changed

4 files changed

+45
-34
lines changed

api/public/v2/pull/serializers.py

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
from typing import Dict, Optional
2+
13
from rest_framework import serializers
24

35
from api.public.v2.owner.serializers import OwnerSerializer
4-
from api.shared.commit.serializers import CommitTotalsSerializer
5-
from compare.models import CommitComparison
6+
from api.shared.commit.serializers import (
7+
CommitTotalsSerializer,
8+
PatchCoverageSerializer,
9+
)
610
from core.models import Pull, PullStates
7-
from services.comparison import ComparisonReport
11+
from services.comparison import CommitComparisonService, ComparisonReport
812

913

1014
class PullSerializer(serializers.ModelSerializer):
@@ -37,38 +41,26 @@ class Meta:
3741
)
3842
fields = read_only_fields
3943

40-
def get_patch(self, obj: Pull):
41-
# 1) Fetch the CommitComparison for (compared_to, head)
42-
comparison_qs = CommitComparison.objects.filter(
43-
base_commit__commitid=obj.compared_to,
44-
compare_commit__commitid=obj.head,
45-
base_commit__repository_id=obj.repository_id,
46-
compare_commit__repository_id=obj.repository_id,
47-
).select_related("compare_commit", "base_commit")
48-
49-
commit_comparison = comparison_qs.first()
44+
def get_patch(self, obj: Pull) -> Optional[Dict[str, float]]:
45+
commit_comparison = CommitComparisonService.get_commit_comparison_for_pull(obj)
5046
if not commit_comparison or not commit_comparison.is_processed:
5147
return None
52-
53-
# 2) Wrap it in ComparisonReport
5448
cr = ComparisonReport(commit_comparison)
55-
56-
# 3) Summation of patch coverage across impacted files
5749
hits = misses = partials = 0
5850
for f in cr.impacted_files:
5951
pc = f.patch_coverage
6052
if pc:
6153
hits += pc.hits
6254
misses += pc.misses
6355
partials += pc.partials
64-
6556
total_branches = hits + misses + partials
66-
if total_branches == 0:
67-
return None
68-
69-
return dict(
57+
coverage = 0
58+
if total_branches != 0:
59+
coverage = round(100 * hits / total_branches, 2)
60+
data = dict(
7061
hits=hits,
7162
misses=misses,
7263
partials=partials,
73-
coverage=round(100 * hits / total_branches, 2),
64+
coverage=coverage,
7465
)
66+
return PatchCoverageSerializer(data).data

api/public/v2/tests/test_api_pull_viewset.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def setUp(self):
3232
)
3333
self.client = APIClient()
3434
self.client.force_login_owner(self.current_owner)
35+
self.no_patch_response = dict(hits=0, misses=0, partials=0, coverage=0)
3536

3637
def test_list(self):
3738
res = self.client.get(
@@ -59,7 +60,7 @@ def test_list(self):
5960
"state": "open",
6061
"ci_passed": None,
6162
"author": None,
62-
"patch": None,
63+
"patch": self.no_patch_response,
6364
},
6465
{
6566
"pullid": self.pulls[0].pullid,
@@ -70,7 +71,7 @@ def test_list(self):
7071
"state": "open",
7172
"ci_passed": None,
7273
"author": None,
73-
"patch": None,
74+
"patch": self.no_patch_response,
7475
},
7576
],
7677
"total_pages": 1,
@@ -102,7 +103,7 @@ def test_list_state(self):
102103
"state": "closed",
103104
"ci_passed": None,
104105
"author": None,
105-
"patch": None,
106+
"patch": self.no_patch_response,
106107
}
107108
],
108109
"total_pages": 1,
@@ -133,7 +134,7 @@ def test_list_start_date(self):
133134
"state": "open",
134135
"ci_passed": None,
135136
"author": None,
136-
"patch": None,
137+
"patch": self.no_patch_response,
137138
}
138139
],
139140
"total_pages": 1,
@@ -161,7 +162,7 @@ def test_list_cursor_pagination(self):
161162
"state": "open",
162163
"ci_passed": None,
163164
"author": None,
164-
"patch": None,
165+
"patch": self.no_patch_response,
165166
}
166167
]
167168
assert data["previous"] is None
@@ -179,7 +180,7 @@ def test_list_cursor_pagination(self):
179180
"state": "open",
180181
"ci_passed": None,
181182
"author": None,
182-
"patch": None,
183+
"patch": self.no_patch_response,
183184
}
184185
]
185186
assert data["previous"] is not None
@@ -209,7 +210,7 @@ def test_retrieve(self, get_repo_permissions):
209210
"state": "open",
210211
"ci_passed": None,
211212
"author": None,
212-
"patch": None,
213+
"patch": self.no_patch_response,
213214
}
214215

215216
@patch("api.shared.permissions.RepositoryArtifactPermissions.has_permission")
@@ -305,7 +306,7 @@ def test_pull_with_valid_super_token(self):
305306
"state": "open",
306307
"ci_passed": None,
307308
"author": None,
308-
"patch": None,
309+
"patch": self.no_patch_response,
309310
}
310311

311312
@patch("api.public.v2.pull.serializers.ComparisonReport")
@@ -371,4 +372,4 @@ def test_retrieve_with_patch_coverag_no_branches(
371372
)
372373
assert res.status_code == 200
373374
data = res.json()
374-
assert data["patch"] is None
375+
assert data["patch"] is self.no_patch_response

api/shared/commit/serializers.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ def get_coverage(self, totals) -> float:
2121
return 0
2222

2323

24+
class PatchCoverageSerializer(serializers.Serializer):
25+
hits = serializers.IntegerField()
26+
misses = serializers.IntegerField()
27+
partials = serializers.IntegerField()
28+
coverage = serializers.FloatField()
29+
30+
2431
class CommitTotalsSerializer(BaseTotalsSerializer):
2532
files = serializers.IntegerField(source="f")
2633
lines = serializers.IntegerField(source="n")

services/comparison.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from shared.utils.merge import LineType, line_type
2121

2222
from compare.models import CommitComparison
23-
from core.models import Commit
23+
from core.models import Commit, Pull
2424
from reports.models import CommitReport
2525
from services import ServiceException
2626
from services.redis_configuration import get_redis_connection
@@ -1186,7 +1186,8 @@ def update_base_report_with_pseudo_diff(self):
11861186
class CommitComparisonService:
11871187
"""
11881188
Utilities for determining whether a commit comparison needs to be recomputed
1189-
(and enqueueing that recompute when necessary)
1189+
(and enqueueing that recompute when necessary), and fetching associated comparisons
1190+
for pulls
11901191
"""
11911192

11921193
def __init__(self, commit_comparison: CommitComparison):
@@ -1246,6 +1247,16 @@ def _load_commit(self, commit_id: int) -> Optional[Commit]:
12461247
.first()
12471248
)
12481249

1250+
@staticmethod
1251+
def get_commit_comparison_for_pull(obj: Pull):
1252+
comparison_qs = CommitComparison.objects.filter(
1253+
base_commit__commitid=obj.compared_to,
1254+
compare_commit__commitid=obj.head,
1255+
base_commit__repository_id=obj.repository_id,
1256+
compare_commit__repository_id=obj.repository_id,
1257+
).select_related("compare_commit", "base_commit")
1258+
return comparison_qs.first()
1259+
12491260
@classmethod
12501261
def fetch_precomputed(self, repo_id: int, keys: List[Tuple]) -> QuerySet:
12511262
comparison_table = CommitComparison._meta.db_table

0 commit comments

Comments
 (0)