From af7fa279c8f88b4d36856201311d87d7ef534a6c Mon Sep 17 00:00:00 2001 From: Dylan Pulver <35541198+dylanpulver@users.noreply.github.com> Date: Thu, 5 Sep 2024 16:55:30 -0400 Subject: [PATCH] Add Script to Generate CONTRIBUTORS.md with Shields.io Badges Based on Merged PRs (#600) * chore: add script to generate CONTRIBUTORS.md based on merged PRs * Handle Pagination --- CONTRIBUTORS.md | 83 +++++++++++++++++++++++++++++ scripts/generate_contributors.py | 90 ++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 CONTRIBUTORS.md create mode 100644 scripts/generate_contributors.py diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 00000000..bae57d25 --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,83 @@ +# Contributors + +## Valued Contributor + +- ![yeisonvargasf Badge](https://img.shields.io/badge/yeisonvargasf-Valued%20Contributor-brightgreen) (66 merged PRs) + +- ![dylanpulver Badge](https://img.shields.io/badge/dylanpulver-Valued%20Contributor-brightgreen) (29 merged PRs) + +- ![pyup-bot Badge](https://img.shields.io/badge/pyup--bot-Valued%20Contributor-brightgreen) (23 merged PRs) + +## Frequent Contributor + +- ![nicholasks Badge](https://img.shields.io/badge/nicholasks-Frequent%20Contributor-brightgreen) (7 merged PRs) + +- ![cb22 Badge](https://img.shields.io/badge/cb22-Frequent%20Contributor-brightgreen) (6 merged PRs) + +## First Contributor + +- ![Jwomers Badge](https://img.shields.io/badge/Jwomers-First%20Contributor-brightgreen) (4 merged PRs) + +- ![PeterDaveHello Badge](https://img.shields.io/badge/PeterDaveHello-First%20Contributor-brightgreen) (3 merged PRs) + +- ![rafaelpivato Badge](https://img.shields.io/badge/rafaelpivato-First%20Contributor-brightgreen) (3 merged PRs) + +- ![cclauss Badge](https://img.shields.io/badge/cclauss-First%20Contributor-brightgreen) (2 merged PRs) + +- ![chowmean Badge](https://img.shields.io/badge/chowmean-First%20Contributor-brightgreen) (2 merged PRs) + +- ![engnadeau Badge](https://img.shields.io/badge/engnadeau-First%20Contributor-brightgreen) (2 merged PRs) + +- ![Zeckie Badge](https://img.shields.io/badge/Zeckie-First%20Contributor-brightgreen) (1 merged PRs) + +- ![mwermuth Badge](https://img.shields.io/badge/mwermuth-First%20Contributor-brightgreen) (1 merged PRs) + +- ![tarmack Badge](https://img.shields.io/badge/tarmack-First%20Contributor-brightgreen) (1 merged PRs) + +- ![andyjones Badge](https://img.shields.io/badge/andyjones-First%20Contributor-brightgreen) (1 merged PRs) + +- ![bagerard Badge](https://img.shields.io/badge/bagerard-First%20Contributor-brightgreen) (1 merged PRs) + +- ![jorgecarleitao Badge](https://img.shields.io/badge/jorgecarleitao-First%20Contributor-brightgreen) (1 merged PRs) + +- ![GhostofGoes Badge](https://img.shields.io/badge/GhostofGoes-First%20Contributor-brightgreen) (1 merged PRs) + +- ![sobolevn Badge](https://img.shields.io/badge/sobolevn-First%20Contributor-brightgreen) (1 merged PRs) + +- ![eschluntz Badge](https://img.shields.io/badge/eschluntz-First%20Contributor-brightgreen) (1 merged PRs) + +- ![redshiftzero Badge](https://img.shields.io/badge/redshiftzero-First%20Contributor-brightgreen) (1 merged PRs) + +- ![dhrmn Badge](https://img.shields.io/badge/dhrmn-First%20Contributor-brightgreen) (1 merged PRs) + +- ![msmolens Badge](https://img.shields.io/badge/msmolens-First%20Contributor-brightgreen) (1 merged PRs) + +- ![a-recknagel Badge](https://img.shields.io/badge/a--recknagel-First%20Contributor-brightgreen) (1 merged PRs) + +- ![4383 Badge](https://img.shields.io/badge/4383-First%20Contributor-brightgreen) (1 merged PRs) + +- ![hmajid2301 Badge](https://img.shields.io/badge/hmajid2301-First%20Contributor-brightgreen) (1 merged PRs) + +- ![mgedmin Badge](https://img.shields.io/badge/mgedmin-First%20Contributor-brightgreen) (1 merged PRs) + +- ![ayeks Badge](https://img.shields.io/badge/ayeks-First%20Contributor-brightgreen) (1 merged PRs) + +- ![benjaminp Badge](https://img.shields.io/badge/benjaminp-First%20Contributor-brightgreen) (1 merged PRs) + +- ![duncm Badge](https://img.shields.io/badge/duncm-First%20Contributor-brightgreen) (1 merged PRs) + +- ![svenevs Badge](https://img.shields.io/badge/svenevs-First%20Contributor-brightgreen) (1 merged PRs) + +- ![filipochnik Badge](https://img.shields.io/badge/filipochnik-First%20Contributor-brightgreen) (1 merged PRs) + +- ![thatarchguy Badge](https://img.shields.io/badge/thatarchguy-First%20Contributor-brightgreen) (1 merged PRs) + +- ![AndreLouisCaron Badge](https://img.shields.io/badge/AndreLouisCaron-First%20Contributor-brightgreen) (1 merged PRs) + +- ![klada Badge](https://img.shields.io/badge/klada-First%20Contributor-brightgreen) (1 merged PRs) + +- ![Stype Badge](https://img.shields.io/badge/Stype-First%20Contributor-brightgreen) (1 merged PRs) + +- ![maratsh Badge](https://img.shields.io/badge/maratsh-First%20Contributor-brightgreen) (1 merged PRs) + +- ![dveeden Badge](https://img.shields.io/badge/dveeden-First%20Contributor-brightgreen) (1 merged PRs) diff --git a/scripts/generate_contributors.py b/scripts/generate_contributors.py new file mode 100644 index 00000000..b0202086 --- /dev/null +++ b/scripts/generate_contributors.py @@ -0,0 +1,90 @@ +import os +import requests +from collections import defaultdict + +# Repository details and GitHub token +GITHUB_REPO = "pyupio/safety" +GITHUB_TOKEN = os.getenv("YOUR_GITHUB_TOKEN") +CONTRIBUTORS_FILE = "CONTRIBUTORS.md" + +# Tier thresholds +TIERS = {"Valued Contributor": 10, "Frequent Contributor": 5, "First Contributor": 1} + + +# API request to get merged PRs +def get_merged_prs(): + prs = [] + page = 1 + while True: + url = f"https://api.github.com/repos/{GITHUB_REPO}/pulls?state=closed&per_page=100&page={page}" + headers = {"Authorization": f"token {GITHUB_TOKEN}"} + response = requests.get(url, headers=headers) + response.raise_for_status() + page_prs = response.json() + + # Break if there are no more PRs + if not page_prs: + break + + prs.extend(page_prs) + page += 1 + + return prs + + +# Count contributions for each user +def count_contributions(prs): + contributions = defaultdict(int) + for pr in prs: + if pr.get("merged_at"): + user = pr["user"]["login"] + contributions[user] += 1 + return contributions + + +# Categorize contributors by tier +def categorize_contributors(contributions): + tiers = {tier: [] for tier in TIERS} + for user, count in contributions.items(): + for tier, threshold in TIERS.items(): + if count >= threshold: + tiers[tier].append((user, count)) + break + return tiers + + +# Generate Shieldify badge +def generate_badge(user, tier): + badge_url = f"https://img.shields.io/badge/{user.replace('-', '--')}-{tier.replace(' ', '%20')}-brightgreen" + return f"![{user} Badge]({badge_url})" + + +# Generate CONTRIBUTORS.md content +def generate_contributors_md(tiers): + lines = ["# Contributors\n"] + for tier, contributors in tiers.items(): + if contributors: + lines.append(f"## {tier}\n") + for user, count in sorted(contributors, key=lambda x: x[1], reverse=True): + badge = generate_badge(user, tier) + lines.append(f"- {badge} ({count} merged PRs)\n") + return "\n".join(lines) + + +# Write the CONTRIBUTORS.md file +def write_contributors_file(content): + with open(CONTRIBUTORS_FILE, "w") as file: + file.write(content) + + +def main(): + prs = get_merged_prs() + contributions = count_contributions(prs) + tiers = categorize_contributors(contributions) + content = generate_contributors_md(tiers) + write_contributors_file(content) + print(f"{CONTRIBUTORS_FILE} generated successfully.") + + +if __name__ == "__main__": + main()