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

tn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-atr-experiments.git


The following commit(s) were added to refs/heads/main by this push:
     new 3efcf10  chore: use async requests for updating the list of projects
3efcf10 is described below

commit 3efcf104866ddfec5ed75d9b4ddf1cff98691886
Author: Thomas Neidhart <[email protected]>
AuthorDate: Tue Mar 4 16:24:38 2025 +0100

    chore: use async requests for updating the list of projects
---
 atr/blueprints/admin/admin.py                   | 176 +++++++++++++-----------
 atr/blueprints/admin/templates/update-pmcs.html |  57 +++++++-
 2 files changed, 148 insertions(+), 85 deletions(-)

diff --git a/atr/blueprints/admin/admin.py b/atr/blueprints/admin/admin.py
index 6240234..ca603e2 100644
--- a/atr/blueprints/admin/admin.py
+++ b/atr/blueprints/admin/admin.py
@@ -16,12 +16,14 @@
 # under the License.
 
 from collections import defaultdict
+from collections.abc import Mapping
 from pathlib import Path
 from statistics import mean, median, stdev
+from typing import Any
 
 import aiofiles.os
 import httpx
-from quart import current_app, flash, redirect, render_template, request, 
url_for
+from quart import current_app, flash, render_template, request
 from sqlmodel import select
 from werkzeug.wrappers.response import Response
 
@@ -176,98 +178,106 @@ async def admin_data(model: str = "PMC") -> str:
 
 
 @blueprint.route("/projects/update", methods=["GET", "POST"])
-async def admin_projects_update() -> str | Response:
+async def admin_projects_update() -> str | Response | tuple[Mapping[str, Any], 
int]:
     """Update projects from remote data."""
     if request.method == "POST":
         try:
-            apache_projects = await get_projects_data()
-            podlings_data = await get_current_podlings_data()
-            groups_data = await get_groups_data()
+            updated_count = await _update_pmcs()
+            return {
+                "message": f"Successfully updated {updated_count} projects 
(PMCs and PPMCs) with membership data",
+                "category": "success",
+            }, 200
         except httpx.RequestError as e:
-            await flash(f"Failed to fetch data: {e!s}", "error")
-            return redirect(url_for("admin.admin_projects_update"))
-
-        updated_count = 0
-
-        try:
-            async with get_session() as db_session:
-                async with db_session.begin():
-                    # First update PMCs
-                    for project in apache_projects.projects:
-                        name = project.name
-                        # Skip non-PMC committees
-                        if not project.pmc:
-                            continue
-
-                        # Get or create PMC
-                        statement = select(PMC).where(PMC.project_name == name)
-                        pmc = (await 
db_session.execute(statement)).scalar_one_or_none()
-                        if not pmc:
-                            pmc = PMC(project_name=name)
-                            db_session.add(pmc)
-
-                        # Update PMC data from groups.json
-                        pmc_members = groups_data.get(f"{name}-pmc")
-                        committers = groups_data.get(name)
-                        pmc.pmc_members = pmc_members if pmc_members is not 
None else []
-                        pmc.committers = committers if committers is not None 
else []
-                        # Ensure this is set for PMCs
-                        pmc.is_podling = False
-
-                        # For release managers, use PMC members for now
-                        # TODO: Consider a more sophisticated way to determine 
release managers
-                        pmc.release_managers = pmc.pmc_members
-
-                        updated_count += 1
-
-                    # Then add PPMCs (podlings)
-                    for podling_name, podling_data in podlings_data:
-                        # Get or create PPMC
-                        statement = select(PMC).where(PMC.project_name == 
podling_name)
-                        ppmc = (await 
db_session.execute(statement)).scalar_one_or_none()
-                        if not ppmc:
-                            ppmc = PMC(project_name=podling_name)
-                            db_session.add(ppmc)
-
-                        # Update PPMC data from groups.json
-                        ppmc.is_podling = True
-                        pmc_members = groups_data.get(f"{podling_name}-pmc")
-                        committers = groups_data.get(podling_name)
-                        ppmc.pmc_members = pmc_members if pmc_members is not 
None else []
-                        ppmc.committers = committers if committers is not None 
else []
-                        # Use PPMC members as release managers
-                        ppmc.release_managers = ppmc.pmc_members
-
-                        updated_count += 1
-
-                    # Add special entry for Tooling PMC
-                    # Not clear why, but it's not in the Whimsy data
-                    statement = select(PMC).where(PMC.project_name == 
"tooling")
-                    tooling_pmc = (await 
db_session.execute(statement)).scalar_one_or_none()
-                    if not tooling_pmc:
-                        tooling_pmc = PMC(project_name="tooling")
-                        db_session.add(tooling_pmc)
-                        updated_count += 1
-
-                    # Update Tooling PMC data
-                    # Could put this in the "if not tooling_pmc" block, perhaps
-                    tooling_pmc.pmc_members = ["wave", "tn", "sbp"]
-                    tooling_pmc.committers = ["wave", "tn", "sbp"]
-                    tooling_pmc.release_managers = ["wave"]
-                    tooling_pmc.is_podling = False
-
-            await flash(
-                f"Successfully updated {updated_count} projects (PMCs and 
PPMCs) with membership data", "success"
-            )
+            return {
+                "message": f"Failed to fetch data: {e!s}",
+                "category": "error",
+            }, 200
         except Exception as e:
-            await flash(f"Failed to update projects: {e!s}", "error")
-
-        return redirect(url_for("admin.admin_projects_update"))
+            return {
+                "message": f"Failed to update projects: {e!s}",
+                "category": "error",
+            }, 200
 
     # For GET requests, show the update form
     return await render_template("update-pmcs.html")
 
 
+async def _update_pmcs() -> int:
+    apache_projects = await get_projects_data()
+    podlings_data = await get_current_podlings_data()
+    groups_data = await get_groups_data()
+
+    updated_count = 0
+
+    async with get_session() as db_session:
+        async with db_session.begin():
+            # First update PMCs
+            for project in apache_projects.projects:
+                name = project.name
+                # Skip non-PMC committees
+                if not project.pmc:
+                    continue
+
+                # Get or create PMC
+                statement = select(PMC).where(PMC.project_name == name)
+                pmc = (await 
db_session.execute(statement)).scalar_one_or_none()
+                if not pmc:
+                    pmc = PMC(project_name=name)
+                    db_session.add(pmc)
+
+                # Update PMC data from groups.json
+                pmc_members = groups_data.get(f"{name}-pmc")
+                committers = groups_data.get(name)
+                pmc.pmc_members = pmc_members if pmc_members is not None else 
[]
+                pmc.committers = committers if committers is not None else []
+                # Ensure this is set for PMCs
+                pmc.is_podling = False
+
+                # For release managers, use PMC members for now
+                # TODO: Consider a more sophisticated way to determine release 
managers
+                pmc.release_managers = pmc.pmc_members
+
+                updated_count += 1
+
+            # Then add PPMCs (podlings)
+            for podling_name, podling_data in podlings_data:
+                # Get or create PPMC
+                statement = select(PMC).where(PMC.project_name == podling_name)
+                ppmc = (await 
db_session.execute(statement)).scalar_one_or_none()
+                if not ppmc:
+                    ppmc = PMC(project_name=podling_name)
+                    db_session.add(ppmc)
+
+                # Update PPMC data from groups.json
+                ppmc.is_podling = True
+                pmc_members = groups_data.get(f"{podling_name}-pmc")
+                committers = groups_data.get(podling_name)
+                ppmc.pmc_members = pmc_members if pmc_members is not None else 
[]
+                ppmc.committers = committers if committers is not None else []
+                # Use PPMC members as release managers
+                ppmc.release_managers = ppmc.pmc_members
+
+                updated_count += 1
+
+            # Add special entry for Tooling PMC
+            # Not clear why, but it's not in the Whimsy data
+            statement = select(PMC).where(PMC.project_name == "tooling")
+            tooling_pmc = (await 
db_session.execute(statement)).scalar_one_or_none()
+            if not tooling_pmc:
+                tooling_pmc = PMC(project_name="tooling")
+                db_session.add(tooling_pmc)
+                updated_count += 1
+
+            # Update Tooling PMC data
+            # Could put this in the "if not tooling_pmc" block, perhaps
+            tooling_pmc.pmc_members = ["wave", "tn", "sbp"]
+            tooling_pmc.committers = ["wave", "tn", "sbp"]
+            tooling_pmc.release_managers = ["wave"]
+            tooling_pmc.is_podling = False
+
+    return updated_count
+
+
 @blueprint.route("/debug/database")
 async def admin_debug_database() -> str:
     """Debug information about the database."""
diff --git a/atr/blueprints/admin/templates/update-pmcs.html 
b/atr/blueprints/admin/templates/update-pmcs.html
index bbb272d..16714ed 100644
--- a/atr/blueprints/admin/templates/update-pmcs.html
+++ b/atr/blueprints/admin/templates/update-pmcs.html
@@ -30,6 +30,10 @@
           background: #047;
       }
 
+      button:disabled {
+          color: gray;
+      }
+
       div.warning {
           margin: 1.5rem 0;
           padding: 1rem;
@@ -84,7 +88,56 @@
     </ul>
   </div>
 
-  <form method="post">
-    <button type="submit">Update Projects</button>
+  <div id="status"></div>
+
+  <form action="javascript:submitForm().then(_ => { return false; })">
+    <button type="submit" id="submitButton">Update Projects</button>
   </form>
+
+  <script>
+    const submitForm = async () => {
+      const button = document.getElementById("submitButton");
+      button.disabled = true;
+      document.body.style.cursor = 'wait'
+
+      const statusElement = document.getElementById("status");
+      while (statusElement.firstChild) {
+        statusElement.firstChild.remove();
+      }
+
+      try {
+          const response = await fetch(window.location.href, {
+              method: "POST",
+          });
+
+          if (!response.ok) {
+              addStatusMessage(statusElement, "Could not make network 
request", "error");
+              return
+          }
+
+          const data = await response.json();
+          addStatusMessage(statusElement, data.message, data.category)
+      } catch (error) {
+          addStatusMessage(statusElement, error, "error")
+      } finally {
+        button.disabled = false;
+        document.body.style.cursor = 'default'
+      }
+    };
+
+    function addStatusMessage(parentElement, message, category) {
+      const divElement = document.createElement("div");
+      divElement.classList.add("status-message");
+      divElement.classList.add(category);
+      if (category === "error") {
+          const prefixElement = document.createElement("strong");
+          const textElement = document.createTextNode("Error: ");
+          prefixElement.appendChild(textElement);
+          divElement.appendChild(prefixElement);
+      }
+      const textNode = document.createTextNode(message);
+      divElement.appendChild(textNode);
+      parentElement.appendChild(divElement);
+    }
+  </script>
 {% endblock content %}


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

Reply via email to