blob: 8a3dadbd111a0a29d0e0c422dbae50856419c3b9 [file] [log] [blame]
Patrick Williamsac13d5f2023-11-24 18:59:46 -06001#!/usr/bin/env python3
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4#
5# patchtest: execute all unittest test cases discovered for a single patch
6# Note that this script is currently under development and has been
7# hard-coded with default values for testing purposes. This script
8# should not be used without changing the default recipient, at minimum.
9#
10# Copyright (C) 2023 BayLibre Inc.
11#
12# SPDX-License-Identifier: GPL-2.0-only
13#
14
15import argparse
16import boto3
17import configparser
18import mailbox
19import os
20import re
21import sys
22
23greeting = """Thank you for your submission. Patchtest identified one
24or more issues with the patch. Please see the log below for
25more information:\n\n---\n"""
26
27suggestions = """\n---\n\nPlease address the issues identified and
28submit a new revision of the patch, or alternatively, reply to this
29email with an explanation of why the patch should be accepted. If you
30believe these results are due to an error in patchtest, please submit a
31bug at https://bugzilla.yoctoproject.org/ (use the 'Patchtest' category
32under 'Yocto Project Subprojects'). For more information on specific
33failures, see: https://wiki.yoctoproject.org/wiki/Patchtest. Thank
34you!"""
35
Patrick Williams73bd93f2024-02-20 08:07:48 -060036def has_a_failed_test(raw_results):
37 return any(raw_result.split(':')[0] == "FAIL" for raw_result in raw_results.splitlines())
38
Patrick Williamsac13d5f2023-11-24 18:59:46 -060039parser = argparse.ArgumentParser(description="Send patchtest results to a submitter for a given patch")
40parser.add_argument("-p", "--patch", dest="patch", required=True, help="The patch file to summarize")
Patrick Williams73bd93f2024-02-20 08:07:48 -060041parser.add_argument("-d", "--debug", dest="debug", required=False, action='store_true', help="Print raw email headers and content, but don't actually send it")
Patrick Williamsac13d5f2023-11-24 18:59:46 -060042args = parser.parse_args()
43
44if not os.path.exists(args.patch):
45 print(f"Patch '{args.patch}' not found - did you provide the right path?")
46 sys.exit(1)
47elif not os.path.exists(args.patch + ".testresult"):
48 print(f"Found patch '{args.patch}' but '{args.patch}.testresult' was not present. Have you run patchtest on the patch?")
49 sys.exit(1)
50
51result_file = args.patch + ".testresult"
Patrick Williamsac13d5f2023-11-24 18:59:46 -060052testresult = None
53
54with open(result_file, "r") as f:
55 testresult = f.read()
56
57# we know these patch files will only contain a single patch, so only
58# worry about the first element for getting the subject
59mbox = mailbox.mbox(args.patch)
60mbox_subject = mbox[0]['subject']
61subject_line = f"Patchtest results for {mbox_subject}"
62
63# extract the submitter email address and use it as the reply address
64# for the results
65reply_address = mbox[0]['from']
66
67# extract the message ID and use that as the in-reply-to address
Patrick Williams73bd93f2024-02-20 08:07:48 -060068# TODO: This will need to change again when patchtest can handle a whole
69# series at once
70in_reply_to = mbox[0]['Message-ID']
Patrick Williamsac13d5f2023-11-24 18:59:46 -060071
72# the address the results email is sent from
73from_address = "patchtest@automation.yoctoproject.org"
74
75# mailing list to CC
76cc_address = "openembedded-core@lists.openembedded.org"
77
Patrick Williams73bd93f2024-02-20 08:07:48 -060078if has_a_failed_test(testresult):
Patrick Williamsac13d5f2023-11-24 18:59:46 -060079 reply_contents = None
80 if len(max(open(result_file, 'r'), key=len)) > 220:
81 warning = "Tests failed for the patch, but the results log could not be processed due to excessive result line length."
82 reply_contents = greeting + warning + suggestions
83 else:
84 reply_contents = greeting + testresult + suggestions
85
86 ses_client = boto3.client('ses', region_name='us-west-2')
Patrick Williams73bd93f2024-02-20 08:07:48 -060087
88 # Construct the headers for the email. We only want to reply
89 # directly to the tested patch, so make In-Reply-To and References
90 # the same value.
Patrick Williamsac13d5f2023-11-24 18:59:46 -060091 raw_data = 'From: ' + from_address + '\nTo: ' + reply_address + \
92 '\nCC: ' + cc_address + '\nSubject:' + subject_line + \
93 '\nIn-Reply-To:' + in_reply_to + \
Patrick Williams73bd93f2024-02-20 08:07:48 -060094 '\nReferences:' + in_reply_to + \
Patrick Williamsac13d5f2023-11-24 18:59:46 -060095 '\nMIME-Version: 1.0" + \
96 "\nContent-type: Multipart/Mixed;boundary="NextPart"\n\n--NextPart\nContent-Type: text/plain\n\n' + \
97 reply_contents + '\n\n--NextPart'
Patrick Williams73bd93f2024-02-20 08:07:48 -060098
99 if args.debug:
100 print(f"RawMessage: \n\n{raw_data}")
101 else:
102 response = ses_client.send_raw_email(
103 Source="patchtest@automation.yoctoproject.org",
104 RawMessage={
105 "Data": raw_data,
106 },
107 )
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600108
109else:
110 print(f"No failures identified for {args.patch}.")