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

Commit 50828ff

Browse files
committed
Do not double-filter Reports in ReportPaths
Previously, the `ReportPaths.files` accessor would manually filter through the `unfiltered_report`. Even though the `self.report` was already filtered. Now the custom filtering logic is a bit updated, but taking care of existing bugs in `FilteredReport`, as that is still yielding files even though they are not matching any `flags`.
1 parent de5e284 commit 50828ff

File tree

2 files changed

+50
-53
lines changed

2 files changed

+50
-53
lines changed

graphql_api/tests/test_branch.py

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -772,18 +772,15 @@ def test_fetch_path_contents_component_filter_missing_coverage(
772772
@patch("services.components.component_filtered_report")
773773
@patch("services.components.commit_components")
774774
@patch("shared.reports.api_report_service.build_report_from_commit")
775+
@patch("services.path.ReportPaths.files", new_callable=PropertyMock)
775776
def test_fetch_path_contents_component_filter_has_coverage(
776-
self, report_mock, commit_components_mock, filtered_mock
777+
self, files_mock, report_mock, commit_components_mock, filtered_mock
777778
):
778-
components = ["Global"]
779-
variables = {
780-
"org": self.org.username,
781-
"repo": self.repo.name,
782-
"branch": self.branch.name,
783-
"path": "",
784-
"filters": {"components": components},
785-
}
786-
779+
files_mock.return_value = [
780+
"folder/fileB.py",
781+
"folder/subfolder/fileC.py",
782+
"folder/subfolder/fileD.py",
783+
]
787784
report_mock.return_value = MockReport()
788785
commit_components_mock.return_value = [
789786
Component.from_dict(
@@ -810,6 +807,14 @@ def test_fetch_path_contents_component_filter_has_coverage(
810807
]
811808
filtered_mock.return_value = MockReport()
812809

810+
components = ["Global"]
811+
variables = {
812+
"org": self.org.username,
813+
"repo": self.repo.name,
814+
"branch": self.branch.name,
815+
"path": "",
816+
"filters": {"components": components},
817+
}
813818
data = self.gql_request(query_files, variables=variables)
814819

815820
assert data == {
@@ -841,18 +846,15 @@ def test_fetch_path_contents_component_filter_has_coverage(
841846
@patch("services.components.component_filtered_report")
842847
@patch("services.components.commit_components")
843848
@patch("shared.reports.api_report_service.build_report_from_commit")
844-
@patch("services.report.files_belonging_to_flags")
845-
@patch("services.report.files_in_sessions")
849+
@patch("services.path.ReportPaths.files", new_callable=PropertyMock)
846850
def test_fetch_path_contents_component_and_flag_filters(
847851
self,
848-
session_files_mock,
849-
flag_files_mock,
852+
files_mock,
850853
report_mock,
851854
commit_components_mock,
852855
filtered_mock,
853856
):
854-
session_files_mock.return_value = ["fileA.py"]
855-
flag_files_mock.return_value = ["fileA.py"]
857+
files_mock.return_value = ["fileA.py"]
856858
report_mock.return_value = MockReport()
857859
commit_components_mock.return_value = [
858860
Component.from_dict(
@@ -945,11 +947,11 @@ def test_fetch_path_contents_component_and_flag_filters(
945947
@patch("services.components.component_filtered_report")
946948
@patch("services.components.commit_components")
947949
@patch("shared.reports.api_report_service.build_report_from_commit")
948-
@patch("services.report.files_belonging_to_flags")
950+
@patch("services.path.ReportPaths.files", new_callable=PropertyMock)
949951
def test_fetch_path_contents_component_and_flag_filters_unknown_flags(
950-
self, flag_files_mock, report_mock, commit_components_mock, filtered_mock
952+
self, files_mock, report_mock, commit_components_mock, filtered_mock
951953
):
952-
flag_files_mock.return_value = ["fileA.py"]
954+
files_mock.return_value = ["fileA.py"]
953955
report_mock.return_value = MockNoFlagsReport()
954956
commit_components_mock.return_value = [
955957
Component.from_dict(
@@ -1035,18 +1037,15 @@ def test_fetch_path_contents_component_and_flag_filters_unknown_flags(
10351037
@patch("services.components.component_filtered_report")
10361038
@patch("services.components.commit_components")
10371039
@patch("shared.reports.api_report_service.build_report_from_commit")
1038-
@patch("services.report.files_belonging_to_flags")
1039-
@patch("services.report.files_in_sessions")
1040+
@patch("services.path.ReportPaths.files", new_callable=PropertyMock)
10401041
def test_fetch_path_contents_component_flags_filters(
10411042
self,
1042-
session_files_mock,
1043-
flag_files_mock,
1043+
files_mock,
10441044
report_mock,
10451045
commit_components_mock,
10461046
filtered_mock,
10471047
):
1048-
session_files_mock.return_value = ["fileA.py"]
1049-
flag_files_mock.return_value = ["fileA.py"]
1048+
files_mock.return_value = ["fileA.py"]
10501049
report_mock.return_value = MockReport()
10511050
commit_components_mock.return_value = [
10521051
Component.from_dict(

services/path.py

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@
88
import sentry_sdk
99
from asgiref.sync import async_to_sync
1010
from django.conf import settings
11+
from shared.reports.filtered import FilteredReport, FilteredReportFile
1112
from shared.reports.resources import Report
1213
from shared.reports.types import ReportTotals
1314
from shared.torngit.exceptions import TorngitClientError
14-
from shared.utils.match import Matcher
1515

16-
import services.report as report_service
1716
from codecov_auth.models import Owner
1817
from core.models import Commit
1918
from services.repo_providers import RepoProviderService
@@ -150,13 +149,12 @@ def __init__(
150149
report: Report,
151150
path: str | None = None,
152151
search_term: str | None = None,
153-
filter_flags: list[str] = [],
154-
filter_paths: list[str] = [],
152+
filter_flags: list[str] = None,
153+
filter_paths: list[str] = None,
155154
):
156-
self.report = report
157-
self.unfiltered_report = report
158-
self.filter_flags = filter_flags
159-
self.filter_paths = filter_paths
155+
self.report: Report | FilteredReport = report
156+
self.filter_flags = filter_flags or []
157+
self.filter_paths = filter_paths or []
160158
self.prefix = path or ""
161159

162160
# Filter report if flags or paths exist
@@ -172,37 +170,37 @@ def __init__(
172170
]
173171

174172
if search_term:
173+
search_term = search_term.lower()
175174
self._paths = [
176175
path
177-
for path in self.paths
178-
if search_term.lower() in path.relative_path.lower()
176+
for path in self._paths
177+
if search_term in path.relative_path.lower()
179178
]
180179

181180
@cached_property
182181
def files(self) -> list[str]:
183-
# No filtering, just return files in Report
184-
if not self.filter_flags and not self.filter_paths:
182+
# No flags filtering, just return (path-filtered) files in Report
183+
if not self.filter_flags:
185184
return self.report.files
186185

186+
# When there is a flag filter, `FilteredReport` currently yields
187+
# `FilteredReportFile`s without actually checking whether they match the sessions.
188+
# Before that bug is fixed, lets do the filtering manually here. Once that bug is fixed,
189+
# this should just forward to `self.report.files` like above.
187190
files = []
188-
# Do flag filtering if needed
189-
if self.filter_flags:
190-
files = report_service.files_belonging_to_flags(
191-
commit_report=self.unfiltered_report, flags=self.filter_flags
192-
)
193-
else:
194-
files = [file.name for file in self.unfiltered_report]
195-
196-
# Do path filtering if needed
197-
if self.filter_paths:
198-
matcher = Matcher(self.filter_paths)
199-
files = [file for file in files if matcher.match(file)]
200-
191+
for file in self.report:
192+
if isinstance(file, FilteredReportFile):
193+
found = False
194+
for _ln, line in file.lines:
195+
if line and any(s.id in file.session_ids for s in line.sessions):
196+
found = True
197+
break
198+
if not found:
199+
continue
200+
201+
files.append(file.name)
201202
return files
202203

203-
def _filter_commit_report(self) -> None:
204-
self.report = self.report.filter(flags=self.filter_flags)
205-
206204
@property
207205
def paths(self) -> list[PrefixedPath]:
208206
return self._paths

0 commit comments

Comments
 (0)