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

Commit e72e553

Browse files
Make sure calls to fetch_commit_yaml are Owner type (#823)
Co-authored-by: michelletran-codecov <[email protected]>
1 parent 822487b commit e72e553

File tree

11 files changed

+153
-8
lines changed

11 files changed

+153
-8
lines changed

api/public/v2/compare/views.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def components(self, request, *args, **kwargs):
117117
Returns component comparisons
118118
"""
119119
comparison = self.get_object()
120-
components = commit_components(comparison.head_commit, request.user)
120+
components = commit_components(comparison.head_commit, self.owner)
121121
component_comparisons = [
122122
ComponentComparison(comparison, component) for component in components
123123
]

api/public/v2/component/views.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def list(self, request, *args, **kwargs):
4040
"""
4141
commit = self.get_commit()
4242
report = commit.full_report
43-
components = commit_components(commit, request.user)
43+
components = commit_components(commit, self.owner)
4444
components_with_coverage = []
4545
for component in components:
4646
component_report = component_filtered_report(report, [component])

api/public/v2/report/views.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def filter_report(
9898
component = next(
9999
(
100100
component
101-
for component in commit_components(commit, self.request.user)
101+
for component in commit_components(commit, self.owner)
102102
if component.component_id == component_id
103103
),
104104
None,

api/public/v2/tests/test_api_compare_viewset.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,7 @@ def test_components_comparison(
715715
content_type="application/json",
716716
)
717717

718+
commit_components.assert_called_once_with(self.head, self.org)
718719
assert res.status_code == 200
719720
assert res.json() == [
720721
{

api/public/v2/tests/test_api_component_viewset.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,11 @@ def _request_components(self):
7272
@patch("api.public.v2.component.views.commit_components")
7373
@patch("shared.reports.api_report_service.build_report_from_commit")
7474
def test_component_list(
75-
self, build_report_from_commit, commit_compontents, get_repo_permissions
75+
self, build_report_from_commit, commit_components, get_repo_permissions
7676
):
7777
get_repo_permissions.return_value = (True, True)
7878
build_report_from_commit.side_effect = [sample_report()]
79-
commit_compontents.return_value = [
79+
commit_components.return_value = [
8080
Component(
8181
component_id="foo",
8282
paths=[r".*foo"],
@@ -94,6 +94,7 @@ def test_component_list(
9494
]
9595

9696
res = self._request_components()
97+
commit_components.assert_called_once_with(self.commit, self.org)
9798
assert res.status_code == 200
9899
assert res.json() == [
99100
{"component_id": "foo", "name": "Foo", "coverage": 62.5},
@@ -103,11 +104,11 @@ def test_component_list(
103104
@patch("api.public.v2.component.views.commit_components")
104105
@patch("shared.reports.api_report_service.build_report_from_commit")
105106
def test_component_list_no_coverage(
106-
self, build_report_from_commit, commit_compontents, get_repo_permissions
107+
self, build_report_from_commit, commit_components, get_repo_permissions
107108
) -> None:
108109
get_repo_permissions.return_value = (True, True)
109110
build_report_from_commit.side_effect = [empty_report()]
110-
commit_compontents.return_value = [
111+
commit_components.return_value = [
111112
Component(
112113
component_id="foo",
113114
paths=[r".*foo"],
@@ -118,6 +119,7 @@ def test_component_list_no_coverage(
118119
]
119120

120121
res = self._request_components()
122+
commit_components.assert_called_once_with(self.commit, self.org)
121123
assert res.status_code == 200
122124
assert res.json() == [
123125
{

api/public/v2/tests/test_report_viewset.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,7 @@ def test_report_component(
971971
build_report_from_commit.return_value = flags_report()
972972

973973
res = self._request_report(component_id="foo")
974+
commit_components.assert_called_once_with(self.commit1, self.org)
974975
assert res.status_code == 200
975976
assert res.json() == {
976977
"totals": {

api/public/v2/tests/test_totals_viewset.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,7 @@ def test_report_component(
617617
build_report_from_commit.return_value = sample_report()
618618

619619
res = self._request_report(component_id="foo")
620+
commit_components.assert_called_once_with(self.commit1, self.org)
620621
assert res.status_code == 200
621622
assert res.json() == {
622623
"totals": {

services/tests/test_yaml.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from unittest.mock import patch
22

3+
import pytest
34
from django.test import TransactionTestCase
45
from shared.torngit.exceptions import TorngitObjectNotFoundError
56

@@ -31,3 +32,27 @@ def test_when_commit_has_no_yaml(self, mock_fetch_yaml):
3132
)
3233
config = yaml.final_commit_yaml(self.commit, None)
3334
assert config["codecov"]["require_ci_to_pass"] is True
35+
36+
@patch("services.yaml.fetch_current_yaml_from_provider_via_reference")
37+
def test_when_commit_has_yaml_with_wrongly_typed_owner_arg(self, mock_fetch_yaml):
38+
mock_fetch_yaml.return_value = """
39+
codecov:
40+
notify:
41+
require_ci_to_pass: no
42+
"""
43+
with pytest.raises(TypeError) as exc_info:
44+
yaml.final_commit_yaml(self.commit, "something else")
45+
assert (
46+
str(exc_info.value)
47+
== "fetch_commit_yaml owner arg must be Owner or None. Provided: <class 'str'>"
48+
)
49+
50+
@patch("services.yaml.fetch_current_yaml_from_provider_via_reference")
51+
def test_when_commit_has_yaml_with_owner(self, mock_fetch_yaml):
52+
mock_fetch_yaml.return_value = """
53+
codecov:
54+
notify:
55+
require_ci_to_pass: no
56+
"""
57+
config = yaml.final_commit_yaml(self.commit, self.org)
58+
assert config["codecov"]["require_ci_to_pass"] is False

services/yaml.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ def fetch_commit_yaml(commit: Commit, owner: Owner | None) -> Dict | None:
2525
Fetches the codecov.yaml file for a particular commit from the service provider.
2626
Service provider API request is made on behalf of the given `owner`.
2727
"""
28+
29+
# There's been a lot of instances where this function is called where the owner arg is not Owner type
30+
# Previously this issue is masked by the catch all exception handling. Most badly typed calls have
31+
# been addressed, but there might still be some entrypoints unaccounted for, will fix new discoveries
32+
# from this assertion being raised.
33+
if owner is not None and not isinstance(owner, Owner):
34+
raise TypeError(
35+
f"fetch_commit_yaml owner arg must be Owner or None. Provided: {type(owner)}"
36+
)
37+
2838
try:
2939
repository_service = RepoProviderService().get_adapter(
3040
owner=owner, repo=commit.repository

upload/tests/views/test_empty_upload.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from rest_framework.test import APIClient
55
from shared.yaml.user_yaml import UserYaml
66

7+
from codecov_auth.tests.factories import OrganizationLevelTokenFactory
78
from core.tests.factories import CommitFactory, RepositoryFactory
89
from upload.views.uploads import CanDoCoverageUploadsPermission
910

@@ -481,3 +482,101 @@ def test_empty_upload_no_auth(db, mocker):
481482
== "Failed token authentication, please double-check that your repository token matches in the Codecov UI, "
482483
"or review the docs https://docs.codecov.com/docs/adding-the-codecov-token"
483484
)
485+
486+
487+
@patch("services.yaml.fetch_commit_yaml")
488+
@patch("services.task.TaskService.notify")
489+
@patch("services.repo_providers.RepoProviderService.get_adapter")
490+
def test_empty_upload_commit_yaml_org_token(
491+
mock_repo_provider_service, notify_mock, fetch_yaml_mock, db, mocker
492+
):
493+
mocker.patch.object(
494+
CanDoCoverageUploadsPermission, "has_permission", return_value=True
495+
)
496+
mock_repo_provider_service.return_value = MockedProviderAdapter(
497+
["README.md", "codecov.yml", "template.txt", "base.py"]
498+
)
499+
fetch_yaml_mock.return_value = None
500+
501+
repository = RepositoryFactory(
502+
name="the_repo", author__username="codecov", author__service="github"
503+
)
504+
commit = CommitFactory(repository=repository)
505+
org_token = OrganizationLevelTokenFactory.create(owner=repository.author)
506+
repository.save()
507+
commit.save()
508+
org_token.save()
509+
510+
client = APIClient()
511+
url = reverse(
512+
"new_upload.empty_upload",
513+
args=[
514+
"github",
515+
"codecov::::the_repo",
516+
commit.commitid,
517+
],
518+
)
519+
response = client.post(
520+
url,
521+
headers={"Authorization": f"token {org_token.token}"},
522+
)
523+
response_json = response.json()
524+
assert response.status_code == 200
525+
assert (
526+
response_json.get("result")
527+
== "Some files cannot be ignored. Triggering failing notifications."
528+
)
529+
assert response_json.get("non_ignored_files") == ["base.py"]
530+
notify_mock.assert_called_once_with(
531+
repoid=repository.repoid, commitid=commit.commitid, empty_upload="fail"
532+
)
533+
534+
fetch_yaml_mock.assert_called_once_with(commit, repository.author)
535+
536+
537+
@patch("services.yaml.fetch_commit_yaml")
538+
@patch("services.task.TaskService.notify")
539+
@patch("services.repo_providers.RepoProviderService.get_adapter")
540+
def test_empty_upload_ommit_yaml_repo_token(
541+
mock_repo_provider_service, notify_mock, fetch_yaml_mock, db, mocker
542+
):
543+
mocker.patch.object(
544+
CanDoCoverageUploadsPermission, "has_permission", return_value=True
545+
)
546+
mock_repo_provider_service.return_value = MockedProviderAdapter(
547+
["README.md", "codecov.yml", "template.txt", "base.py"]
548+
)
549+
fetch_yaml_mock.return_value = None
550+
551+
repository = RepositoryFactory(
552+
name="the_repo", author__username="codecov", author__service="github"
553+
)
554+
commit = CommitFactory(repository=repository)
555+
repository.save()
556+
commit.save()
557+
558+
client = APIClient()
559+
url = reverse(
560+
"new_upload.empty_upload",
561+
args=[
562+
"github",
563+
"codecov::::the_repo",
564+
commit.commitid,
565+
],
566+
)
567+
response = client.post(
568+
url,
569+
headers={"Authorization": f"token {repository.upload_token}"},
570+
)
571+
response_json = response.json()
572+
assert response.status_code == 200
573+
assert (
574+
response_json.get("result")
575+
== "Some files cannot be ignored. Triggering failing notifications."
576+
)
577+
assert response_json.get("non_ignored_files") == ["base.py"]
578+
notify_mock.assert_called_once_with(
579+
repoid=repository.repoid, commitid=commit.commitid, empty_upload="fail"
580+
)
581+
582+
fetch_yaml_mock.assert_called_once_with(commit, repository.author)

0 commit comments

Comments
 (0)