import os import subprocess import sys from datetime import datetime, timedelta import requests LIMIT_COMMITS_30_DAYS = 50 # Has to be <= 100 LIMIT_STARS = 200 LIMIT_NLOC = 100000 MARGIN = 0.1 def get_stars_info(owner, repo, token): headers = {"Authorization": f"token {token}"} stars_url = f"https://api.github.com/repos/{owner}/{repo}" stars_response = requests.get(stars_url, headers=headers) if stars_response.status_code != 200: return -1 stars = stars_response.json()["stargazers_count"] return stars def get_commits_last_30_days(owner, repo, token): headers = {"Authorization": f"token {token}"} since = (datetime.now() - timedelta(days=30)).isoformat() print(since) commits_url = f"https://api.github.com/repos/{owner}/{repo}/commits?since={since}&per_page={LIMIT_COMMITS_30_DAYS}" commits_response = requests.get(commits_url, headers=headers) if commits_response.status_code != 200: return -1 commits_30_days = len(commits_response.json()) return commits_30_days def get_lines_of_code(owner, repo): repo_url = f"https://github.com/{owner}/{repo}.git" clone_dir = os.path.expanduser("~/temp/PICable") try: subprocess.run(["git", "clone", repo_url, clone_dir], check=True, stdout=sys.stdout, stderr=sys.stderr) except: return -1 result = subprocess.run(["sloccount", clone_dir], capture_output=True, text=True, check=True) for line in result.stdout.splitlines(): if "Total Physical Source Lines of Code (SLOC)" in line: loc = int(line.split()[8].replace(",", "")) break else: loc = 0 subprocess.run(["rm", "-rf", clone_dir], check=True) return loc def PICable(owner, repository, token): margin_percentage = round(MARGIN * 100) res = "" stars = get_stars_info(owner, repository, token) if stars == -1: return "The repository does not exist or the token is invalid. :x:" if stars >= LIMIT_STARS: res += f"The repository has at least {LIMIT_STARS} stars. :white_check_mark:\n" elif stars >= LIMIT_STARS * (1 - MARGIN): res += f"The repository has {stars}, which is close to the limit of {LIMIT_STARS} stars, considering a {margin_percentage}% margin. :warning:\n" else: res += f"The repository has {stars} stars, which is way below the limit of {LIMIT_STARS} stars, even if considering a {margin_percentage}% margin. :x:\n" commits_30_days = get_commits_last_30_days(owner, repository, token) if commits_30_days == -1: return "The repository does not exist or the token is invalid. :x:" if commits_30_days >= LIMIT_COMMITS_30_DAYS: res += f"The repository has at least {LIMIT_COMMITS_30_DAYS} commits in the last 30 days. :white_check_mark:\n" elif commits_30_days >= LIMIT_COMMITS_30_DAYS * (1 - MARGIN): res += f"The repository has {commits_30_days} commits in the last 30 days, which is close to the limit of {LIMIT_COMMITS_30_DAYS} commits, considering a {margin_percentage}% margin. :warning:\n" else: res += f"The repository has {commits_30_days} commits in the last 30 days, which is way below the limit of {LIMIT_COMMITS_30_DAYS} commits, even if considering a {margin_percentage}% margin. :x:\n" nloc = get_lines_of_code(owner, repository) if nloc == -1: return "The repository does not exist. :x:" if nloc >= LIMIT_NLOC: res += f"The repository has at least {LIMIT_NLOC} lines of code. :white_check_mark:\n" elif nloc >= LIMIT_NLOC * (1 - MARGIN): res += f"The repository has {nloc} lines of code, which is close to the limit of {LIMIT_NLOC} lines of code, considering a {margin_percentage}% margin. :warning:\n" else: res += f"The repository has {nloc} lines of code, which is way below the limit of {LIMIT_NLOC} lines of code, even if considering a {margin_percentage}% margin. :x:\n" res += "\n" repository_url = f"https://www.github.com/{owner}/{repository}" if any( [ stars < LIMIT_STARS * (1 - MARGIN), commits_30_days < LIMIT_COMMITS_30_DAYS * (1 - MARGIN), nloc < LIMIT_NLOC * (1 - MARGIN), ] ): res += f"The repository {repository_url} is not PICable. There are some requirements that are way below the requested limits. :x:\n" elif all([stars >= LIMIT_STARS, commits_30_days >= LIMIT_COMMITS_30_DAYS, nloc >= LIMIT_NLOC]): res += f"The repository {repository_url} is PICable. :white_check_mark:\n" else: res += f"The repository {repository_url} is almost PICable. There are certain requirements which are almost met by this repository. Consult with a professor before proceeding. :warning:\n" return res