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

Commit 87c2414

Browse files
Merge branch 'rvinnakota/update-ai-repo' of https://github.com/codecov/codecov-api into rvinnakota/update-ai-repo
2 parents 7111b1b + f8e566c commit 87c2414

File tree

32 files changed

+431
-307
lines changed

32 files changed

+431
-307
lines changed

api/internal/owner/serializers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def validate_value(self, value: str) -> str:
131131

132132
plan_service = PlanService(current_org=current_org)
133133
plan_values = [
134-
plan["value"] for plan in plan_service.available_plans(current_owner)
134+
plan.name for plan in plan_service.available_plans(current_owner)
135135
]
136136
if value not in plan_values:
137137
raise serializers.ValidationError(

api/internal/tests/views/test_user_viewset.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
PullFactory,
1111
RepositoryFactory,
1212
)
13-
from shared.plan.constants import PlanName, TierName
13+
from shared.plan.constants import DEFAULT_FREE_PLAN, TierName
1414

1515
from core.models import Pull
1616
from utils.test_utils import APIClient
@@ -20,7 +20,7 @@ class UserViewSetTests(APITestCase):
2020
def setUp(self):
2121
non_org_active_user = OwnerFactory()
2222
tier = TierFactory(tier_name=TierName.BASIC.value)
23-
plan = PlanFactory(name=PlanName.BASIC_PLAN_NAME.value, tier=tier)
23+
plan = PlanFactory(name=DEFAULT_FREE_PLAN, tier=tier)
2424
self.current_owner = OwnerFactory(
2525
plan=plan.name,
2626
plan_user_count=5,

billing/tests/test_views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,7 @@ def test_customer_subscription_updated_does_not_change_subscription_if_not_paid_
871871
has_unverified_initial_payment_method_mock,
872872
):
873873
has_unverified_initial_payment_method_mock.return_value = False
874-
self.owner.plan = PlanName.BASIC_PLAN_NAME.value
874+
self.owner.plan = DEFAULT_FREE_PLAN
875875
self.owner.plan_user_count = 0
876876
self.owner.plan_auto_activate = False
877877
self.owner.save()
@@ -895,7 +895,7 @@ def test_customer_subscription_updated_does_not_change_subscription_if_not_paid_
895895
)
896896

897897
self.owner.refresh_from_db()
898-
assert self.owner.plan == PlanName.BASIC_PLAN_NAME.value
898+
assert self.owner.plan == DEFAULT_FREE_PLAN
899899
assert self.owner.plan_user_count == 0
900900
assert self.owner.plan_auto_activate == False
901901
pm_mock.assert_called_once_with(

codecov/settings_base.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,11 +345,11 @@
345345
IS_ENTERPRISE = get_settings_module() == SettingsModule.ENTERPRISE.value
346346
IS_DEV = get_settings_module() == SettingsModule.DEV.value
347347

348-
DATA_UPLOAD_MAX_MEMORY_SIZE = get_config(
349-
"setup", "http", "upload_max_memory_size", default=2621440
348+
DATA_UPLOAD_MAX_MEMORY_SIZE = int(
349+
get_config("setup", "http", "upload_max_memory_size", default=2621440)
350350
)
351-
FILE_UPLOAD_MAX_MEMORY_SIZE = get_config(
352-
"setup", "http", "file_upload_max_memory_size", default=2621440
351+
FILE_UPLOAD_MAX_MEMORY_SIZE = int(
352+
get_config("setup", "http", "file_upload_max_memory_size", default=2621440)
353353
)
354354

355355
CORS_ALLOWED_ORIGIN_REGEXES = get_config(
@@ -433,6 +433,8 @@
433433
"setup", "stripe", "payment_method_configuration_id", default=None
434434
)
435435

436+
AMPLITUDE_API_KEY = os.environ.get("AMPLITUDE_API_KEY", None)
437+
436438
# Allows to do migrations from another module
437439
MIGRATION_MODULES = {
438440
"codecov_auth": "shared.django_apps.codecov_auth.migrations",

codecov_auth/tests/unit/services/test_org_level_token_service.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
PlanFactory,
1111
TierFactory,
1212
)
13-
from shared.plan.constants import PlanName, TierName
13+
from shared.plan.constants import DEFAULT_FREE_PLAN, PlanName, TierName
1414

1515
from codecov_auth.models import OrganizationLevelToken
1616
from codecov_auth.services.org_level_token_service import OrgLevelTokenService
@@ -47,7 +47,7 @@ def setUp(self):
4747
self.basic_tier = TierFactory(tier_name=TierName.BASIC.value)
4848
self.basic_plan = PlanFactory(
4949
tier=self.basic_tier,
50-
name=PlanName.BASIC_PLAN_NAME.value,
50+
name=DEFAULT_FREE_PLAN,
5151
)
5252
self.owner = OwnerFactory(plan=self.enterprise_plan.name)
5353

codecov_auth/tests/unit/views/test_base.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from datetime import datetime, timedelta, timezone
2-
from unittest.mock import Mock, patch
2+
from unittest.mock import Mock, call, patch
33

44
import pytest
55
from django.conf import settings
@@ -174,6 +174,27 @@ def test_get_or_create_calls_analytics_user_signed_up_when_owner_created(
174174
)
175175
user_signed_up_mock.assert_called_once()
176176

177+
@patch("shared.events.amplitude.AmplitudeEventPublisher.publish")
178+
def test_get_or_create_calls_amplitude_user_created_when_owner_created(
179+
self, amplitude_publish_mock
180+
):
181+
self.mixin_instance._get_or_create_owner(
182+
{
183+
"user": {"id": 12345, "key": "4567", "login": "testuser"},
184+
"has_private_access": False,
185+
},
186+
self.request,
187+
)
188+
189+
owner = Owner.objects.get(service_id=12345, username="testuser")
190+
191+
amplitude_publish_mock.assert_has_calls(
192+
[
193+
call("User Created", {"user_ownerid": owner.ownerid}),
194+
call("set_orgs", {"user_ownerid": owner.ownerid, "org_ids": []}),
195+
]
196+
)
197+
177198
@patch("services.analytics.AnalyticsService.user_signed_in")
178199
def test_get_or_create_calls_analytics_user_signed_in_when_owner_not_created(
179200
self, user_signed_in_mock
@@ -192,6 +213,30 @@ def test_get_or_create_calls_analytics_user_signed_in_when_owner_not_created(
192213
)
193214
user_signed_in_mock.assert_called_once()
194215

216+
@patch("shared.events.amplitude.AmplitudeEventPublisher.publish")
217+
def test_get_or_create_calls_amplitude_user_logged_in_when_owner_not_created(
218+
self, amplitude_publish_mock
219+
):
220+
owner = OwnerFactory(service_id=89, service="github", organizations=[1, 2])
221+
self.mixin_instance._get_or_create_owner(
222+
{
223+
"user": {
224+
"id": owner.service_id,
225+
"key": "02or0sa",
226+
"login": owner.username,
227+
},
228+
"has_private_access": owner.private_access,
229+
},
230+
self.request,
231+
)
232+
233+
amplitude_publish_mock.assert_has_calls(
234+
[
235+
call("User Logged in", {"user_ownerid": owner.ownerid}),
236+
call("set_orgs", {"user_ownerid": owner.ownerid, "org_ids": [1, 2]}),
237+
]
238+
)
239+
195240
@override_settings(IS_ENTERPRISE=False)
196241
@patch("services.analytics.AnalyticsService.user_signed_in")
197242
def test_set_marketing_tags_on_cookies(self, user_signed_in_mock):

codecov_auth/views/base.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from django.utils import timezone
1616
from django.utils.timezone import now
1717
from shared.encryption.token import encode_token
18+
from shared.events.amplitude import AmplitudeEventPublisher
1819
from shared.license import LICENSE_ERRORS_MESSAGES, get_current_license
1920

2021
from codecov_auth.models import Owner, OwnerProfile, Session, User
@@ -393,10 +394,21 @@ def _get_or_create_owner(
393394
owner.save(update_fields=fields_to_update)
394395

395396
marketing_tags = self.retrieve_marketing_tags_from_cookie()
397+
amplitude = AmplitudeEventPublisher()
396398
if was_created:
397399
self.analytics_service.user_signed_up(owner, **marketing_tags)
400+
amplitude.publish("User Created", {"user_ownerid": owner.ownerid})
398401
else:
399402
self.analytics_service.user_signed_in(owner, **marketing_tags)
403+
amplitude.publish("User Logged in", {"user_ownerid": owner.ownerid})
404+
orgs = owner.organizations
405+
amplitude.publish(
406+
"set_orgs",
407+
{
408+
"user_ownerid": owner.ownerid,
409+
"org_ids": orgs if orgs is not None else [],
410+
},
411+
)
400412

401413
return (owner, was_created)
402414

compare/commands/compare/interactors/fetch_impacted_files.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import enum
22
from typing import List, Optional
33

4-
from shared.utils.match import match
4+
from shared.utils.match import Matcher
55

66
import services.components as components
77
from codecov.commands.base import BaseInteractor
@@ -74,11 +74,8 @@ def _apply_filters(
7474
res = impacted_files
7575

7676
if components_paths:
77-
res = [
78-
file
79-
for file in impacted_files
80-
if match(components_paths, file.head_name)
81-
]
77+
matcher = Matcher(components_paths)
78+
res = [file for file in impacted_files if matcher.match(file.head_name)]
8279
return res
8380

8481
def get_attribute(
Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,18 @@
1-
from typing import Iterable, Union
2-
31
import sentry_sdk
42

53
from graphql_api.types.enums import PathContentDisplayType
64
from services.path import Dir, File
75

86

9-
def partition_list_into_files_and_directories(
10-
items: Iterable[Union[File, Dir]],
11-
) -> tuple[Union[File, Dir]]:
12-
files = []
13-
directories = []
14-
15-
# Separate files and directories
16-
for item in items:
17-
if isinstance(item, Dir):
18-
directories.append(item)
19-
else:
20-
files.append(item)
21-
22-
return (files, directories)
23-
24-
25-
def sort_list_by_directory(
26-
items: Iterable[Union[File, Dir]],
27-
) -> Iterable[Union[File, Dir]]:
28-
(files, directories) = partition_list_into_files_and_directories(items=items)
29-
return directories + files
30-
31-
327
@sentry_sdk.trace
33-
def sort_path_contents(
34-
items: Iterable[Union[File, Dir]], filters={}
35-
) -> Iterable[Union[File, Dir]]:
8+
def sort_path_contents(items: list[File | Dir], filters: dict = {}) -> list[File | Dir]:
369
filter_parameter = filters.get("ordering", {}).get("parameter")
3710
filter_direction = filters.get("ordering", {}).get("direction")
3811

3912
if filter_parameter and filter_direction:
4013
parameter_value = filter_parameter.value
4114
direction_value = filter_direction.value
42-
items = sorted(
43-
items,
15+
items.sort(
4416
key=lambda item: getattr(item, parameter_value),
4517
reverse=direction_value == "descending",
4618
)
@@ -49,6 +21,6 @@ def sort_path_contents(
4921
parameter_value == "name"
5022
and display_type is not PathContentDisplayType.LIST
5123
):
52-
items = sort_list_by_directory(items=items)
24+
items.sort(key=lambda item: isinstance(item, File))
5325

5426
return items

graphql_api/tests/mutation/test_erase_repository.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
class EraseRepositoryTests(GraphQLTestHelper, TransactionTestCase):
2323
def setUp(self):
2424
self.org = OwnerFactory(username="codecov", service="github")
25+
self.non_admin_user = OwnerFactory(organizations=[self.org.ownerid])
26+
self.admin_user = OwnerFactory(organizations=[self.org.ownerid])
27+
self.org.add_admin(self.admin_user)
28+
2529
self.repo = RepositoryFactory(author=self.org, name="gazebo", active=True)
2630

2731
def test_when_authenticated(self):
@@ -92,3 +96,31 @@ def test_when_self_hosted_admin(self, is_admin_owner):
9296
)
9397

9498
assert data == {"eraseRepository": None}
99+
100+
def test_when_other_admin(self):
101+
data = self.gql_request(
102+
query,
103+
owner=self.admin_user,
104+
variables={
105+
"input": {
106+
"owner": "codecov",
107+
"repoName": "gazebo",
108+
}
109+
},
110+
)
111+
112+
assert data == {"eraseRepository": None}
113+
114+
def test_when_not_other_admin(self):
115+
data = self.gql_request(
116+
query,
117+
owner=self.non_admin_user,
118+
variables={
119+
"input": {
120+
"owner": "codecov",
121+
"repoName": "gazebo",
122+
}
123+
},
124+
)
125+
126+
assert data["eraseRepository"]["error"]["__typename"] == "UnauthorizedError"

0 commit comments

Comments
 (0)