From eb20bc78f2db820c242d36b6b2dc2c9162390deb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 4 Apr 2026 10:02:23 +0000 Subject: [PATCH 1/4] Initial plan From af1a1ac04f01810d1a36f05c4bb51b51b70dab16 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 4 Apr 2026 10:05:38 +0000 Subject: [PATCH 2/4] Add leaderboard Python script and daily workflow Agent-Logs-Url: https://github.com/NextCommunity/NextCommunity.github.io/sessions/aa529b1f-6c33-47b9-854e-af24ac43a895 Co-authored-by: jbampton <418747+jbampton@users.noreply.github.com> --- .github/workflows/leaderboard.yml | 24 +++ .../__pycache__/leaderboard.cpython-312.pyc | Bin 0 -> 9350 bytes scripts/leaderboard.py | 188 ++++++++++++++++++ 3 files changed, 212 insertions(+) create mode 100644 .github/workflows/leaderboard.yml create mode 100644 scripts/__pycache__/leaderboard.cpython-312.pyc create mode 100644 scripts/leaderboard.py diff --git a/.github/workflows/leaderboard.yml b/.github/workflows/leaderboard.yml new file mode 100644 index 0000000..b82f8c7 --- /dev/null +++ b/.github/workflows/leaderboard.yml @@ -0,0 +1,24 @@ +name: Update organization leaderboard + +on: + schedule: + - cron: "0 0 * * *" # every day at midnight UTC + workflow_dispatch: # allow manual runs + +jobs: + leaderboard: + if: github.repository == 'NextCommunity/NextCommunity.github.io' + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: "3.12" + - name: Run leaderboard script + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: python scripts/leaderboard.py diff --git a/scripts/__pycache__/leaderboard.cpython-312.pyc b/scripts/__pycache__/leaderboard.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba63f4fd43023f01b69b1088efbb014f8362c980 GIT binary patch literal 9350 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 literal 0 HcmV?d00001 diff --git a/scripts/leaderboard.py b/scripts/leaderboard.py new file mode 100644 index 0000000..9aae9f8 --- /dev/null +++ b/scripts/leaderboard.py @@ -0,0 +1,188 @@ +"""Fetch contributor stats from all NextCommunity repos and update the org profile README.""" + +import base64 +import json +import os +import sys +import urllib.request +import urllib.error + +ORG = "NextCommunity" +TARGET_REPO = ".github" +TARGET_PATH = "profile/README.md" +LEADERBOARD_START = "" +LEADERBOARD_END = "" +API_BASE = "https://api.github.com" + + +def _headers(): + """Return common request headers including authentication if available.""" + token = os.environ.get("GITHUB_TOKEN", "") + headers = {"Accept": "application/vnd.github+json", "User-Agent": ORG} + if token: + headers["Authorization"] = f"token {token}" + return headers + + +def _api_get(url): + """Perform a GET request against the GitHub API and return parsed JSON.""" + req = urllib.request.Request(url, headers=_headers()) + try: + with urllib.request.urlopen(req) as resp: + return json.loads(resp.read().decode()) + except urllib.error.HTTPError as exc: + print(f"HTTP {exc.code} for {url}: {exc.reason}", file=sys.stderr) + return None + + +def _api_get_paginated(url): + """Paginate through all results for a GitHub API endpoint.""" + results = [] + page = 1 + while True: + sep = "&" if "?" in url else "?" + page_url = f"{url}{sep}page={page}&per_page=100" + data = _api_get(page_url) + if not data: + break + results.extend(data) + if len(data) < 100: + break + page += 1 + return results + + +def get_repos(): + """Return a list of all public repos in the organization.""" + url = f"{API_BASE}/orgs/{ORG}/repos?type=public" + repos = _api_get_paginated(url) + return [r["full_name"] for r in repos if not r.get("fork")] + + +def get_contributors(repo_full_name): + """Return contributor list for a single repo via the contributors endpoint.""" + url = f"{API_BASE}/repos/{repo_full_name}/contributors" + data = _api_get_paginated(url) + return data or [] + + +def build_leaderboard(): + """Aggregate contributor commits across all org repos and return sorted list.""" + repos = get_repos() + if not repos: + print("No repos found.", file=sys.stderr) + return [] + + contributors = {} # login -> {name, login, commits} + for repo in repos: + print(f"Fetching contributors for {repo} ...") + for c in get_contributors(repo): + if c.get("type") != "User": + continue + login = c["login"] + if login not in contributors: + contributors[login] = { + "login": login, + "commits": 0, + } + contributors[login]["commits"] += c.get("contributions", 0) + + # Fetch display names from user profiles + for login, info in contributors.items(): + user = _api_get(f"{API_BASE}/users/{login}") + info["name"] = (user.get("name") or login) if user else login + + # Sort by total commits descending + leaderboard = sorted(contributors.values(), key=lambda x: x["commits"], reverse=True) + return leaderboard + + +def render_table(leaderboard): + """Render the leaderboard as a Markdown table.""" + lines = [ + "## 🏆 Organization Leaderboard", + "", + "| Rank | Contributor | Username | Total Commits |", + "|------|------------|----------|---------------|", + ] + for rank, entry in enumerate(leaderboard, start=1): + name = entry["name"] + login = entry["login"] + commits = entry["commits"] + lines.append(f"| {rank} | {name} | [@{login}](https://github.com/{login}) | {commits} |") + + lines.append("") + lines.append(f"_Last updated: {_now_utc()}_") + return "\n".join(lines) + + +def _now_utc(): + """Return current UTC date-time as an ISO-like string (stdlib only).""" + import datetime + + return datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%d %H:%M UTC") + + +def update_readme(leaderboard_md): + """Update the profile README in the target repo with the new leaderboard.""" + url = f"{API_BASE}/repos/{ORG}/{TARGET_REPO}/contents/{TARGET_PATH}" + data = _api_get(url) + if data is None: + print(f"Could not fetch {TARGET_PATH} from {ORG}/{TARGET_REPO}", file=sys.stderr) + sys.exit(1) + + current_content = base64.b64decode(data["content"]).decode() + sha = data["sha"] + + section = f"{LEADERBOARD_START}\n{leaderboard_md}\n{LEADERBOARD_END}" + + if LEADERBOARD_START in current_content and LEADERBOARD_END in current_content: + start = current_content.index(LEADERBOARD_START) + end = current_content.index(LEADERBOARD_END) + len(LEADERBOARD_END) + new_content = current_content[:start] + section + current_content[end:] + else: + new_content = current_content.rstrip() + "\n\n" + section + "\n" + + if new_content == current_content: + print("Leaderboard is already up to date.") + return + + encoded = base64.b64encode(new_content.encode()).decode() + payload = json.dumps( + { + "message": "Update organization leaderboard", + "content": encoded, + "sha": sha, + } + ).encode() + + token = os.environ.get("GITHUB_TOKEN", "") + headers = { + "Accept": "application/vnd.github+json", + "User-Agent": ORG, + "Content-Type": "application/json", + } + if token: + headers["Authorization"] = f"token {token}" + + req = urllib.request.Request(url, data=payload, headers=headers, method="PUT") + try: + with urllib.request.urlopen(req) as resp: + print(f"README updated successfully ({resp.status}).") + except urllib.error.HTTPError as exc: + print(f"Failed to update README: HTTP {exc.code} {exc.reason}", file=sys.stderr) + sys.exit(1) + + +def main(): + leaderboard = build_leaderboard() + if not leaderboard: + print("No contributors found. Skipping update.") + return + table = render_table(leaderboard) + print(table) + update_readme(table) + + +if __name__ == "__main__": + main() From aa10f62bca11e5a89eddab5fdd9e643334552bd9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 4 Apr 2026 10:05:54 +0000 Subject: [PATCH 3/4] Add __pycache__ to .gitignore and remove cached files Agent-Logs-Url: https://github.com/NextCommunity/NextCommunity.github.io/sessions/aa529b1f-6c33-47b9-854e-af24ac43a895 Co-authored-by: jbampton <418747+jbampton@users.noreply.github.com> --- .gitignore | 1 + scripts/__pycache__/leaderboard.cpython-312.pyc | Bin 9350 -> 0 bytes 2 files changed, 1 insertion(+) delete mode 100644 scripts/__pycache__/leaderboard.cpython-312.pyc diff --git a/.gitignore b/.gitignore index 7f88f9e..ebdccbc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ vendor .idea .jekyll-cache .venv +__pycache__ # Generated CSS (compiled from TailwindCSS) src/assets/css/tailwind.css diff --git a/scripts/__pycache__/leaderboard.cpython-312.pyc b/scripts/__pycache__/leaderboard.cpython-312.pyc deleted file mode 100644 index ba63f4fd43023f01b69b1088efbb014f8362c980..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9350 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 From 6db7a74a0ee4ff91dc7c3d2ec00204d57a880fce Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 4 Apr 2026 10:07:08 +0000 Subject: [PATCH 4/4] Add explicit permissions block to leaderboard workflow Agent-Logs-Url: https://github.com/NextCommunity/NextCommunity.github.io/sessions/aa529b1f-6c33-47b9-854e-af24ac43a895 Co-authored-by: jbampton <418747+jbampton@users.noreply.github.com> --- .github/workflows/leaderboard.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/leaderboard.yml b/.github/workflows/leaderboard.yml index b82f8c7..f964ce5 100644 --- a/.github/workflows/leaderboard.yml +++ b/.github/workflows/leaderboard.yml @@ -5,6 +5,9 @@ on: - cron: "0 0 * * *" # every day at midnight UTC workflow_dispatch: # allow manual runs +permissions: + contents: read + jobs: leaderboard: if: github.repository == 'NextCommunity/NextCommunity.github.io'