From 8392bc4969ae20e38e422e58941ceb142069e0bd Mon Sep 17 00:00:00 2001 From: Michaela Robosova Date: Fri, 7 Feb 2025 16:25:45 +0100 Subject: [PATCH 1/2] Add a script that lists all issues assigned to community --- scripts/get_community_assigned_issues.py | 73 ++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 scripts/get_community_assigned_issues.py diff --git a/scripts/get_community_assigned_issues.py b/scripts/get_community_assigned_issues.py new file mode 100644 index 0000000..b290c2f --- /dev/null +++ b/scripts/get_community_assigned_issues.py @@ -0,0 +1,73 @@ +# Prints a list of links to all issues that are assigned +# to external contributors. +# This is not used by any workflows, and meant to be used locally +# whenever need arises. The script requires `GITHUB_TOKEN` +# environment variable with 'repo' and 'read:org' permissions. + +import os +import requests + +ORG = "learningequality" +REPOS = ["kolibri", "studio", "kolibri-design-system", "le-utils", ".github","ricecooker"] + +TOKEN = os.getenv("GITHUB_TOKEN") +if not TOKEN: + raise EnvironmentError("Please set the GITHUB_TOKEN environment variable with 'repo' and 'read:org' permissions.") + +BASE_URL = "https://api.github.com" +HEADERS = { + "Authorization": f"token {TOKEN}", + "Accept": "application/vnd.github+json" +} + +def get_team_members(org): + """Fetch all team members for the organization.""" + team_members = set() + url = f"{BASE_URL}/orgs/{org}/members" + while url: + response = requests.get(url, headers=HEADERS) + response.raise_for_status() + members = response.json() + team_members.update(member["login"] for member in members) + url = response.links.get("next", {}).get("url") + return team_members + +def get_issues_for_repo(org, repo): + """Fetch all issues for a specific repository.""" + issues = [] + url = f"{BASE_URL}/repos/{org}/{repo}/issues?state=open" + while url: + response = requests.get(url, headers=HEADERS) + response.raise_for_status() + issues.extend(response.json()) + url = response.links.get("next", {}).get("url") + return issues + +def filter_issues(issues, team_members): + """Filter issues assigned to external contributors""" + return [ + issue for issue in issues + if issue.get("assignee") and issue["assignee"]["login"] not in team_members + ] + +def main(): + team_members = get_team_members(ORG) + print(f"Found {len(team_members)} team members in {ORG}.") + + all_filtered_issues = [] + print(f"Processing {len(REPOS)} repositories in {ORG}...") + + for repo in REPOS: + print(f"Processing repository: {repo}") + issues = get_issues_for_repo(ORG, repo) + filtered_issues = filter_issues(issues, team_members) + all_filtered_issues.extend( + issue["html_url"] + for issue in filtered_issues + ) + + for url in all_filtered_issues: + print(url) + +if __name__ == "__main__": + main() From 3f239287c8f18bea04ec434432f83aa4fd148b81 Mon Sep 17 00:00:00 2001 From: Michaela Robosova Date: Wed, 12 Feb 2025 16:51:16 +0100 Subject: [PATCH 2/2] Extract pagination to helper --- scripts/get_community_assigned_issues.py | 28 ++++++++++-------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/scripts/get_community_assigned_issues.py b/scripts/get_community_assigned_issues.py index b290c2f..4e59bf5 100644 --- a/scripts/get_community_assigned_issues.py +++ b/scripts/get_community_assigned_issues.py @@ -20,28 +20,24 @@ "Accept": "application/vnd.github+json" } +def fetch_paginated_results(url): + results = [] + while url: + response = requests.get(url, headers=HEADERS) + response.raise_for_status() + results.extend(response.json()) + url = response.links.get("next", {}).get("url") + return results + def get_team_members(org): """Fetch all team members for the organization.""" - team_members = set() - url = f"{BASE_URL}/orgs/{org}/members" - while url: - response = requests.get(url, headers=HEADERS) - response.raise_for_status() - members = response.json() - team_members.update(member["login"] for member in members) - url = response.links.get("next", {}).get("url") + results = fetch_paginated_results(f"{BASE_URL}/orgs/{org}/members") + team_members = [member["login"] for member in results] return team_members def get_issues_for_repo(org, repo): """Fetch all issues for a specific repository.""" - issues = [] - url = f"{BASE_URL}/repos/{org}/{repo}/issues?state=open" - while url: - response = requests.get(url, headers=HEADERS) - response.raise_for_status() - issues.extend(response.json()) - url = response.links.get("next", {}).get("url") - return issues + return fetch_paginated_results(f"{BASE_URL}/repos/{org}/{repo}/issues?state=open") def filter_issues(issues, team_members): """Filter issues assigned to external contributors"""