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

Commit 3c3d300

Browse files
committed
Add backend code to transplant coverage reports from one commit to another
1 parent 20eb6c5 commit 3c3d300

File tree

3 files changed

+103
-2
lines changed

3 files changed

+103
-2
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import pytest
2+
from shared.django_apps.core.tests.factories import (
3+
CommitFactory,
4+
CommitWithReportFactory,
5+
RepositoryFactory,
6+
)
7+
from shared.django_apps.reports.models import ReportLevelTotals
8+
9+
from services.archive import ArchiveService
10+
from services.report.transplant import transplant_commit_report
11+
12+
13+
@pytest.mark.django_db()
14+
def test_transplanting_commit(mock_storage):
15+
repo = RepositoryFactory()
16+
commit_from = CommitWithReportFactory(repository=repo)
17+
18+
archive_service = ArchiveService(repo)
19+
with open("tasks/tests/samples/sample_chunks_1.txt", "rb") as f:
20+
chunks = f.read()
21+
archive_service.write_chunks(commit_from.commitid, chunks)
22+
23+
commit_to = CommitFactory(repository=repo)
24+
25+
transplant_commit_report(
26+
repo_id=repo.repoid, from_sha=commit_from.commitid, to_sha=commit_to.commitid
27+
)
28+
commit_to.refresh_from_db()
29+
30+
from_totals = commit_from.commitreport.reportleveltotals
31+
to_totals = commit_to.commitreport.reportleveltotals
32+
33+
def totals_tuple(totals: ReportLevelTotals):
34+
return (
35+
totals.branches,
36+
totals.coverage,
37+
totals.hits,
38+
totals.lines,
39+
totals.methods,
40+
totals.misses,
41+
totals.partials,
42+
totals.files,
43+
)
44+
45+
assert totals_tuple(from_totals) == totals_tuple(to_totals)
46+
47+
report = commit_to.full_report
48+
file = report.get("tests/__init__.py")
49+
assert file.get(1).coverage == 1

services/report/transplant.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from shared.django_apps.core.models import Commit
2+
from shared.django_apps.reports.models import CommitReport, ReportType
3+
4+
from services.archive import ArchiveService
5+
6+
7+
def transplant_commit_report(repo_id: int, from_sha: str, to_sha: str):
8+
"""
9+
This copies a `Report` from one commit to another commit.
10+
11+
The `to_sha` commit has to exist already (being auto-created using a git provider sync).
12+
13+
It does so by creating a copy of the underlying `report_json` and `chunks` storage files,
14+
as well as some related DB models.
15+
"""
16+
17+
from_commit = Commit.objects.select_related("repository").get(
18+
repository=repo_id, commitid=from_sha
19+
)
20+
to_commit = Commit.objects.get(repository=repo_id, commitid=to_sha)
21+
22+
archive_service = ArchiveService(from_commit.repository)
23+
24+
chunks = archive_service.read_chunks(from_commit.commitid)
25+
report_json = from_commit.report
26+
totals = from_commit.totals
27+
28+
archive_service.write_chunks(to_commit.commitid, chunks)
29+
30+
to_commit.report = report_json
31+
to_commit.totals = totals
32+
to_commit.state = "complete"
33+
to_commit.save()
34+
35+
if old_commit_report := from_commit.commitreport:
36+
commit_report = CommitReport(
37+
commit=to_commit, report_type=ReportType.COVERAGE.value
38+
)
39+
commit_report.save()
40+
41+
if totals := old_commit_report.reportleveltotals:
42+
# See <https://docs.djangoproject.com/en/5.1/topics/db/queries/#copying-model-instances>
43+
totals.pk = None
44+
totals.id = None
45+
totals._state.adding = True
46+
47+
totals.report = commit_report
48+
totals.save()
49+
50+
# TODO:
51+
# We might also have to create copies of all of `Upload` (aka `Reportsession`),
52+
# `UploadLevelTotals`, `UploadError` and `UploadFlagMembership`

tasks/compute_comparison.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from app import celery_app
1414
from database.enums import CompareCommitError, CompareCommitState
1515
from database.models import CompareCommit, CompareComponent, CompareFlag
16-
from database.models.reports import ReportLevelTotals, RepositoryFlag
16+
from database.models.reports import RepositoryFlag
1717
from helpers.comparison import minimal_totals
1818
from helpers.github_installation import get_installation_name_for_owner_for_task
1919
from rollouts import PARALLEL_COMPONENT_COMPARISON
@@ -216,7 +216,7 @@ def store_flag_comparison(
216216
db_session,
217217
comparison: CompareCommit,
218218
repositoryflag: RepositoryFlag,
219-
totals: ReportLevelTotals,
219+
totals,
220220
):
221221
flag_comparison = CompareFlag(
222222
commit_comparison=comparison,

0 commit comments

Comments
 (0)