Skip to content

Commit daef2de

Browse files
authored
Reports regzbot tracking (#1925)
* reports: drop leading blank lines from report emails base.txt opened with a blank line and an empty header block, so every report rendered with several blank lines before the first content line. Trim the top of base.txt so reports start at their first line, and refresh the metrics example fixture to match. Signed-off-by: Ben Copeland <ben.copeland@linaro.org> * notifications: find last good build/test commit for regzbot range Add kcidb_last_build_without_issue() to fetch the most recent passing build of the same config (filtered by start_time) that does not carry the issue, and set last_pass_commit on build incidents. For standalone test reports, derive the last passing commit from the status history (passing the required group_size). This lets the mails emit a real last_good..HEAD introduced range. Signed-off-by: Ben Copeland <ben.copeland@linaro.org> * reports: reorder regression mails and add regzbot tags Rework the regression report layout so the details humans need come first and the machine-readable tags come last: drop the "Hello," greeting, move the log excerpt up next to the issue description, and list the dashboard details below the attribution with a lead-in explaining where the full logs live. Replace the tag request with the patch submission rules wording, and generate the Message-ID before rendering so each report can carry a Link: to its own thread on lore.kernel.org next to the Reported-by tag. Add a regzbot tracking block (introduced/link) in its own blank-line-delimited paragraph at the very end of the body together with the #kernelci marker. The title command is left out so regzbot takes the mail subject, and the block is only emitted when a last known good commit is available, so regzbot is never handed a single unbisected commit it cannot act on. Signed-off-by: Ben Copeland <ben.copeland@linaro.org> * notifications: drop the new-issues report Cc The regressions list is already added in code for mainline/next, so the explicit Cc is not needed. Signed-off-by: Ben Copeland <ben.copeland@linaro.org> * tests: add golden-file tests for the report templates Render the issue and test report templates with fixed data and compare the output against committed example files, so template changes show up as reviewable diffs. Add a refresh_report_examples management command to regenerate the fixtures when a template change is intentional. Signed-off-by: Ben Copeland <ben.copeland@linaro.org> --------- Signed-off-by: Ben Copeland <ben.copeland@linaro.org>
1 parent 1e4d2a9 commit daef2de

16 files changed

Lines changed: 585 additions & 72 deletions

backend/kernelCI/settings.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ def get_json_env_var(name, default):
175175
"--monitoring-id=notifications_new_issues",
176176
"--action=new_issues",
177177
"--to=kernelci-results@groups.io",
178-
"--cc=gus@collabora.com",
179178
"--send",
180179
"--yes",
181180
],

backend/kernelCI_app/helpers/email.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,15 @@ def smtp_setup_connection():
1111

1212

1313
def smtp_send_email(
14-
connection, sender_email, to, subject, message_text, cc, reply_to, in_reply_to=None
14+
connection,
15+
sender_email,
16+
to,
17+
subject,
18+
message_text,
19+
cc,
20+
reply_to,
21+
in_reply_to=None,
22+
message_id=None,
1523
):
1624
"""Send an email using Django's SMTP backend.
1725
@@ -24,6 +32,9 @@ def smtp_send_email(
2432
cc: CC recipients
2533
reply_to: Reply-to address
2634
in_reply_to: Message ID to set in In-Reply-To header (optional)
35+
message_id: Message ID to use for the email, generated when not given.
36+
Pass one when the message body references its own Message-ID
37+
(e.g. a lore.kernel.org link).
2738
2839
Returns:
2940
Message ID of the sent email
@@ -45,7 +56,8 @@ def smtp_send_email(
4556
)
4657

4758
# Generate a unique message ID for tracking
48-
message_id = make_msgid()
59+
if not message_id:
60+
message_id = make_msgid()
4961
email.extra_headers["Message-ID"] = message_id
5062

5163
if in_reply_to:

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ def send_email_report(
9191
git_url: Optional[str] = None,
9292
signup_folder: Optional[str] = None,
9393
recipients: Optional[list[str]] = None,
94+
message_id: Optional[str] = None,
9495
):
9596
"""Sets up the email arguments and sends the report.
9697
@@ -105,6 +106,9 @@ def send_email_report(
105106
Is only used if git_url is set and default recipients are not ignored.
106107
recipients: a direct list of email recipients to use,
107108
this parameter overrides the use of git_url + signup_folder.
109+
message_id: the Message-ID to send the email with, generated by the
110+
smtp helper when not given. Pass one when the report body references
111+
its own Message-ID (e.g. a lore.kernel.org link).
108112
"""
109113
sender_email = "KernelCI bot <bot@kernelci.org>"
110114
subject = report["title"]
@@ -167,4 +171,5 @@ def send_email_report(
167171
cc,
168172
reply_to,
169173
email_args.in_reply_to,
174+
message_id,
170175
)

backend/kernelCI_app/management/commands/notifications.py

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import sys
33
from collections import defaultdict
44
from datetime import datetime, timedelta, timezone
5+
from email.utils import make_msgid
56
from types import SimpleNamespace
67
from typing import Optional
78
from urllib.parse import quote_plus
@@ -39,6 +40,7 @@
3940
get_metrics_data,
4041
kcidb_build_incidents,
4142
kcidb_issue_details,
43+
kcidb_last_build_without_issue,
4244
kcidb_last_test_without_issue,
4345
kcidb_new_issues,
4446
kcidb_test_incidents,
@@ -153,10 +155,14 @@ def ask_ignore_issue():
153155
print("Please enter 'y' or 'n'.")
154156

155157

156-
def generate_build_issue_report(issue, incidents):
158+
def generate_build_issue_report(issue, incidents, message_id=None):
157159
template = setup_jinja_template("issue_build.txt.j2")
158160
report = {}
159-
report["content"] = template.render(issue=issue, builds=incidents)
161+
report["content"] = template.render(
162+
issue=issue,
163+
builds=incidents,
164+
message_id=message_id.strip("<>") if message_id else None,
165+
)
160166
snippet = (
161167
issue["comment"]
162168
if len(issue["comment"]) <= 70
@@ -168,10 +174,14 @@ def generate_build_issue_report(issue, incidents):
168174
return report
169175

170176

171-
def generate_boot_issue_report(issue, incidents):
177+
def generate_boot_issue_report(issue, incidents, message_id=None):
172178
template = setup_jinja_template("issue_boot.txt.j2")
173179
report = {}
174-
report["content"] = template.render(issue=issue, boots=incidents)
180+
report["content"] = template.render(
181+
issue=issue,
182+
boots=incidents,
183+
message_id=message_id.strip("<>") if message_id else None,
184+
)
175185
snippet = (
176186
issue["comment"]
177187
if len(issue["comment"]) <= 70
@@ -218,11 +228,18 @@ def generate_issue_report(
218228
if isinstance(issue["misc"], str):
219229
issue["misc"] = json.loads(issue["misc"])
220230

231+
# Generated upfront so the report body can link to its own mail on lore
232+
message_id = make_msgid(domain="kernelci.org")
233+
221234
issue_type: PossibleIssueType
222235
if issue["build_id"]:
223236
issue_type = "build"
224237
incidents = kcidb_build_incidents(issue_id)
225-
report = generate_build_issue_report(issue, incidents)
238+
for incident in incidents:
239+
last_build = kcidb_last_build_without_issue(issue, incident)
240+
if last_build:
241+
incident["last_pass_commit"] = last_build[0]["git_commit_hash"]
242+
report = generate_build_issue_report(issue, incidents, message_id)
226243
elif issue["test_id"]:
227244
incidents = kcidb_test_incidents(issue_id)
228245
issue_type = "boot" if is_boot(path=incidents[0]["path"]) else "test"
@@ -231,7 +248,7 @@ def generate_issue_report(
231248
incident["last_pass"] = last_test[0]["start_time"]
232249
incident["last_pass_commit"] = last_test[0]["git_commit_hash"]
233250
incident["last_pass_id"] = last_test[0]["id"]
234-
report = generate_boot_issue_report(issue, incidents)
251+
report = generate_boot_issue_report(issue, incidents, message_id)
235252
else:
236253
print(f"unable to generate issue report for {issue_id}", file=sys.stderr)
237254
sys.exit(-1)
@@ -244,6 +261,7 @@ def generate_issue_report(
244261
email_args=email_args,
245262
signup_folder=signup_folder,
246263
git_url=issue["git_repository_url"],
264+
message_id=message_id,
247265
)
248266

249267
if msg_id and email_args.update:
@@ -566,6 +584,7 @@ def generate_test_report(*, service, test_id, email_args, signup_folder):
566584
test_start_time=test["start_time"],
567585
config_name=test["config_name"],
568586
field_timestamp=test["_timestamp"],
587+
group_size=10,
569588
)
570589

571590
status_symbols = []
@@ -581,8 +600,22 @@ def generate_test_report(*, service, test_id, email_args, signup_folder):
581600
status_symbols.reverse()
582601
test["status_history"] = " → ".join(status_symbols)
583602

603+
# Most recent passing commit before the failure, used to bound the
604+
# regression range for regzbot (history is ordered most recent first).
605+
test["last_pass_commit"] = None
606+
for entry in history:
607+
if (
608+
entry["status"] == "PASS"
609+
and entry["build__checkout__git_commit_hash"] != test["git_commit_hash"]
610+
):
611+
test["last_pass_commit"] = entry["build__checkout__git_commit_hash"]
612+
break
613+
614+
# Generated upfront so the report body can link to its own mail on lore
615+
message_id = make_msgid(domain="kernelci.org")
616+
584617
template = setup_jinja_template("test_report.txt.j2")
585-
report_content = template.render(test=test)
618+
report_content = template.render(test=test, message_id=message_id.strip("<>"))
586619

587620
if is_boot(path=test["path"]):
588621
subject_prefix = "[BOOT REGRESSION]"
@@ -615,6 +648,7 @@ def generate_test_report(*, service, test_id, email_args, signup_folder):
615648
email_args=email_args,
616649
git_url=test["git_repository_url"],
617650
signup_folder=signup_folder,
651+
message_id=message_id,
618652
)
619653

620654

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from django.core.management.base import BaseCommand
2+
3+
from kernelCI_app.tests.unitTests.commands.fixtures.report_notifications_data import (
4+
ISSUE_BOOT_REPORT_EXAMPLE_FILEPATH,
5+
ISSUE_BUILD_REPORT_EXAMPLE_FILEPATH,
6+
TEST_REPORT_EXAMPLE_FILEPATH,
7+
)
8+
from kernelCI_app.tests.unitTests.commands.report_notifications_test import (
9+
TestReportTemplates,
10+
)
11+
12+
13+
class Command(BaseCommand):
14+
help = (
15+
"Refreshes the example report fixtures used by the report notification "
16+
"unit tests. Run this manually when a report template changes."
17+
)
18+
19+
def handle(self, *args, **options):
20+
outputs = [
21+
(
22+
ISSUE_BUILD_REPORT_EXAMPLE_FILEPATH,
23+
TestReportTemplates.render_build_report(),
24+
),
25+
(
26+
ISSUE_BOOT_REPORT_EXAMPLE_FILEPATH,
27+
TestReportTemplates.render_boot_report(),
28+
),
29+
(TEST_REPORT_EXAMPLE_FILEPATH, TestReportTemplates.render_test_report()),
30+
]
31+
for filepath, content in outputs:
32+
with open(filepath, "w") as f:
33+
f.write(content)
34+
self.stdout.write(self.style.SUCCESS(f"{filepath} updated."))

backend/kernelCI_app/management/commands/templates/base.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
2-
{% block header %}{% endblock %}
1+
{% block header %}{% endblock -%}
32
{% block content %}{% endblock %}
43
{% block footer %}
54
--
Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,33 @@
1-
21
{% extends "base.txt" %}
32
{% block header %}{% endblock %}
4-
{% block content %}
5-
6-
Hello,
7-
3+
{% block content -%}
84
New boot regression found on {{ issue["tree_name"] }}/{{ issue["git_repository_branch"] }}:
95

106
---
117
{{ issue["comment"]}}
128
---
13-
14-
- dashboard: https://d.kernelci.org/i/{{ issue["id"] }}
15-
- giturl: {{ issue["git_repository_url"]}}
16-
- commit HEAD: {{ issue["git_commit_hash"] }}
17-
{% if issue["git_commit_tags"] -%}
18-
- tags: {% for tag in issue["git_commit_tags"] %}{{tag}}{% if not loop.last %},{% endif %}{% endfor %}
19-
{%- endif %}
20-
21-
Please include the KernelCI tag when submitting a fix:
22-
23-
Reported-by: kernelci.org bot <bot@kernelci.org>
24-
259
{% if "misc" in issue.keys() and "logspec" in issue["misc"].keys() %}
2610
Log excerpt:
2711
=====================================================
2812
{{ issue["misc"]["logspec"]["error"]["log_excerpt"] }}
2913
=====================================================
3014
{% endif %}
15+
When fixing this issue, please attribute this report according to the
16+
patch submission rules:
17+
18+
Reported-by: kernelci.org bot <bot@kernelci.org>
19+
{% if message_id -%}
20+
Link: https://lore.kernel.org/all/{{ message_id }}/
21+
{% endif %}
22+
For complete logs and details about the environment used, see the issue
23+
on the KernelCI dashboard:
3124

25+
- dashboard: https://d.kernelci.org/i/{{ issue["id"] }}
26+
- giturl: {{ issue["git_repository_url"]}}
27+
- commit HEAD: {{ issue["git_commit_hash"] }}
28+
{% if issue["git_commit_tags"] -%}
29+
- tags: {% for tag in issue["git_commit_tags"] %}{{tag}}{% if not loop.last %},{% endif %}{% endfor %}
30+
{% endif %}
3231
# Hardware platforms affected:
3332
{% for boot in boots %}
3433
## {{boot["platform"]}}
@@ -46,7 +45,10 @@ Log excerpt:
4645
- commit hash: {{ boot["last_pass_commit"] }}
4746
- test id: {{ boot["last_pass_id"] }}
4847
{% endfor %}
48+
{% if boots and boots[0]["last_pass_commit"] -%}
49+
#regzbot introduced: {{ boots[0]["last_pass_commit"] }}..{{ issue["git_commit_hash"] }}
50+
#regzbot link: https://d.kernelci.org/i/{{ issue["id"] }}
4951

52+
{% endif -%}
5053
#kernelci issue {{ issue["id"] }}
51-
5254
{%- endblock -%}
Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,44 @@
1-
21
{% extends "base.txt" %}
32
{% block header %}{% endblock %}
4-
{% block content %}
5-
Hello,
6-
3+
{% block content -%}
74
New build issue found on {{ issue["tree_name"] }}/{{ issue["git_repository_branch"] }}:
85

96
---
107
{{ issue["comment"]}}
118
---
12-
13-
- dashboard: https://d.kernelci.org/i/{{ issue["id"] }}
14-
- giturl: {{ issue["git_repository_url"]}}
15-
- commit HEAD: {{ issue["git_commit_hash"] }}
16-
{% if issue["git_commit_tags"] -%}
17-
- tags: {% for tag in issue["git_commit_tags"] %}{{tag}}{% if not loop.last %},{% endif %}{% endfor %}
18-
{%- endif %}
19-
20-
Please include the KernelCI tag when submitting a fix:
21-
22-
Reported-by: kernelci.org bot <bot@kernelci.org>
23-
249
{% if "misc" in issue.keys() and "logspec" in issue["misc"].keys() %}
2510
Log excerpt:
2611
=====================================================
2712
{{ issue["misc"]["logspec"]["error"]["log_excerpt"] }}
2813
=====================================================
2914
{% endif %}
15+
When fixing this issue, please attribute this report according to the
16+
patch submission rules:
3017

18+
Reported-by: kernelci.org bot <bot@kernelci.org>
19+
{% if message_id -%}
20+
Link: https://lore.kernel.org/all/{{ message_id }}/
21+
{% endif %}
22+
For complete logs and details about the environment used, see the issue
23+
on the KernelCI dashboard:
24+
25+
- dashboard: https://d.kernelci.org/i/{{ issue["id"] }}
26+
- giturl: {{ issue["git_repository_url"]}}
27+
- commit HEAD: {{ issue["git_commit_hash"] }}
28+
{% if issue["git_commit_tags"] -%}
29+
- tags: {% for tag in issue["git_commit_tags"] %}{{tag}}{% if not loop.last %},{% endif %}{% endfor %}
30+
{% endif %}
3131
# Builds where the incident occurred:
3232
{% for build in builds %}
3333
## {{ build["config_name"] }} on ({{ build["architecture"] }}):
3434
- compiler: {{ build["compiler"] }}
3535
- config: {{ build["config_url"] }}
3636
- dashboard: https://d.kernelci.org/build/{{build["id"]}}
3737
{% endfor %}
38+
{% if builds and builds[0]["last_pass_commit"] -%}
39+
#regzbot introduced: {{ builds[0]["last_pass_commit"] }}..{{ issue["git_commit_hash"] }}
40+
#regzbot link: https://d.kernelci.org/i/{{ issue["id"] }}
3841

42+
{% endif -%}
3943
#kernelci issue {{ issue["id"] }}
40-
41-
4244
{%- endblock -%}

0 commit comments

Comments
 (0)