Skip to content

Commit e856bb0

Browse files
fix: new tree listing count (#1706)
- Fixes problems where trees with null values weren't being correctly compared; - Also changes behavior of treeListing to keep storing every commit for the trees, because it is possible to receive multiple checkouts for the same commit. In case we receive commit A, then commit B, then commit A again, we should be able to keep the counts from the last commit A checkout. Closes #1703
1 parent cb6900c commit e856bb0

5 files changed

Lines changed: 80 additions & 36 deletions

File tree

backend/kernelCI_app/management/commands/helpers/aggregation_helpers.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ def update_tree_listing(checkouts_instances: Sequence[Checkouts]):
5656
5757
We should also remove the old tree row from the listing
5858
"""
59+
if not checkouts_instances:
60+
return
5961

6062
t0 = time.time()
6163
checkout_values = [
@@ -74,7 +76,8 @@ def update_tree_listing(checkouts_instances: Sequence[Checkouts]):
7476
]
7577

7678
with connections["default"].cursor() as cursor:
77-
# Set values as 0 when inserting a new tree and update as 0 when tree already exists
79+
# Set values as 0 when inserting a new tree
80+
# and only updates basic information when tree already exists
7881
cursor.executemany(
7982
"""
8083
INSERT INTO tree_listing (
@@ -86,22 +89,13 @@ def update_tree_listing(checkouts_instances: Sequence[Checkouts]):
8689
test_pass, test_failed, test_inc
8790
)
8891
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, 0, 0, 0, 0, 0, 0, 0, 0, 0)
89-
ON CONFLICT (origin, tree_name, git_repository_url, git_repository_branch)
92+
ON CONFLICT (origin, tree_name, git_repository_url, git_repository_branch, git_commit_hash)
9093
DO UPDATE SET
9194
checkout_id = EXCLUDED.checkout_id,
9295
git_commit_hash = EXCLUDED.git_commit_hash,
9396
git_commit_name = EXCLUDED.git_commit_name,
9497
git_commit_tags = EXCLUDED.git_commit_tags,
95-
start_time = EXCLUDED.start_time,
96-
build_pass = 0,
97-
build_failed = 0,
98-
build_inc = 0,
99-
boot_pass = 0,
100-
boot_failed = 0,
101-
boot_inc = 0,
102-
test_pass = 0,
103-
test_failed = 0,
104-
test_inc = 0
98+
start_time = EXCLUDED.start_time
10599
WHERE tree_listing.start_time < EXCLUDED.start_time
106100
""",
107101
checkout_values,

backend/kernelCI_app/management/commands/process_pending_aggregations.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,11 @@ def _process_tree_listing(
592592
data["test_pass"],
593593
data["test_failed"],
594594
data["test_inc"],
595-
data["checkout_id"],
595+
data["origin"],
596+
data["tree_name"],
597+
data["git_repository_branch"],
598+
data["git_repository_url"],
599+
data["git_commit_hash"],
596600
)
597601
for data in tree_listing_data.values()
598602
]
@@ -612,7 +616,13 @@ def _process_tree_listing(
612616
test_pass = tree_listing.test_pass + %s,
613617
test_failed = tree_listing.test_failed + %s,
614618
test_inc = tree_listing.test_inc + %s
615-
WHERE tree_listing.checkout_id = %s
619+
WHERE
620+
-- IS NOT DISTINCT FROM used to treat NULLs as equal
621+
tree_listing.origin = %s
622+
AND tree_listing.tree_name IS NOT DISTINCT FROM %s
623+
AND tree_listing.git_repository_branch IS NOT DISTINCT FROM %s
624+
AND tree_listing.git_repository_url IS NOT DISTINCT FROM %s
625+
AND tree_listing.git_commit_hash IS NOT DISTINCT FROM %s
616626
""",
617627
values,
618628
)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Generated by Django 5.2.9 on 2026-01-20 18:33
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("kernelCI_app", "0015_alter_pendingtest_platform"),
10+
]
11+
12+
operations = [
13+
migrations.RemoveConstraint(
14+
model_name="treelisting",
15+
name="tree_listing_tree_unique",
16+
),
17+
migrations.AddConstraint(
18+
model_name="treelisting",
19+
constraint=models.UniqueConstraint(
20+
fields=(
21+
"origin",
22+
"tree_name",
23+
"git_repository_url",
24+
"git_repository_branch",
25+
"git_commit_hash",
26+
),
27+
name="tree_listing_tree_unique",
28+
nulls_distinct=False,
29+
),
30+
),
31+
]

backend/kernelCI_app/models.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,10 @@ class Meta:
391391
"tree_name",
392392
"git_repository_url",
393393
"git_repository_branch",
394+
"git_commit_hash",
394395
],
395396
name="tree_listing_tree_unique",
397+
nulls_distinct=False,
396398
),
397399
]
398400
indexes = [

backend/kernelCI_app/queries/tree.py

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -302,30 +302,37 @@ def get_tree_listing_data_denormalized(
302302
with connection.cursor() as cursor:
303303
cursor.execute(
304304
"""
305+
WITH latest AS (
306+
SELECT
307+
checkout_id
308+
FROM
309+
latest_checkout
310+
WHERE
311+
start_time >= NOW() - INTERVAL %(interval_param)s
312+
AND origin = %(origin_param)s
313+
)
305314
SELECT
306-
checkout_id,
307-
origin,
308-
tree_name,
309-
git_repository_url,
310-
git_repository_branch,
311-
git_commit_hash,
312-
git_commit_name,
313-
git_commit_tags,
314-
start_time,
315-
build_pass,
316-
build_failed,
317-
build_inc,
318-
boot_pass,
319-
boot_failed,
320-
boot_inc,
321-
test_pass,
322-
test_failed,
323-
test_inc
315+
tl.checkout_id,
316+
tl.origin,
317+
tl.tree_name,
318+
tl.git_repository_url,
319+
tl.git_repository_branch,
320+
tl.git_commit_hash,
321+
tl.git_commit_name,
322+
tl.git_commit_tags,
323+
tl.start_time,
324+
tl.build_pass,
325+
tl.build_failed,
326+
tl.build_inc,
327+
tl.boot_pass,
328+
tl.boot_failed,
329+
tl.boot_inc,
330+
tl.test_pass,
331+
tl.test_failed,
332+
tl.test_inc
324333
FROM
325-
tree_listing
326-
WHERE
327-
start_time >= NOW() - INTERVAL %(interval_param)s
328-
AND origin = %(origin_param)s
334+
tree_listing tl
335+
JOIN latest l ON tl.checkout_id = l.checkout_id
329336
""",
330337
params,
331338
)

0 commit comments

Comments
 (0)