This is an automated email from the ASF dual-hosted git repository. arm pushed a commit to branch arm in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git
commit 13448a2ec06d7724cae3253986d22b1a03577efe Author: Alastair McFarlane <[email protected]> AuthorDate: Fri Mar 13 15:29:20 2026 +0000 #870 - Get email from CC if sent from external domain via mailing list and include name in tabulated votes --- atr/models/tabulate.py | 2 ++ atr/tabulate.py | 29 +++++++++++++++++++++-------- atr/templates/resolve-tabulated.html | 18 ++++++++++-------- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/atr/models/tabulate.py b/atr/models/tabulate.py index da6fac30..6790ce13 100644 --- a/atr/models/tabulate.py +++ b/atr/models/tabulate.py @@ -37,6 +37,7 @@ class VoteStatus(enum.Enum): class VoteEmail(schema.Strict): + name: str = schema.example("Example User") asf_uid_or_email: str = schema.example("user") from_email: str = schema.example("[email protected]") status: VoteStatus = schema.example(VoteStatus.BINDING) @@ -62,6 +63,7 @@ class VoteDetails(schema.Strict): votes: dict[str, VoteEmail] = schema.example( { "user": VoteEmail( + name="Example User", asf_uid_or_email="user", from_email="[email protected]", status=VoteStatus.BINDING, diff --git a/atr/tabulate.py b/atr/tabulate.py index 2030437a..597439d0 100644 --- a/atr/tabulate.py +++ b/atr/tabulate.py @@ -155,18 +155,19 @@ async def votes( # noqa: C901 tabulated_votes = {} start_unixtime = None message_count = 0 - async for _mid, msg in util.thread_messages(thread_id): + async for mid, msg in util.thread_messages(thread_id): message_count += 1 if message_count > MAX_THREAD_MESSAGES: raise ValueError(f"Thread exceeds maximum of {MAX_THREAD_MESSAGES} messages") from_raw = msg.get("from_raw", "") - ok, from_email_lower, asf_uid = _vote_identity(from_raw, email_to_uid) + list_raw = msg.get("list_raw", "") + cc = msg.get("cc", "").split(",\n") + ok, name, from_email_lower, asf_uid = _vote_identity(from_raw, email_to_uid, list_raw, cc) if not ok: continue if asf_uid is not None: asf_uid_or_email = asf_uid - list_raw = msg.get("list_raw", "") status = await _vote_status(asf_uid, list_raw, committee) else: asf_uid_or_email = from_email_lower @@ -196,6 +197,7 @@ async def votes( # noqa: C901 quotation = " // ".join([c[1] for c in castings]) vote_email = models.tabulate.VoteEmail( + name=name, asf_uid_or_email=asf_uid_or_email, from_email=from_email_lower, status=status, @@ -289,17 +291,28 @@ def _vote_continue(line: str) -> bool: return False -def _vote_identity(from_raw: str, email_to_uid: dict[str, str]) -> tuple[bool, str, str | None]: +def _vote_identity( + from_raw: str, email_to_uid: dict[str, str], list_email: str, cc: list[str] +) -> tuple[bool, str, str, str | None]: from_email_lower = util.email_from_uid(from_raw) if not from_email_lower: - return False, "", None + return False, "", "", None + name = "" from_email_lower = from_email_lower.removesuffix(".invalid") asf_uid = None if from_email_lower.endswith("@apache.org"): + name = "-" asf_uid = from_email_lower.split("@")[0] - elif from_email_lower in email_to_uid: - asf_uid = email_to_uid[from_email_lower] - return True, from_email_lower, asf_uid + else: + if "via" in from_raw and from_email_lower.replace("@", ".") in list_email: + # Take the last CC, appended by ezmlm, and use that as the email. Otherwise, use their name + name = from_raw[: from_raw.index("via") - 1] + if cc: + from_email_lower = util.email_from_uid(cc[-1]) or from_email_lower + if from_email_lower in email_to_uid: + asf_uid = email_to_uid[from_email_lower] + + return True, name, from_email_lower, asf_uid def _vote_outcome_format( diff --git a/atr/templates/resolve-tabulated.html b/atr/templates/resolve-tabulated.html index 843d72c6..56b4a0f1 100644 --- a/atr/templates/resolve-tabulated.html +++ b/atr/templates/resolve-tabulated.html @@ -27,6 +27,7 @@ <thead> <tr> <th>ASF UID or email</th> + <th>Name</th> <th class="text-center">Vote</th> <th class="text-center">Status</th> <th class="text-center">Link</th> @@ -34,20 +35,21 @@ </tr> </thead> <tbody> - {% for asf_uid, vote_email in tabulated_votes.items() %} + {% for asf_uid, vote_detail in tabulated_votes.items() %} <tr> - <td class="atr-nowrap">{{ vote_email.asf_uid_or_email }}</td> - <td class="atr-nowrap text-center {% if vote_email.status.value == 'Binding' %}fw-bold{% endif %} {% if vote_email.vote.value == 'Yes' %}atr-green{% elif vote_email.vote.value == 'No' %}atr-red{% endif %}"> - {{ vote_email.vote.value }} + <td class="atr-nowrap">{{ vote_detail.asf_uid_or_email }}</td> + <td class="atr-nowrap">{{ vote_detail.name }}</td> + <td class="atr-nowrap text-center {% if vote_detail.status.value == 'Binding' %}fw-bold{% endif %} {% if vote_detail.vote.value == 'Yes' %}atr-green{% elif vote_detail.vote.value == 'No' %}atr-red{% endif %}"> + {{ vote_detail.vote.value }} </td> - <td class="atr-nowrap text-center {% if vote_email.status.value == 'Binding' %}fw-bold{% endif %}"> - {{ vote_email.status.value }} + <td class="atr-nowrap text-center {% if vote_detail.status.value == 'Binding' %}fw-bold{% endif %}"> + {{ vote_detail.status.value }} </td> <td class="atr-nowrap text-center"> - <a href="https://lists.apache.org/thread/{{ vote_email.asf_eid }}" + <a href="https://lists.apache.org/thread/{{ vote_detail.asf_eid }}" target="_blank">Email</a> </td> - <td>{{ vote_email.quotation }}</td> + <td>{{ vote_detail.quotation }}</td> </tr> {% endfor %} </tbody> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
