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

Commit d30abc6

Browse files
Merge branch 'main' into revert-972-temporarily-dismiss-trial-extension-for-paid-customers
2 parents 231f3fe + 6fa33eb commit d30abc6

File tree

11 files changed

+643
-157
lines changed

11 files changed

+643
-157
lines changed

docker/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# syntax=docker/dockerfile:1.4
22
ARG REQUIREMENTS_IMAGE
33
ARG BUILD_ENV=self-hosted
4-
ARG BERGLAS_VERSION=2.0.2
4+
ARG BERGLAS_VERSION=2.0.6
55

66
FROM us-docker.pkg.dev/berglas/berglas/berglas:$BERGLAS_VERSION as berglas
77

graphql_api/types/test_analytics/test_analytics.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ def generate_test_results(
218218
table = table.filter(pl.col("total_flaky_fail_count") > 0)
219219
case TestResultsFilterParameter.SKIPPED_TESTS:
220220
table = table.filter(
221-
pl.col("total_skip_count") > 0 & pl.col("total_pass_count") == 0
221+
(pl.col("total_skip_count") > 0) & (pl.col("total_pass_count") == 0)
222222
)
223223
case TestResultsFilterParameter.SLOWEST_TESTS:
224224
table = table.filter(
@@ -285,7 +285,7 @@ def get_test_suites(
285285
if term:
286286
testsuites = testsuites.filter(pl.col("testsuite").str.starts_with(term))
287287

288-
return testsuites.to_series().to_list()
288+
return testsuites.to_series().drop_nulls().to_list() or []
289289

290290

291291
def get_flags(repoid: int, term: str | None = None, interval: int = 30) -> list[str]:
@@ -295,12 +295,12 @@ def get_flags(repoid: int, term: str | None = None, interval: int = 30) -> list[
295295
if table is None:
296296
return []
297297

298-
flags = table.select(pl.col("flags")).unique()
298+
flags = table.select(pl.col("flags").explode()).unique()
299299

300300
if term:
301301
flags = flags.filter(pl.col("flags").str.starts_with(term))
302302

303-
return flags.to_series().to_list()
303+
return flags.to_series().drop_nulls().to_list() or []
304304

305305

306306
class TestResultsOrdering(TypedDict):

services/task/task.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,8 @@ def send_email(
398398
from_addr: str | None = None,
399399
**kwargs,
400400
):
401+
# Disabling this while we fix HTML templates.
402+
return
401403
# Templates can be found in worker/templates
402404
self._create_signature(
403405
"app.tasks.send_email.SendEmail",
Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
from unittest.mock import patch
2+
3+
from django.conf import settings
4+
from django.test import override_settings
5+
from django.urls import reverse
6+
from rest_framework.test import APIClient
7+
from shared.django_apps.core.tests.factories import (
8+
CommitFactory,
9+
RepositoryFactory,
10+
)
11+
12+
from reports.models import (
13+
ReportSession,
14+
RepositoryFlag,
15+
UploadFlagMembership,
16+
)
17+
from services.archive import ArchiveService, MinioEndpoints
18+
from upload.views.combined_upload import CanDoCoverageUploadsPermission
19+
20+
21+
def test_get_repo(db):
22+
repository = RepositoryFactory(
23+
name="the_repo", author__username="codecov", author__service="github"
24+
)
25+
repository.save()
26+
repo_slug = f"{repository.author.username}::::{repository.name}"
27+
url = reverse(
28+
"new_upload.combined_upload",
29+
args=[repository.author.service, repo_slug],
30+
)
31+
client = APIClient()
32+
client.credentials(HTTP_AUTHORIZATION="token " + repository.upload_token)
33+
response = client.post(url, {}, format="json")
34+
assert response.status_code == 400 # Bad request due to missing required fields
35+
assert "commitid" in response.json()
36+
37+
38+
@patch("services.task.TaskService.upload")
39+
def test_get_repo_not_found(upload, db):
40+
repository = RepositoryFactory(
41+
name="the_repo", author__username="codecov", author__service="github"
42+
)
43+
repo_slug = "codecov::::wrong-repo-name"
44+
url = reverse(
45+
"new_upload.combined_upload",
46+
args=[repository.author.service, repo_slug],
47+
)
48+
client = APIClient()
49+
response = client.post(url, {}, format="json")
50+
assert response.status_code == 401
51+
assert response.json() == {"detail": "Not valid tokenless upload"}
52+
assert not upload.called
53+
54+
55+
def test_deactivated_repo(db):
56+
repository = RepositoryFactory(
57+
name="the_repo",
58+
author__username="codecov",
59+
author__service="github",
60+
active=True,
61+
activated=False,
62+
)
63+
repository.save()
64+
repo_slug = f"{repository.author.username}::::{repository.name}"
65+
url = reverse(
66+
"new_upload.combined_upload",
67+
args=[repository.author.service, repo_slug],
68+
)
69+
client = APIClient()
70+
client.credentials(HTTP_AUTHORIZATION="token " + repository.upload_token)
71+
response = client.post(url, {"commit_sha": "abc123"}, format="json")
72+
assert response.status_code == 400
73+
assert "This repository is deactivated" in str(response.json())
74+
75+
76+
def test_combined_upload_with_errors(db):
77+
repository = RepositoryFactory()
78+
repo_slug = f"{repository.author.username}::::{repository.name}"
79+
url = reverse(
80+
"new_upload.combined_upload",
81+
args=[repository.author.service, repo_slug],
82+
)
83+
84+
client = APIClient()
85+
client.credentials(HTTP_AUTHORIZATION="token " + repository.upload_token)
86+
87+
# Missing required fields
88+
response = client.post(url, {}, format="json")
89+
assert response.status_code == 400
90+
assert "commitid" in response.json()
91+
92+
# Invalid flag format
93+
response = client.post(
94+
url, {"commit_sha": "abc123", "flags": "not-a-list"}, format="json"
95+
)
96+
assert response.status_code == 400
97+
assert "flags" in response.json()
98+
99+
100+
def test_combined_upload_post(db, mocker):
101+
mocker.patch.object(
102+
CanDoCoverageUploadsPermission, "has_permission", return_value=True
103+
)
104+
presigned_put_mock = mocker.patch(
105+
"services.archive.StorageService.create_presigned_put",
106+
return_value="presigned put",
107+
)
108+
upload_task_mock = mocker.patch(
109+
"upload.views.uploads.trigger_upload_task", return_value=True
110+
)
111+
112+
repository = RepositoryFactory(
113+
name="the_repo1", author__username="codecov", author__service="github"
114+
)
115+
commit = CommitFactory(repository=repository)
116+
repository.save()
117+
commit.save()
118+
119+
owner = repository.author
120+
client = APIClient()
121+
client.force_authenticate(user=owner)
122+
repo_slug = f"{repository.author.username}::::{repository.name}"
123+
url = reverse(
124+
"new_upload.combined_upload",
125+
args=[repository.author.service, repo_slug],
126+
)
127+
response = client.post(
128+
url,
129+
{
130+
"branch": "branch",
131+
"ci_service": "ci_service",
132+
"ci_url": "ci_url",
133+
"code": "code",
134+
"commit_sha": commit.commitid,
135+
"flags": ["flag1", "flag2"],
136+
"job_code": "job_code",
137+
"version": "version",
138+
},
139+
format="json",
140+
)
141+
response_json = response.json()
142+
upload = ReportSession.objects.filter(
143+
report__commit=commit,
144+
report__code="code",
145+
upload_extras={"format_version": "v1"},
146+
).first()
147+
assert response.status_code == 201
148+
assert all(
149+
map(
150+
lambda x: x in response_json.keys(),
151+
["external_id", "created_at", "raw_upload_location", "url"],
152+
)
153+
)
154+
assert (
155+
response_json.get("url")
156+
== f"{settings.CODECOV_DASHBOARD_URL}/{repository.author.service}/{repository.author.username}/{repository.name}/commit/{commit.commitid}"
157+
)
158+
159+
assert ReportSession.objects.filter(
160+
report__commit=commit,
161+
report__code="code",
162+
upload_extras={"format_version": "v1"},
163+
).exists()
164+
assert RepositoryFlag.objects.filter(
165+
repository_id=repository.repoid, flag_name="flag1"
166+
).exists()
167+
assert RepositoryFlag.objects.filter(
168+
repository_id=repository.repoid, flag_name="flag2"
169+
).exists()
170+
flag1 = RepositoryFlag.objects.filter(
171+
repository_id=repository.repoid, flag_name="flag1"
172+
).first()
173+
flag2 = RepositoryFlag.objects.filter(
174+
repository_id=repository.repoid, flag_name="flag2"
175+
).first()
176+
assert UploadFlagMembership.objects.filter(
177+
report_session_id=upload.id, flag_id=flag1.id
178+
).exists()
179+
assert UploadFlagMembership.objects.filter(
180+
report_session_id=upload.id, flag_id=flag2.id
181+
).exists()
182+
assert [flag for flag in upload.flags.all()] == [flag1, flag2]
183+
184+
archive_service = ArchiveService(repository)
185+
assert upload.storage_path == MinioEndpoints.raw_with_upload_id.get_path(
186+
version="v4",
187+
date=upload.created_at.strftime("%Y-%m-%d"),
188+
repo_hash=archive_service.storage_hash,
189+
commit_sha=commit.commitid,
190+
reportid=upload.report.external_id,
191+
uploadid=upload.external_id,
192+
)
193+
presigned_put_mock.assert_called_with("archive", upload.storage_path, 10)
194+
upload_task_mock.assert_called()
195+
196+
197+
@override_settings(SHELTER_SHARED_SECRET="shelter-shared-secret")
198+
def test_combined_upload_post_shelter(db, mocker):
199+
mocker.patch.object(
200+
CanDoCoverageUploadsPermission, "has_permission", return_value=True
201+
)
202+
presigned_put_mock = mocker.patch(
203+
"services.archive.StorageService.create_presigned_put",
204+
return_value="presigned put",
205+
)
206+
upload_task_mock = mocker.patch(
207+
"upload.views.uploads.trigger_upload_task", return_value=True
208+
)
209+
210+
repository = RepositoryFactory(
211+
name="the_repo", author__username="codecov", author__service="github"
212+
)
213+
commit = CommitFactory(repository=repository)
214+
repository.save()
215+
commit.save()
216+
217+
owner = repository.author
218+
client = APIClient()
219+
client.force_authenticate(user=owner)
220+
repo_slug = f"{repository.author.username}::::{repository.name}"
221+
url = reverse(
222+
"new_upload.combined_upload",
223+
args=[repository.author.service, repo_slug],
224+
)
225+
response = client.post(
226+
url,
227+
{
228+
"branch": "branch",
229+
"ci_service": "ci_service",
230+
"ci_url": "ci_url",
231+
"code": "code",
232+
"commit_sha": commit.commitid,
233+
"flags": ["flag1", "flag2"],
234+
"job_code": "job_code",
235+
"storage_path": "shelter/test/path.txt",
236+
"version": "version",
237+
},
238+
headers={
239+
"X-Shelter-Token": "shelter-shared-secret",
240+
"User-Agent": "codecov-cli/0.4.7",
241+
},
242+
format="json",
243+
)
244+
response_json = response.json()
245+
upload = ReportSession.objects.filter(
246+
report__commit=commit,
247+
report__code="code",
248+
upload_extras={"format_version": "v1"},
249+
).first()
250+
assert response.status_code == 201
251+
assert all(
252+
map(
253+
lambda x: x in response_json.keys(),
254+
["external_id", "created_at", "raw_upload_location", "url"],
255+
)
256+
)
257+
assert (
258+
response_json.get("url")
259+
== f"{settings.CODECOV_DASHBOARD_URL}/{repository.author.service}/{repository.author.username}/{repository.name}/commit/{commit.commitid}"
260+
)
261+
262+
assert ReportSession.objects.filter(
263+
report__commit=commit,
264+
report__code="code",
265+
upload_extras={"format_version": "v1"},
266+
).exists()
267+
assert RepositoryFlag.objects.filter(
268+
repository_id=repository.repoid, flag_name="flag1"
269+
).exists()
270+
assert RepositoryFlag.objects.filter(
271+
repository_id=repository.repoid, flag_name="flag2"
272+
).exists()
273+
flag1 = RepositoryFlag.objects.filter(
274+
repository_id=repository.repoid, flag_name="flag1"
275+
).first()
276+
flag2 = RepositoryFlag.objects.filter(
277+
repository_id=repository.repoid, flag_name="flag2"
278+
).first()
279+
assert UploadFlagMembership.objects.filter(
280+
report_session_id=upload.id, flag_id=flag1.id
281+
).exists()
282+
assert UploadFlagMembership.objects.filter(
283+
report_session_id=upload.id, flag_id=flag2.id
284+
).exists()
285+
assert [flag for flag in upload.flags.all()] == [flag1, flag2]
286+
287+
assert upload.storage_path == "shelter/test/path.txt"
288+
presigned_put_mock.assert_called_with("archive", upload.storage_path, 10)
289+
upload_task_mock.assert_called()

0 commit comments

Comments
 (0)