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 9493c95 Better integrate download buttons throughout the site
9493c95 is described below
commit 9493c9547fd86fdd8b20094abe48c2974cae5fee
Author: Sean B. Palmer <[email protected]>
AuthorDate: Fri May 2 09:32:38 2025 +0100
Better integrate download buttons throughout the site
---
atr/db/models.py | 1 +
atr/routes/announce.py | 2 ++
atr/routes/mapping.py | 4 ++--
atr/routes/release.py | 19 +++++++++++++--
atr/templates/candidate-resolve-release.html | 4 ++--
atr/templates/check-selected.html | 4 ++--
atr/templates/finish-selected.html | 12 +++++-----
atr/templates/index-committer.html | 2 +-
atr/templates/releases-completed.html | 35 +++++++++++-----------------
atr/templates/releases.html | 20 +++++++---------
playwright/test.py | 17 +++++++-------
11 files changed, 64 insertions(+), 56 deletions(-)
diff --git a/atr/db/models.py b/atr/db/models.py
index d46aba4..66791cd 100644
--- a/atr/db/models.py
+++ b/atr/db/models.py
@@ -383,6 +383,7 @@ class Release(sqlmodel.SQLModel, table=True):
stage: ReleaseStage
phase: ReleasePhase
created: datetime.datetime =
sqlmodel.Field(sa_column=sqlalchemy.Column(UTCDateTime))
+ released: datetime.datetime | None = sqlmodel.Field(default=None,
sa_column=sqlalchemy.Column(UTCDateTime))
# Many-to-one: A release belongs to one project, a project can have
multiple releases
project_name: str = sqlmodel.Field(foreign_key="project.name")
diff --git a/atr/routes/announce.py b/atr/routes/announce.py
index c320d47..6427723 100644
--- a/atr/routes/announce.py
+++ b/atr/routes/announce.py
@@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
+import datetime
import logging
from typing import TYPE_CHECKING, Any, Protocol
@@ -172,6 +173,7 @@ async def selected_post(
# That would require moving this, and the filesystem operations,
into a task
release.phase = models.ReleasePhase.RELEASE
release.revision = None
+ release.released = datetime.datetime.now(datetime.UTC)
await data.commit()
# This must come after updating the release object
diff --git a/atr/routes/mapping.py b/atr/routes/mapping.py
index 9dfc81c..b34ad66 100644
--- a/atr/routes/mapping.py
+++ b/atr/routes/mapping.py
@@ -32,5 +32,5 @@ def release_as_url(release: models.Release) -> str:
case models.ReleasePhase.RELEASE_PREVIEW:
return util.as_url(finish.selected,
project_name=release.project.name, version_name=release.version)
case models.ReleasePhase.RELEASE:
- view = routes_release.view # type: ignore[has-type]
- return util.as_url(view, project_name=release.project.name,
version_name=release.version)
+ completed = routes_release.completed # type: ignore[has-type]
+ return util.as_url(completed, project_name=release.project.name)
diff --git a/atr/routes/release.py b/atr/routes/release.py
index 73d53f2..ade1536 100644
--- a/atr/routes/release.py
+++ b/atr/routes/release.py
@@ -17,6 +17,7 @@
"""release.py"""
+import datetime
import logging
import logging.handlers
@@ -84,8 +85,13 @@ async def completed(project_name: str) -> str:
_committee=True,
).all()
+ def sort_releases(release: models.Release) -> datetime.datetime:
+ return release.released or release.created
+
+ releases = sorted(releases, key=sort_releases, reverse=True)
+
return await quart.render_template(
- "releases-completed.html", releases=releases,
format_datetime=routes.format_datetime
+ "releases-completed.html", project=project, releases=releases,
format_datetime=routes.format_datetime
)
@@ -98,11 +104,20 @@ async def releases() -> str:
stage=models.ReleaseStage.RELEASE,
phase=models.ReleasePhase.RELEASE,
_committee=True,
+ _project=True,
).all()
+ projects = {}
+ for release in releases:
+ if release.project.display_name not in projects:
+ projects[release.project.display_name] = (release.project, 1)
+ else:
+ projects[release.project.display_name] = (release.project,
projects[release.project.display_name][1] + 1)
+
return await quart.render_template(
"releases.html",
- releases=list(releases),
+ projects=projects,
+ releases=releases,
)
diff --git a/atr/templates/candidate-resolve-release.html
b/atr/templates/candidate-resolve-release.html
index 219fb91..a0a4f6e 100644
--- a/atr/templates/candidate-resolve-release.html
+++ b/atr/templates/candidate-resolve-release.html
@@ -57,10 +57,10 @@
</div>
</div>
<div class="card-body">
- <a href="{{ as_url(routes.candidate.view,
project_name=release.project.name, version_name=release.version) }}"
- class="btn btn-primary me-2"><i class="bi bi-eye me-1"></i> View
files</a>
<a href="{{ as_url(routes.download.all_selected,
project_name=release.project.name, version_name=release.version) }}"
class="btn btn-primary me-2"><i class="bi bi-download me-1"></i>
Download files</a>
+ <a href="{{ as_url(routes.candidate.view,
project_name=release.project.name, version_name=release.version) }}"
+ class="btn btn-secondary me-2"><i class="bi bi-eye me-1"></i> View
files</a>
<a href="{{ as_url(routes.vote.selected,
project_name=release.project.name, version_name=release.version) }}"
class="btn btn-success"><i class="bi bi-check-circle me-1"></i> Vote
on release</a>
</div>
diff --git a/atr/templates/check-selected.html
b/atr/templates/check-selected.html
index 0aed8f0..564286d 100644
--- a/atr/templates/check-selected.html
+++ b/atr/templates/check-selected.html
@@ -98,10 +98,10 @@
</div>
{% if phase == "release_candidate" %}
<div class="card-body">
- <a href="{{ as_url(routes.candidate.view,
project_name=release.project.name, version_name=release.version) }}"
- class="btn btn-primary me-2"><i class="bi bi-eye me-1"></i> View
files</a>
<a href="{{ as_url(routes.download.all_selected,
project_name=release.project.name, version_name=release.version) }}"
class="btn btn-primary me-2"><i class="bi bi-download me-1"></i>
Download files</a>
+ <a href="{{ as_url(routes.candidate.view,
project_name=release.project.name, version_name=release.version) }}"
+ class="btn btn-secondary me-2"><i class="bi bi-eye me-1"></i> View
files</a>
<a href="{{ as_url(routes.resolve.selected,
project_name=release.project.name, version_name=release.version) }}"
class="btn btn-success"><i class="bi bi-clipboard-check me-1"></i>
Resolve vote</a>
</div>
diff --git a/atr/templates/finish-selected.html
b/atr/templates/finish-selected.html
index ec9118b..e7645ed 100644
--- a/atr/templates/finish-selected.html
+++ b/atr/templates/finish-selected.html
@@ -35,18 +35,18 @@
<span class="page-preview-meta-item">Created: {{
release.created.strftime("%Y-%m-%d %H:%M:%S UTC") }}</span>
</div>
<div>
+ <a title="Download all files"
+ href="{{ as_url(routes.download.all_selected,
project_name=release.project.name, version_name=release.version) }}"
+ class="btn btn-primary me-2">
+ <i class="bi bi-download"></i>
+ Download all files
+ </a>
<a title="Show files for {{ release.name }}"
href="{{ as_url(routes.preview.view,
project_name=release.project.name, version_name=release.version) }}"
class="btn btn-secondary me-2">
<i class="bi bi-archive"></i>
Show files
</a>
- <a title="Download all files"
- href="{{ as_url(routes.download.all_selected,
project_name=release.project.name, version_name=release.version) }}"
- class="btn btn-secondary me-2">
- <i class="bi bi-download"></i>
- Download all files
- </a>
<a title="Show revisions for {{ release.name }}"
href="{{ as_url(routes.revisions.selected,
project_name=release.project.name, version_name=release.version) }}"
class="btn btn-secondary me-2">
diff --git a/atr/templates/index-committer.html
b/atr/templates/index-committer.html
index 33ee3e5..d354aac 100644
--- a/atr/templates/index-committer.html
+++ b/atr/templates/index-committer.html
@@ -100,7 +100,7 @@
{% if completed_releases %}
<span class="text-muted me-2">/</span>
<a href="{{ as_url(routes.release.completed,
project_name=project.name) }}"
- class="text-decoration-none">Show completed releases</a>
+ class="text-decoration-none">Completed releases</a>
{% endif %}
</p>
diff --git a/atr/templates/releases-completed.html
b/atr/templates/releases-completed.html
index 12a48de..eadf8d1 100644
--- a/atr/templates/releases-completed.html
+++ b/atr/templates/releases-completed.html
@@ -1,32 +1,19 @@
{% extends "layouts/base.html" %}
{% block title %}
- Completed releases of {{ project_display_name }} ~ ATR
+ Completed releases of {{ project.display_name }} ~ ATR
{% endblock title %}
{% block description %}
- All of the completed releases of {{ project_display_name }} on ATR.
+ All of the completed releases of {{ project.display_name }} on ATR.
{% endblock description %}
{% block content %}
- {% set project_name = releases[0].project.name if releases else "" %}
- {% set project_display_name = releases[0].project.display_name if releases
else "Unknown project" %}
+ <p>
+ <a href="{{ as_url(routes.root.index) }}" class="atr-back-link">← Back to
Select a release</a>
+ </p>
- <nav aria-label="breadcrumb" class="mb-5">
- <ol class="breadcrumb">
- <li class="breadcrumb-item">
- <a href="{{ as_url(routes.root.index) }}">ATR</a>
- </li>
- {% if project_name %}
- <li class="breadcrumb-item">
- <a href="{{ as_url(routes.projects.view, name=project_name) }}">{{
project_display_name }}</a>
- </li>
- {% endif %}
- <li class="breadcrumb-item active" aria-current="page">Completed
releases</li>
- </ol>
- </nav>
-
- <h1>Completed releases of {{ project_display_name }}</h1>
+ <h1>Completed releases of {{ project.display_name }}</h1>
{% if releases %}
<p class="mb-4">The following releases have been completed and published
for this project.</p>
@@ -38,9 +25,13 @@
<strong class="card-title fs-5">{{ release.version }}</strong>
<p class="card-text text-muted">Released on {{
format_datetime(release.created) }}</p>
<div class="mt-auto">
+ <a href="{{ as_url(routes.download.all_selected,
project_name=release.project.name, version_name=release.version) }}"
+ class="btn btn-outline-primary w-100 mb-2">
+ <i class="bi bi-download me-1"></i> Download files
+ </a>
<a href="{{ as_url(routes.release.view,
project_name=release.project.name, version_name=release.version) }}"
- class="btn btn-outline-primary w-100">
- <i class="bi bi-folder2-open me-1"></i> View release files
+ class="btn btn-outline-secondary w-100">
+ <i class="bi bi-folder2-open me-1"></i> View files
</a>
</div>
</div>
@@ -50,7 +41,7 @@
</div>
{% else %}
<div class="alert alert-info mt-4" role="alert">
- <i class="bi bi-info-circle me-2"></i> There are no completed releases
recorded for {{ project_display_name }}.
+ <i class="bi bi-info-circle me-2"></i> There are no completed releases
recorded for {{ project.display_name }}.
</div>
{% endif %}
{% endblock content %}
diff --git a/atr/templates/releases.html b/atr/templates/releases.html
index e36e55b..20fda49 100644
--- a/atr/templates/releases.html
+++ b/atr/templates/releases.html
@@ -27,19 +27,17 @@
<h1>Releases</h1>
{% if releases %}
- {% for release in releases %}
+ {% for project_display_name in projects|sort %}
+ {% set project, count = projects[project_display_name] %}
<div class="card mb-3 bg-light">
<div class="card-body">
- <h3 class="card-title mb-2">{{ release.project.display_name }} {{
release.version }}</h3>
- <div class="d-flex flex-wrap gap-3 pb-3 mb-2 border-bottom
text-secondary fs-6">
- <span class="page-release-meta-item">Created: {{
release.created.strftime("%Y-%m-%d %H:%M:%S UTC") }}</span>
- </div>
- <div class="d-flex gap-3 align-items-center pt-2">
- <a class="btn btn-outline-primary"
- href="{{ as_url(routes.release.view,
project_name=release.project.name, version_name=release.version) }}"><i
class="bi bi-eye me-1"></i> View files</a>
- <a class="btn btn-outline-primary"
- href="{{ as_url(routes.download.all_selected,
project_name=release.project.name, version_name=release.version) }}"><i
class="bi bi-download me-1"></i> Download files</a>
- </div>
+ <h3 class="card-title mb-3">{{ project_display_name }}</h3>
+ <p class="card-text">
+ <a href="{{ as_url(routes.release.completed,
project_name=project.name) }}"
+ class="btn btn-outline-primary">
+ <i class="bi bi-folder2-open me-1"></i> Completed releases
(<code>{{ count }}</code>)
+ </a>
+ </p>
</div>
</div>
{% endfor %}
diff --git a/playwright/test.py b/playwright/test.py
index 342a94c..9615988 100644
--- a/playwright/test.py
+++ b/playwright/test.py
@@ -241,17 +241,18 @@ def lifecycle_06_announce_preview(page: sync_api.Page,
credentials: Credentials,
def lifecycle_07_release_exists(page: sync_api.Page, credentials: Credentials,
version_name: str) -> None:
- logging.info(f"Checking for release tooling-test-example {version_name} on
the /releases page")
+ logging.info(
+ f"Checking for release tooling-test-example {version_name} on
/releases/completed/tooling-test-example"
+ )
+ go_to_path(page, "/releases/completed/tooling-test-example")
+ logging.info("Releases completed page loaded successfully")
- release_card_locator = page.locator(f'div.card:has(h3:has-text("Apache
Tooling Test Example {version_name}"))')
+ release_card_locator =
page.locator(f'div.card:has(strong.card-title:has-text("{version_name}"))')
sync_api.expect(release_card_locator).to_be_visible()
logging.info(f"Found card for tooling-test-example {version_name} release")
- logging.info(f"Release tooling-test-example {version_name} confirmed
exists on /releases page")
-
- logging.info(f"Verifying release tooling-test-example {version_name} card
exists")
- release_card_locator = page.locator(f'div.card:has(h3:has-text("Apache
Tooling Test Example {version_name}"))')
- sync_api.expect(release_card_locator).to_be_visible()
- logging.info(f"Release tooling-test-example {version_name} card found")
+ logging.info(
+ f"Release tooling-test-example {version_name} confirmed exists on
/releases/completed/tooling-test-example"
+ )
def main() -> None:
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]