| import plugins.ldap |
| import plugins.repositories |
| import asfpy.sqlite |
| import typing |
| import datetime |
| |
| |
| class Committer: |
| def save(self, dbhandle: asfpy.sqlite.DB): |
| document = { |
| 'asfid': self.asf_id, |
| 'githubid': self.github_id, |
| 'mfa': 1 if self.github_mfa else 0, |
| 'updated': datetime.datetime.now(), |
| } |
| dbhandle.update("ids", document, asfid=self.asf_id) |
| |
| def __init__(self, asf_id: str, linkdb: asfpy.sqlite.DB,): |
| self.asf_id = asf_id |
| self.repositories = set() |
| self.projects = set() |
| if linkdb: |
| row = linkdb.fetchone("ids", limit=1, asfid=asf_id) |
| else: |
| row = None |
| if row: |
| self.github_id = row['githubid'] |
| self.github_mfa = bool(row['mfa']) |
| self.real_name = "Foo Bar" |
| else: |
| self.github_id = None |
| self.github_mfa = False |
| self.real_name = "Unknown" |
| |
| def __repr__(self): |
| return self.asf_id |
| |
| def __eq__(self, other): |
| if isinstance(other, str): |
| return other == self.asf_id |
| if not isinstance(other, Committer): |
| return False |
| return self.asf_id == other.asf_id |
| |
| def __hash__(self): |
| return self.asf_id |
| |
| |
| class Project: |
| name: str |
| committers: typing.List[Committer] |
| pmc: typing.List[Committer] |
| public_repos: typing.List[str] |
| private_repos: typing.List[str] |
| |
| def __init__(self, org: 'Organization', name: str, committers: list, pmc: list): |
| self.name = name |
| self.committers = [] |
| for committer in committers: |
| account = org.add_committer(committer) |
| self.committers.append(account) |
| account.projects.add(self) |
| self.pmc = pmc |
| self.public_repos = [] |
| self.private_repos = [] |
| |
| def __repr__(self): |
| return f"Project<{self.name}>" |
| |
| def add_repository(self, reponame: str, private: bool): |
| """Adds a repository to a project and assigns the repo to the commmitter/PMC group as applicable""" |
| if private: |
| self.private_repos.append(reponame) |
| for account in self.pmc: |
| account.repositories.add(reponame) |
| else: |
| self.public_repos.append(reponame) |
| for account in self.committers: |
| account.repositories.add(reponame) |
| |
| def public_github_team(self): |
| """Returns the GitHub IDs of everyone that should be on the GitHub team for this project""" |
| team_ids = set() |
| for committer in self.committers: |
| if committer.github_mfa: |
| team_ids.add(committer.github_id) |
| return list(team_ids) |
| |
| def private_github_team(self): |
| """Returns the GitHub IDs of everyone that should be on the GitHub private team for this project""" |
| team_ids = set() |
| for committer in self.pmc: |
| if committer.github_mfa: |
| team_ids.add(committer.github_id) |
| return list(team_ids) |
| |
| |
| class Organization: |
| committers: typing.List[Committer] |
| projects: typing.Dict[str, Project] |
| linkdb: typing.Optional[asfpy.sqlite.DB] |
| |
| def __init__(self, linkdb: asfpy.sqlite.DB = None): |
| self.committers = list() |
| self.projects = dict() |
| self.linkdb = linkdb |
| |
| def add_project(self, name: str, committers: typing.List[str], pmc: typing.List[str]) -> typing.Optional[Project]: |
| if name and name not in self.projects: |
| project = Project(org=self, name=name, committers=committers, pmc=pmc) |
| if project: |
| self.projects[name] = project |
| return project |
| return None |
| |
| def add_committer(self, asf_id: str): |
| """Adds a new committer to the organization. |
| If already found in previous projects, returns the old committer object""" |
| if asf_id not in self.committers: |
| committer = Committer(asf_id, self.linkdb) |
| self.committers.append(committer) |
| return committer |
| else: |
| for committer in self.committers: |
| if committer.asf_id == asf_id: |
| return committer |
| |
| async def compile_data(ldap: plugins.ldap.LDAPConfig, repositories: typing.List[plugins.repositories.Repository], dbhandle: asfpy.sqlite.DB = None) -> Organization: |
| """Compiles a comprehensive list of projects and people associated with them""" |
| org = Organization() |
| discovered = 0 |
| async with plugins.ldap.LDAPClient(ldap) as lc: |
| for repo in repositories: |
| project = repo.project |
| if project not in org.projects: |
| committers, pmc = await lc.get_members(project) |
| if committers and pmc: |
| discovered += 1 |
| #print(f"Discovered project: {project} - {len(committers)} committers, {len(pmc)} in pmc") |
| if discovered % 50 == 0: |
| print("Discovered %u projects so far..." % discovered) |
| org.add_project(name=project, committers=committers, pmc=pmc) |
| xproject = org.projects[project] |
| xproject.add_repository(repo, repo.private) |
| |
| return org |