This is an automated email from the ASF dual-hosted git repository. tn pushed a commit to branch add-project-model in repository https://gitbox.apache.org/repos/asf/tooling-trusted-release.git
The following commit(s) were added to refs/heads/add-project-model by this push: new 5829387 further updates 5829387 is described below commit 5829387f153f38110034f7fd57f38ec240cab038 Author: Thomas Neidhart <t...@apache.org> AuthorDate: Tue Mar 11 16:14:13 2025 +0100 further updates --- atr/blueprints/admin/admin.py | 66 ++++++++++++++++++------------------ atr/datasources/apache.py | 15 ++++++++ atr/db/models.py | 6 ++-- atr/templates/pmc-directory.html | 6 +++- atr/templates/pmc-view.html | 21 ++++++++++-- atr/templates/project-directory.html | 6 +++- atr/templates/project-view.html | 2 +- 7 files changed, 81 insertions(+), 41 deletions(-) diff --git a/atr/blueprints/admin/admin.py b/atr/blueprints/admin/admin.py index 3f3d716..f721dd1 100644 --- a/atr/blueprints/admin/admin.py +++ b/atr/blueprints/admin/admin.py @@ -30,9 +30,7 @@ from werkzeug.wrappers.response import Response from asfquart.base import ASFQuartException from asfquart.session import read as session_read from atr.datasources.apache import ( - get_active_committee_data, get_current_podlings_data, - get_groups_data, get_ldap_projects_data, get_projects_data, ) @@ -209,10 +207,8 @@ async def admin_projects_update() -> str | Response | tuple[Mapping[str, Any], i async def _update_pmcs() -> int: - committee_data = await get_active_committee_data() ldap_projects = await get_ldap_projects_data() podlings_data = await get_current_podlings_data() - groups_data = await get_groups_data() projects_data = await get_projects_data() updated_count = 0 @@ -220,37 +216,36 @@ async def _update_pmcs() -> int: async with create_async_db_session() as db_session: async with db_session.begin(): # First update PMCs - for committee in committee_data.committees: - name = committee.name - # Skip non-PMC committees - if not committee.pmc: + for ldap_project_data in ldap_projects.projects: + name = ldap_project_data.name + if not ldap_project_data.pmc and ldap_project_data.podling is None: continue + _LOGGER.debug(f"Updating PMC {name}") + # Get or create PMC pmc = await get_pmc_by_name(name, db_session) if not pmc: pmc = PMC(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 [] - pmc.full_name = committee.display_name - pmc.description = committee.description - # 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 - # from my POV, the list of release managers should be the list of people - # that have actually cut a release for that project - pmc.release_managers = pmc.pmc_members + pmc.pmc_members = ldap_project_data.owners + pmc.committers = ldap_project_data.members + if ldap_project_data.pmc: + pmc.is_podling = False + elif ldap_project_data.podling == "current": + pmc.is_podling = True + else: + _LOGGER.error(f"unexpected pmc/podling state for project {name}") + + project_data = projects_data.get(name) + if project_data: + pmc.full_name = project_data.name + pmc.description = project_data.description updated_count += 1 - # Then add PPMCs (podlings) + # Fill PPMC data from podlings.json for podling_name, podling_data in podlings_data: # Get or create PPMC ppmc = await get_pmc_by_name(podling_name, db_session) @@ -258,27 +253,31 @@ async def _update_pmcs() -> int: ppmc = PMC(name=podling_name) db_session.add(ppmc) - # Update PPMC data from groups.json - 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 ppmc.full_name = podling_data.name ppmc.description = podling_data.description ppmc.parent_pmc = await get_pmc_by_name(podling_data.pmc, db_session) # type: ignore ppmc.is_podling = True + podling_project = await get_project_by_name(podling_name, db_session) + if not podling_project: + podling_project = Project(name=podling_name) + db_session.add(podling_project) + + podling_project.full_name = podling_data.name + podling_project.description = podling_data.description + podling_project.is_podling = True + podling_project.pmc = ppmc # type: ignore + updated_count += 1 + # TODO: this is only for testing purposes, tooling should not be a PMC afaict # Add special entry for Tooling PMC # Not clear why, but it's not in the Whimsy data - statement = select(PMC).where(PMC.name == "tooling") - tooling_pmc = (await db_session.execute(statement)).scalar_one_or_none() + tooling_pmc = await get_pmc_by_name("tooling", db_session) if not tooling_pmc: tooling_pmc = PMC(name="tooling") db_session.add(tooling_pmc) + updated_count += 1 # Update Tooling PMC data @@ -288,6 +287,7 @@ async def _update_pmcs() -> int: tooling_pmc.release_managers = ["wave"] tooling_pmc.is_podling = False + # create projects from projects.json for project_name, project_status in projects_data: # Get or create Project project = await get_project_by_name(project_name, db_session) diff --git a/atr/datasources/apache.py b/atr/datasources/apache.py index 797227a..ae1da1a 100644 --- a/atr/datasources/apache.py +++ b/atr/datasources/apache.py @@ -36,6 +36,7 @@ _WHIMSY_PROJECTS_URL = "https://whimsy.apache.org/public/public_ldap_projects.js _PROJECTS_PROJECTS_URL = "https://projects.apache.org/json/foundation/projects.json" _PROJECTS_PODLINGS_URL = "https://projects.apache.org/json/foundation/podlings.json" _PROJECTS_GROUPS_URL = "https://projects.apache.org/json/foundation/groups.json" +_PROJECTS_PEOPLE_NAME_URL = "https://projects.apache.org/json/foundation/people_name.json" VT = TypeVar("VT") @@ -159,6 +160,10 @@ class ProjectsData(_DictRootModel[ProjectStatus]): pass +class PeopleNameData(_DictRootModel[str]): + pass + + async def get_ldap_projects_data() -> LDAPProjectsData: async with httpx.AsyncClient() as client: response = await client.get(_WHIMSY_PROJECTS_URL) @@ -218,3 +223,13 @@ async def get_projects_data() -> ProjectsData: response.raise_for_status() data = response.json() return ProjectsData.model_validate(data) + + +async def get_people_name_data() -> PeopleNameData: + """Returns the list users and their names.""" + + async with httpx.AsyncClient() as client: + response = await client.get(_PROJECTS_PEOPLE_NAME_URL) + response.raise_for_status() + data = response.json() + return PeopleNameData.model_validate(data) diff --git a/atr/db/models.py b/atr/db/models.py index fa05a9c..7e72b3d 100644 --- a/atr/db/models.py +++ b/atr/db/models.py @@ -90,9 +90,10 @@ class PMC(ATRSQLModel, table=True): id: int | None = sqlmodel.Field(default=None, primary_key=True) name: str = sqlmodel.Field(unique=True) full_name: str | None = sqlmodel.Field(default=None) + description: str | None = sqlmodel.Field(default=None) + # True if this a podling PPMC is_podling: bool = sqlmodel.Field(default=False) - description: str | None = sqlmodel.Field(default=None) # One-to-many: A PMC can have parent PMC, e.g. in the case of a PPMC child_pmcs: list["PMC"] = sqlmodel.Relationship( @@ -135,13 +136,14 @@ class PMC(ATRSQLModel, table=True): @property def display_name(self) -> str: """Get the display name for the PMC/PPMC.""" - return self.name if self.full_name is None else self.full_name + return f"{self.name.capitalize()}{' (PPMC)' if self.is_podling else ''}" class Project(ATRSQLModel, table=True): id: int | None = sqlmodel.Field(default=None, primary_key=True) name: str = sqlmodel.Field(unique=True) full_name: str | None = sqlmodel.Field(default=None) + description: str | None = sqlmodel.Field(default=None) # True if this a podling PPMC is_podling: bool = sqlmodel.Field(default=False) diff --git a/atr/templates/pmc-directory.html b/atr/templates/pmc-directory.html index 2fbde53..572d09e 100644 --- a/atr/templates/pmc-directory.html +++ b/atr/templates/pmc-directory.html @@ -109,7 +109,11 @@ for (let card of cards) { const nameElement = card.getElementsByClassName("pmc-name"); const name = nameElement[0].innerHTML; - card.hidden = !pmcFilter || name.search(new RegExp(pmcFilter, "i")) < 0; + if (!pmcFilter) { + card.hidden = false; + } else { + card.hidden = name.search(new RegExp(pmcFilter, "i")) < 0; + } } } </script> diff --git a/atr/templates/pmc-view.html b/atr/templates/pmc-view.html index f0ee969..af9e96f 100644 --- a/atr/templates/pmc-view.html +++ b/atr/templates/pmc-view.html @@ -79,14 +79,27 @@ {% endblock stylesheets %} {% block content %} - <h1>{{ pmc.display_name | capitalize }}</h1> + <h1>{{ pmc.display_name }}</h1> + + {% if pmc.parent_pmc %} + <div class="card-header"> + <h3>Parent PMC</h3> + <div class="card-meta"></div> + <div class="card-body"></div> + <a href="{{ url_for('root_pmc_view', name=pmc.parent_pmc.name) }}"> + {{ pmc.parent_pmc.display_name }} + </a> + </div> + {% endif %} <div class="card-header"> <h3>PMC members</h3> <div class="card-meta"></div> <div class="card-body"> <p> - {% for user in pmc.pmc_members %}{{ user }},{% endfor %} + {% for user in pmc.pmc_members %} + {{ user }}, + {% endfor %} </p> </div> </div> @@ -96,7 +109,9 @@ <div class="card-meta"></div> <div class="card-body"> <p> - {% for user in pmc.committers %}{{ user }},{% endfor %} + {% for user in pmc.committers %} + {{ user }}, + {% endfor %} </p> </div> </div> diff --git a/atr/templates/project-directory.html b/atr/templates/project-directory.html index aca5812..f9d7c58 100644 --- a/atr/templates/project-directory.html +++ b/atr/templates/project-directory.html @@ -96,7 +96,11 @@ for (let card of cards) { const nameElement = card.getElementsByClassName("project-name"); const name = nameElement[0].innerHTML; - card.hidden = !projectFilter || name.search(new RegExp(projectFilter, "i")) < 0; + if (!projectFilter) { + card.hidden = false; + } else { + card.hidden = name.search(new RegExp(projectFilter, "i")) < 0; + } } } </script> diff --git a/atr/templates/project-view.html b/atr/templates/project-view.html index 8d09a61..8048b1c 100644 --- a/atr/templates/project-view.html +++ b/atr/templates/project-view.html @@ -79,7 +79,7 @@ {% endblock stylesheets %} {% block content %} - <h1>{{ project.display_name | capitalize }}</h1> + <h1>{{ project.display_name }}</h1> <div class="card-header"> <h3>PMC</h3> --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@tooling.apache.org For additional commands, e-mail: commits-h...@tooling.apache.org