From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 2A576A0C51; Fri, 6 Aug 2021 19:56:39 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 2F8D5412C6; Fri, 6 Aug 2021 19:56:29 +0200 (CEST) Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by mails.dpdk.org (Postfix) with ESMTP id 1761C4014D for ; Fri, 6 Aug 2021 19:56:25 +0200 (CEST) X-IronPort-AV: E=McAfee;i="6200,9189,10068"; a="194688225" X-IronPort-AV: E=Sophos;i="5.84,301,1620716400"; d="scan'208";a="194688225" Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Aug 2021 10:56:20 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.84,301,1620716400"; d="scan'208";a="672368373" Received: from silpixa00396680.ir.intel.com (HELO silpixa00396680.ger.corp.intel.com) ([10.237.223.54]) by fmsmga005.fm.intel.com with ESMTP; 06 Aug 2021 10:56:18 -0700 From: Ray Kinsella To: dev@dpdk.org Cc: bruce.richardson@intel.com, stephen@networkplumber.org, ferruh.yigit@intel.com, thomas@monjalon.net, ktraynor@redhat.com, mdr@ashroe.eu Date: Fri, 6 Aug 2021 18:54:12 +0100 Message-Id: <20210806175412.872237-3-mdr@ashroe.eu> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210806175412.872237-1-mdr@ashroe.eu> References: <20210618163659.85933-1-mdr@ashroe.eu> <20210806175412.872237-1-mdr@ashroe.eu> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [dpdk-dev] [PATCH v8 2/2] devtools: script to send notifications of expired symbols X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Use this script with the output of the DPDK symbol tool, to notify maintainers of expired symbols by email. You need to define the environment variable DPDK_GETMAINTAINER_PATH, for this tool to work. Use terminal output to review the emails before sending. e.g. $ devtools/symbol-tool.py list-expired --format-output csv \ | DPDK_GETMAINTAINER_PATH=/get_maintainer.pl \ devtools/notify_expired_symbols.py --format-output terminal Then use email output to send the emails to the maintainers. e.g. $ devtools/symbol-tool.py list-expired --format-output csv \ | DPDK_GETMAINTAINER_PATH=/get_maintainer.pl \ --smtp-server --sender \ --password Signed-off-by: Ray Kinsella --- devtools/notify-symbol-maintainers.py | 224 ++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100755 devtools/notify-symbol-maintainers.py diff --git a/devtools/notify-symbol-maintainers.py b/devtools/notify-symbol-maintainers.py new file mode 100755 index 0000000000..447f88bb03 --- /dev/null +++ b/devtools/notify-symbol-maintainers.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2021 Intel Corporation +'''Tool to notify maintainers of expired symbols''' +import smtplib +import ssl +import sys +import subprocess +import argparse +from argparse import RawTextHelpFormatter +import time +from email.message import EmailMessage + +DESCRIPTION = ''' +Use this script with the output of the DPDK symbol tool, to notify maintainers +of expired symbols by email. You need to define the environment variable +DPDK_GETMAINTAINER_PATH, for this tool to work. + +Use terminal output to review the emails before sending. +e.g. +$ devtools/symbol-tool.py list-expired --format-output csv \\ +| DPDK_GETMAINTAINER_PATH=/get_maintainer.pl \\ +devtools/notify_expired_symbols.py --format-output terminal + +Then use email output to send the emails to the maintainers. +e.g. +$ devtools/symbol-tool.py list-expired --format-output csv \\ +| DPDK_GETMAINTAINER_PATH=/get_maintainer.pl \\ +--smtp-server --sender --password +''' + +EMAIL_TEMPLATE = '''Hi there, + +Please note the symbols listed below have expired. In line with the DPDK ABI +policy, they should be scheduled for removal, in the next DPDK release. + +For more information, please see the DPDK ABI Policy, section 3.5.3. +https://doc.dpdk.org/guides/contributing/abi_policy.html + +Thanks, + +The DPDK Symbol Bot + +''' + +default_maintainers = ['Ray Kinsella ', \ + 'Thomas Monjalon '] +get_maintainer = ['devtools/get-maintainer.sh', \ + '--email', '-f'] + +def get_maintainers(libpath): + '''Get the maintainers for given library''' + try: + cmd = get_maintainer + [libpath] + result = subprocess.run(cmd, \ + stdout=subprocess.PIPE, \ + stderr=subprocess.PIPE, + check=True) + except subprocess.CalledProcessError: + result = None + + if result is not None: + email = result.stdout.decode('utf-8') + if email == '': + email = default_maintainers + else: + email = list(filter(None,email.split('\n'))) + else: + email = default_maintainers + + return email + +def get_message(library, symbols): + '''Build email message from symbols, config and maintainers''' + message = {} + maintainers = get_maintainers(library) + + message['To'] = maintainers + if maintainers != default_maintainers: + message['CC'] = default_maintainers + + message['Subject'] = 'Expired symbols in {}\n'.format(library) + + body = EMAIL_TEMPLATE + for sym in symbols: + body += ('{}\n'.format(sym)) + + message['Body'] = body + + return message + +class OutputEmail(): + '''Format the output for email''' + def __init__(self, config): + self.config = config + + self.terminal = OutputTerminal(config) + context = ssl.create_default_context() + + # Try to log in to server and send email + try: + self.server = smtplib.SMTP(config['smtp_server'], 587) + self.server.starttls(context=context) # Secure the connection + self.server.login(config['sender'], config['password']) + except Exception as exception: + print(exception) + raise exception + + def message(self,message): + '''send email''' + self.terminal.message(message) + + msg = EmailMessage() + msg.set_content(message.pop('Body')) + + for key in message.keys(): + msg[key] = message[key] + + msg['From'] = self.config['sender'] + msg['Reply-To'] = 'no-reply@dpdk.org' + + self.server.send_message(msg) + + time.sleep(1) + + def __del__(self): + self.server.quit() + +class OutputTerminal(): # pylint: disable=too-few-public-methods + '''Format the output for the terminal''' + def __init__(self, config): + self.config = config + + def message(self,message): + '''Print email to terminal''' + terminal = 'To:' + ', '.join(message['To']) + '\n' + if 'sender' in self.config.keys(): + terminal += 'From:' + self.config['sender'] + '\n' + + terminal += 'Reply-To:' + 'no-reply@dpdk.org' + '\n' + if 'CC' in message.keys(): + terminal += 'CC:' + ', '.join(message['CC']) + '\n' + + terminal += 'Subject:' + message['Subject'] + '\n' + terminal += 'Body:' + message['Body'] + '\n' + + print(terminal) + print('-' * 80) + +def parse_config(args): + '''put the command line args in the right places''' + config = {} + error_msg = None + + outputs = { + None : OutputTerminal, + 'terminal' : OutputTerminal, + 'email' : OutputEmail + } + + if args.format_output == 'email': + if args.smtp_server is None: + error_msg = 'SMTP server' + else: + config['smtp_server'] = args.smtp_server + + if args.sender is None: + error_msg = 'sender' + else: + config['sender'] = args.sender + + if args.password is None: + error_msg = 'password' + else: + config['password'] = args.password + + if error_msg is not None: + print('Please specify a {} for email output'.format(error_msg)) + return None + + config['output'] = outputs[args.format_output] + return config + +def main(): + '''Main entry point''' + parser = argparse.ArgumentParser(description=DESCRIPTION, \ + formatter_class=RawTextHelpFormatter) + parser.add_argument('--format-output', choices=['terminal','email'], \ + default='terminal') + parser.add_argument('--smtp-server') + parser.add_argument('--password') + parser.add_argument('--sender') + + args = parser.parse_args() + config = parse_config(args) + if config is None: + return + + symbols = [] + lastlib = library = '' + + output = config['output'](config) + + for line in sys.stdin: + line = line.rstrip('\n') + library, symbol = [line[:line.find(',')], \ + line[line.find(',') + 1: len(line)]] + if library == 'mapfile': + continue + + if library != lastlib: + message = get_message(lastlib, symbols) + output.message(message) + symbols = [] + + lastlib = library + symbols = symbols + [symbol] + + #print the last library + message = get_message(lastlib, symbols) + output.message(message) + +if __name__ == '__main__': + main() -- 2.26.2