Skip to content

Commit 4d96ee0

Browse files
authored
Merge pull request #80 from OpenRailAssociation/remove-surplus-members-and-teams
2 parents ae19bc1 + d091001 commit 4d96ee0

File tree

4 files changed

+66
-19
lines changed

4 files changed

+66
-19
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Afterwards, the tool is executable with the command `gh-org-mgr`. The `--help` f
4848

4949
Inside [`config/example`](./config/example), you can find an example configuration that shall help you to understand the structure:
5050

51-
* `app.yaml`: Configuration necessary to run this tool
51+
* `app.yaml`: Configuration necessary to run this tool and controlling some behaviour
5252
* `org.yaml`: Organization-wide configuration
5353
* `teams/*.yaml`: Configuration concerning the teams of your organization.
5454

config/example/app.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,10 @@ github_app_private_key: |
3838
D9zgrlJ8D4bxPrwDrCuXHY7s/1/uCX3K+mS7CWpybOcJY4XzsNznOYcMQzw22fxl
3939
u1ioG/s3Ahhd778VIjj5d32Xbjj8vbSFj8vJe5bBNblYbelWfETg
4040
-----END RSA PRIVATE KEY-----
41+
42+
# Remove members from organisation who are not member of any team or
43+
# organisation owners. Default: false
44+
remove_members_without_team: false
45+
46+
# Delete teams that are not configured. Default: false
47+
delete_unconfigured_teams: false

gh_org_mgr/_gh_org.py

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,10 @@ def sync_teams_members(self, dry: bool = False) -> None: # pylint: disable=too-
550550
open_invitations = [user.login.lower() for user in self.org.invitations()]
551551

552552
for team, team_attrs in self.current_teams.items():
553+
# Ignore any team not being configured locally, will be handled later
554+
if team.name not in self.configured_teams:
555+
continue
556+
553557
# Update current team members with dict[NamedUser, str (role)]
554558
team_attrs["members"] = self._get_current_team_members(team)
555559

@@ -559,15 +563,6 @@ def sync_teams_members(self, dry: bool = False) -> None: # pylint: disable=too-
559563
user.login.lower(): role for user, role in team_attrs["members"].items()
560564
}
561565

562-
# Handle the team not being configured locally
563-
if team.name not in self.configured_teams:
564-
logging.warning(
565-
"Team '%s' does not seem to be configured locally. "
566-
"Taking no action about this team at all",
567-
team.name,
568-
)
569-
continue
570-
571566
# Get configuration from current team
572567
if team_configuration := self.configured_teams.get(team.name):
573568
pass
@@ -666,8 +661,35 @@ def sync_teams_members(self, dry: bool = False) -> None: # pylint: disable=too-
666661
team.name,
667662
)
668663

669-
def get_members_without_team(self) -> None:
670-
"""Get all organisation members without any team membership"""
664+
def get_unconfigured_teams(
665+
self, dry: bool = False, delete_unconfigured_teams: bool = False
666+
) -> None:
667+
"""Get all teams that are not configured locally and optionally remove them"""
668+
# Get all teams that are not configured locally
669+
unconfigured_teams: list[Team] = []
670+
for team in self.current_teams:
671+
if team.name not in self.configured_teams:
672+
unconfigured_teams.append(team)
673+
674+
if unconfigured_teams:
675+
if delete_unconfigured_teams:
676+
for team in unconfigured_teams:
677+
logging.info("Deleting team '%s' as it is not configured locally", team.name)
678+
if not dry:
679+
team.delete()
680+
else:
681+
unconfigured_teams_str = [team.name for team in unconfigured_teams]
682+
logging.warning(
683+
"The following teams of your GitHub organisation are not "
684+
"configured locally: %s. Taking no action about these teams.",
685+
", ".join(unconfigured_teams_str),
686+
)
687+
688+
def get_members_without_team(
689+
self, dry: bool = False, remove_members_without_team: bool = False
690+
) -> None:
691+
"""Get all organisation members without any team membership, and
692+
optionally remove them"""
671693
# Combine org owners and org members
672694
all_org_members = set(self.org_members + self.current_org_owners)
673695

@@ -685,11 +707,21 @@ def get_members_without_team(self) -> None:
685707
members_without_team = all_org_members.difference(all_team_members)
686708

687709
if members_without_team:
688-
members_without_team_str = [user.login for user in members_without_team]
689-
logging.warning(
690-
"The following members of your GitHub organisation are not member of any team: %s",
691-
", ".join(members_without_team_str),
692-
)
710+
if remove_members_without_team:
711+
for user in members_without_team:
712+
logging.info(
713+
"Removing user '%s' from organisation as they are not member of any team",
714+
user.login,
715+
)
716+
if not dry:
717+
self.org.remove_from_membership(user)
718+
else:
719+
members_without_team_str = [user.login for user in members_without_team]
720+
logging.warning(
721+
"The following members of your GitHub organisation are not "
722+
"member of any team: %s",
723+
", ".join(members_without_team_str),
724+
)
693725

694726
# --------------------------------------------------------------------------
695727
# Repos

gh_org_mgr/manage.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,16 @@ def main():
129129
org.sync_current_teams_settings(dry=args.dry)
130130
# Synchronise the team memberships
131131
org.sync_teams_members(dry=args.dry)
132-
# Report about organisation members that do not belong to any team
133-
org.get_members_without_team()
132+
# Report and act on teams that are not configured locally
133+
org.get_unconfigured_teams(
134+
dry=args.dry,
135+
delete_unconfigured_teams=cfg_app.get("delete_unconfigured_teams", False),
136+
)
137+
# Report and act on organisation members that do not belong to any team
138+
org.get_members_without_team(
139+
dry=args.dry,
140+
remove_members_without_team=cfg_app.get("remove_members_without_team", False),
141+
)
134142
# Synchronise the permissions of teams for all repositories
135143
org.sync_repo_permissions(dry=args.dry, ignore_archived=args.ignore_archived)
136144
# Remove individual collaborator permissions if they are higher than the one

0 commit comments

Comments
 (0)