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-releases.git


The following commit(s) were added to refs/heads/main by this push:
     new 82abb2b  Move release validation code to the interaction module
82abb2b is described below

commit 82abb2b1156263c969cc15465697bde128b4483b
Author: Sean B. Palmer <[email protected]>
AuthorDate: Sun Nov 9 10:26:34 2025 +0000

    Move release validation code to the interaction module
---
 atr/db/interaction.py      | 48 ++++++++++++++++++++++++++++++++
 atr/get/manual.py          |  6 ++--
 atr/post/manual.py         |  6 ++--
 atr/shared/__init__.py     |  2 --
 atr/shared/distribution.py |  2 +-
 atr/shared/manual.py       | 68 ----------------------------------------------
 6 files changed, 57 insertions(+), 75 deletions(-)

diff --git a/atr/db/interaction.py b/atr/db/interaction.py
index c5e342e..7a2060e 100644
--- a/atr/db/interaction.py
+++ b/atr/db/interaction.py
@@ -34,6 +34,7 @@ import atr.models.results as results
 import atr.models.sql as sql
 import atr.user as user
 import atr.util as util
+import atr.web as web
 
 # TEST_MID: Final[str | None] = 
"CAH5JyZo8QnWmg9CwRSwWY=givhxw4nilyenjo71fkdk81j5...@mail.gmail.com"
 TEST_MID: Final[str | None] = None
@@ -257,6 +258,53 @@ async def release_latest_vote_task(release: sql.Release) 
-> sql.Task | None:
         return task
 
 
+async def release_ready_for_vote(
+    session: web.Committer,
+    project_name: str,
+    version_name: str,
+    revision: str,
+    data: db.Session,
+    manual_vote: bool = False,
+) -> tuple[sql.Release, sql.Committee] | str:
+    release = await session.release(
+        project_name,
+        version_name,
+        data=data,
+        with_project=True,
+        with_committee=True,
+        with_project_release_policy=True,
+    )
+
+    selected_revision_number = release.latest_revision_number
+    if selected_revision_number is None:
+        return "No revision found for this release"
+
+    if selected_revision_number != revision:
+        return "This revision does not match the revision you are voting on"
+
+    committee = release.committee
+    if committee is None:
+        return "The committee for this release was not found"
+
+    if manual_vote and (not release.project.policy_manual_vote):
+        return "This release does not have manual vote mode enabled"
+    elif (not manual_vote) and release.project.policy_manual_vote:
+        return "This release has manual vote mode enabled"
+
+    if release.project.policy_strict_checking:
+        if await has_failing_checks(release, revision, caller_data=data):
+            return "This release candidate draft has errors. Please fix the 
errors before starting a vote."
+
+    if not (user.is_committee_member(committee, session.uid) or 
user.is_admin(session.uid)):
+        return "You must be on the PMC of this project to start a vote"
+
+    has_files = await util.has_files(release)
+    if not has_files:
+        return "This release candidate draft has no files yet. Please add some 
files before starting a vote."
+
+    return release, committee
+
+
 async def releases_by_phase(project: sql.Project, phase: sql.ReleasePhase) -> 
list[sql.Release]:
     """Get the releases for the project by phase."""
 
diff --git a/atr/get/manual.py b/atr/get/manual.py
index 7cb5b16..a49b662 100644
--- a/atr/get/manual.py
+++ b/atr/get/manual.py
@@ -17,12 +17,12 @@
 
 import atr.blueprints.get as get
 import atr.db as db
+import atr.db.interaction as interaction
 import atr.form as form
 import atr.get.compose as compose
 import atr.htm as htm
 import atr.post.manual as post_manual
 import atr.shared.distribution as distribution
-import atr.shared.manual as shared_manual
 import atr.template as template
 import atr.util as util
 import atr.web as web
@@ -35,7 +35,9 @@ async def selected_revision(
     await session.check_access(project_name)
 
     async with db.session() as data:
-        match await shared_manual.validated_release(session, project_name, 
version_name, revision, data):
+        match await interaction.release_ready_for_vote(
+            session, project_name, version_name, revision, data, 
manual_vote=True
+        ):
             case str() as error:
                 return await session.redirect(
                     compose.selected,
diff --git a/atr/post/manual.py b/atr/post/manual.py
index 25a5919..14ab1f2 100644
--- a/atr/post/manual.py
+++ b/atr/post/manual.py
@@ -17,8 +17,8 @@
 
 import atr.blueprints.post as post
 import atr.db as db
+import atr.db.interaction as interaction
 import atr.get.vote as vote
-import atr.shared.manual as shared_manual
 import atr.storage as storage
 import atr.web as web
 
@@ -31,7 +31,9 @@ async def selected_revision(
     await session.check_access(project_name)
 
     async with db.session() as data:
-        match await shared_manual.validated_release(session, project_name, 
version_name, revision, data):
+        match await interaction.release_ready_for_vote(
+            session, project_name, version_name, revision, data, 
manual_vote=True
+        ):
             case str() as error:
                 return await session.redirect(
                     vote.selected,
diff --git a/atr/shared/__init__.py b/atr/shared/__init__.py
index e8a07e1..1426353 100644
--- a/atr/shared/__init__.py
+++ b/atr/shared/__init__.py
@@ -30,7 +30,6 @@ import atr.shared.draft as draft
 import atr.shared.finish as finish
 import atr.shared.ignores as ignores
 import atr.shared.keys as keys
-import atr.shared.manual as manual
 import atr.shared.projects as projects
 import atr.shared.resolve as resolve
 import atr.shared.start as start
@@ -192,7 +191,6 @@ __all__ = [
     "finish",
     "ignores",
     "keys",
-    "manual",
     "projects",
     "resolve",
     "start",
diff --git a/atr/shared/distribution.py b/atr/shared/distribution.py
index fc1b22a..68e8c88 100644
--- a/atr/shared/distribution.py
+++ b/atr/shared/distribution.py
@@ -90,7 +90,7 @@ class FormProjectVersion:
 # TODO: Move this to an appropriate module
 def html_nav(container: htm.Block, back_url: str, back_anchor: str, phase: 
Phase) -> None:
     classes = ".d-flex.justify-content-between.align-items-center"
-    block = htm.Block(htm.p(classes=classes))
+    block = htm.Block(htm.p, classes=classes)
     block.a(".atr-back-link", href=back_url)[f"← Back to {back_anchor}"]
     span = htm.Block(htm.span)
 
diff --git a/atr/shared/manual.py b/atr/shared/manual.py
deleted file mode 100644
index 21c917d..0000000
--- a/atr/shared/manual.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-import atr.db as db
-import atr.db.interaction as interaction
-import atr.models.sql as sql
-import atr.user as user
-import atr.util as util
-import atr.web as web
-
-
-async def validated_release(
-    session: web.Committer,
-    project_name: str,
-    version_name: str,
-    revision: str,
-    data: db.Session,
-) -> tuple[sql.Release, sql.Committee] | str:
-    """Validate release for manual vote and return (release, committee) or 
error message."""
-    release = await session.release(
-        project_name,
-        version_name,
-        data=data,
-        with_project=True,
-        with_committee=True,
-        with_project_release_policy=True,
-    )
-
-    selected_revision_number = release.latest_revision_number
-    if selected_revision_number is None:
-        return "No revision found for this release"
-
-    if selected_revision_number != revision:
-        return "This revision does not match the revision you are voting on"
-
-    committee = release.committee
-    if committee is None:
-        return "The committee for this release was not found"
-
-    if not release.project.policy_manual_vote:
-        return "This release does not have manual vote mode enabled"
-
-    if release.project.policy_strict_checking:
-        if await interaction.has_failing_checks(release, revision, 
caller_data=data):
-            return "This release candidate draft has errors. Please fix the 
errors before starting a vote."
-
-    if not (user.is_committee_member(committee, session.uid) or 
user.is_admin(session.uid)):
-        return "You must be on the PMC of this project to start a vote"
-
-    has_files = await util.has_files(release)
-    if not has_files:
-        return "This release candidate draft has no files yet. Please add some 
files before starting a vote."
-
-    return release, committee


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

Reply via email to