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]