Files
carbon-lang/github_tools/update_label_access.py
T
Jon Meow 107848e30f Switch mypy approach to pre-commit (#1234)
I'm treating my PR to mypy bazel integration as dead in the water. Abandoning that approach, this seems to work reasonably well as a replacement. It's actually a slightly newer version of mypy too -- the bazel integration was stuck on an old version.

Note I don't think we're losing much: we shouldn't be writing too much python.
2022-05-09 09:54:12 -07:00

146 lines
4.0 KiB
Python

"""Updates the contributors-with-label-access team.
This team exists because we need a team to manage triage access to repos;
GitHub doesn't allow the org to be set to triage access, only read/write. It
will be updated to include all members of the carbon-language organization.
"""
__copyright__ = """
Part of the Carbon Language project, under the Apache License v2.0 with LLVM
Exceptions. See /LICENSE for license information.
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
"""
import argparse
from typing import List, Optional, Set
# https://github.com/PyGithub/PyGithub
# GraphQL is preferred, but falling back to pygithub for unsupported mutations.
import github
from github_tools import github_helpers
# The organization to mirror members from.
_ORG = "carbon-language"
# The team to mirror to.
_TEAM = "contributors"
# Accounts in the org to skip mirroring.
_IGNORE_ACCOUNTS = ("CarbonLangInfra", "google-admin", "googlebot")
# Queries organization members.
_ORG_MEMBER_QUERY = """
query {
organization(login: "%s") {
membersWithRole(first: 100%%(cursor)s) {
nodes {
login
}
%%(pagination)s
}
}
}
"""
# The path for nodes in _ORG_MEMBER_QUERY.
_ORG_MEMBER_PATH = ("organization", "membersWithRole")
# Queries team members.
_TEAM_MEMBER_QUERY = """
query {
organization(login: "%s") {
team(slug: "%s") {
members(first: 100%%(cursor)s) {
nodes {
login
}
%%(pagination)s
}
}
}
}
"""
# The path for nodes in _TEAM_MEMBER_QUERY.
_TEAM_MEMBER_PATH = ("organization", "team", "members")
def _parse_args(args: Optional[List[str]] = None) -> argparse.Namespace:
"""Parses command-line arguments and flags."""
parser = argparse.ArgumentParser(description=__doc__)
github_helpers.add_access_token_arg(parser, "admin:org, repo")
return parser.parse_args(args=args)
def _load_org_members(client: github_helpers.Client) -> Set[str]:
"""Loads org members."""
print("Loading %s..." % _ORG)
org_members = set()
ignored = set()
for node in client.execute_and_paginate(
_ORG_MEMBER_QUERY % _ORG, _ORG_MEMBER_PATH
):
login = node["login"]
if login not in _IGNORE_ACCOUNTS:
org_members.add(login)
else:
ignored.add(login)
print(
"%s has %d non-ignored members, and %d ignored."
% (_ORG, len(org_members), len(ignored))
)
unignored = set(_IGNORE_ACCOUNTS) - ignored
assert not unignored, "Missing ignored accounts: %s" % unignored
return org_members
def _load_team_members(client: github_helpers.Client) -> Set[str]:
"""Load team members."""
print("Loading %s..." % _TEAM)
team_members = set()
for node in client.execute_and_paginate(
_TEAM_MEMBER_QUERY % (_ORG, _TEAM), _TEAM_MEMBER_PATH
):
team_members.add(node["login"])
print("%s has %d members." % (_ORG, len(team_members)))
return team_members
def _update_team(
gh: github.Github, org_members: Set[str], team_members: Set[str]
) -> None:
"""Updates the team if needed.
This switches to pygithub because GraphQL lacks equivalent mutation support.
"""
gh_team = gh.get_organization(_ORG).get_team_by_slug(_TEAM)
add_members = org_members - team_members
if add_members:
print("Adding members: %s" % ", ".join(add_members))
for member in add_members:
gh_team.add_membership(gh.get_user(member))
remove_members = team_members - org_members
if remove_members:
print("Removing members: %s" % ", ".join(remove_members))
for member in remove_members:
gh_team.remove_membership(gh.get_user(member))
def main() -> None:
parsed_args = _parse_args()
print("Connecting...")
client = github_helpers.Client(parsed_args)
org_members = _load_org_members(client)
team_members = _load_team_members(client)
if org_members != team_members:
gh = github.Github(parsed_args.access_token)
_update_team(gh, org_members, team_members)
print("Done!")
if __name__ == "__main__":
main()