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 a9223c4  Add a mechanism to distinguish between the two rounds of 
incubated voting
a9223c4 is described below

commit a9223c47e4db58fc51f88a119eb32f1314db8f55
Author: Sean B. Palmer <[email protected]>
AuthorDate: Mon Jun 30 17:05:09 2025 +0100

    Add a mechanism to distinguish between the two rounds of incubated voting
---
 atr/db/models.py                                |  1 +
 atr/routes/resolve.py                           | 35 ++++++++++-
 atr/routes/vote.py                              | 78 ++++++++++++-------------
 migrations/versions/0012_2025.06.30_f3240855.py | 27 +++++++++
 4 files changed, 99 insertions(+), 42 deletions(-)

diff --git a/atr/db/models.py b/atr/db/models.py
index 9a6874d..b026a30 100644
--- a/atr/db/models.py
+++ b/atr/db/models.py
@@ -631,6 +631,7 @@ class Release(sqlmodel.SQLModel, table=True):
 
     vote_started: datetime.datetime | None = sqlmodel.Field(default=None, 
sa_column=sqlalchemy.Column(UTCDateTime))
     vote_resolved: datetime.datetime | None = sqlmodel.Field(default=None, 
sa_column=sqlalchemy.Column(UTCDateTime))
+    podling_thread_id: str | None = sqlmodel.Field(default=None)
 
     revisions: list["Revision"] = sqlmodel.Relationship(
         back_populates="release",
diff --git a/atr/routes/resolve.py b/atr/routes/resolve.py
index 9748477..1a38ba9 100644
--- a/atr/routes/resolve.py
+++ b/atr/routes/resolve.py
@@ -68,7 +68,9 @@ async def selected_post(
         )
     email_body = util.unwrap(resolve_form.email_body.data)
     vote_result = util.unwrap(resolve_form.vote_result.data)
-    release, success_message = await _resolve_vote(session, project_name, 
version_name, vote_result, email_body)
+    release, success_message = await _resolve_vote(
+        session, project_name, version_name, vote_result, email_body, 
latest_vote_task
+    )
     destination = finish.selected if (vote_result == "passed") else 
compose.selected
     return await session.redirect(
         destination, project_name=project_name, version_name=version_name, 
success=success_message
@@ -101,7 +103,12 @@ def task_mid_get(latest_vote_task: models.Task) -> str | 
None:
 
 
 async def _resolve_vote(
-    session: routes.CommitterSession, project_name: str, version_name: str, 
vote_result: str, resolution_body: str
+    session: routes.CommitterSession,
+    project_name: str,
+    version_name: str,
+    vote_result: str,
+    resolution_body: str,
+    latest_vote_task: models.Task,
 ) -> tuple[models.Release, str]:
     # Check that the user has access to the project
     await session.check_access(project_name)
@@ -113,12 +120,34 @@ async def _resolve_vote(
                 project_name,
                 version_name,
                 with_project=True,
+                with_committee=True,
                 phase=models.ReleasePhase.RELEASE_CANDIDATE,
                 data=data,
             )
 
+            is_podling = False
+            if release.project.committee is not None:
+                is_podling = release.project.committee.is_podling
+            podling_thread_id = release.podling_thread_id
+
             # Update the release phase based on vote result
-            if vote_result == "passed":
+            if is_podling and (podling_thread_id is None) and (vote_result == 
"passed"):
+                # This is the first podling vote, by the PPMC and not the 
Incubator PMC
+                # In this branch, we do not move to RELEASE_PREVIEW but keep 
everything the same
+                # We only set the podling_thread_id to the thread_id of the 
vote thread
+                # Then we automatically start the Incubator PMC vote
+                # TODO: Note on the resolve vote page that resolving the 
Project PPMC vote starts the Incubator PMC vote
+                task_mid = task_mid_get(latest_vote_task)
+                archive_url = await vote.task_archive_url_cached(task_mid)
+                if archive_url is None:
+                    await quart.flash("No archive URL found for podling vote", 
"error")
+                    return release, "Failure"
+                thread_id = archive_url.split("/")[-1]
+                release.podling_thread_id = thread_id
+                # TODO: We need to start the Incubator PMC vote here
+                success_message = "Project PPMC vote marked as passed, and 
Incubator PMC vote automatically started"
+                raise NotImplementedError("Incubator PMC vote not implemented")
+            elif vote_result == "passed":
                 release.phase = models.ReleasePhase.RELEASE_PREVIEW
                 success_message = "Vote marked as passed"
 
diff --git a/atr/routes/vote.py b/atr/routes/vote.py
index 1c05ebf..8a7470c 100644
--- a/atr/routes/vote.py
+++ b/atr/routes/vote.py
@@ -109,7 +109,7 @@ async def selected(session: routes.CommitterSession, 
project_name: str, version_
 
         # Move task_mid_get here?
         task_mid = resolve.task_mid_get(latest_vote_task)
-        archive_url = await _task_archive_url_cached(task_mid)
+        archive_url = await task_archive_url_cached(task_mid)
 
     form = await CastVoteForm.create_form()
     hidden_form = await util.HiddenFieldForm.create_form()
@@ -223,6 +223,44 @@ async def tabulate(session: routes.CommitterSession, 
project_name: str, version_
     )
 
 
+async def task_archive_url_cached(task_mid: str | None) -> str | None:
+    dev_urls = {
+        "CAH5JyZo8QnWmg9CwRSwWY=givhxw4nilyenjo71fkdk81j5...@mail.gmail.com": 
"https://lists.apache.org/thread/z0o7xnjnyw2o886rxvvq2ql4rdfn754w";,
+        "[email protected]": 
"https://lists.apache.org/thread/619hn4x796mh3hkk3kxg1xnl48dy2s64";,
+        "CAA9ykM+bMPNk=bof9hj0o+mjn1igppoj+pkdzhcam0ddvi+...@mail.gmail.com": 
"https://lists.apache.org/thread/x0m3p2xqjvflgtkb6oxqysm36cr9l5mg";,
+        "CAFHDsVzgtfboqYF+a3owaNf+55MUiENWd3g53mU4rD=whkx...@mail.gmail.com": 
"https://lists.apache.org/thread/brj0k3g8pq63g8f7xhmfg2rbt1240nts";,
+        "camomwmrvktqk7k2-otztreo0jjxzo2g5ynw3gsoks_pxwpz...@mail.gmail.com": 
"https://lists.apache.org/thread/y5rqp5qk6dmo08wlc3g20n862hznc9m8";,
+        "CANVKqzfLYj6TAVP_Sfsy5vFbreyhKskpRY-vs=f7aled+rl...@mail.gmail.com": 
"https://lists.apache.org/thread/oy969lhh6wlzd51ovckn8fly9rvpopwh";,
+        "cah4123zwgtkwszheu7qnmbyla-yvykz2w+djh_uchpmuzaa...@mail.gmail.com": 
"https://lists.apache.org/thread/7111mqyc25sfqxm6bf4ynwhs0bk0r4ys";,
+        "CADL1oArKFcXvNb1MJfjN=10-yrfkxgpltrurdmm1r7ygatk...@mail.gmail.com": 
"https://lists.apache.org/thread/d7119h2qm7jrd5zsbp8ghkk0lpvnnxnw";,
+    }
+    if task_mid in dev_urls:
+        return dev_urls[task_mid]
+
+    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
+
+
 async def _send_vote(
     session: routes.CommitterSession,
     release: models.Release,
@@ -620,41 +658,3 @@ async def _task_archive_url(task_mid: str) -> str | None:
     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:
-    dev_urls = {
-        "CAH5JyZo8QnWmg9CwRSwWY=givhxw4nilyenjo71fkdk81j5...@mail.gmail.com": 
"https://lists.apache.org/thread/z0o7xnjnyw2o886rxvvq2ql4rdfn754w";,
-        "[email protected]": 
"https://lists.apache.org/thread/619hn4x796mh3hkk3kxg1xnl48dy2s64";,
-        "CAA9ykM+bMPNk=bof9hj0o+mjn1igppoj+pkdzhcam0ddvi+...@mail.gmail.com": 
"https://lists.apache.org/thread/x0m3p2xqjvflgtkb6oxqysm36cr9l5mg";,
-        "CAFHDsVzgtfboqYF+a3owaNf+55MUiENWd3g53mU4rD=whkx...@mail.gmail.com": 
"https://lists.apache.org/thread/brj0k3g8pq63g8f7xhmfg2rbt1240nts";,
-        "camomwmrvktqk7k2-otztreo0jjxzo2g5ynw3gsoks_pxwpz...@mail.gmail.com": 
"https://lists.apache.org/thread/y5rqp5qk6dmo08wlc3g20n862hznc9m8";,
-        "CANVKqzfLYj6TAVP_Sfsy5vFbreyhKskpRY-vs=f7aled+rl...@mail.gmail.com": 
"https://lists.apache.org/thread/oy969lhh6wlzd51ovckn8fly9rvpopwh";,
-        "cah4123zwgtkwszheu7qnmbyla-yvykz2w+djh_uchpmuzaa...@mail.gmail.com": 
"https://lists.apache.org/thread/7111mqyc25sfqxm6bf4ynwhs0bk0r4ys";,
-        "CADL1oArKFcXvNb1MJfjN=10-yrfkxgpltrurdmm1r7ygatk...@mail.gmail.com": 
"https://lists.apache.org/thread/d7119h2qm7jrd5zsbp8ghkk0lpvnnxnw";,
-    }
-    if task_mid in dev_urls:
-        return dev_urls[task_mid]
-
-    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/migrations/versions/0012_2025.06.30_f3240855.py 
b/migrations/versions/0012_2025.06.30_f3240855.py
new file mode 100644
index 0000000..74a94b5
--- /dev/null
+++ b/migrations/versions/0012_2025.06.30_f3240855.py
@@ -0,0 +1,27 @@
+"""Add podling thread ID to releases
+
+Revision ID: 0012_2025.06.30_f3240855
+Revises: 0011_2025.06.20_b1fa791d
+Create Date: 2025-06-30 15:56:26.123627+00:00
+"""
+
+from collections.abc import Sequence
+
+import sqlalchemy as sa
+from alembic import op
+
+# Revision identifiers, used by Alembic
+revision: str = "0012_2025.06.30_f3240855"
+down_revision: str | None = "0011_2025.06.20_b1fa791d"
+branch_labels: str | Sequence[str] | None = None
+depends_on: str | Sequence[str] | None = None
+
+
+def upgrade() -> None:
+    with op.batch_alter_table("release", schema=None) as batch_op:
+        batch_op.add_column(sa.Column("podling_thread_id", sa.String(), 
nullable=True))
+
+
+def downgrade() -> None:
+    with op.batch_alter_table("release", schema=None) as batch_op:
+        batch_op.drop_column("podling_thread_id")


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

Reply via email to