This is an automated email from the ASF dual-hosted git repository.

sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-release.git


The following commit(s) were added to refs/heads/main by this push:
     new 24a3c90  Restore the information about a vote thread
24a3c90 is described below

commit 24a3c90f0895b771123c818ee3bfbb90e7c20f44
Author: Sean B. Palmer <[email protected]>
AuthorDate: Mon May 5 17:02:49 2025 +0100

    Restore the information about a vote thread
---
 atr/routes/compose.py                             |  4 ++
 atr/routes/resolve.py                             | 51 ------------------
 atr/routes/vote.py                                | 65 ++++++++++++++++++++++-
 atr/templates/check-selected-candidate-forms.html |  3 ++
 atr/templates/check-selected-vote-email.html      | 45 ++++++++++++++++
 5 files changed, 116 insertions(+), 52 deletions(-)

diff --git a/atr/routes/compose.py b/atr/routes/compose.py
index 5dc69fe..95822ee 100644
--- a/atr/routes/compose.py
+++ b/atr/routes/compose.py
@@ -38,6 +38,8 @@ async def check(
     release: models.Release,
     task_mid: str | None = None,
     form: wtforms.Form | None = None,
+    archive_url: str | None = None,
+    vote_task: models.Task | None = None,
 ) -> response.Response | str:
     base_path = util.release_directory(release)
 
@@ -82,6 +84,8 @@ async def check(
         task_mid=task_mid,
         form=form,
         resolve_form=resolve_form,
+        vote_task=vote_task,
+        archive_url=archive_url,
     )
 
 
diff --git a/atr/routes/resolve.py b/atr/routes/resolve.py
index 87eedfc..07b3041 100644
--- a/atr/routes/resolve.py
+++ b/atr/routes/resolve.py
@@ -16,10 +16,7 @@
 # under the License.
 
 import json
-import logging
-import os
 
-import httpx
 import quart
 import werkzeug.wrappers.response as response
 import wtforms
@@ -207,51 +204,3 @@ async def _send_resolution(
         await data.flush()
         await data.commit()
     return None
-
-
-async def _task_archive_url(task_mid: str) -> str | None:
-    if "@" not in task_mid:
-        return None
-
-    # TODO: This List ID will be dynamic when we allow posting to arbitrary 
lists
-    lid = "user-tests.tooling.apache.org"
-    url = 
f"https://lists.apache.org/api/email.lua?id=%3C{task_mid}%3E&listid=%3C{lid}%3E";
-    try:
-        async with httpx.AsyncClient() as client:
-            response = await client.get(url)
-        response.raise_for_status()
-        email_data = response.json()
-        mid = email_data["mid"]
-        if not isinstance(mid, str):
-            return None
-        return "https://lists.apache.org/thread/"; + mid
-    except Exception:
-        logging.exception("Failed to get archive URL for task %s", task_mid)
-        return None
-
-
-async def _task_archive_url_cached(task_mid: str | None) -> str | None:
-    if "LOCAL_DEBUG" in os.environ:
-        return 
"https://lists.apache.org/thread/619hn4x796mh3hkk3kxg1xnl48dy2s64";
-    if task_mid is None:
-        return None
-    if "@" not in task_mid:
-        return None
-
-    async with db.session() as data:
-        url = await data.ns_text_get(
-            "mid-url-cache",
-            task_mid,
-        )
-        if url is not None:
-            return url
-
-    url = await _task_archive_url(task_mid)
-    if url is not None:
-        await data.ns_text_set(
-            "mid-url-cache",
-            task_mid,
-            url,
-        )
-
-    return url
diff --git a/atr/routes/vote.py b/atr/routes/vote.py
index 540af6e..3928b38 100644
--- a/atr/routes/vote.py
+++ b/atr/routes/vote.py
@@ -15,6 +15,11 @@
 # specific language governing permissions and limitations
 # under the License.
 
+import json
+import logging
+import os
+
+import httpx
 import quart
 import werkzeug.wrappers.response as response
 import wtforms
@@ -49,12 +54,22 @@ async def selected(session: routes.CommitterSession, 
project_name: str, version_
         project_name, version_name, with_committee=True, with_tasks=True, 
phase=models.ReleasePhase.RELEASE_CANDIDATE
     )
     latest_vote_task = resolve.release_latest_vote_task(release)
+    archive_url = None
     task_mid = None
     if latest_vote_task is not None:
+        # Move task_mid_get here?
         task_mid = resolve.task_mid_get(latest_vote_task)
+        archive_url = await _task_archive_url_cached(task_mid)
+
+    if ("LOCAL_DEBUG" in os.environ) and (latest_vote_task is not None):
+        logging.warning("LOCAL_DEBUG: Setting vote task to completed")
+        latest_vote_task.status = models.TaskStatus.COMPLETED
+        latest_vote_task.result = [json.dumps({"mid": 
"[email protected]"})]
 
     form = await CastVoteForm.create_form()
-    return await compose.check(session, release, task_mid=task_mid, form=form)
+    return await compose.check(
+        session, release, task_mid=task_mid, form=form, 
archive_url=archive_url, vote_task=latest_vote_task
+    )
 
 
 @routes.committer("/vote/<project_name>/<version_name>", methods=["POST"])
@@ -135,3 +150,51 @@ async def _send_vote(
         await data.commit()
 
     return email_recipient, ""
+
+
+async def _task_archive_url(task_mid: str) -> str | None:
+    if "@" not in task_mid:
+        return None
+
+    # TODO: This List ID will be dynamic when we allow posting to arbitrary 
lists
+    lid = "user-tests.tooling.apache.org"
+    url = 
f"https://lists.apache.org/api/email.lua?id=%3C{task_mid}%3E&listid=%3C{lid}%3E";
+    try:
+        async with httpx.AsyncClient() as client:
+            response = await client.get(url)
+        response.raise_for_status()
+        email_data = response.json()
+        mid = email_data["mid"]
+        if not isinstance(mid, str):
+            return None
+        return "https://lists.apache.org/thread/"; + mid
+    except Exception:
+        logging.exception("Failed to get archive URL for task %s", task_mid)
+        return None
+
+
+async def _task_archive_url_cached(task_mid: str | None) -> str | None:
+    if "LOCAL_DEBUG" in os.environ:
+        return 
"https://lists.apache.org/thread/619hn4x796mh3hkk3kxg1xnl48dy2s64";
+    if task_mid is None:
+        return None
+    if "@" not in task_mid:
+        return None
+
+    async with db.session() as data:
+        url = await data.ns_text_get(
+            "mid-url-cache",
+            task_mid,
+        )
+        if url is not None:
+            return url
+
+    url = await _task_archive_url(task_mid)
+    if url is not None:
+        await data.ns_text_set(
+            "mid-url-cache",
+            task_mid,
+            url,
+        )
+
+    return url
diff --git a/atr/templates/check-selected-candidate-forms.html 
b/atr/templates/check-selected-candidate-forms.html
index edc2fc2..f7e0848 100644
--- a/atr/templates/check-selected-candidate-forms.html
+++ b/atr/templates/check-selected-candidate-forms.html
@@ -6,6 +6,9 @@
     <strong>TODO:</strong> We plan to make "Binding" dynamic based on 
membership. Currently this form always says "Binding" which is known to be 
wrong.
   </div>
 </div>
+
+{% include "check-selected-vote-email.html" %}
+
 <form method="post"
       action="{{ as_url(routes.vote.selected_post, project_name=project_name, 
version_name=version_name) }}"
       class="atr-canary py-4 px-5 mb-4 border rounded">
diff --git a/atr/templates/check-selected-vote-email.html 
b/atr/templates/check-selected-vote-email.html
new file mode 100644
index 0000000..dfd01e6
--- /dev/null
+++ b/atr/templates/check-selected-vote-email.html
@@ -0,0 +1,45 @@
+
+<div class="p-3 border rounded bg-white mb-3">
+  {% if vote_task %}
+    {% if vote_task.status.value == "completed" %}
+      <p class="mb-0 text-success fw-semibold">
+        <i class="bi bi-check-circle me-1"></i> Vote thread started: {{ 
format_datetime(vote_task.completed) }}
+      </p>
+      {% if task_mid %}
+        <p class="mt-2 mb-0 text-muted ps-4">
+          Message-ID: <code class="user-select-all">{{ task_mid }}</code>
+        </p>
+      {% endif %}
+    {% elif vote_task.status.value == "failed" %}
+      <p class="mb-1 text-danger fw-semibold">
+        <i class="bi bi-x-circle me-1"></i> Vote thread failed: {{ 
format_datetime(vote_task.completed) }}
+      </p>
+      <div class="alert alert-danger mt-2 mb-0 p-2" role="alert">
+        <p class="mb-0 p-2 text-danger">{{ vote_task.error }}</p>
+      </div>
+    {% else %}
+      <p class="mb-0 text-warning fw-semibold">
+        <i class="bi bi-hourglass-split me-1"></i> Vote thread task status: {{ 
vote_task.status.value.upper() }}
+        {% if vote_task.started %}
+          (Started: {{ format_datetime(vote_task.started) }})
+        {% else %}
+          (Added: {{ format_datetime(vote_task.added) }})
+        {% endif %}
+      </p>
+    {% endif %}
+    {% if archive_url %}
+      <p class="mt-2 mb-0 text-muted ps-4">
+        <a href="{{ archive_url }}"
+           rel="noopener"
+           target="_blank"
+           title="View vote email thread in the archive (opens in new 
window)">View vote email thread in the archive <i class="bi 
bi-box-arrow-up-right ms-1"></i></a>
+      </p>
+    {% elif task_mid %}
+      <p class="mt-2 mb-0 text-muted ps-4">Could not retrieve archive URL for 
this message.</p>
+    {% endif %}
+  {% else %}
+    <p class="mb-0 text-muted">
+      <i class="bi bi-question-circle me-1"></i> Vote email: No vote 
initiation task found for this release.
+    </p>
+  {% endif %}
+</div>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to