Skip to content
This repository was archived by the owner on Jun 13, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions services/task/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,12 @@
kwargs=dict(repository_id=repository_id),
).apply_async()

def transplant_report(self, repo_id: int, from_sha: str, to_sha: str) -> None:
self._create_signature(

Check warning on line 328 in services/task/task.py

View check run for this annotation

Codecov Notifications / codecov/patch

services/task/task.py#L328

Added line #L328 was not covered by tests
"app.tasks.reports.transplant_report",
kwargs={"repo_id": repo_id, "from_sha": from_sha, "to_sha": to_sha},
).apply_async()

def update_commit(self, commitid, repoid):
self._create_signature(
"app.tasks.commit_update.CommitUpdate",
Expand Down
34 changes: 34 additions & 0 deletions upload/tests/views/test_transplant_report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from django.urls import reverse
from rest_framework.test import APIClient
from shared.django_apps.core.tests.factories import RepositoryFactory

from upload.views.uploads import CanDoCoverageUploadsPermission


def test_uploads_get_not_allowed(db, mocker):
mocker.patch.object(
CanDoCoverageUploadsPermission, "has_permission", return_value=True
)
task_mock = mocker.patch("services.task.TaskService.transplant_report")

repository = RepositoryFactory(
name="the-repo", author__username="codecov", author__service="github"
)
owner = repository.author
client = APIClient()
client.force_authenticate(user=owner)

url = reverse(
"new_upload.transplant_report",
args=["github", "codecov::::the-repo"],
)
assert url == "/upload/github/codecov::::the-repo/commits/transplant"

res = client.post(
url, data={"from_sha": "sha to copy from", "to_sha": "sha to copy to"}
)
assert res.status_code == 200

task_mock.assert_called_once_with(
repo_id=repository.repoid, from_sha="sha to copy from", to_sha="sha to copy to"
)
6 changes: 6 additions & 0 deletions upload/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from upload.views.legacy import UploadDownloadHandler, UploadHandler
from upload.views.reports import ReportResultsView, ReportViews
from upload.views.test_results import TestResultsView
from upload.views.transplant_report import TransplantReportView
from upload.views.upload_completion import UploadCompletionView
from upload.views.upload_coverage import UploadCoverageView
from upload.views.uploads import UploadViews
Expand Down Expand Up @@ -58,6 +59,11 @@
CommitViews.as_view(),
name="new_upload.commits",
),
path(
"<str:service>/<str:repo>/commits/transplant",
TransplantReportView.as_view(),
name="new_upload.transplant_report",
),
path(
"<str:service>/<str:repo>/upload-coverage",
UploadCoverageView.as_view(),
Expand Down
69 changes: 69 additions & 0 deletions upload/views/transplant_report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import logging
from typing import Any, Callable

from django.http import HttpRequest
from rest_framework import serializers, status
from rest_framework.generics import CreateAPIView
from rest_framework.response import Response
from shared.metrics import inc_counter

from codecov_auth.authentication.repo_auth import (
GitHubOIDCTokenAuthentication,
GlobalTokenAuthentication,
OrgLevelTokenAuthentication,
RepositoryLegacyTokenAuthentication,
UploadTokenRequiredAuthenticationCheck,
repo_auth_custom_exception_handler,
)
from services.task import TaskService
from upload.helpers import generate_upload_prometheus_metrics_labels
from upload.metrics import API_UPLOAD_COUNTER
from upload.views.base import GetterMixin
from upload.views.uploads import CanDoCoverageUploadsPermission

log = logging.getLogger(__name__)


class TransplantReportSerializer(serializers.Serializer):
from_sha = serializers.CharField(required=True)
to_sha = serializers.CharField(required=True)


class TransplantReportView(CreateAPIView, GetterMixin):
permission_classes = [CanDoCoverageUploadsPermission]
authentication_classes = [
UploadTokenRequiredAuthenticationCheck,
GlobalTokenAuthentication,
OrgLevelTokenAuthentication,
GitHubOIDCTokenAuthentication,
RepositoryLegacyTokenAuthentication,
]

def get_exception_handler(self) -> Callable[[Exception, dict[str, Any]], Response]:
return repo_auth_custom_exception_handler

Check warning on line 43 in upload/views/transplant_report.py

View check run for this annotation

Codecov Notifications / codecov/patch

upload/views/transplant_report.py#L43

Added line #L43 was not covered by tests

def post(self, request: HttpRequest, *args: Any, **kwargs: Any) -> Response:
inc_counter(
API_UPLOAD_COUNTER,
labels=generate_upload_prometheus_metrics_labels(
action="coverage",
endpoint="transplant_report",
request=self.request,
is_shelter_request=self.is_shelter_request(),
),
)
serializer = TransplantReportSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Check warning on line 57 in upload/views/transplant_report.py

View check run for this annotation

Codecov Notifications / codecov/patch

upload/views/transplant_report.py#L57

Added line #L57 was not covered by tests

data = serializer.validated_data
TaskService().transplant_report(
repo_id=self.get_repo().repoid,
from_sha=data["from_sha"],
to_sha=data["to_sha"],
)

return Response(
data={"result": "All good, transplant scheduled"},
status=status.HTTP_200_OK,
)
Loading