diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml
index 9e05b7f..d5dd999 100644
--- a/.github/workflows/build-and-push.yml
+++ b/.github/workflows/build-and-push.yml
@@ -19,7 +19,7 @@ jobs:
registry_username: ${{ secrets.QUAY_IMAGE_SCLORG_BUILDER_USERNAME }}
registry_token: ${{ secrets.QUAY_IMAGE_SCLORG_BUILDER_TOKEN }}
dockerfile: Dockerfile.daily-tests
- tag: "0.10.4"
+ tag: "0.10.5"
image_name: "upstream-daily-tests"
quay_application_token: ${{ secrets.QUAY_IMAGE_SCLORG_UPDATE_DESC }}
@@ -31,6 +31,6 @@ jobs:
registry_username: ${{ secrets.QUAY_IMAGE_SCLORG_BUILDER_USERNAME }}
registry_token: ${{ secrets.QUAY_IMAGE_SCLORG_BUILDER_TOKEN }}
dockerfile: Dockerfile.eol-checker
- tag: "0.10.4"
+ tag: "0.10.5"
image_name: "upstream-eol-checker"
quay_application_token: ${{ secrets.QUAY_IMAGE_SCLORG_UPDATE_DESC }}
diff --git a/Dockerfile.daily-tests b/Dockerfile.daily-tests
index b77a26e..38f81e3 100644
--- a/Dockerfile.daily-tests
+++ b/Dockerfile.daily-tests
@@ -2,7 +2,7 @@ FROM quay.io/fedora/fedora:42
ENV SHARED_DIR="/var/ci-scripts" \
VERSION="42" \
- RELEASE_UPSTREAM="0.10.4" \
+ RELEASE_UPSTREAM="0.10.5" \
UPSTREAM_TMT_REPO="https://github.com/sclorg/sclorg-testing-farm" \
UPSTREAM_TMT_DIR="sclorg-testing-farm" \
HOME="/home/nightly" \
diff --git a/Dockerfile.eol-checker b/Dockerfile.eol-checker
index 368e298..0d05327 100644
--- a/Dockerfile.eol-checker
+++ b/Dockerfile.eol-checker
@@ -1,7 +1,7 @@
FROM quay.io/fedora/fedora:42
ENV VERSION="42" \
- RELEASE_UPSTREAM="0.10.4" \
+ RELEASE_UPSTREAM="0.10.5" \
HOME="/home/eol-checker" \
SUMMARY="EOL checker for SCL org projects" \
DESCRIPTION="This image is used to run EOL checker for SCL org projects in CI." \
diff --git a/Makefile b/Makefile
index cb15c41..2ec3302 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ shellcheck:
build_images: daily_tests eol_checker
daily_tests:
- podman build -t quay.io/sclorg/upstream-daily-tests:0.10.4 -f Dockerfile.daily-tests .
+ podman build -t quay.io/sclorg/upstream-daily-tests:0.10.5 -f Dockerfile.daily-tests .
eol_checker:
- podman build -t quay.io/sclorg/upstream-eol-checker:0.10.4 -f Dockerfile.eol-checker .
+ podman build -t quay.io/sclorg/upstream-eol-checker:0.10.5 -f Dockerfile.eol-checker .
diff --git a/eol-checker/eol-checker b/eol-checker/eol-checker
index 231cc05..fd117c6 100755
--- a/eol-checker/eol-checker
+++ b/eol-checker/eol-checker
@@ -64,7 +64,6 @@ def main(args):
Returns:
The exit code. 0 if successful, 1 if error.
"""
- print(f"Arguments: {args}")
checker = ContainerEolChecker(debug=args.debug, send_email=args.send_email)
checker.run()
sys.exit(0)
diff --git a/eol-checker/eol_checker/checker.py b/eol-checker/eol_checker/checker.py
index 03965e3..f2054fc 100755
--- a/eol-checker/eol_checker/checker.py
+++ b/eol-checker/eol_checker/checker.py
@@ -44,7 +44,6 @@
is_eol_version,
get_lifecycles,
load_mails_from_environment,
- get_env_variable,
)
from eol_checker.constants import OS_NAMES, CONTAINER_NAMES
@@ -60,21 +59,21 @@ class ContainerEolChecker(object):
def __init__(self, debug: bool = False, send_email: bool = False):
self.today = date.today()
+ # Used for OpenShift CronJob
+ env_debug = os.getenv("DEBUG")
+ debug_enabled = (
+ debug if env_debug is None else env_debug.strip().lower() in {"1", "true", "yes", "on"}
+ )
+ self._setup_logger(debug=debug_enabled)
self.lifecycle_data: Any = None
self.eol_images: dict = {}
self.already_eol_images: dict = {}
self.approaching_eol_images: dict = {}
self.os_name: str = ""
- self.default_mails: List[str] = os.getenv("DEFAULT_EMAILS", "").split(",")
+ self.default_mails: List[str] = os.getenv("DEFAULT_EMAILS").split(",")
self.container_to_analyze: str = ""
self.jira_fetcher = JiraFetcher()
self.eol_sme_mails = load_mails_from_environment()
- # Used for OpenShift CronJob
- env_debug = os.getenv("DEBUG")
- debug_enabled = (
- debug if env_debug is None else env_debug.strip().lower() in {"1", "true", "yes", "on"}
- )
- self._setup_logger(debug=debug_enabled)
env_send_email = os.getenv("SEND_EMAIL")
self.send_email = (
@@ -150,7 +149,7 @@ def analyze_lifecycle_yaml(self, data: Any) -> None:
for lifecycle in get_lifecycles(data):
self.check_enddate(lifecycle)
- def _get_jira_msg(self, report_type: str, enddate: str) -> str:
+ def _get_jira_msg(self, report_type: str, enddate: str, jira_id: str = "") -> str:
"""
Generate a Jira message.
Args:
@@ -159,12 +158,15 @@ def _get_jira_msg(self, report_type: str, enddate: str) -> str:
Returns:
The Jira message.
"""
- jira_msg = (
- "Connection to Jira not available"
- if self.jira_fetcher.jira is None
- else "Jira ticket is not filled. Use Jira issue template:"
- )
- return self.bold_line + f"{report_type} in {enddate}" + self.bold_line_end + f". {jira_msg}"
+ jira_url = get_jira_ticket_url(jira_issue_id=self.jira_fetcher.jira_deprecation_ticket)
+ url = f"{jira_url}" if self.send_email else jira_url
+ msg = "Jira ticket is not filled. Use this template: "
+ if jira_id != "":
+ jira_url = get_jira_ticket_url(jira_issue_id=jira_id)
+ url = f"{jira_url}" if self.send_email else jira_url
+ msg = "Jira ticket is already filed: "
+ jira_msg = f"{msg} {url}"
+ return self.bold_line + f"{report_type} in {enddate}. " + self.bold_line_end + jira_msg
def summary_for_images(self, images: dict, os_name: str, eol_type: bool = True) -> str:
"""
@@ -188,27 +190,25 @@ def summary_for_images(self, images: dict, os_name: str, eol_type: bool = True)
logger.info("Processing container: '%s' with values: '%s'", container_name, values)
stream_name = values["name"]
if self.send_email:
- for mail in self.eol_sme_mails[container_name]:
+ mails = [
+ self.eol_sme_mails[group]
+ for group in self.eol_sme_mails.keys()
+ if container_name.startswith(group)
+ ]
+ logger.debug("Mails: '%s' for container: '%s'", mails, container_name)
+ for mail in mails:
if mail and mail not in self.default_mails:
- self.default_mails.append(mail)
+ self.default_mails.extend(mail)
if self.jira_fetcher.jira is None:
logger.error("Connection to Jira failed")
jira_msg = self._get_jira_msg(report_type=report_type, enddate=values["enddate"])
- jira_id = self.jira_fetcher.jira_deprecation_ticket
- jira_url = get_jira_ticket_url(jira_issue_id=jira_id)
- url = f"{jira_url}" if self.send_email else jira_url
- report += f"{stream_name} for {os_name} {jira_msg} {url}{self.end_line}"
+ report += f"{stream_name} for {os_name}.{jira_msg} {self.end_line}"
continue
- jira_msg = self._get_jira_msg(report_type=report_type, enddate=values["enddate"])
- jira_msg += "Jira ticket is already filed:"
- jira_id = self.jira_fetcher.is_jira_filled_for_container(stream_name=stream_name)
- if jira_id == "":
- jira_msg = self._get_jira_msg(report_type=report_type, enddate=values["enddate"])
- jira_id = self.jira_fetcher.jira_deprecation_ticket
- jira_url = get_jira_ticket_url(jira_issue_id=jira_id)
- url = f"{jira_url}" if self.send_email else jira_url
- report += f"{stream_name} for {os_name} {jira_msg} {url}{self.end_line}"
- report += "\n"
+ jira_id = self.jira_fetcher.is_jira_filed_for_container(stream_name=stream_name)
+ jira_msg = self._get_jira_msg(
+ report_type=report_type, enddate=values["enddate"], jira_id=jira_id
+ )
+ report += f"{stream_name} for {os_name} {jira_msg} {self.end_line}\n"
return report
@@ -265,18 +265,17 @@ def send_emails(self):
Send emails with the container EOL information.
"""
logger.debug("Sending emails is enabled")
- logger.debug(", ".join(self.default_mails))
- self.smtp_server = get_env_variable("SMTP_SERVER", "smtp.redhat.com")
- self.smtp_port = int(get_env_variable("SMTP_PORT", "25"))
+ logger.debug(self.default_mails)
+ self.smtp_server = os.getenv("SMTP_SERVER", "smtp.redhat.com")
+ self.smtp_port = int(os.getenv("SMTP_PORT", "25"))
send_from = "phracek@redhat.com"
- send_to = self.default_mails
self.mime_msg["From"] = send_from
- self.mime_msg["To"] = ", ".join(send_to)
+ self.mime_msg["To"] = ",".join(self.default_mails)
self.mime_msg["Subject"] = "Container EOL Checker Report"
logger.debug(
"Sending email with subject: 'Container EOL Checker Report' to: '%s'",
- send_to,
+ self.default_mails,
)
logger.debug("Email body: '%s'", self.body)
logger.debug("Message: '%s'", self.mime_msg)
@@ -284,7 +283,7 @@ def send_emails(self):
try:
smtp = SMTP(self.smtp_server, int(self.smtp_port))
smtp.set_debuglevel(5)
- smtp.sendmail(send_from, send_to, self.mime_msg.as_string())
+ smtp.sendmail(send_from, self.default_mails, self.mime_msg.as_string())
except smtplib.SMTPRecipientsRefused as e:
logger.error("Error sending email(SMTPRecipientsRefused): %s", e.strerror)
except smtplib.SMTPException as e:
@@ -297,12 +296,13 @@ def run(self):
"""
Run the container EOL checker.
"""
+ logger.debug("Variables:\n%s", vars(self))
logger.info("Running container EOL checker")
if self.jira_fetcher.jira is None:
logger.error("Connection to Jira failed")
else:
self.jira_fetcher.get_jira_deprecation_details()
- self.jira_fetcher.check_if_jira_is_filled()
+ self.jira_fetcher.check_if_jira_is_filed()
self.analyze_containers()
self.body = self.summary_report()
logger.info(self.body)
diff --git a/eol-checker/eol_checker/constants.py b/eol-checker/eol_checker/constants.py
index d1becb1..2463949 100644
--- a/eol-checker/eol_checker/constants.py
+++ b/eol-checker/eol_checker/constants.py
@@ -22,7 +22,7 @@
JIRA_URL = "https://redhat.atlassian.net"
OS_NAMES = ["RHEL8", "RHEL9", "RHEL10"]
-ALLOWED_STATUSES = ["Open", "In Progress", "To Do"]
+ALLOWED_STATUSES = ["New", "Open", "In Progress", "To Do"]
CONTAINER_NAMES = [
"nodejs",
"httpd",
@@ -40,6 +40,7 @@
"python39",
"python311",
"python312",
+ "python314",
"ruby",
]
JIRA_DEPRECATION_TICKET = "RHELMISC-20810"
diff --git a/eol-checker/eol_checker/custom_logger.py b/eol-checker/eol_checker/custom_logger.py
index 04d697e..6355f6e 100644
--- a/eol-checker/eol_checker/custom_logger.py
+++ b/eol-checker/eol_checker/custom_logger.py
@@ -25,6 +25,10 @@
class ColoredFormatter(logging.Formatter):
+ """
+ Colored formatter for the logger.
+ """
+
COLORS = {
"DEBUG": Fore.LIGHTBLUE_EX,
"INFO": Fore.GREEN,
@@ -50,6 +54,14 @@ def format(self, record):
def setup_logger(logger_name: str = "eol_checker", level=logging.INFO):
+ """
+ Setup the logger.
+ Args:
+ logger_name: The name of the logger.
+ level: The level of the logger.
+ Returns:
+ The logger.
+ """
logger = logging.getLogger(logger_name)
# Check if handlers already exist (to avoid duplicate logs)
diff --git a/eol-checker/eol_checker/jira.py b/eol-checker/eol_checker/jira.py
index 11f6464..aa5430a 100644
--- a/eol-checker/eol_checker/jira.py
+++ b/eol-checker/eol_checker/jira.py
@@ -55,17 +55,26 @@ def get_jira_deprecation_details(self):
except HTTPError as e:
logger.error("Error occurred while fetching JIRA issue: %s", e)
self.jira_details = None
+ logger.debug("JIRA details: '%s'", self.jira_details)
- def is_jira_filled_for_container(self, stream_name: str) -> str:
+ def is_jira_filed_for_container(self, stream_name: str) -> str:
+ """
+ Check if the JIRA ticket is filled for a container.
+ Args:
+ stream_name: The stream name.
+ Returns:
+ The JIRA issue ID if the JIRA ticket is filled, empty string otherwise.
+ """
jira_id = ""
for issue in self.jira_deprecated_opened_issues:
- logger.info("Check is stream '%s' in issue '%s'", stream_name, issue)
+ logger.info("Check if stream '%s' in issue '%s'", stream_name, issue)
if "summary" in issue and stream_name in issue["summary"]:
jira_id = issue["jira_issue_id"]
+ logger.debug("Jira is already filed for container '%s'", stream_name)
break
return jira_id
- def check_if_jira_is_filled(self) -> bool:
+ def check_if_jira_is_filed(self) -> bool:
"""
Check if the JIRA ticket is filled.
Returns:
diff --git a/eol-checker/eol_checker/utils.py b/eol-checker/eol_checker/utils.py
index aa590c5..940a70d 100644
--- a/eol-checker/eol_checker/utils.py
+++ b/eol-checker/eol_checker/utils.py
@@ -23,7 +23,7 @@
import logging
import os
-from typing import Any, Iterable, Dict
+from typing import Any, Iterable, Dict, List
from datetime import date
from eol_checker.constants import JIRA_URL
@@ -72,7 +72,7 @@ def get_jira_ticket_url(jira_issue_id: str) -> str:
return f"{JIRA_URL}/browse/{jira_issue_id}"
-def get_env_variable(var_name: str, default_value: str = "") -> str:
+def get_env_variable(var_name: str, default_value: str = "") -> List[str]:
"""
Get environment variable value or return default value if not set.
:param var_name: Name of the environment variable
@@ -81,9 +81,9 @@ def get_env_variable(var_name: str, default_value: str = "") -> str:
"""
if var_name in os.environ:
value = os.getenv(var_name, default_value)
- print(f"Environment variable '{var_name}': '{value}'")
- return value
- return default_value
+ if value:
+ return value.split(",")
+ return []
def load_mails_from_environment():
@@ -91,23 +91,19 @@ def load_mails_from_environment():
Load email addresses from environment variables.
"""
sclorg_mails = {}
- sclorg_mails["mariadb"] = get_env_variable("DB_MAILS").split(",")
- sclorg_mails["mysql"] = get_env_variable("DB_MAILS").split(",")
- sclorg_mails["postgresql"] = get_env_variable("DB_MAILS").split(",")
- sclorg_mails["ruby"] = get_env_variable("RUBY_MAILS").split(",")
- python_mails = get_env_variable("PYTHON_MAILS").split(",")
- sclorg_mails["python"] = python_mails
- sclorg_mails["python36"] = python_mails
- sclorg_mails["python38"] = python_mails
- sclorg_mails["python39"] = python_mails
- sclorg_mails["python311"] = python_mails
- sclorg_mails["python312"] = python_mails
- sclorg_mails["nodejs"] = get_env_variable("NODEJS_MAILS").split(",")
- sclorg_mails["perl"] = get_env_variable("PERL_MAILS").split(",")
- sclorg_mails["php"] = get_env_variable("PHP_MAILS").split(",")
- sclorg_mails["redis"] = get_env_variable("REDIS_MAILS").split(",")
- sclorg_mails["varnish"] = get_env_variable("VARNISH_MAILS").split(",")
- sclorg_mails["valkey"] = get_env_variable("VALKEY_MAILS").split(",")
- sclorg_mails["httpd"] = get_env_variable("HTTPD_MAILS").split(",")
- sclorg_mails["nginx"] = get_env_variable("NGINX_MAILS").split(",")
+ db_mails = get_env_variable("DB_EMAILS")
+ sclorg_mails["mariadb"] = db_mails
+ sclorg_mails["mysql"] = db_mails
+ sclorg_mails["postgresql"] = db_mails
+ sclorg_mails["ruby"] = get_env_variable("RUBY_EMAILS")
+ sclorg_mails["python"] = get_env_variable("PYTHON_EMAILS")
+ sclorg_mails["nodejs"] = get_env_variable("NODEJS_EMAILS")
+ sclorg_mails["perl"] = get_env_variable("PERL_EMAILS")
+ sclorg_mails["php"] = get_env_variable("PHP_EMAILS")
+ sclorg_mails["redis"] = get_env_variable("REDIS_EMAILS")
+ sclorg_mails["varnish"] = get_env_variable("VARNISH_EMAILS")
+ sclorg_mails["valkey"] = get_env_variable("VALKEY_EMAILS")
+ sclorg_mails["httpd"] = get_env_variable("HTTPD_EMAILS")
+ sclorg_mails["nginx"] = get_env_variable("NGINX_EMAILS")
+ logger.debug("SCLorg mails: '%s'", sclorg_mails)
return sclorg_mails
diff --git a/eol-checker/tests/test_checker.py b/eol-checker/tests/test_checker.py
index aa8d59a..fd53518 100644
--- a/eol-checker/tests/test_checker.py
+++ b/eol-checker/tests/test_checker.py
@@ -32,18 +32,22 @@ def _container_struct(name, enddate):
def test_init_defaults(monkeypatch):
- monkeypatch.delenv("DEFAULT_EMAILS", raising=False)
+ monkeypatch.setenv("DEFAULT_EMAILS", "default@redhat.com")
+ monkeypatch.delenv("DEBUG", raising=False)
+ monkeypatch.delenv("SEND_EMAIL", raising=False)
instance = ContainerEolChecker()
assert instance.today == date.today()
assert instance.send_email is False
assert instance.end_line == "\n"
assert instance.bold_line == ""
+ assert instance.default_mails == ["default@redhat.com"]
assert instance.eol_images == {}
assert instance.body == ""
-def test_init_send_email_formatting():
+def test_init_send_email_formatting(monkeypatch):
+ monkeypatch.setenv("DEFAULT_EMAILS", "default@redhat.com")
instance = ContainerEolChecker(send_email=True)
assert instance.end_line == "
"
@@ -128,22 +132,31 @@ def test_analyze_lifecycle_yaml_processes_all_lifecycles(checker_with_os_context
)
-def test_get_jira_msg_when_jira_unavailable(checker):
- flexmock(checker.jira_fetcher).should_receive("jira").and_return(None)
-
+def test_get_jira_msg_without_filed_ticket(checker):
message = checker._get_jira_msg("reached EOL", "20250501")
assert "reached EOL in 20250501" in message
- assert "Connection to Jira not available" in message
-
+ assert "Jira ticket is not filled" in message
+ assert f"{JIRA_URL}/browse/{JIRA_DEPRECATION_TICKET}" in message
-def test_get_jira_msg_when_jira_available(checker):
- flexmock(checker.jira_fetcher).should_receive("jira").and_return(flexmock())
- message = checker._get_jira_msg("approaching EOL", "20250601")
+def test_get_jira_msg_with_filed_ticket(checker):
+ message = checker._get_jira_msg("approaching EOL", "20250601", jira_id="RHELMISC-999")
assert "approaching EOL in 20250601" in message
- assert "Jira ticket is not filled" in message
+ assert "Jira ticket is already filed" in message
+ assert f"{JIRA_URL}/browse/RHELMISC-999" in message
+
+
+def test_get_jira_msg_html_links_when_sending_email(checker):
+ checker.send_email = True
+ checker.bold_line = ""
+ checker.bold_line_end = ""
+
+ message = checker._get_jira_msg("reached EOL", "20250501")
+
+ assert "