Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend inactive user automation to warn about inactive WG users #918

Merged
merged 2 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions org/org_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@ def load_from_project(self):
def get_contributors(self) -> Set[str]:
return set(self.contributors)

def get_community_members_with_role(self) -> Set[str]:
result = set(self.toc)
def get_community_members_with_role_by_wg(self) -> Dict[str, Set[str]]:
result = {"toc": set(self.toc)}
for wg in self.working_groups:
result |= OrgGenerator._wg_github_users(wg)
result[wg["name"]] = OrgGenerator._wg_github_users(wg)
return result

def generate_org_members(self):
Expand Down
38 changes: 27 additions & 11 deletions org/org_user_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,21 @@ def _write_yaml_file(self, path, data):
with open(path, "w") as f:
yaml.dump(data, f)

def _get_inactive_users_msg_for_wgs(self, inactive_users_by_wg, user_tagging_prefix):
result = "\n\nWarning:\n" if inactive_users_by_wg else ""
for wg, users in inactive_users_by_wg.items():
wg_users_as_list = "\n".join(str(user_tagging_prefix + s) for s in users)
result += f'Inactive users of Working Group "{wg}" are: \n{wg_users_as_list}\n'
return result

def delete_inactive_contributors(self, users_to_delete):
path = f"{_SCRIPT_PATH}/contributors.yml"
contributors_yaml = self._load_yaml_file(path)
users_to_delete_lower = [user.lower() for user in users_to_delete]
contributors_yaml["contributors"] = [c for c in contributors_yaml["contributors"] if c.lower() not in users_to_delete_lower]
self._write_yaml_file(path, contributors_yaml)

def get_inactive_users_msg(self, users_to_delete, tagusers):
def get_inactive_users_msg(self, users_to_delete, inactive_users_by_wg, tagusers):
rfc = (
"https://github.com/cloudfoundry/community/blob/main/toc/rfc/"
"rfc-0025-define-criteria-and-removal-process-for-inactive-members.md"
Expand All @@ -107,21 +114,28 @@ def get_inactive_users_msg(self, users_to_delete, tagusers):
"criteria-and-removal-process-for-inactive-members.md#remove-the-membership-to-the-cloud-foundry-github-organization"
)

rfc_promotion_rules = (
"https://github.com/cloudfoundry/community/blob/main/toc/rfc/rfc-0008-role-change-process.md#proposal"
)
rfc_promotion_rules = "https://github.com/cloudfoundry/community/blob/main/toc/rfc/rfc-0008-role-change-process.md#proposal"

user_tagging_prefix = "@" if tagusers else ""
users_as_list = "\n".join(str(user_tagging_prefix + s) for s in users_to_delete)
return (
f"According to the rules for inactivity defined in [RFC-0025]({rfc}) following users will be deleted:\n"
f"{users_as_list}\nAccording to the [revocation policy in the RFC]({rfc_revocation_rules}), users have"
" two weeks to refute this revocation, if they wish by commenting on this pull-request\n"
" two weeks to refute this revocation, if they wish by commenting on this pull-request "
"and open a new pull-request to be re-added as contributor after this one is merged.\n"
f"As alternative, if you are active in a working group please check the [promotion rules]({rfc_promotion_rules})\n"
f"As alternative, if you are active in a working group please check the [promotion rules]({rfc_promotion_rules}) "
"and if you are eligible and wish apply for a role in that working group."
f"{self._get_inactive_users_msg_for_wgs(inactive_users_by_wg, user_tagging_prefix)}"
)

def get_inactive_users_by_wg(self, inactive_users, community_members_with_role_by_wg):
result = dict()
for wg, members in community_members_with_role_by_wg.items():
wg_inactive_members = inactive_users.intersection(members)
if len(wg_inactive_members) != 0 and wg != "Admin":
result[wg] = wg_inactive_members
return result

@staticmethod
def _get_bool_env_var(env_var_name, default):
return os.getenv(env_var_name, default).lower() == "true"
Expand Down Expand Up @@ -154,7 +168,10 @@ def _get_bool_env_var(env_var_name, default):
print("Get information about community users")
generator = OrgGenerator()
generator.load_from_project()
community_members_with_role = generator.get_community_members_with_role()
community_members_with_role_by_wg = generator.get_community_members_with_role_by_wg()
community_members_with_role = set()
for members in community_members_with_role_by_wg.values():
community_members_with_role |= set(members)

print("Analyzing Cloud Foundry org user activity.")
userHandler = InactiveUserHandler(args.githuborg, args.githuborgid, args.sincedate, args.githubtoken)
Expand All @@ -163,16 +180,15 @@ def _get_bool_env_var(env_var_name, default):
print(f"Inactive users length is {len(inactive_users)} and inactive users are {inactive_users}")
users_to_delete = inactive_users - community_members_with_role
tagusers = args.tagusers or InactiveUserHandler._get_bool_env_var("INACTIVE_USER_MANAGEMENT_TAG_USERS", "False")
inactive_users_msg = userHandler.get_inactive_users_msg(users_to_delete, tagusers)
inactive_users_by_wg = userHandler.get_inactive_users_by_wg(inactive_users, community_members_with_role_by_wg)
inactive_users_msg = userHandler.get_inactive_users_msg(users_to_delete, inactive_users_by_wg, tagusers)
if args.dryrun or InactiveUserHandler._get_bool_env_var("INACTIVE_USER_MANAGEMENT_DRY_RUN", "False"):
print(f"Dry-run mode.\nInactive_users_msg is: {inactive_users_msg}")
print(f"Following users will be deleted: {inactive_users}")
print(f"Inactive users by wg are {inactive_users_by_wg}")
elif users_to_delete:
userHandler.delete_inactive_contributors(users_to_delete)
with open(os.environ["GITHUB_OUTPUT"], "a") as env:
separator = uuid.uuid1()
step_output_name = "inactive_users_pr_description"
print(f"{step_output_name}<<{separator}\n{inactive_users_msg}\n{separator}", file=env)

inactive_users_with_role = community_members_with_role.intersection(inactive_users)
print(f"Inactive users with role length is {len(inactive_users_with_role)} and users are {inactive_users_with_role}")