From f9af5eb8008d14e56d528a8acbeda72886ba6f53 Mon Sep 17 00:00:00 2001 From: Arjun Suresh Date: Mon, 24 Mar 2025 14:17:44 +0000 Subject: [PATCH 1/7] Support send-email (#317) * Added send-email script --- script/send-mail/customize.py | 48 ++++++++++++++ script/send-mail/meta.yaml | 18 ++++++ script/send-mail/run.bat | 23 +++++++ script/send-mail/run.sh | 18 ++++++ script/send-mail/send-email.py | 112 +++++++++++++++++++++++++++++++++ 5 files changed, 219 insertions(+) create mode 100644 script/send-mail/customize.py create mode 100644 script/send-mail/meta.yaml create mode 100644 script/send-mail/run.bat create mode 100644 script/send-mail/run.sh create mode 100644 script/send-mail/send-email.py diff --git a/script/send-mail/customize.py b/script/send-mail/customize.py new file mode 100644 index 000000000..9a2089594 --- /dev/null +++ b/script/send-mail/customize.py @@ -0,0 +1,48 @@ +from mlc import utils +import os +import subprocess + + +def preprocess(i): + + env = i['env'] + state = i['state'] + + os_info = i['os_info'] + + # Start constructing the argument string + args = f"--subject \"{env.get('MLC_EMAIL_SUBJECT', '')}\" " + + # Process other arguments + args += f"--to_addresses \"{','.join(env.get('MLC_TO_ADDRESS', []))}\" " + args += f"--cc_addresses \"{env.get('MLC_CC_ADDRESS', '')}\" " + args += f"--bcc_addresses \"{env.get('MLC_BCC_ADDRESS', '')}\" " + args += f"--content_file \"{env.get('MLC_CONTENT_FILE', '')}\" " + + # Process attachments + attachments = ' '.join(env.get('MLC_ATTACHMENTS', '').split()) + args += f"--attachments \"{attachments}\" " + + # Add flags for SMTP server, email and password if needed + if env.get('USE_SMTP_SERVER'): + args += "--use_smtp_server " + args += f"--email \"{env.get('EMAIL', '')}\" " + args += f"--password \"{env.get('PASSWORD', '')}\" " + args += f"--smtp_server \"{env.get('SMTP_SERVER', '')}\" " + + subject = env.get('MLC_EMAIL_SUBJECT', '') + to_address = ",".join(env.get('MLC_TO_ADDRESS', [])) + + env['MLC_RUN_CMD'] = f"""{env['MLC_PYTHON_BIN_WITH_PATH'] {os.path.join(env['MLC_TMP_CURRENT_SCRIPT_PATH'], 'send-email.py')} {args}""" + + return {'return': 0} + + +def postprocess(i): + + env = i['env'] + state = i['state'] + + os_info = i['os_info'] + + return {'return': 0} diff --git a/script/send-mail/meta.yaml b/script/send-mail/meta.yaml new file mode 100644 index 000000000..d19dcc15c --- /dev/null +++ b/script/send-mail/meta.yaml @@ -0,0 +1,18 @@ +alias: send-mail +automation_alias: script +automation_uid: 5b4e0237da074764 +category: Utils +deps: + - tags: get,generic-sys-util,_postfix + enable_if_env: + MLC_HOST_OS_FLAVOR: + - ubuntu +new_env_keys: [] +new_state_keys: [] +post_deps: [] +posthook_deps: [] +prehook_deps: [] +tags: +- generic +- template +uid: 5f9b9654ecbe4662 diff --git a/script/send-mail/run.bat b/script/send-mail/run.bat new file mode 100644 index 000000000..80625c80e --- /dev/null +++ b/script/send-mail/run.bat @@ -0,0 +1,23 @@ +@echo off +setlocal enabledelayedexpansion + +:: Function to exit if the last command failed +:exit_if_error +if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% +exit /b 0 + +:: Function to run a command +:run +echo Running: +echo %1 +echo. + +if /I "%MLC_FAKE_RUN%" NEQ "yes" ( + call %1 + call :exit_if_error +) +exit /b 0 + +:: Add your run commands here... +:: call :run "%MLC_RUN_CMD%" + diff --git a/script/send-mail/run.sh b/script/send-mail/run.sh new file mode 100644 index 000000000..d191bbd97 --- /dev/null +++ b/script/send-mail/run.sh @@ -0,0 +1,18 @@ +#!/bin/bash +function exit_if_error() { + test $? -eq 0 || exit $? +} + +function run() { + echo "Running: " + echo "$1" + echo "" + if [[ ${MLC_FAKE_RUN} != 'yes' ]]; then + eval "$1" + exit_if_error + fi +} + +#Add your run commands here... +MLC_RUN_CMD="${MLC_PYTHON_BIN_WITH_PATH} ${MLC_TMP_CURRENT_SCRIPT_PATH}/send-email.py" +run "$MLC_RUN_CMD" diff --git a/script/send-mail/send-email.py b/script/send-mail/send-email.py new file mode 100644 index 000000000..631b729b8 --- /dev/null +++ b/script/send-mail/send-email.py @@ -0,0 +1,112 @@ +import smtplib +import sys +import argparse +from email.mime.multipart import MIMEMultipart +from email.mime.base import MIMEBase +from email.mime.text import MIMEText +from email.utils import COMMASPACE +from email import encoders + + +def send_email(subject, to_addresses, cc_addresses, bcc_addresses, content_file, + attachments, use_smtp_server=False, smtp_server=None, email=None, password=None): + + to_list = to_addresses.split(',') + cc_list = cc_addresses.split(',') + bcc_list = bcc_addresses.split(',') + attachment_list = attachments.split(',') + + with open(content_file, 'r') as file: + email_content = file.read() + + msg = MIMEMultipart() + msg['From'] = email if use_smtp_server else 'localhost' + msg['To'] = COMMASPACE.join(to_list) + msg['Cc'] = COMMASPACE.join(cc_list) + msg['Subject'] = subject + + msg.attach(MIMEText(email_content, 'plain')) + + for attachment in attachment_list: + with open(attachment, 'rb') as file: + part = MIMEBase('application', 'octet-stream') + part.set_payload(file.read()) + encoders.encode_base64(part) + part.add_header( + 'Content-Disposition', + f'attachment; filename={attachment}') + msg.attach(part) + + recipients = to_list + cc_list + bcc_list + + if use_smtp_server: + with smtplib.SMTP_SSL(smtp_server) as server: + server.login(email, password) + server.sendmail(email, recipients, msg.as_string()) + print("Email sent successfully using SMTP server!") + else: + with smtplib.SMTP('localhost') as server: + server.sendmail( + 'localhost@example.com', + recipients, + msg.as_string()) + print("Email sent successfully using localhost!") + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description='Send an email with specified attachments') + parser.add_argument('subject', type=str, help='Email subject') + parser.add_argument( + 'to_addresses', + type=str, + help='To addresses, comma-separated') + parser.add_argument( + 'cc_addresses', + type=str, + help='CC addresses, comma-separated') + parser.add_argument( + 'bcc_addresses', + type=str, + help='BCC addresses, comma-separated') + parser.add_argument( + 'content_file', + type=str, + help='File containing email content') + parser.add_argument( + 'attachments', + type=str, + help='Attachments, comma-separated file paths') + + parser.add_argument( + '--use_smtp_server', + action='store_true', + help='Use an SMTP server instead of localhost') + parser.add_argument( + '--email', + type=str, + help='Email address for SMTP server') + parser.add_argument( + '--password', + type=str, + help='Password for SMTP server') + parser.add_argument('--smtp_server', type=str, help='SMTP server address') + + args = parser.parse_args() + + if args.use_smtp_server and not all( + [args.email, args.password, args.smtp_server]): + parser.error( + '--email, --password, and --smtp_server are required when --use_smtp_server is set') + + send_email( + args.subject, + args.to_addresses, + args.cc_addresses, + args.bcc_addresses, + args.content_file, + args.attachments, + args.use_smtp_server, + args.smtp_server, + args.email, + args.password) From a4fb62490efdfb1b78a90e716fa2a043fa0ebfeb Mon Sep 17 00:00:00 2001 From: Arjun Suresh Date: Mon, 24 Mar 2025 16:48:40 +0000 Subject: [PATCH 2/7] Support email (#319) * Added send-email script * Fixes for send-email --- script/send-mail/customize.py | 25 ++++++++++++------------ script/send-mail/meta.yaml | 15 +++++++++++++-- script/send-mail/run.sh | 2 +- script/send-mail/send-email.py | 35 ++++++++++++++++++++++++++-------- 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/script/send-mail/customize.py b/script/send-mail/customize.py index 9a2089594..d561f8466 100644 --- a/script/send-mail/customize.py +++ b/script/send-mail/customize.py @@ -11,29 +11,28 @@ def preprocess(i): os_info = i['os_info'] # Start constructing the argument string - args = f"--subject \"{env.get('MLC_EMAIL_SUBJECT', '')}\" " + args = f"--subject '{env.get('MLC_EMAIL_SUBJECT', '')}' " # Process other arguments - args += f"--to_addresses \"{','.join(env.get('MLC_TO_ADDRESS', []))}\" " - args += f"--cc_addresses \"{env.get('MLC_CC_ADDRESS', '')}\" " - args += f"--bcc_addresses \"{env.get('MLC_BCC_ADDRESS', '')}\" " - args += f"--content_file \"{env.get('MLC_CONTENT_FILE', '')}\" " + args += f"--to_addresses '{env.get('MLC_EMAIL_TO_ADDRESSES', '')}' " + args += f"--cc_addresses '{env.get('MLC_EMAIL_CC_ADDRESSES', '')}' " + args += f"--bcc_addresses '{env.get('MLC_EMAIL_BCC_ADDRESSES', '')}' " + args += f"--content_file '{env.get('MLC_EMAIL_CONTENT_FILE', '')}' " # Process attachments - attachments = ' '.join(env.get('MLC_ATTACHMENTS', '').split()) - args += f"--attachments \"{attachments}\" " + args += f"--attachments '{env.get('MLC_EMAIL_ATTACHMENTS', '')}'" # Add flags for SMTP server, email and password if needed - if env.get('USE_SMTP_SERVER'): + if env.get('MLC_EMAIL_USE_SMTP_SERVER'): args += "--use_smtp_server " - args += f"--email \"{env.get('EMAIL', '')}\" " - args += f"--password \"{env.get('PASSWORD', '')}\" " - args += f"--smtp_server \"{env.get('SMTP_SERVER', '')}\" " + args += f"--email '{env.get('MLC_EMAIL_SMPT_EMAIL', '')}' " + args += f"--password '{env.get('MLC_EMAIL_SMTP_PASSWORD', '')}' " + args += f"--smtp_server '{env.get('MLC_EMAIL_SMTP_SERVER', '')}' " subject = env.get('MLC_EMAIL_SUBJECT', '') - to_address = ",".join(env.get('MLC_TO_ADDRESS', [])) + to_address = ",".join(env.get('MLC_EMAIL_TO_ADDRESS', [])) - env['MLC_RUN_CMD'] = f"""{env['MLC_PYTHON_BIN_WITH_PATH'] {os.path.join(env['MLC_TMP_CURRENT_SCRIPT_PATH'], 'send-email.py')} {args}""" + env['MLC_RUN_CMD'] = f"""{env['MLC_PYTHON_BIN_WITH_PATH']} {os.path.join(env['MLC_TMP_CURRENT_SCRIPT_PATH'], 'send-email.py')} {args}""" return {'return': 0} diff --git a/script/send-mail/meta.yaml b/script/send-mail/meta.yaml index d19dcc15c..72cf19fa3 100644 --- a/script/send-mail/meta.yaml +++ b/script/send-mail/meta.yaml @@ -3,6 +3,10 @@ automation_alias: script automation_uid: 5b4e0237da074764 category: Utils deps: + - tags: get,python + names: + - python + - python3 - tags: get,generic-sys-util,_postfix enable_if_env: MLC_HOST_OS_FLAVOR: @@ -12,7 +16,14 @@ new_state_keys: [] post_deps: [] posthook_deps: [] prehook_deps: [] +input_mapping: + subject: MLC_EMAIL_SUBJECT + to_addresses: MLC_EMAIL_TO_ADDRESSES + to_address: MLC_EMAIL_TO_ADDRESSES + attachments: MLC_EMAIL_ATTACHMENTS + attachment: MLC_EMAIL_ATTACHMENTS tags: -- generic -- template +- send +- mail +- email uid: 5f9b9654ecbe4662 diff --git a/script/send-mail/run.sh b/script/send-mail/run.sh index d191bbd97..99e53cc91 100644 --- a/script/send-mail/run.sh +++ b/script/send-mail/run.sh @@ -14,5 +14,5 @@ function run() { } #Add your run commands here... -MLC_RUN_CMD="${MLC_PYTHON_BIN_WITH_PATH} ${MLC_TMP_CURRENT_SCRIPT_PATH}/send-email.py" + run "$MLC_RUN_CMD" diff --git a/script/send-mail/send-email.py b/script/send-mail/send-email.py index 631b729b8..0bb25f7e2 100644 --- a/script/send-mail/send-email.py +++ b/script/send-mail/send-email.py @@ -16,8 +16,11 @@ def send_email(subject, to_addresses, cc_addresses, bcc_addresses, content_file, bcc_list = bcc_addresses.split(',') attachment_list = attachments.split(',') - with open(content_file, 'r') as file: - email_content = file.read() + if content_file and os.path.exists(content_file): + with open(content_file, 'r') as file: + email_content = file.read() + else: + email_content = '' msg = MIMEMultipart() msg['From'] = email if use_smtp_server else 'localhost' @@ -28,6 +31,9 @@ def send_email(subject, to_addresses, cc_addresses, bcc_addresses, content_file, msg.attach(MIMEText(email_content, 'plain')) for attachment in attachment_list: + if attachment.strip() == '': + continue + with open(attachment, 'rb') as file: part = MIMEBase('application', 'octet-stream') part.set_payload(file.read()) @@ -56,26 +62,35 @@ def send_email(subject, to_addresses, cc_addresses, bcc_addresses, content_file, if __name__ == '__main__': parser = argparse.ArgumentParser( description='Send an email with specified attachments') - parser.add_argument('subject', type=str, help='Email subject') + parser.add_argument('--subject', type=str, help='Email subject') parser.add_argument( - 'to_addresses', + '--to_addresses', type=str, help='To addresses, comma-separated') parser.add_argument( - 'cc_addresses', + '--cc_addresses', type=str, + nargs='?', + default='', help='CC addresses, comma-separated') parser.add_argument( - 'bcc_addresses', + '--bcc_addresses', type=str, + nargs='?', + default='', help='BCC addresses, comma-separated') parser.add_argument( - 'content_file', + '--content_file', type=str, + nargs='?', + default='', help='File containing email content') parser.add_argument( - 'attachments', + '--attachments', type=str, + nargs='?', + default='', + help='Attachments, comma-separated file paths') parser.add_argument( @@ -85,10 +100,14 @@ def send_email(subject, to_addresses, cc_addresses, bcc_addresses, content_file, parser.add_argument( '--email', type=str, + default='', + nargs='?', help='Email address for SMTP server') parser.add_argument( '--password', type=str, + default='', + nargs='?', help='Password for SMTP server') parser.add_argument('--smtp_server', type=str, help='SMTP server address') From b2aa081e5b6a893ce39a90661a97e40299c1d303 Mon Sep 17 00:00:00 2001 From: Arjun Suresh Date: Mon, 24 Mar 2025 16:57:35 +0000 Subject: [PATCH 3/7] Update VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3eefcb9dd..7dea76edb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0 +1.0.1 From 79d538234dd934fe9df6f1eadf47dd5104406cda Mon Sep 17 00:00:00 2001 From: Arjun Suresh Date: Mon, 24 Mar 2025 17:13:07 +0000 Subject: [PATCH 4/7] Create build_wheels_on_release.yml --- .github/workflows/build_wheels_on_release.yml | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/workflows/build_wheels_on_release.yml diff --git a/.github/workflows/build_wheels_on_release.yml b/.github/workflows/build_wheels_on_release.yml new file mode 100644 index 000000000..31059e44a --- /dev/null +++ b/.github/workflows/build_wheels_on_release.yml @@ -0,0 +1,49 @@ +name: Build wheel and release into PYPI + +on: + release: + types: [published] + +jobs: + + build_wheels: + if: github.repository_owner == 'mlcommons' + name: Build wheel + runs-on: ubuntu-latest + environment: release + + permissions: + id-token: write + contents: write + + strategy: + fail-fast: false + steps: + # Step : Checkout the code + - uses: actions/checkout@v4 + with: + fetch-depth: 2 + ssh-key: ${{ secrets.DEPLOY_KEY }} + ref: ${{ github.ref_name }} + + # Step : Set up Python + - uses: actions/setup-python@v3 + + # Step : Install required dependencies + - name: Install requirements + run: python3 -m pip install setuptools wheel build + + # Step : Build the Python wheel + - name: Build wheels + working-directory: ./ + run: python3 -m build && rm dist/*.whl + + # Step : Publish to PyPI + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + verify-metadata: true + skip-existing: true + packages-dir: dist + repository-url: https://upload.pypi.org/legacy/ + verbose: true From cce1f75777e9015509a845118851b056bdfd61ca Mon Sep 17 00:00:00 2001 From: Arjun Suresh Date: Mon, 24 Mar 2025 17:13:37 +0000 Subject: [PATCH 5/7] Update build_wheel.yml --- .github/workflows/build_wheel.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index 1edf42589..5467a7cc9 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -1,9 +1,6 @@ name: Build wheel and release into PYPI -on: - release: - types: [published] - +on: push: branches: - dev_off From a5aad57def9794d030f242ee32d10cbf9895f0cf Mon Sep 17 00:00:00 2001 From: Arjun Suresh Date: Mon, 24 Mar 2025 17:14:14 +0000 Subject: [PATCH 6/7] Update build_wheels_on_release.yml --- .github/workflows/build_wheels_on_release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build_wheels_on_release.yml b/.github/workflows/build_wheels_on_release.yml index 31059e44a..fd62c80c2 100644 --- a/.github/workflows/build_wheels_on_release.yml +++ b/.github/workflows/build_wheels_on_release.yml @@ -3,6 +3,7 @@ name: Build wheel and release into PYPI on: release: types: [published] + workflow_dispatch: {} jobs: From bd9294452b2e5a5065adaaac2e36d696c7798d78 Mon Sep 17 00:00:00 2001 From: Arjun Suresh Date: Mon, 24 Mar 2025 21:11:50 +0000 Subject: [PATCH 7/7] Fix postfix deps (#321) --- script/get-generic-sys-util/meta.yaml | 8 ++++++++ script/send-mail/meta.yaml | 1 + 2 files changed, 9 insertions(+) diff --git a/script/get-generic-sys-util/meta.yaml b/script/get-generic-sys-util/meta.yaml index bd4006e72..8f75171de 100644 --- a/script/get-generic-sys-util/meta.yaml +++ b/script/get-generic-sys-util/meta.yaml @@ -602,6 +602,14 @@ variations: brew: pkg-config dnf: pkg-config yum: pkg-config + postfix: + env: + MLC_SYS_UTIL_NAME: postfix + new_env_keys: + - MLC_POSTFIX_VERSION + state: + postfix: + apt: postfix psmisc: env: MLC_SYS_UTIL_NAME: psmisc diff --git a/script/send-mail/meta.yaml b/script/send-mail/meta.yaml index 72cf19fa3..90abe9d63 100644 --- a/script/send-mail/meta.yaml +++ b/script/send-mail/meta.yaml @@ -3,6 +3,7 @@ automation_alias: script automation_uid: 5b4e0237da074764 category: Utils deps: + - tags: detect,os - tags: get,python names: - python