Skip to content

Fix sending mail about EOL status.#234

Merged
phracek merged 1 commit into
masterfrom
fix_sending_email_openshift
Jun 3, 2026
Merged

Fix sending mail about EOL status.#234
phracek merged 1 commit into
masterfrom
fix_sending_email_openshift

Conversation

@phracek
Copy link
Copy Markdown
Member

@phracek phracek commented Jun 3, 2026

Several typos fixed.

Also added information in case EOL ticket is present

Summary by CodeRabbit

  • New Features

    • Added Python 3.14 support.
    • Expanded allowed Jira statuses.
  • Bug Fixes

    • Improved email recipient configuration handling.
    • Enhanced Jira integration with updated ticket tracking logic.
  • Documentation

    • Added docstrings to logging components.
  • Chores

    • Updated container image versions to 0.10.5 across workflows and build configurations.
  • Tests

    • Expanded test coverage for Jira messaging, email sending, and configuration handling.

Several typos fixed.

Also added information in case EOL ticket is present

Signed-off-by: Petr "Stone" Hracek <phracek@redhat.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR bumps the container image version from 0.10.4 to 0.10.5 and refactors the eol-checker module to improve environment variable handling, fix Jira terminology ("filled" → "filed"), extend the Jira message method signature, and expand test coverage to validate the updated behavior.

Changes

Container Release and Jira Integration Refactoring

Layer / File(s) Summary
Version Bump and Cleanup
.github/workflows/build-and-push.yml, Dockerfile.daily-tests, Dockerfile.eol-checker, Makefile, eol-checker/eol-checker
Tag version updated from 0.10.4 to 0.10.5 in GitHub workflow, both Dockerfiles, and Makefile build targets; debug print of arguments removed from main script.
Environment Variable and Configuration Updates
eol-checker/eol_checker/constants.py, eol-checker/eol_checker/utils.py
ALLOWED_STATUSES extended with "New" status; CONTAINER_NAMES extended with "python314"; get_env_variable refactored to return List[str] and split comma-separated values; load_mails_from_environment updated to use *_EMAILS environment variable names and new list-returning utility.
Checker Initialization with Environment Handling
eol-checker/eol_checker/checker.py
get_env_variable import removed; ContainerEolChecker.__init__ updated to read DEBUG and DEFAULT_EMAILS directly via os.getenv() and split emails inline.
Jira Integration Refactoring and Terminology Fix
eol-checker/eol_checker/checker.py, eol-checker/eol_checker/jira.py
_get_jira_msg method signature extended with optional jira_id parameter; summary_for_images logic refactored to obtain container-specific Jira IDs via is_jira_filed_for_container() and build dynamic email recipient lists by prefix matching; is_jira_filled_for_container renamed to is_jira_filed_for_container with expanded docstring and debug logging; run method updated to call corrected method name.
Email Sending and Orchestration Updates
eol-checker/eol_checker/checker.py
send_emails now reads SMTP_SERVER and SMTP_PORT via os.getenv, sets MIME To header using comma-joined recipients; run logs vars(self) before Jira operations.
Documentation Enhancements
eol-checker/eol_checker/custom_logger.py
Docstrings added to ColoredFormatter class and setup_logger function describing purpose, parameters, and return values.
Comprehensive Test Suite Updates
eol-checker/tests/test_utils.py, eol-checker/tests/test_checker.py, eol-checker/tests/test_jira.py
New tests added for comma-separated environment variable parsing and mail loading from environment; Jira message tests refactored to cover "ticket filed" vs "not filed" scenarios with HTML link validation; email tests updated to use monkeypatch for SMTP configuration; test function names corrected to reflect "filed" terminology; new test for Jira unavailability edge case; extended initialization test assertions for default_mails.

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly Related PRs

  • sclorg/ci-scripts#231: Introduced Dockerfile.eol-checker and restructured ContainerEolChecker initialization; this PR continues the refactoring of those same files with additional method signature updates and logic changes.

  • sclorg/ci-scripts#228: Initially added the eol-checker module; this PR directly refactors the same core modules (checker.py, constants.py, jira.py, utils.py, custom_logger.py) with extended signatures and improved test coverage.

  • sclorg/ci-scripts#229: Introduced email-sending and Jira integration functionality; this PR extends and refines those features with the _get_jira_msg() signature update and terminology correction from "filled" to "filed".

Poem

🐰 A rabbit hops through versions, bumping high—
From 0.10.4 to .5, reaching for the sky!
Jira "filed" now (no longer "filled" with grace),
Email lists and env vars find their place.
Tests abound to validate each refined trace! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.58% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Fix sending mail about EOL status' directly aligns with the main changes: correcting email sending logic, adding Jira ticket information to reports, and fixing typos in the email-related code.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix_sending_email_openshift

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
eol-checker/tests/test_checker.py (1)

208-221: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Test does not catch the empty-string recipient added by summary_for_images.

eol_sme_mails = {"nodejs": ["sme@redhat.com", ""]} exercises the path that appends "" into default_mails (see checker.py Lines 193-201). The assertions only check "sme@redhat.com" in default_mails and the default@redhat.com count, so the spurious empty recipient goes unnoticed. Once the dedup fix is applied, consider asserting "" not in checker.default_mails.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@eol-checker/tests/test_checker.py` around lines 208 - 221, The test exposes
that summary_for_images is appending empty-string recipients from eol_sme_mails
into default_mails; update the implementation in summary_for_images to filter
out empty or falsy recipients (e.g., when extending/adding
eol_sme_mails["nodejs"] into default_mails) so only non-empty strings are
appended, and then update the test
(test_summary_for_images_adds_sme_mails_when_sending_email) to assert that ""
not in checker.default_mails in addition to the existing assertions; reference
summary_for_images, eol_sme_mails, and default_mails to locate the change.
eol-checker/eol_checker/checker.py (1)

283-293: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

finally: smtp.close() can raise UnboundLocalError and mask the real error.

Only SMTPRecipientsRefused/SMTPException are caught, but SMTP(self.smtp_server, ...) can raise other errors (e.g. socket.gaierror, OSError) on connection failure. When the constructor raises, smtp is never bound, so the finally block dereferences an undefined name and throws UnboundLocalError, hiding the original exception.

🐛 Proposed fix
+        smtp = None
         try:
             smtp = SMTP(self.smtp_server, int(self.smtp_port))
             smtp.set_debuglevel(5)
             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:
             logger.error("Error sending email(SMTPException): %s", e)
         finally:
-            smtp.close()
+            if smtp is not None:
+                smtp.close()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@eol-checker/eol_checker/checker.py` around lines 283 - 293, The try/finally
can raise UnboundLocalError if SMTP(self.smtp_server, ...) fails because smtp is
never assigned; to fix, initialize smtp = None before the try (or use a context
manager with smtplib.SMTP) and in the finally block only call smtp.close() if
smtp is not None (or has been successfully created), ensuring the original
exception is not masked; update the block around the SMTP(...) construction, the
smtp variable, and the finally: smtp.close() to implement this guard.
🧹 Nitpick comments (2)
Dockerfile.eol-checker (1)

5-5: ⚡ Quick win

Remove duplicate HOME environment variable definition.

The HOME environment variable is defined twice with the same value (lines 5 and 9). Remove one of the duplicate definitions to improve clarity.

♻️ Proposed fix to remove duplicate
 ENV VERSION="42" \
     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." \
     NAME="eol-checker" \
     HOME="/home/eol-checker" \
     WORK_DIR="/home/nightly/ci-scripts"

Also applies to: 9-9

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Dockerfile.eol-checker` at line 5, The Dockerfile defines the HOME
environment variable twice; remove one of the duplicate ENV entries so
HOME="/home/eol-checker" appears only once. Locate the duplicate ENV definition
that sets HOME (the line containing HOME="/home/eol-checker") and delete the
redundant occurrence, ensuring any other ENV or RUN lines that depend on HOME
remain unchanged.
eol-checker/eol_checker/utils.py (1)

75-86: 💤 Low value

default_value is now a dead, misleading parameter.

After the return-type change, default_value can never affect the result: when var_name is set, os.getenv returns the real value; when it is unset, the function returns [] regardless. test_get_env_variable_returns_default_when_empty even passes "fallback@redhat.com" and asserts []. Consider dropping the parameter (and updating the one test call) to avoid implying a fallback that never happens.

♻️ Proposed simplification
-def get_env_variable(var_name: str, default_value: str = "") -> List[str]:
+def get_env_variable(var_name: str) -> List[str]:
     """
     Get environment variable value as a list, splitting on commas.
     :param var_name: Name of the environment variable
-    :param default_value: Default value to return if environment variable is not set
-    :return: Value of the environment variable or default value
+    :return: List of values, or an empty list if unset/empty
     """
-    if var_name in os.environ:
-        value = os.getenv(var_name, default_value)
-        if value:
-            return value.split(",")
-    return []
+    value = os.getenv(var_name, "")
+    return value.split(",") if value else []
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@eol-checker/eol_checker/utils.py` around lines 75 - 86, The function
get_env_variable currently has a misleading default_value parameter that never
affects the result; remove the default_value parameter from the signature
(change def get_env_variable(var_name: str, default_value: str = "") ->
List[str] to def get_env_variable(var_name: str) -> List[str]), keep the
implementation that returns env value.split(",") when var_name in os.environ and
[] otherwise, and update all call sites and the test
test_get_env_variable_returns_default_when_empty to stop passing the unused
fallback (assert expecting [] instead). Ensure references to get_env_variable
throughout the codebase and tests are updated to the new single-argument form.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@eol-checker/eol_checker/checker.py`:
- Around line 163-167: The message string uses "not filled" while the other
branch says "already filed"—change the not-filed branch to use "Jira ticket is
not filed. Use this template: " instead of "not filled"; update the logic around
jira_id, get_jira_ticket_url, url construction and the msg variable in
eol_checker/checker.py (the send_email branch using self.send_email remains the
same) and then update the user-facing assertions in tests (test_checker.py and
any test_summary_for_images_* files) to expect the corrected "filed" wording.
- Around line 193-201: The current aggregation builds mails as a list-of-lists
(from self.eol_sme_mails[group]) and then extends self.default_mails with whole
lists, which causes inner empty strings to be added and prevents per-address
deduplication; update the loop that builds/extends self.default_mails to iterate
each address in each mail list (for mail_list in mails: for addr in mail_list),
skip blank/empty addresses (addr.strip() == ""), and only append/extend unique
addresses (check addr not in self.default_mails) so self.default_mails becomes a
flat deduplicated list of strings.
- Line 73: The constructor currently calls
os.getenv("DEFAULT_EMAILS").split(",") which crashes when DEFAULT_EMAILS is
unset; update the initialization of self.default_mails in __init__ to read the
env var with a safe default (e.g. os.getenv("DEFAULT_EMAILS", "")), split on
commas, strip whitespace from each entry and filter out any empty strings so
self.default_mails is always a list (possibly empty); reference the existing
symbol self.default_mails to locate and replace the line.

---

Outside diff comments:
In `@eol-checker/eol_checker/checker.py`:
- Around line 283-293: The try/finally can raise UnboundLocalError if
SMTP(self.smtp_server, ...) fails because smtp is never assigned; to fix,
initialize smtp = None before the try (or use a context manager with
smtplib.SMTP) and in the finally block only call smtp.close() if smtp is not
None (or has been successfully created), ensuring the original exception is not
masked; update the block around the SMTP(...) construction, the smtp variable,
and the finally: smtp.close() to implement this guard.

In `@eol-checker/tests/test_checker.py`:
- Around line 208-221: The test exposes that summary_for_images is appending
empty-string recipients from eol_sme_mails into default_mails; update the
implementation in summary_for_images to filter out empty or falsy recipients
(e.g., when extending/adding eol_sme_mails["nodejs"] into default_mails) so only
non-empty strings are appended, and then update the test
(test_summary_for_images_adds_sme_mails_when_sending_email) to assert that ""
not in checker.default_mails in addition to the existing assertions; reference
summary_for_images, eol_sme_mails, and default_mails to locate the change.

---

Nitpick comments:
In `@Dockerfile.eol-checker`:
- Line 5: The Dockerfile defines the HOME environment variable twice; remove one
of the duplicate ENV entries so HOME="/home/eol-checker" appears only once.
Locate the duplicate ENV definition that sets HOME (the line containing
HOME="/home/eol-checker") and delete the redundant occurrence, ensuring any
other ENV or RUN lines that depend on HOME remain unchanged.

In `@eol-checker/eol_checker/utils.py`:
- Around line 75-86: The function get_env_variable currently has a misleading
default_value parameter that never affects the result; remove the default_value
parameter from the signature (change def get_env_variable(var_name: str,
default_value: str = "") -> List[str] to def get_env_variable(var_name: str) ->
List[str]), keep the implementation that returns env value.split(",") when
var_name in os.environ and [] otherwise, and update all call sites and the test
test_get_env_variable_returns_default_when_empty to stop passing the unused
fallback (assert expecting [] instead). Ensure references to get_env_variable
throughout the codebase and tests are updated to the new single-argument form.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7020ed95-59fc-4b2c-ad0a-c04565ab0ee5

📥 Commits

Reviewing files that changed from the base of the PR and between f46d21e and a57a280.

📒 Files selected for processing (13)
  • .github/workflows/build-and-push.yml
  • Dockerfile.daily-tests
  • Dockerfile.eol-checker
  • Makefile
  • eol-checker/eol-checker
  • eol-checker/eol_checker/checker.py
  • eol-checker/eol_checker/constants.py
  • eol-checker/eol_checker/custom_logger.py
  • eol-checker/eol_checker/jira.py
  • eol-checker/eol_checker/utils.py
  • eol-checker/tests/test_checker.py
  • eol-checker/tests/test_jira.py
  • eol-checker/tests/test_utils.py
💤 Files with no reviewable changes (1)
  • eol-checker/eol-checker

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(",")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Crash when DEFAULT_EMAILS is unset.

os.getenv("DEFAULT_EMAILS") returns None when the variable is missing, so .split(",") raises AttributeError and __init__ fails. The tests always set DEFAULT_EMAILS, masking this in CI, but the OpenShift CronJob will crash if it is not configured. Provide a default and drop empty entries.

🐛 Proposed fix
-        self.default_mails: List[str] = os.getenv("DEFAULT_EMAILS").split(",")
+        self.default_mails: List[str] = [
+            mail for mail in os.getenv("DEFAULT_EMAILS", "").split(",") if mail
+        ]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@eol-checker/eol_checker/checker.py` at line 73, The constructor currently
calls os.getenv("DEFAULT_EMAILS").split(",") which crashes when DEFAULT_EMAILS
is unset; update the initialization of self.default_mails in __init__ to read
the env var with a safe default (e.g. os.getenv("DEFAULT_EMAILS", "")), split on
commas, strip whitespace from each entry and filter out any empty strings so
self.default_mails is always a list (possibly empty); reference the existing
symbol self.default_mails to locate and replace the line.

Comment thread eol-checker/eol_checker/checker.py
Comment thread eol-checker/eol_checker/checker.py
@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 3, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 62.45%. Comparing base (f46d21e) to head (a57a280).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #234      +/-   ##
==========================================
+ Coverage   62.16%   62.45%   +0.28%     
==========================================
  Files          13       13              
  Lines        1348     1345       -3     
==========================================
+ Hits          838      840       +2     
+ Misses        510      505       -5     
Flag Coverage Δ
daily-tests-unit 44.26% <ø> (ø)
eol-checker-unit 97.34% <100.00%> (+1.43%) ⬆️
ocp-stream-generator-unit 84.47% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
eol-checker/eol_checker/checker.py 98.87% <100.00%> (-0.01%) ⬇️
eol-checker/eol_checker/constants.py 100.00% <100.00%> (ø)
eol-checker/eol_checker/custom_logger.py 100.00% <ø> (ø)
eol-checker/eol_checker/jira.py 95.31% <100.00%> (+3.37%) ⬆️
eol-checker/eol_checker/utils.py 100.00% <100.00%> (+6.25%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@phracek phracek merged commit 8eb633e into master Jun 3, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant