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 52562d7 Add a vote comment template to release policies
52562d7 is described below
commit 52562d71f59217a327e802d7636344b6db0a8c97
Author: Sean B. Palmer <[email protected]>
AuthorDate: Fri Dec 5 10:37:03 2025 +0000
Add a vote comment template to release policies
---
atr/get/projects.py | 1 +
atr/get/vote.py | 2 ++
atr/models/policy.py | 2 ++
atr/models/sql.py | 7 +++++++
atr/post/projects.py | 3 +++
atr/shared/projects.py | 5 +++++
atr/storage/writers/policy.py | 1 +
migrations/versions/0030_2025.12.05_211a31e3.py | 27 +++++++++++++++++++++++++
8 files changed, 48 insertions(+)
diff --git a/atr/get/projects.py b/atr/get/projects.py
index e97a7f6..f18207b 100644
--- a/atr/get/projects.py
+++ b/atr/get/projects.py
@@ -527,6 +527,7 @@ def _render_vote_form(project: sql.Project) -> htm.Element:
"min_hours": project.policy_min_hours,
"pause_for_rm": project.policy_pause_for_rm,
"release_checklist": project.policy_release_checklist or "",
+ "vote_comment_template": project.policy_vote_comment_template or "",
"start_vote_template": project.policy_start_vote_template or "",
}
diff --git a/atr/get/vote.py b/atr/get/vote.py
index c7a9c2a..f2fe7e0 100644
--- a/atr/get/vote.py
+++ b/atr/get/vote.py
@@ -513,12 +513,14 @@ async def _render_vote_authenticated(
project_name=release.project.name,
version_name=release.version,
)
+ vote_comment_template = release.project.policy_vote_comment_template
cast_vote_form = form.render(
model_cls=shared.vote.CastVoteForm,
action=vote_action_url,
submit_label="Submit vote",
form_classes=".atr-canary.py-4.px-5.mb-4.border.rounded",
custom={"decision": vote_widget},
+ defaults={"comment": vote_comment_template},
)
page.append(cast_vote_form)
diff --git a/atr/models/policy.py b/atr/models/policy.py
index ecc88ac..6e5e793 100644
--- a/atr/models/policy.py
+++ b/atr/models/policy.py
@@ -44,6 +44,7 @@ class ReleasePolicyData(schema.Lax):
min_hours: int = 72
pause_for_rm: bool = False
release_checklist: str = ""
+ vote_comment_template: str = ""
default_start_vote_template_hash: str = ""
start_vote_template: str = ""
github_vote_workflow_path: list[str] = pydantic.Field(default_factory=list)
@@ -86,6 +87,7 @@ class ReleasePolicyData(schema.Lax):
@pydantic.field_validator(
"github_repository_name",
"release_checklist",
+ "vote_comment_template",
"start_vote_template",
"announce_release_template",
mode="before",
diff --git a/atr/models/sql.py b/atr/models/sql.py
index f5c63a7..2892d86 100644
--- a/atr/models/sql.py
+++ b/atr/models/sql.py
@@ -626,6 +626,12 @@ Thanks,
return ""
return policy.release_checklist
+ @property
+ def policy_vote_comment_template(self) -> str:
+ if ((policy := self.release_policy) is None) or
(policy.vote_comment_template == ""):
+ return ""
+ return policy.vote_comment_template
+
@property
def policy_start_vote_template(self) -> str:
if ((policy := self.release_policy) is None) or
(policy.start_vote_template == ""):
@@ -980,6 +986,7 @@ class ReleasePolicy(sqlmodel.SQLModel, table=True):
manual_vote: bool = sqlmodel.Field(default=False)
min_hours: int | None = sqlmodel.Field(default=None)
release_checklist: str = sqlmodel.Field(default="")
+ vote_comment_template: str = sqlmodel.Field(default="")
pause_for_rm: bool = sqlmodel.Field(default=False)
start_vote_template: str = sqlmodel.Field(default="")
announce_release_template: str = sqlmodel.Field(default="")
diff --git a/atr/post/projects.py b/atr/post/projects.py
index 466b579..3f86ec6 100644
--- a/atr/post/projects.py
+++ b/atr/post/projects.py
@@ -217,6 +217,7 @@ async def _process_compose_form(
min_hours=project.policy_min_hours,
pause_for_rm=project.policy_pause_for_rm,
release_checklist=project.policy_release_checklist or "",
+ vote_comment_template=project.policy_vote_comment_template or "",
start_vote_template=project.policy_start_vote_template or "",
github_finish_workflow_path=project.policy_github_finish_workflow_path,
announce_release_template=project.policy_announce_release_template or
"",
@@ -273,6 +274,7 @@ async def _process_finish_form(
min_hours=project.policy_min_hours,
pause_for_rm=project.policy_pause_for_rm,
release_checklist=project.policy_release_checklist or "",
+ vote_comment_template=project.policy_vote_comment_template or "",
start_vote_template=project.policy_start_vote_template or "",
github_finish_workflow_path=[
p.strip() for p in
finish_form.github_finish_workflow_path.split("\n") if p.strip()
@@ -360,6 +362,7 @@ async def _process_vote_form(session: web.Committer,
vote_form: shared.projects.
min_hours=vote_form.min_hours,
pause_for_rm=vote_form.pause_for_rm,
release_checklist=vote_form.release_checklist or "",
+ vote_comment_template=vote_form.vote_comment_template or "",
start_vote_template=vote_form.start_vote_template or "",
github_finish_workflow_path=project.policy_github_finish_workflow_path,
announce_release_template=project.policy_announce_release_template or
"",
diff --git a/atr/shared/projects.py b/atr/shared/projects.py
index 6ae4da4..a663c16 100644
--- a/atr/shared/projects.py
+++ b/atr/shared/projects.py
@@ -180,6 +180,11 @@ class VotePolicyForm(form.Form):
"Release checklist",
widget=form.Widget.CUSTOM,
)
+ vote_comment_template: str = form.label(
+ "Vote comment template",
+ "Plain text template for vote comments. Voters can edit before
submitting.",
+ widget=form.Widget.TEXTAREA,
+ )
start_vote_template: str = form.label(
"Start vote template",
"Email template for messages to start a vote on a release.",
diff --git a/atr/storage/writers/policy.py b/atr/storage/writers/policy.py
index 03d8192..89f7bf0 100644
--- a/atr/storage/writers/policy.py
+++ b/atr/storage/writers/policy.py
@@ -113,6 +113,7 @@ class CommitteeMember(CommitteeParticipant):
self.__set_default_min_hours(policy_data, project, release_policy)
release_policy.pause_for_rm = policy_data.pause_for_rm
release_policy.release_checklist = policy_data.release_checklist
+ release_policy.vote_comment_template =
policy_data.vote_comment_template
self.__set_default_start_vote_template(policy_data, project,
release_policy)
elif project.committee and project.committee.is_podling:
# The caller ensures that project.committee is not None
diff --git a/migrations/versions/0030_2025.12.05_211a31e3.py
b/migrations/versions/0030_2025.12.05_211a31e3.py
new file mode 100644
index 0000000..172dd2e
--- /dev/null
+++ b/migrations/versions/0030_2025.12.05_211a31e3.py
@@ -0,0 +1,27 @@
+"""Add a field for vote comment templates
+
+Revision ID: 0030_2025.12.05_211a31e3
+Revises: 0029_2025.11.28_6486ff5e
+Create Date: 2025-12-05 10:25:32.833183+00:00
+"""
+
+from collections.abc import Sequence
+
+import sqlalchemy as sa
+from alembic import op
+
+# Revision identifiers, used by Alembic
+revision: str = "0030_2025.12.05_211a31e3"
+down_revision: str | None = "0029_2025.11.28_6486ff5e"
+branch_labels: str | Sequence[str] | None = None
+depends_on: str | Sequence[str] | None = None
+
+
+def upgrade() -> None:
+ with op.batch_alter_table("releasepolicy", schema=None) as batch_op:
+ batch_op.add_column(sa.Column("vote_comment_template", sa.String(),
nullable=False, server_default=""))
+
+
+def downgrade() -> None:
+ with op.batch_alter_table("releasepolicy", schema=None) as batch_op:
+ batch_op.drop_column("vote_comment_template")
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]