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

Commit e016818

Browse files
committed
Merge branch 'main' into Ajay/remove-plan-data-types
2 parents 10237d6 + 659b4ec commit e016818

File tree

15 files changed

+226
-2
lines changed

15 files changed

+226
-2
lines changed

core/commands/commit/commit.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .interactors.get_commit_errors import GetCommitErrorsInteractor
55
from .interactors.get_file_content import GetFileContentInteractor
66
from .interactors.get_final_yaml import GetFinalYamlInteractor
7+
from .interactors.get_latest_upload_error import GetLatestUploadErrorInteractor
78
from .interactors.get_uploads_number import GetUploadsNumberInteractor
89

910

@@ -24,3 +25,6 @@ def get_commit_errors(self, commit, error_type):
2425

2526
def get_uploads_number(self, commit):
2627
return self.get_interactor(GetUploadsNumberInteractor).execute(commit)
28+
29+
def get_latest_upload_error(self, commit):
30+
return self.get_interactor(GetLatestUploadErrorInteractor).execute(commit)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import logging
2+
from typing import Optional
3+
4+
from codecov.commands.base import BaseInteractor
5+
from codecov.db import sync_to_async
6+
from core.models import Commit
7+
from reports.models import CommitReport, UploadError
8+
9+
log = logging.getLogger(__name__)
10+
11+
12+
class GetLatestUploadErrorInteractor(BaseInteractor):
13+
@sync_to_async
14+
def execute(self, commit: Commit) -> Optional[dict]:
15+
try:
16+
return self._get_latest_error(commit)
17+
except Exception as e:
18+
log.error(f"Error fetching upload error: {e}")
19+
return None
20+
21+
def _get_latest_error(self, commit: Commit) -> Optional[dict]:
22+
latest_error = self._fetch_latest_error(commit)
23+
if not latest_error:
24+
return None
25+
26+
return {
27+
"error_code": latest_error.error_code,
28+
"error_message": latest_error.error_params.get("error_message"),
29+
}
30+
31+
def _fetch_latest_error(self, commit: Commit) -> Optional[UploadError]:
32+
return (
33+
UploadError.objects.filter(
34+
report_session__report__commit=commit,
35+
report_session__report__report_type=CommitReport.ReportType.TEST_RESULTS,
36+
)
37+
.only("error_code", "error_params")
38+
.order_by("-created_at")
39+
.first()
40+
)
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
from unittest.mock import patch
2+
3+
from django.test import TransactionTestCase
4+
from shared.django_apps.core.tests.factories import (
5+
CommitFactory,
6+
OwnerFactory,
7+
RepositoryFactory,
8+
)
9+
10+
from core.commands.commit.interactors.get_latest_upload_error import (
11+
GetLatestUploadErrorInteractor,
12+
)
13+
from graphql_api.types.enums import UploadErrorEnum
14+
from reports.models import CommitReport
15+
from reports.tests.factories import (
16+
CommitReportFactory,
17+
UploadErrorFactory,
18+
UploadFactory,
19+
)
20+
21+
22+
class GetLatestUploadErrorInteractorTest(TransactionTestCase):
23+
def setUp(self):
24+
self.org = OwnerFactory()
25+
self.repo = RepositoryFactory(author=self.org)
26+
self.commit = self._create_commit_with_errors()
27+
self.commit_with_no_errors = CommitFactory(repository=self.repo)
28+
self.single_error_commit = self._create_commit_with_single_error()
29+
30+
def _create_commit_with_errors(self):
31+
commit = CommitFactory(repository=self.repo)
32+
report = CommitReportFactory(
33+
commit=commit, report_type=CommitReport.ReportType.TEST_RESULTS
34+
)
35+
upload = UploadFactory(report=report)
36+
37+
# Create two errors with different timestamps
38+
UploadErrorFactory(
39+
report_session=upload,
40+
created_at="2024-01-01T10:00:00Z",
41+
error_code=UploadErrorEnum.FILE_NOT_IN_STORAGE,
42+
error_params={"error_message": "First error"},
43+
)
44+
UploadErrorFactory(
45+
report_session=upload,
46+
created_at="2024-01-01T11:00:00Z",
47+
error_code=UploadErrorEnum.REPORT_EMPTY,
48+
error_params={"error_message": "Latest error"},
49+
)
50+
return commit
51+
52+
def _create_commit_with_single_error(self):
53+
commit = CommitFactory(repository=self.repo)
54+
report = CommitReportFactory(
55+
commit=commit,
56+
report_type=CommitReport.ReportType.TEST_RESULTS,
57+
)
58+
upload = UploadFactory(report=report)
59+
UploadErrorFactory(
60+
report_session=upload,
61+
error_code=UploadErrorEnum.UNKNOWN_PROCESSING,
62+
error_params={"error_message": "Some other error"},
63+
)
64+
return commit
65+
66+
def execute(self, commit, owner=None):
67+
service = owner.service if owner else "github"
68+
return GetLatestUploadErrorInteractor(owner, service).execute(commit)
69+
70+
async def test_when_no_errors_then_returns_none(self):
71+
result = await self.execute(commit=self.commit_with_no_errors, owner=self.org)
72+
assert result is None
73+
74+
async def test_when_multiple_errors_then_returns_most_recent(self):
75+
result = await self.execute(commit=self.commit, owner=self.org)
76+
assert result == {
77+
"error_code": UploadErrorEnum.REPORT_EMPTY,
78+
"error_message": "Latest error",
79+
}
80+
81+
async def test_when_single_error_then_returns_error(self):
82+
result = await self.execute(commit=self.single_error_commit, owner=self.org)
83+
assert result == {
84+
"error_code": UploadErrorEnum.UNKNOWN_PROCESSING,
85+
"error_message": "Some other error",
86+
}
87+
88+
async def test_return_none_on_raised_error(self):
89+
with patch(
90+
"core.commands.commit.interactors.get_latest_upload_error.GetLatestUploadErrorInteractor._get_latest_error",
91+
side_effect=Exception("Test error"),
92+
):
93+
result = await self.execute(commit=self.commit, owner=self.org)
94+
assert result is None

core/commands/commit/tests/test_commit.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,8 @@ def test_get_commit_errors_delegate_to_interactor(self, interactor_mock):
3838
def test_get_uploads_number_delegate_to_interactor(self, interactor_mock):
3939
self.command.get_uploads_number(self.commit)
4040
interactor_mock.assert_called_once_with(self.commit)
41+
42+
@patch("core.commands.commit.commit.GetLatestUploadErrorInteractor.execute")
43+
def test_get_latest_upload_error_delegate_to_interactor(self, interactor_mock):
44+
self.command.get_latest_upload_error(self.commit)
45+
interactor_mock.assert_called_once_with(self.commit)

core/commands/repository/interactors/tests/test_update_bundle_cache_config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ def test_update_bundles_successfully(self):
7676
)
7777

7878
assert res == [
79-
{"bundle_name": "bundle1", "is_cached": False},
80-
{"bundle_name": "bundle2", "is_cached": True},
79+
{"bundle_name": "bundle1", "is_cached": False, "cache_config": False},
80+
{"bundle_name": "bundle2", "is_cached": True, "cache_config": True},
8181
]
8282

8383
assert len(CacheConfig.objects.all()) == 2

core/commands/repository/interactors/update_bundle_cache_config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def execute(
5757
{
5858
"bundle_name": bundle_name,
5959
"is_cached": is_caching,
60+
"cache_config": is_caching,
6061
}
6162
)
6263
return results

graphql_api/tests/mutation/test_update_bundle_cache_config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
results {
3131
bundleName
3232
isCached
33+
cacheConfig
3334
}
3435
error {
3536
__typename

graphql_api/tests/test_commit.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,7 @@ def test_bundle_analysis_report(self, get_storage_service):
12021202
}
12031203
}
12041204
isCached
1205+
cacheConfig
12051206
}
12061207
bundleData {
12071208
loadTime {
@@ -1263,6 +1264,7 @@ def test_bundle_analysis_report(self, get_storage_service):
12631264
},
12641265
},
12651266
"isCached": False,
1267+
"cacheConfig": False,
12661268
},
12671269
{
12681270
"name": "b2",
@@ -1285,6 +1287,7 @@ def test_bundle_analysis_report(self, get_storage_service):
12851287
},
12861288
},
12871289
"isCached": False,
1290+
"cacheConfig": False,
12881291
},
12891292
{
12901293
"name": "b3",
@@ -1307,6 +1310,7 @@ def test_bundle_analysis_report(self, get_storage_service):
13071310
},
13081311
},
13091312
"isCached": False,
1313+
"cacheConfig": False,
13101314
},
13111315
{
13121316
"name": "b5",
@@ -1329,6 +1333,7 @@ def test_bundle_analysis_report(self, get_storage_service):
13291333
},
13301334
},
13311335
"isCached": False,
1336+
"cacheConfig": False,
13321337
},
13331338
],
13341339
"bundleData": {
@@ -3523,3 +3528,45 @@ def test_bundle_analysis_report_info(self, get_storage_service):
35233528
assert bundle_info["duration"] == 331
35243529
assert bundle_info["bundlerName"] == "rollup"
35253530
assert bundle_info["bundlerVersion"] == "3.29.4"
3531+
3532+
def test_latest_upload_error(self):
3533+
commit = CommitFactory(repository=self.repo)
3534+
report = CommitReportFactory(
3535+
commit=commit, report_type=CommitReport.ReportType.TEST_RESULTS
3536+
)
3537+
upload = UploadFactory(report=report)
3538+
UploadErrorFactory(
3539+
report_session=upload,
3540+
error_code=UploadErrorEnum.UNKNOWN_PROCESSING,
3541+
error_params={"error_message": "Unknown processing error"},
3542+
)
3543+
3544+
query = """
3545+
query FetchCommit($org: String!, $repo: String!, $commit: String!) {
3546+
owner(username: $org) {
3547+
repository(name: $repo) {
3548+
... on Repository {
3549+
commit(id: $commit) {
3550+
latestUploadError {
3551+
errorCode
3552+
errorMessage
3553+
}
3554+
}
3555+
}
3556+
}
3557+
}
3558+
}
3559+
"""
3560+
3561+
variables = {
3562+
"org": self.org.username,
3563+
"repo": self.repo.name,
3564+
"commit": commit.commitid,
3565+
}
3566+
data = self.gql_request(query, variables=variables)
3567+
commit = data["owner"]["repository"]["commit"]
3568+
3569+
assert commit["latestUploadError"] == {
3570+
"errorCode": "UNKNOWN_PROCESSING",
3571+
"errorMessage": "Unknown processing error",
3572+
}

graphql_api/types/bundle_analysis/base.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ type BundleReport {
9393
before: String
9494
): AssetConnection
9595
info: BundleReportInfo!
96+
cacheConfig: Boolean!
9697
}
9798

9899
type BundleAnalysisMeasurements{

graphql_api/types/bundle_analysis/base.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,13 @@ def resolve_bundle_report_is_cached(
372372
return bundle_report.is_cached
373373

374374

375+
@bundle_report_bindable.field("cacheConfig")
376+
def resolve_bundle_report_cache_config(
377+
bundle_report: BundleReport, info: GraphQLResolveInfo
378+
) -> bool:
379+
return bundle_report.cache_config(info.context["commit"].repository.pk)
380+
381+
375382
@bundle_report_bindable.field("info")
376383
def resolve_bundle_report_info(
377384
bundle_report: BundleReport, info: GraphQLResolveInfo

0 commit comments

Comments
 (0)