atr/datasources/apache.py (127 lines of code) (raw):

# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """Apache specific data-sources.""" from __future__ import annotations import datetime from typing import Annotated, Final import httpx import pydantic import atr.util as util _WHIMSY_COMMITTEE_INFO_URL: Final[str] = "https://whimsy.apache.org/public/committee-info.json" _WHIMSY_COMMITTEE_RETIRED_URL: Final[str] = "https://whimsy.apache.org/public/committee-retired.json" _WHIMSY_PROJECTS_URL: Final[str] = "https://whimsy.apache.org/public/public_ldap_projects.json" _PROJECTS_PROJECTS_URL: Final[str] = "https://projects.apache.org/json/foundation/projects.json" _PROJECTS_PODLINGS_URL: Final[str] = "https://projects.apache.org/json/foundation/podlings.json" _PROJECTS_GROUPS_URL: Final[str] = "https://projects.apache.org/json/foundation/groups.json" class LDAPProjectsData(pydantic.BaseModel): last_timestamp: str = pydantic.Field(alias="lastTimestamp") project_count: int projects: Annotated[list[LDAPProject], util.DictToList(key="name")] @property def last_time(self) -> datetime.datetime: return datetime.datetime.strptime(self.last_timestamp, "%Y%m%d%H%M%S%z") class LDAPProject(pydantic.BaseModel): name: str create_timestamp: str = pydantic.Field(alias="createTimestamp") modify_timestamp: str = pydantic.Field(alias="modifyTimestamp") member_count: int owner_count: int members: list[str] owners: list[str] pmc: bool = False podling: str | None = None class User(pydantic.BaseModel): id: str name: str date: str | None = None class Committee(pydantic.BaseModel): name: str display_name: str site: str | None description: str | None mail_list: str established: str | None report: list[str] chair: Annotated[list[User], util.DictToList(key="id")] roster_count: int roster: Annotated[list[User], util.DictToList(key="id")] pmc: bool class CommitteeData(pydantic.BaseModel): last_updated: str committee_count: int pmc_count: int committees: Annotated[list[Committee], util.DictToList(key="name")] class RetiredCommittee(pydantic.BaseModel): name: str display_name: str retired: str description: str | None class RetiredCommitteeData(pydantic.BaseModel): last_updated: str retired_count: int retired: Annotated[list[RetiredCommittee], util.DictToList(key="name")] class PodlingStatus(pydantic.BaseModel): description: str homepage: str name: str = pydantic.Field(alias="name") pmc: str podling: bool started: str champion: str | None = None retiring: bool | None = None resolution: str | None = None class PodlingsData(util.DictRootModel[PodlingStatus]): pass class GroupsData(util.DictRootModel[list[str]]): pass class Release(pydantic.BaseModel): created: str | None = None name: str revision: str | None = None class ProjectStatus(pydantic.BaseModel): category: str | None = None created: str | None = None description: str | None = None programming_language: str | None = pydantic.Field(alias="programming-language", default=None) doap: str homepage: str name: str pmc: str shortdesc: str | None = None repository: list[str | dict] = pydantic.Field(default_factory=list) release: list[Release] = pydantic.Field(default_factory=list) class ProjectsData(util.DictRootModel[ProjectStatus]): pass async def get_active_committee_data() -> CommitteeData: """Returns the list of currently active committees.""" async with httpx.AsyncClient() as client: response = await client.get(_WHIMSY_COMMITTEE_INFO_URL) response.raise_for_status() data = response.json() return CommitteeData.model_validate(data) async def get_current_podlings_data() -> PodlingsData: """Returns the list of current podlings.""" async with httpx.AsyncClient() as client: response = await client.get(_PROJECTS_PODLINGS_URL) response.raise_for_status() data = response.json() return PodlingsData.model_validate(data) async def get_groups_data() -> GroupsData: """Returns LDAP Groups with their members.""" async with httpx.AsyncClient() as client: response = await client.get(_PROJECTS_GROUPS_URL) response.raise_for_status() data = response.json() return GroupsData.model_validate(data) async def get_ldap_projects_data() -> LDAPProjectsData: async with httpx.AsyncClient() as client: response = await client.get(_WHIMSY_PROJECTS_URL) response.raise_for_status() data = response.json() return LDAPProjectsData.model_validate(data) async def get_projects_data() -> ProjectsData: """Returns the list of projects.""" async with httpx.AsyncClient() as client: response = await client.get(_PROJECTS_PROJECTS_URL) response.raise_for_status() data = response.json() return ProjectsData.model_validate(data) async def get_retired_committee_data() -> RetiredCommitteeData: """Returns the list of retired committees.""" async with httpx.AsyncClient() as client: response = await client.get(_WHIMSY_COMMITTEE_RETIRED_URL) response.raise_for_status() data = response.json() return RetiredCommitteeData.model_validate(data)