From bbe53a9ea100af60c4763436841b8a5fc608364f Mon Sep 17 00:00:00 2001 From: Gguidini Date: Wed, 23 Apr 2025 20:03:23 +0200 Subject: [PATCH 1/2] feat(admin): add action to trigger sync repos This new action triggers the "sync_repos" for the selected owner from the admin dashboard. Would have been helpful for me today. (only tested through the unit tests) --- codecov_auth/admin.py | 38 +++++++++++++++++++++++++++++- codecov_auth/tests/test_admin.py | 40 +++++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/codecov_auth/admin.py b/codecov_auth/admin.py index 935f2fbd7a..f22a580bb1 100644 --- a/codecov_auth/admin.py +++ b/codecov_auth/admin.py @@ -12,6 +12,8 @@ from django.http import HttpRequest from django.shortcuts import redirect, render from django.utils import timezone +from services.task import TaskService + from django.utils.html import format_html from shared.django_apps.codecov_auth.models import ( Account, @@ -111,6 +113,40 @@ def impersonate_owner(self, request, queryset): impersonate_owner.short_description = "Impersonate the selected owner" +def refresh_owner(self, request, queryset): + if queryset.count() != 1: + self.message_user( + request, "You must refresh exactly one Owner.", level=messages.ERROR + ) + return + + owner = queryset.first() + + task_service = TaskService() + task_service.refresh( + ownerid=owner.ownerid, + username=owner.username, + sync_teams=True, + sync_repos=True, + manual_trigger=True, + ) + + self.message_user( + request, + f"Refresh task triggered for {owner.username} (ownerid: {owner.ownerid})", + level=messages.SUCCESS, + ) + History.log( + Owner.objects.get(ownerid=owner.ownerid), + "Refresh task triggered", + request.user, + ) + return + + +refresh_owner.short_description = "Sync repos and teams for the selected owner" + + class AccountsUsersInline(admin.TabularInline): model = AccountsUsers max_num = 10 @@ -559,7 +595,7 @@ class OwnerAdmin(AdminMixin, admin.ModelAdmin): list_display = ("name", "username", "email", "service") readonly_fields = [] search_fields = ("name__iregex", "username__iregex", "email__iregex", "ownerid") - actions = [impersonate_owner, extend_trial] + actions = [impersonate_owner, extend_trial, refresh_owner] autocomplete_fields = ("bot", "account") inlines = [OrgUploadTokenInline] diff --git a/codecov_auth/tests/test_admin.py b/codecov_auth/tests/test_admin.py index 824b7929d4..31af8ba280 100644 --- a/codecov_auth/tests/test_admin.py +++ b/codecov_auth/tests/test_admin.py @@ -107,6 +107,45 @@ def test_owner_admin_impersonate_owner(self): str(owner_to_impersonate.pk), ) + @patch("codecov_auth.admin.TaskService.refresh") + def test_owner_admin_refresh_owner(self, mock_refresh): + owner_to_refresh = OwnerFactory(service="github", plan=DEFAULT_FREE_PLAN) + other_owner = OwnerFactory(plan=DEFAULT_FREE_PLAN) + + with self.subTest("more than one user selected"): + response = self.client.post( + reverse("admin:codecov_auth_owner_changelist"), + { + "action": "refresh_owner", + ACTION_CHECKBOX_NAME: [ + owner_to_refresh.pk, + other_owner.pk, + ], + }, + follow=True, + ) + assert "You must refresh exactly one Owner." in str(response.content) + + with self.subTest("one user selected"): + response = self.client.post( + reverse("admin:codecov_auth_owner_changelist"), + { + "action": "refresh_owner", + ACTION_CHECKBOX_NAME: [owner_to_refresh.pk], + }, + follow=True, + ) + assert f"Refresh task triggered for {owner_to_refresh.username}" in str( + response.content + ) + mock_refresh.assert_called_once_with( + ownerid=owner_to_refresh.ownerid, + username=owner_to_refresh.username, + sync_teams=True, + sync_repos=True, + manual_trigger=True, + ) + @patch("codecov_auth.admin.TaskService.delete_owner") def test_delete_queryset(self, delete_mock): user_to_delete = OwnerFactory(plan=DEFAULT_FREE_PLAN) @@ -607,7 +646,6 @@ def test_link_users_to_account(self): # another user joins another_owner_with_user = OwnerFactory(user=UserFactory()) self.org_1.plan_activated_users.append(another_owner_with_user.ownerid) - self.org_1.save() # rerun action to re-sync res = self.client.post( reverse("admin:codecov_auth_account_changelist"), From 06d3fe1391a8945ab249e0662555c8f829ac0a50 Mon Sep 17 00:00:00 2001 From: Gguidini Date: Thu, 24 Apr 2025 10:51:39 +0200 Subject: [PATCH 2/2] fix test unrelated to changes --- codecov_auth/tests/test_admin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/codecov_auth/tests/test_admin.py b/codecov_auth/tests/test_admin.py index 31af8ba280..d5a3a8439f 100644 --- a/codecov_auth/tests/test_admin.py +++ b/codecov_auth/tests/test_admin.py @@ -646,6 +646,8 @@ def test_link_users_to_account(self): # another user joins another_owner_with_user = OwnerFactory(user=UserFactory()) self.org_1.plan_activated_users.append(another_owner_with_user.ownerid) + self.org_1.save() + # rerun action to re-sync res = self.client.post( reverse("admin:codecov_auth_account_changelist"),