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