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 7ba7f46 List existing versions on the page to start a new release
7ba7f46 is described below
commit 7ba7f46f5e2b61c039f4b76e47ac9f6fbad2ff00
Author: Sean B. Palmer <[email protected]>
AuthorDate: Wed Sep 10 14:34:52 2025 +0100
List existing versions on the page to start a new release
---
atr/db/interaction.py | 18 ++++++++++++++++++
atr/routes/start.py | 6 +++++-
atr/templates/start-selected.html | 37 +++++++++++++++++++++++++++++++++++++
pyproject.toml | 1 +
uv.lock | 2 ++
5 files changed, 63 insertions(+), 1 deletion(-)
diff --git a/atr/db/interaction.py b/atr/db/interaction.py
index e8d968f..f7a8dad 100644
--- a/atr/db/interaction.py
+++ b/atr/db/interaction.py
@@ -25,6 +25,7 @@ from typing import Any, Final
import aiofiles.os
import aioshutil
import asfquart.base as base
+import packaging.version as version
import quart
import sqlalchemy
import sqlmodel
@@ -79,6 +80,23 @@ class TrustedProjectPhase(enum.Enum):
FINISH = "finish"
+async def all_releases(project: sql.Project) -> list[sql.Release]:
+ """Get all releases for the project, sorted by version."""
+ query = sqlmodel.select(sql.Release).where(sql.Release.project_name ==
project.name)
+
+ results = []
+ async with db.session() as data:
+ for result in (await data.execute(query)).all():
+ release = result[0]
+ results.append(release)
+
+ for release in results:
+ release.project = project
+
+ results.sort(key=lambda r: version.Version(r.version), reverse=True)
+ return results
+
+
async def candidate_drafts(project: sql.Project) -> list[sql.Release]:
"""Get the candidate drafts for the project."""
return await releases_by_phase(project,
sql.ReleasePhase.RELEASE_CANDIDATE_DRAFT)
diff --git a/atr/routes/start.py b/atr/routes/start.py
index 8df425c..70e452a 100644
--- a/atr/routes/start.py
+++ b/atr/routes/start.py
@@ -22,6 +22,7 @@ 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
@@ -128,5 +129,8 @@ async def selected(session: routes.CommitterSession,
project_name: str) -> respo
# Flash the error and let the code fall through to render the
template below
await quart.flash(str(e), "error")
+ # Get all releases for the project
+ releases = await interaction.all_releases(project)
+
# Render the template for GET requests or POST requests with validation
errors
- return await template.render("start-selected.html", project=project,
form=form, routes=routes)
+ return await template.render("start-selected.html", project=project,
form=form, routes=routes, releases=releases)
diff --git a/atr/templates/start-selected.html
b/atr/templates/start-selected.html
index fe55db7..a755fbb 100644
--- a/atr/templates/start-selected.html
+++ b/atr/templates/start-selected.html
@@ -39,4 +39,41 @@
</div>
</form>
+ {% if releases %}
+ {% set max_revisions = 18 %}
+ <div class="mt-5">
+ <h2>Existing releases</h2>
+ <div class="row">
+ <div class="col-12">
+ <ul class="list-unstyled row g-3">
+ {% for release in releases[:max_revisions] %}
+ <li class="col-6 col-sm-4 col-md-3 col-lg-2">
+ <div class="text-nowrap">
+ {% if release.phase.value == "release_candidate_draft" %}
+ <span class="atr-phase-one atr-phase-symbol fs-6">{{ "①"
}}</span>
+ {% elif release.phase.value == "release_candidate" %}
+ <span class="atr-phase-two atr-phase-symbol fs-6">{{ "②"
}}</span>
+ {% elif release.phase.value == "release_preview" %}
+ <span class="atr-phase-three atr-phase-symbol fs-6">{{ "③"
}}</span>
+ {% elif release.phase.value == "release" %}
+ <span class="atr-phase-symbol fs-6">{{ "Ⓡ" }}</span>
+ {% endif %}
+ {{ release.version }}
+ </div>
+ </li>
+ {% endfor %}
+ {% if releases|length > max_revisions %}
+ <li class="col-6 col-sm-4 col-md-3 col-lg-2">
+ <div class="text-center">
+ <strong>...</strong>
+ <span class="text-muted ms-1">{{ releases|length -
max_revisions }} more</span>
+ </div>
+ </li>
+ {% endif %}
+ </ul>
+ </div>
+ </div>
+ </div>
+ {% endif %}
+
{% endblock content %}
diff --git a/pyproject.toml b/pyproject.toml
index f8ff2d8..b975f46 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -31,6 +31,7 @@ dependencies = [
"htpy (>=25.7.0,<26.0.0)",
"hypercorn~=0.17",
"ldap3 (==2.10.2rc2)",
+ "packaging>=25.0",
"pgpy>=0.6.0",
"pydantic-xml (>=2.17.2,<3.0.0)",
"pyjwt (>=2.10.1,<3.0.0)",
diff --git a/uv.lock b/uv.lock
index b3f95ac..54c4e7b 100644
--- a/uv.lock
+++ b/uv.lock
@@ -1691,6 +1691,7 @@ dependencies = [
{ name = "htpy" },
{ name = "hypercorn" },
{ name = "ldap3" },
+ { name = "packaging" },
{ name = "pgpy" },
{ name = "pydantic-xml" },
{ name = "pyjwt" },
@@ -1744,6 +1745,7 @@ requires-dist = [
{ name = "htpy", specifier = ">=25.7.0,<26.0.0" },
{ name = "hypercorn", specifier = "~=0.17" },
{ name = "ldap3", specifier = "==2.10.2rc2" },
+ { name = "packaging", specifier = ">=25.0" },
{ name = "pgpy", specifier = ">=0.6.0" },
{ name = "pydantic-xml", specifier = ">=2.17.2,<3.0.0" },
{ name = "pyjwt", specifier = ">=2.10.1,<3.0.0" },
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]