You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tooling.apache.org by ar...@apache.org on 2026/09/07 10:50:21 UTC

(tooling-trusted-releases) branch arm updated (9791215f -> c0a6401b)

This is an automated email from the ASF dual-hosted git repository.

alitheg pushed a change to branch arm
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git


    from 9791215f #1439 - hide non-signing keys
     new c0374544 #1574 - Add link to verification instructions
     new c0a6401b #1564 - catalog dashboard

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 atr/admin/__init__.py                           | 128 +++++++++++++++++++-----
 atr/admin/templates/catalog-committee.html      |   2 +-
 atr/admin/templates/current-releases.html       |   6 +-
 atr/templates/catalog_site/project.html         |  19 ++--
 atr/templates/catalog_site/project_archive.html |  12 ++-
 atr/templates/includes/topnav.html              |   5 +
 tests/unit/test_admin_delete_committee_keys.py  |   2 +-
 7 files changed, 133 insertions(+), 41 deletions(-)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tooling.apache.org
For additional commands, e-mail: commits-help@tooling.apache.org


(tooling-trusted-releases) 02/02: #1564 - catalog dashboard

Posted by ar...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

alitheg pushed a commit to branch arm
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git

commit c0a6401ba82378cf1c4b43121682c7c41a8c9d86
Author: Alastair McFarlane <ar...@apache.org>
AuthorDate: Mon Sep 7 11:49:28 2026 +0100

    #1564 - catalog dashboard
---
 atr/admin/__init__.py                          | 128 ++++++++++++++++++++-----
 atr/admin/templates/catalog-committee.html     |   2 +-
 atr/admin/templates/current-releases.html      |   6 +-
 atr/templates/includes/topnav.html             |   5 +
 tests/unit/test_admin_delete_committee_keys.py |   2 +-
 5 files changed, 114 insertions(+), 29 deletions(-)

diff --git a/atr/admin/__init__.py b/atr/admin/__init__.py
index 839c14b6..66e25490 100644
--- a/atr/admin/__init__.py
+++ b/atr/admin/__init__.py
@@ -322,7 +322,7 @@ async def catalog_get(_session: web.Committer, _catalog: Literal["catalog"], que
         validation.pagination_args_validate(query_args)
     except ValueError as e:
         raise exceptions.BadRequest(str(e))
-    return await _catalog_page(quart.request.args.get("tab", "catalog"), query_args)
+    return await _catalog_page(quart.request.args.get("tab", "update-projects"), query_args)
 
 
 @admin.typed
@@ -338,6 +338,19 @@ async def catalog_post(
             return await _catalog_site_rebuild(session)
 
 
+@admin.typed
+async def committee_keys_get(_session: web.Committer, _committee_keys: Literal["committee-keys"]) -> str:
+    """
+    URL: GET /committee-keys
+
+    Delete all the signing keys held for a committee.
+    """
+    page = htm.Block()
+    page.h1["Delete committee keys"]
+    page.append(await _catalog_delete_committee_keys_tab())
+    return await template.render("admin-blank.html", title="Delete committee keys", content=page.collect())
+
+
 @admin.typed
 async def catalog_dump_get(
     _session: web.Committer,
@@ -1947,7 +1960,7 @@ async def _catalog_delete_committee_keys(
             num_unlinked, num_deleted, publication = await waca.keys.delete_committee_keys(datatypes.KeySource.WEB)
     except storage.AccessError as e:
         await quart.flash(str(e), "error")
-        return await session.redirect(catalog_get, tab="committee-keys")
+        return await session.redirect(committee_keys_get)
 
     if num_unlinked == 0:
         await quart.flash(f"Committee '{committee_key}' has no keys.", "info")
@@ -1967,7 +1980,7 @@ async def _catalog_delete_committee_keys(
         if failure := shared.keys.publication_failed_warning(publications):
             await quart.flash(failure, "error")
 
-    return await session.redirect(catalog_get, tab="committee-keys")
+    return await session.redirect(committee_keys_get)
 
 
 async def _catalog_delete_committee_keys_tab() -> htm.Element:
@@ -1979,7 +1992,7 @@ async def _catalog_delete_committee_keys_tab() -> htm.Element:
 
     rendered_form = await form.render(
         model_cls=DeleteCommitteeKeysForm,
-        action=util.as_url(catalog_post, tab="committee-keys"),
+        action=util.as_url(catalog_post),
         submit_label="Delete all keys for selected committee",
         defaults={"committee_key": committee_choices},
     )
@@ -1991,10 +2004,10 @@ async def _catalog_delete_committee_keys_tab() -> htm.Element:
 
 async def _catalog_page(active_tab: str, query_args: web.PageQuery) -> str:
     tab_items = [
-        htm.Tab("catalog", "Catalog", _catalog_tab),
-        htm.Tab("releases", "Releases", lambda: _catalog_releases_tab(query_args)),
-        htm.Tab("update-projects", "Update projects", _catalog_projects_update_tab),
-        htm.Tab("committee-keys", "Delete committee keys", _catalog_delete_committee_keys_tab),
+        htm.Tab("update-projects", "Update", _catalog_projects_update_tab),
+        htm.Tab("releases", "Current releases", lambda: _catalog_releases_tab(query_args)),
+        htm.Tab("admin", "Catalog admin", _catalog_admin_tab),
+        htm.Tab("rebuild", "Rebuild catalog", _catalog_rebuild_tab),
     ]
     page = htm.Block()
     page.h1["Catalog"]
@@ -2075,38 +2088,105 @@ async def _catalog_site_rebuild(session: web.Committer) -> web.WerkzeugResponse:
     except Exception as e:
         log.exception("Failed to queue catalog site rebuild task")
         await quart.flash(f"Failed to queue catalog site rebuild: {e!s}", "error")
-    return await session.redirect(catalog_get, tab="catalog")
+    return await session.redirect(catalog_get, tab="rebuild")
 
 
-async def _catalog_tab() -> htm.Element:
+async def _catalog_rebuild_tab() -> htm.Element:
     async with db.session() as data:
-        committees = await data.committee().order_by(sql.Committee.key).all()
+        in_flight = await (
+            data.task(
+                task_type=sql.TaskType.CATALOG_SITE_GENERATE,
+                status_in=[sql.TaskStatus.QUEUED, sql.TaskStatus.ACTIVE],
+            )
+            .order_by(sql.Task.added)
+            .all()
+        )
 
-    listing = htpy.ul(".list-group")[
-        [
-            htpy.li(".list-group-item")[htpy.a(href=f"/admin/catalog/{committee.key}")[committee.name or committee.key]]
-            for committee in committees
-        ]
-    ]
     rendered_form = await form.render(
         model_cls=CatalogSiteRebuildForm,
-        action=util.as_url(catalog_post, tab="catalog"),
-        submit_label="Rebuild catalog site",
+        action=util.as_url(catalog_post, tab="rebuild"),
+        submit_label="Queue full rebuild",
         empty=True,
         form_classes="",
     )
     block = htm.Block()
-    block.h2["Catalogue corrections"]
-    block.p[htm.a(href="/admin/catalog/dump")["Dump full catalog contents"]]
-    block.h3["Rebuild catalog site"]
+    block.h2["Rebuild catalog"]
     block.p[
         "Catalogue changes refresh the affected pages on their own, so a full rebuild is only needed to"
         " populate a fresh deployment or to clear up after project renames, moves or deletions."
     ]
+    block.append(_catalog_regeneration_status(in_flight))
     block.append(rendered_form)
-    block.h3(".mt-4")["Committees"]
-    block.p["Choose a committee to review and correct its catalogued projects."]
+    return block.collect()
+
+
+def _catalog_regeneration_status(in_flight: Sequence[sql.Task]) -> htm.Element:
+    block = htm.Block()
+    block.h3["Regeneration status"]
+    if not in_flight:
+        block.append(htm.div(".alert.alert-secondary", role="alert")["No regeneration is queued or running."])
+        return block.collect()
+
+    rows = []
+    for task in in_flight:
+        # A regeneration with no project is a whole-site rebuild; one with a project
+        # only rewrites that project's subtree
+        scope = "Whole site" if (task.project_key is None) else f"Project: {task.project_key}"
+        if task.status == sql.TaskStatus.ACTIVE:
+            status_badge: htm.Element = htpy.span(".badge.bg-info")["Running"]
+        else:
+            status_badge = htpy.span(".badge.bg-secondary")["Queued"]
+        rows.append(
+            htpy.tr[
+                htpy.td[scope],
+                htpy.td[status_badge],
+                htpy.td[util.format_datetime(task.added)],
+                htpy.td[task.asf_uid],
+            ]
+        )
+    block.append(
+        htpy.table(".table.table-sm")[
+            htpy.thead[
+                htpy.tr[
+                    htpy.th["Scope"],
+                    htpy.th["Status"],
+                    htpy.th["Queued"],
+                    htpy.th["Requested by"],
+                ]
+            ],
+            htpy.tbody[rows],
+        ]
+    )
+    return block.collect()
+
+
+async def _catalog_admin_tab() -> htm.Element:
+    async with db.session() as data:
+        committees = await data.committee().order_by(sql.Committee.key).all()
+
+    listing = htpy.ul(".list-group")[
+        [
+            htpy.li(".list-group-item")[htpy.a(href=f"/admin/catalog/{committee.key}")[committee.name or committee.key]]
+            for committee in committees
+        ]
+    ]
+    block = htm.Block()
+    block.append(
+        htm.div(".alert.alert-warning", role="alert")[
+            "This is the published catalogue: releases imported from external sources, together with ATR"
+            " releases that have finished their workflow. Releases still moving through ATR's workflow are"
+            " managed under ",
+            htm.a(".alert-link", href=util.as_url(catalog_get, tab="releases"))["Current releases"],
+            ".",
+        ]
+    )
+    block.h2["Committees"]
+    block.p[
+        "Choose a committee to review and correct its catalogued projects:"
+        " archive, rename, or move projects between committees."
+    ]
     block.append(listing)
+    block.p(".mt-3")[htm.a(href="/admin/catalog/dump")["Dump full catalog contents"]]
     return block.collect()
 
 
diff --git a/atr/admin/templates/catalog-committee.html b/atr/admin/templates/catalog-committee.html
index 075846e7..f807dd02 100644
--- a/atr/admin/templates/catalog-committee.html
+++ b/atr/admin/templates/catalog-committee.html
@@ -6,7 +6,7 @@
 
 {% block content %}
     <h1>Catalogue: {{ committee_key }}</h1>
-    <p><a href="/admin/catalog">Back to committees</a></p>
+    <p><a href="{{ as_url(admin.catalog_get, tab="admin") }}">Back to committees</a></p>
     <p><a href="/admin/catalog/{{ committee_key }}/import" class="btn btn-primary">Import CSVs</a></p>
     {{ projects }}
 
diff --git a/atr/admin/templates/current-releases.html b/atr/admin/templates/current-releases.html
index 43135397..75b66d49 100644
--- a/atr/admin/templates/current-releases.html
+++ b/atr/admin/templates/current-releases.html
@@ -1,9 +1,9 @@
 <h2>Current releases</h2>
 
 <div class="alert alert-info" role="alert">
-  These are live release-workflow releases, across all phases. Historical
-  catalogued releases (those with no workflow revisions) are managed in
-  <a href="{{ as_url(admin.catalog_get) }}" class="alert-link">Catalog admin</a>.
+  These are in-progress release-workflow releases: drafts, candidates, and
+  previews. Once finished, a release moves to the published catalogue, managed in
+  <a href="{{ as_url(admin.catalog_get, tab="admin") }}" class="alert-link">Catalog admin</a>.
 </div>
 
 {% if release_rows %}
diff --git a/atr/templates/includes/topnav.html b/atr/templates/includes/topnav.html
index a8363b4f..bc0787d9 100644
--- a/atr/templates/includes/topnav.html
+++ b/atr/templates/includes/topnav.html
@@ -252,6 +252,11 @@
                    href="{{ as_url(admin.keys_update_get) }}"
                    {% if request.endpoint == 'atr_admin_keys_update_get' %}class="active"{% endif %}><i class="bi bi-key"></i> Update keys</a>
               </li>
+              <li>
+                <a class="dropdown-item"
+                   href="{{ as_url(admin.committee_keys_get) }}"
+                   {% if request.endpoint == 'atr_admin_committee_keys_get' %}class="active"{% endif %}><i class="bi bi-trash"></i> Delete committee keys</a>
+              </li>
               <li>
                 <hr class="dropdown-divider" />
               </li>
diff --git a/tests/unit/test_admin_delete_committee_keys.py b/tests/unit/test_admin_delete_committee_keys.py
index 00276c57..99bbecb0 100644
--- a/tests/unit/test_admin_delete_committee_keys.py
+++ b/tests/unit/test_admin_delete_committee_keys.py
@@ -57,4 +57,4 @@ async def test_delete_committee_keys_post_surfaces_storage_error(monkeypatch):
     write.as_committee_admin.assert_called_once_with("alpha")
     keys.delete_committee_keys.assert_awaited_once()
     flash.assert_awaited_once_with(str(delete_error), "error")
-    session.redirect.assert_awaited_once_with(admin_routes.catalog_get, tab="committee-keys")
+    session.redirect.assert_awaited_once_with(admin_routes.committee_keys_get)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tooling.apache.org
For additional commands, e-mail: commits-help@tooling.apache.org


(tooling-trusted-releases) 01/02: #1574 - Add link to verification instructions

Posted by ar...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

alitheg pushed a commit to branch arm
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git

commit c037454483db3e8d4868b10b5445e53f91882573
Author: Alastair McFarlane <ar...@apache.org>
AuthorDate: Mon Sep 7 10:50:43 2026 +0100

    #1574 - Add link to verification instructions
---
 atr/templates/catalog_site/project.html         | 19 +++++++++++--------
 atr/templates/catalog_site/project_archive.html | 12 ++++++++----
 2 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/atr/templates/catalog_site/project.html b/atr/templates/catalog_site/project.html
index cde92a07..5e5e4958 100644
--- a/atr/templates/catalog_site/project.html
+++ b/atr/templates/catalog_site/project.html
@@ -20,15 +20,12 @@
   {% include "_project_back_link.html" %}
   <div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-3">
     <h1 class="mb-0">{{ heading }}</h1>
-    <span>
-      <a class="btn btn-sm btn-outline-secondary" href="{{ keys_url }}">Public KEYS</a>
+    <span class="d-flex align-items-center flex-wrap gap-2">
       {% if project %}
-        <a class="btn btn-sm btn-outline-secondary ms-2" href="cle.json">Project CLE</a>
-        {# A retired project has nothing current, so the archive is always the way on #}
-        {% if has_archive or retired %}
-          <a class="btn btn-sm btn-outline-secondary ms-2" href="archive.html">Archived releases</a>
-        {% endif %}
+        <a class="btn btn-sm btn-outline-secondary" href="cle.json">Project CLE</a>
       {% endif %}
+      <a class="btn btn-sm btn-outline-secondary" href="{{ keys_url }}">Public KEYS</a>
+      <span>(<a href="https://www.apache.org/info/verification.html" target="_blank" rel="noopener">Verification</a>)</span>
     </span>
   </div>
   {% include "_unreviewed.html" %}
@@ -44,7 +41,13 @@
     </div>
   {% endif %}
   {% if project %}
-    <h2 class="fs-4 border-bottom pb-1">Releases</h2>
+    <div class="d-flex justify-content-between align-items-center border-bottom pb-1 mb-2">
+      <h2 class="fs-4 mb-0 border-bottom-0">Releases</h2>
+      {# A retired project has nothing current, so the archive is always the way on #}
+      {% if has_archive or retired %}
+        <a class="btn btn-sm btn-outline-secondary" href="archive.html">Archived releases</a>
+      {% endif %}
+    </div>
     {# A retired project can still hold releases that were never archived themselves.
        They belong to nothing else, so list them here rather than drop them #}
     {% if versions %}
diff --git a/atr/templates/catalog_site/project_archive.html b/atr/templates/catalog_site/project_archive.html
index e5ad3401..db4c8a41 100644
--- a/atr/templates/catalog_site/project_archive.html
+++ b/atr/templates/catalog_site/project_archive.html
@@ -7,14 +7,18 @@
 {% block content %}
   {% include "_project_back_link.html" %}
   <div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-3">
-    <h1 class="mb-0">{{ project.display_name }} &ndash; archived releases</h1>
-    <span>
+    <h1 class="mb-0">{{ project.display_name }}</h1>
+    <span class="d-flex align-items-center flex-wrap gap-2">
+      <a class="btn btn-sm btn-outline-secondary" href="cle.json">Project CLE</a>
       <a class="btn btn-sm btn-outline-secondary" href="{{ keys_url }}">Public KEYS</a>
-      <a class="btn btn-sm btn-outline-secondary ms-2" href="cle.json">Project CLE</a>
-      <a class="btn btn-sm btn-outline-secondary ms-2" href="index.html">Current releases</a>
+      <span>(<a href="https://www.apache.org/info/verification.html" target="_blank" rel="noopener">Verification</a>)</span>
     </span>
   </div>
   {% include "_unreviewed.html" %}
+  <div class="d-flex justify-content-between align-items-center border-bottom pb-1 mb-2">
+    <h2 class="fs-4 mb-0 border-bottom-0">Archived releases</h2>
+    <a class="btn btn-sm btn-outline-secondary" href="index.html">Current releases</a>
+  </div>
   {% if versions %}
     {% include "_release_list.html" %}
   {% else %}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tooling.apache.org
For additional commands, e-mail: commits-help@tooling.apache.org