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 be99d8a Make the vote resolution interface easier to use in the API
be99d8a is described below
commit be99d8a1a468232451005037e3f8ddd0217534d9
Author: Sean B. Palmer <[email protected]>
AuthorDate: Fri Sep 5 17:09:26 2025 +0100
Make the vote resolution interface easier to use in the API
---
atr/routes/resolve.py | 31 ++++---------------------------
atr/storage/__init__.py | 9 +++++++++
atr/storage/writers/vote.py | 44 ++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 55 insertions(+), 29 deletions(-)
diff --git a/atr/routes/resolve.py b/atr/routes/resolve.py
index 95eeb5c..bb9a864 100644
--- a/atr/routes/resolve.py
+++ b/atr/routes/resolve.py
@@ -20,7 +20,6 @@ import quart
import werkzeug.wrappers.response as response
import atr.db as db
-import atr.db.interaction as interaction
import atr.forms as forms
import atr.models.sql as sql
import atr.revision as revision
@@ -144,22 +143,6 @@ async def submit_selected(
"""Resolve a vote."""
await session.check_access(project_name)
- release = await session.release(
- project_name,
- version_name,
- with_project=True,
- with_committee=True,
- phase=sql.ReleasePhase.RELEASE_CANDIDATE,
- )
-
- is_podling = False
- if release.project.committee is not None:
- is_podling = release.project.committee.is_podling
- podling_thread_id = release.podling_thread_id
-
- latest_vote_task = await interaction.release_latest_vote_task(release)
- if latest_vote_task is None:
- raise RuntimeError("No vote task found, unable to send resolution
message.")
resolve_form = await ResolveVoteForm.create_form()
if not (await resolve_form.validate_on_submit()):
# TODO: Render the page again with errors
@@ -171,18 +154,12 @@ async def submit_selected(
)
email_body = util.unwrap(resolve_form.email_body.data)
vote_result = util.unwrap(resolve_form.vote_result.data)
- voting_round = None
- if is_podling is True:
- voting_round = 1 if (podling_thread_id is None) else 2
- if release.committee is None:
- raise ValueError("Project has no committee")
- async with storage.write_as_committee_member(release.committee.name) as
wacm:
- release, success_message, error_message = await wacm.vote.resolve(
+
+ async with storage.write_as_project_committee_member(project_name) as wacm:
+ _release, voting_round, success_message, error_message = await
wacm.vote.resolve(
project_name,
- release,
- voting_round,
+ version_name,
vote_result,
- latest_vote_task,
session.fullname,
email_body,
)
diff --git a/atr/storage/__init__.py b/atr/storage/__init__.py
index 947b001..4032a18 100644
--- a/atr/storage/__init__.py
+++ b/atr/storage/__init__.py
@@ -376,3 +376,12 @@ async def write_as_committee_member(
) -> AsyncGenerator[WriteAsCommitteeMember]:
async with write(asf_uid) as w:
yield w.as_committee_member(committee_name)
+
+
[email protected]
+async def write_as_project_committee_member(
+ project_name: str,
+ asf_uid: str | None | ArgumentNoneType = ArgumentNone,
+) -> AsyncGenerator[WriteAsCommitteeMember]:
+ async with write(asf_uid) as w:
+ yield await w.as_project_committee_member(project_name)
diff --git a/atr/storage/writers/vote.py b/atr/storage/writers/vote.py
index aa0119e..d90fbea 100644
--- a/atr/storage/writers/vote.py
+++ b/atr/storage/writers/vote.py
@@ -96,6 +96,46 @@ class CommitteeMember(CommitteeParticipant):
self.__committee_name = committee_name
async def resolve(
+ self,
+ project_name: str,
+ version_name: str,
+ vote_result: Literal["passed", "failed"],
+ asf_fullname: str,
+ resolution_body: str,
+ ) -> tuple[sql.Release, int | None, str, str | None]:
+ release = await self.__data.release(
+ name=sql.release_name(project_name, version_name),
+ phase=sql.ReleasePhase.RELEASE_CANDIDATE,
+ _project=True,
+ _committee=True,
+ ).demand(storage.AccessError("Release not found"))
+
+ is_podling = False
+ if release.project.committee is not None:
+ is_podling = release.project.committee.is_podling
+ podling_thread_id = release.podling_thread_id
+
+ latest_vote_task = await interaction.release_latest_vote_task(release)
+ if latest_vote_task is None:
+ raise RuntimeError("No vote task found, unable to send resolution
message.")
+
+ voting_round = None
+ if is_podling is True:
+ voting_round = 1 if (podling_thread_id is None) else 2
+ if release.committee is None:
+ raise ValueError("Project has no committee")
+
+ return await self.resolve_release(
+ project_name,
+ release,
+ voting_round,
+ vote_result,
+ latest_vote_task,
+ asf_fullname,
+ resolution_body,
+ )
+
+ async def resolve_release(
self,
project_name: str,
release: sql.Release,
@@ -104,7 +144,7 @@ class CommitteeMember(CommitteeParticipant):
latest_vote_task: sql.Task,
asf_fullname: str,
resolution_body: str,
- ) -> tuple[sql.Release, str, str | None]:
+ ) -> tuple[sql.Release, int | None, str, str | None]:
# Attach the existing release to the session
release = await self.__data.merge(release)
# Update the release phase based on vote result
@@ -170,7 +210,7 @@ class CommitteeMember(CommitteeParticipant):
asf_fullname=asf_fullname,
extra_destination=extra_destination,
)
- return release, success_message, error_message
+ return release, voting_round, success_message, error_message
async def resolve_api(self, project_name: str, version_name: str,
resolution: Literal["passed", "failed"]) -> None:
release_name = sql.release_name(project_name, version_name)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]