From 149d945a51055f37c0c4f549b399960338b1f029 Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Tue, 20 Jan 2026 13:33:45 -0500 Subject: [PATCH 1/8] Add per-project All Contributors setup Set up separate contributor tracking for each sub-project: - book/.all-contributorsrc - Book content contributors - kits/.all-contributorsrc - Hardware kit contributors - labs/.all-contributorsrc - Lab exercise contributors - tinytorch/.all-contributorsrc - Framework contributors Each project now has: - Its own .all-contributorsrc config file - Contributors section in README with All Contributors format - Project-specific contribution types in the recognition guide - Cheatsheet in CONTRIBUTING.md (where applicable) Added @AmirAlasady as first TinyTorch contributor for bug report #1122. Usage: Comment on any issue/PR with: @all-contributors please add @username for bug, code, doc, or ideas --- book/.all-contributorsrc | 14 ++++++++++++++ book/README.md | 20 ++++++++++++++++++++ book/docs/CONTRIBUTING.md | 29 +++++++++++++++++++++++++++++ kits/.all-contributorsrc | 14 ++++++++++++++ kits/README.md | 20 ++++++++++++++++++++ labs/.all-contributorsrc | 14 ++++++++++++++ labs/README.md | 20 ++++++++++++++++++++ tinytorch/.all-contributorsrc | 22 ++++++++++++++++++++++ tinytorch/CONTRIBUTING.md | 32 ++++++++++++++++++++++++++++++++ tinytorch/README.md | 29 +++++++++++++++++++++++++++-- 10 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 book/.all-contributorsrc create mode 100644 kits/.all-contributorsrc create mode 100644 labs/.all-contributorsrc create mode 100644 tinytorch/.all-contributorsrc diff --git a/book/.all-contributorsrc b/book/.all-contributorsrc new file mode 100644 index 000000000..45f638b2d --- /dev/null +++ b/book/.all-contributorsrc @@ -0,0 +1,14 @@ +{ + "projectName": "MLSysBook - Textbook", + "projectOwner": "harvard-edge", + "repoType": "github", + "repoHost": "https://github.com", + "files": ["README.md"], + "imageSize": 80, + "commit": false, + "commitConvention": "angular", + "contributorsPerLine": 7, + "linkToUsage": false, + "skipCi": true, + "contributors": [] +} diff --git a/book/README.md b/book/README.md index 0b8a7ed4f..8d4d3c3bc 100644 --- a/book/README.md +++ b/book/README.md @@ -156,6 +156,26 @@ We welcome contributions! See [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for g --- +## Contributors + +Thanks to these wonderful people who helped improve the book ([emoji key](https://allcontributors.org/docs/en/emoji-key)): + + + + + + + + + + +**Recognize a contributor:** Comment on any issue or PR: +``` +@all-contributors please add @username for doc, review, translation, or design +``` + +--- + ## License Book content is licensed under **Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International** (CC BY-NC-SA 4.0). diff --git a/book/docs/CONTRIBUTING.md b/book/docs/CONTRIBUTING.md index 8222a24a0..b843b78b5 100644 --- a/book/docs/CONTRIBUTING.md +++ b/book/docs/CONTRIBUTING.md @@ -88,3 +88,32 @@ Opening an early PR is encouraged. This will allow us to provide feedback on you For a more detailed guide on the CS249r documentation process and peer review, check [here](https://docs.google.com/document/d/1izDoWwFLnV8XK2FYCl23_9KYL_7EQ5OWLo-PCNUGle0). + +## Contributor Recognition + +We use [All Contributors](https://allcontributors.org) to recognize everyone who helps improve the book. + +### How to Recognize a Contributor + +After merging a PR or resolving an issue, comment: + +``` +@all-contributors please add @username for TYPE +``` + +### Contribution Types + +| Type | Emoji | Use For | +|------|-------|---------| +| `doc` | πŸ“– | Wrote or improved content | +| `review` | πŸ‘€ | Reviewed chapters or PRs | +| `translation` | 🌍 | Translated content | +| `design` | 🎨 | Created diagrams or figures | +| `bug` | πŸ› | Found errors or typos | +| `ideas` | πŸ’‘ | Suggested improvements | + +### Example + +``` +@all-contributors please add @contributor for doc, review +``` diff --git a/kits/.all-contributorsrc b/kits/.all-contributorsrc new file mode 100644 index 000000000..4d47483db --- /dev/null +++ b/kits/.all-contributorsrc @@ -0,0 +1,14 @@ +{ + "projectName": "MLSysBook - Hardware Kits", + "projectOwner": "harvard-edge", + "repoType": "github", + "repoHost": "https://github.com", + "files": ["README.md"], + "imageSize": 80, + "commit": false, + "commitConvention": "angular", + "contributorsPerLine": 7, + "linkToUsage": false, + "skipCi": true, + "contributors": [] +} diff --git a/kits/README.md b/kits/README.md index 5adb573d5..e013939a7 100644 --- a/kits/README.md +++ b/kits/README.md @@ -132,6 +132,26 @@ We welcome contributions to the hardware labs! To contribute: --- +## Contributors + +Thanks to these wonderful people who helped improve the hardware kits ([emoji key](https://allcontributors.org/docs/en/emoji-key)): + + + + + + + + + + +**Recognize a contributor:** Comment on any issue or PR: +``` +@all-contributors please add @username for tool, test, video, or doc +``` + +--- + ## Authors - **Marcelo Rovai** - Primary author diff --git a/labs/.all-contributorsrc b/labs/.all-contributorsrc new file mode 100644 index 000000000..f96500ff7 --- /dev/null +++ b/labs/.all-contributorsrc @@ -0,0 +1,14 @@ +{ + "projectName": "MLSysBook - Labs", + "projectOwner": "harvard-edge", + "repoType": "github", + "repoHost": "https://github.com", + "files": ["README.md"], + "imageSize": 80, + "commit": false, + "commitConvention": "angular", + "contributorsPerLine": 7, + "linkToUsage": false, + "skipCi": true, + "contributors": [] +} diff --git a/labs/README.md b/labs/README.md index bdba3d4f5..e1cef90f9 100644 --- a/labs/README.md +++ b/labs/README.md @@ -67,6 +67,26 @@ Labs are under active development. To be notified when they launch: --- +## Contributors + +Thanks to these wonderful people who helped build the labs ([emoji key](https://allcontributors.org/docs/en/emoji-key)): + + + + + + + + + + +**Recognize a contributor:** Comment on any issue or PR: +``` +@all-contributors please add @username for code, tutorial, test, or doc +``` + +--- +
**Read. Explore. Build.** *(Labs coming soon)* diff --git a/tinytorch/.all-contributorsrc b/tinytorch/.all-contributorsrc new file mode 100644 index 000000000..55d0852c0 --- /dev/null +++ b/tinytorch/.all-contributorsrc @@ -0,0 +1,22 @@ +{ + "projectName": "MLSysBook - TinyTorch", + "projectOwner": "harvard-edge", + "repoType": "github", + "repoHost": "https://github.com", + "files": ["README.md"], + "imageSize": 80, + "commit": false, + "commitConvention": "angular", + "contributorsPerLine": 7, + "linkToUsage": false, + "skipCi": true, + "contributors": [ + { + "login": "AmirAlasady", + "name": "Amir Alasady", + "avatar_url": "https://avatars.githubusercontent.com/AmirAlasady", + "profile": "https://github.com/AmirAlasady", + "contributions": ["bug"] + } + ] +} diff --git a/tinytorch/CONTRIBUTING.md b/tinytorch/CONTRIBUTING.md index 95729eb65..78cb48cc9 100644 --- a/tinytorch/CONTRIBUTING.md +++ b/tinytorch/CONTRIBUTING.md @@ -268,6 +268,38 @@ Your commits will be included in the next release with appropriate version bump. --- +## πŸ† Contributor Recognition + +We use [All Contributors](https://allcontributors.org) to recognize everyone who helps improve TinyTorch. + +### How to Recognize a Contributor + +After merging a PR or resolving an issue, comment: + +``` +@all-contributors please add @username for TYPE +``` + +### Contribution Types + +| Type | Emoji | Use For | +|------|-------|---------| +| `bug` | πŸ› | Found a bug or issue | +| `code` | πŸ’» | Submitted code | +| `doc` | πŸ“– | Improved documentation | +| `ideas` | πŸ’‘ | Suggested improvements | +| `test` | πŸ§ͺ | Added tests | +| `review` | πŸ‘€ | Reviewed PRs | + +### Examples + +``` +@all-contributors please add @AmirAlasady for bug +@all-contributors please add @student123 for code, doc +``` + +--- + **Remember**: TinyTorch is about teaching students to understand ML systems by building them. Every contribution should enhance that educational mission! πŸŽ“πŸ”₯ **Questions?** Check the docs or open a GitHub Discussion. diff --git a/tinytorch/README.md b/tinytorch/README.md index 6c4257e5e..eac2cc755 100644 --- a/tinytorch/README.md +++ b/tinytorch/README.md @@ -255,12 +255,37 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. --- +## Contributors + +Thanks to these wonderful people who helped improve TinyTorch ([emoji key](https://allcontributors.org/docs/en/emoji-key)): + + + + + + + + + + +
Amir Alasady
Amir Alasady

πŸ›
+ + + + + + +**Recognize a contributor:** Comment on any issue or PR: +``` +@all-contributors please add @username for bug, code, doc, or ideas +``` + +--- + ## Acknowledgments Created by [Prof. Vijay Janapa Reddi](https://vijay.seas.harvard.edu) at Harvard University. -Special thanks to students and contributors who helped build this framework. - --- ## License From b8ee62da44ffed862da473914c7a07eaeaee8491 Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Tue, 20 Jan 2026 13:47:46 -0500 Subject: [PATCH 2/8] Add contributor scanning script Script to analyze git history and identify contributors per project: - Scans book/, kits/, labs/, tinytorch/ folders - Detects contribution types from commit messages and files - Maps git emails to GitHub usernames - Filters out bots and AI tools (github-actions, claude, cursor, etc.) - Deduplicates by GitHub username - Can output as table, JSON, or all-contributorsrc format - Supports dry-run and direct update of config files Usage: python scan_contributors.py # Show all as table python scan_contributors.py --project tinytorch python scan_contributors.py --output rc # Show RC format python scan_contributors.py --dry-run # Preview updates python scan_contributors.py --update # Apply updates --- .../contributors/scan_contributors.py | 465 ++++++++++++++++++ 1 file changed, 465 insertions(+) create mode 100755 .github/workflows/contributors/scan_contributors.py diff --git a/.github/workflows/contributors/scan_contributors.py b/.github/workflows/contributors/scan_contributors.py new file mode 100755 index 000000000..b7fa0f69f --- /dev/null +++ b/.github/workflows/contributors/scan_contributors.py @@ -0,0 +1,465 @@ +#!/usr/bin/env python3 +""" +Scan git history to identify contributors per project. + +This script analyzes git commits to: +1. Find unique contributors per project folder +2. Categorize contribution types based on commit messages and files changed +3. Map git emails to GitHub usernames where possible +4. Filter out bots and AI tools +5. Output data for .all-contributorsrc files + +Usage: + python scan_contributors.py [--project PROJECT] [--output json|table|rc] + +Examples: + python scan_contributors.py # Scan all projects + python scan_contributors.py --project tinytorch # Scan only tinytorch + python scan_contributors.py --output json # Output as JSON +""" + +import subprocess +import json +import re +import argparse +from collections import defaultdict +from pathlib import Path + +# Project folders to scan +PROJECTS = { + "book": "book/", + "kits": "kits/", + "labs": "labs/", + "tinytorch": "tinytorch/", +} + +# Patterns to exclude (bots, AI tools, etc.) +EXCLUDE_PATTERNS = [ + r"bot", + r"github-actions", + r"dependabot", + r"claude", + r"cursor", + r"copilot", + r"\[bot\]", + r"noreply\.github\.com.*bot", +] + +# Contribution type detection based on commit message keywords +CONTRIBUTION_PATTERNS = { + "bug": [ + r"\bfix(es|ed|ing)?\b", + r"\bbug\b", + r"\bissue\b", + r"\berror\b", + r"\bpatch\b", + r"\bresolve[sd]?\b", + ], + "doc": [ + r"\bdoc(s|umentation)?\b", + r"\breadme\b", + r"\bcomment\b", + r"\btypo\b", + r"\bspelling\b", + r"\bgrammar\b", + r"\bexplain\b", + r"\bdescription\b", + ], + "test": [ + r"\btest(s|ing)?\b", + r"\bspec\b", + r"\bcoverage\b", + r"\bvalidat(e|ion)\b", + ], + "code": [ + r"\bfeat(ure)?\b", + r"\badd(s|ed|ing)?\b", + r"\bimplement(s|ed|ing|ation)?\b", + r"\bcreate[sd]?\b", + r"\bbuild\b", + r"\brefactor\b", + r"\bupdate[sd]?\b", + r"\benhance\b", + r"\bimprove[sd]?\b", + ], + "review": [ + r"\breview(ed|ing)?\b", + r"\bfeedback\b", + r"\bsuggestion\b", + ], + "design": [ + r"\bdesign\b", + r"\bdiagram\b", + r"\bfigure\b", + r"\bimage\b", + r"\billustrat(e|ion)\b", + r"\bvisual\b", + ], + "translation": [ + r"\btranslat(e|ion|ed)\b", + r"\blocali[sz](e|ation)\b", + r"\bi18n\b", + ], + "tool": [ + r"\btool(s|ing)?\b", + r"\bscript\b", + r"\bautomation\b", + r"\bworkflow\b", + r"\bci\b", + r"\bcd\b", + ], + "ideas": [ + r"\bidea\b", + r"\bpropos(e|al)\b", + r"\bsuggest\b", + r"\brfc\b", + ], +} + +# Known email to GitHub username mappings (extend as needed) +EMAIL_TO_GITHUB = { + # Core team + "vj@eecs.harvard.edu": "profvjreddi", + "zeljko.hrcek@gmail.com": "hzeljko", + "mjrovai@gmail.com": "Mjrovai", + "jjj4se@virginia.edu": "jasonjabbour", + "iuchendu@g.harvard.edu": "uchendui", + + # Contributors + "kkleinbard@avaya.com": "kai4avaya", + "kai4avaya@gmail.com": "kai4avaya", + "khoshnevis.naeem@gmail.com": "Naeemkh", + "matthew_stewart@g.harvard.edu": "mrdragonbear", + "jeffreyma@g.harvard.edu": "18jeffreyma", + "douwedb@gmail.com": "V0XNIHILI", + "shanzeh.batool@gmail.com": "shanzehbatool", + "jaredping@yahoo.com": "JaredP94", + "sara.khosravi.ds@gmail.com": "Sara-Khosravi", + "i.j.shapira@gmail.com": "ishapira1", + "durand.didier@gmail.com": "didier-durand", + "gabriel.amazonas.eng@gmail.com": "GabrielAmazonas", + "cbanbury@g.harvard.edu": "colbybanbury", + "zishenwan@g.harvard.edu": "zishenwan", + "mark@markmaz.com": "mmaz", + "lazio2013@gmail.com": "ma3mool", + "divya.amirtharaj@gmail.com": "DivyaAmirtharaj", + "91.srivatsan@gmail.com": "srivatsankrishnan", + "alexbrodriguez@gmail.com": "alxrod", + "jlin3@college.harvard.edu": "jaysonzlin", + "jwnchung@umich.edu": "jaywonchung", + "jettythek@gmail.com": "jettythek", + "anfe4949anfe@gmail.com": "andreamurillomtz", + "oishibanerjee@gmail.com": "oishib", + "yushun_hsiao@g.harvard.edu": "leo47007", + "michael.schnebly@gmail.com": "MichaelSchnebly", + "duongvanthuong9a8@gmail.com": "VThuong99", + "eliasab@college.harvard.edu": "eliasab16", +} + + +def is_excluded(name: str, email: str) -> bool: + """Check if contributor should be excluded (bot, AI, etc.).""" + combined = f"{name} {email}".lower() + for pattern in EXCLUDE_PATTERNS: + if re.search(pattern, combined, re.IGNORECASE): + return True + return False + + +def detect_contribution_types(commit_message: str, files_changed: list[str]) -> set[str]: + """Detect contribution types from commit message and files changed.""" + types = set() + message_lower = commit_message.lower() + + # Check commit message patterns + for contrib_type, patterns in CONTRIBUTION_PATTERNS.items(): + for pattern in patterns: + if re.search(pattern, message_lower, re.IGNORECASE): + types.add(contrib_type) + break + + # Check file extensions for additional hints + for file in files_changed: + file_lower = file.lower() + if file_lower.endswith(('.md', '.rst', '.txt')): + types.add("doc") + elif file_lower.endswith(('test_', '_test.py', 'test.py', '.spec.')): + types.add("test") + elif 'test' in file_lower: + types.add("test") + elif file_lower.endswith(('.png', '.jpg', '.svg', '.gif')): + types.add("design") + elif file_lower.endswith(('.py', '.js', '.ts', '.c', '.cpp', '.h')): + types.add("code") + + # Default to "code" if nothing detected + if not types: + types.add("code") + + return types + + +def get_github_username(name: str, email: str) -> str | None: + """Try to get GitHub username from email or name.""" + email_lower = email.lower() + + # Check known mappings + if email_lower in EMAIL_TO_GITHUB: + return EMAIL_TO_GITHUB[email_lower] + + # Try to extract from noreply email + # Format: 12345+username@users.noreply.github.com + noreply_match = re.match(r'(\d+\+)?([^@]+)@users\.noreply\.github\.com', email_lower) + if noreply_match: + return noreply_match.group(2) + + return None + + +def get_commits_for_project(project_path: str) -> list[dict]: + """Get all commits for a project folder.""" + # Format: hash|author_name|author_email|subject + cmd = [ + "git", "log", + "--format=%H|%an|%ae|%s", + "--name-only", + "--", project_path + ] + + try: + result = subprocess.run(cmd, capture_output=True, text=True, check=True) + except subprocess.CalledProcessError: + return [] + + commits = [] + current_commit = None + + for line in result.stdout.split('\n'): + if '|' in line and line.count('|') >= 3: + # This is a commit line + if current_commit: + commits.append(current_commit) + + parts = line.split('|', 3) + current_commit = { + 'hash': parts[0], + 'name': parts[1], + 'email': parts[2], + 'message': parts[3] if len(parts) > 3 else '', + 'files': [] + } + elif line.strip() and current_commit: + # This is a file line + current_commit['files'].append(line.strip()) + + if current_commit: + commits.append(current_commit) + + return commits + + +def analyze_project(project_name: str, project_path: str) -> dict: + """Analyze a project and return contributor data.""" + commits = get_commits_for_project(project_path) + + # Aggregate by contributor + contributors = defaultdict(lambda: { + 'name': '', + 'email': '', + 'github': None, + 'commits': 0, + 'types': set(), + }) + + for commit in commits: + name = commit['name'] + email = commit['email'] + + # Skip excluded contributors + if is_excluded(name, email): + continue + + # Use email as key for deduplication + key = email.lower() + + contributors[key]['name'] = name + contributors[key]['email'] = email + contributors[key]['github'] = get_github_username(name, email) + contributors[key]['commits'] += 1 + + # Detect contribution types + types = detect_contribution_types(commit['message'], commit['files']) + contributors[key]['types'].update(types) + + # Convert to list and sort by commits + result = [] + for email, data in contributors.items(): + result.append({ + 'name': data['name'], + 'email': data['email'], + 'github': data['github'], + 'commits': data['commits'], + 'types': sorted(list(data['types'])), + }) + + result.sort(key=lambda x: x['commits'], reverse=True) + return { + 'project': project_name, + 'path': project_path, + 'contributors': result, + 'total_contributors': len(result), + } + + +def format_as_table(data: dict) -> str: + """Format project data as a markdown table.""" + lines = [ + f"\n## {data['project']} ({data['total_contributors']} contributors)\n", + "| Name | GitHub | Commits | Types |", + "|------|--------|---------|-------|", + ] + + for c in data['contributors']: + github = f"@{c['github']}" if c['github'] else "?" + types = ", ".join(c['types']) + lines.append(f"| {c['name']} | {github} | {c['commits']} | {types} |") + + return "\n".join(lines) + + +def format_as_allcontributorsrc(data: dict) -> dict: + """Format project data as .all-contributorsrc contributor entries.""" + # Dedupe by GitHub username + seen_github = {} + + for c in data['contributors']: + if not c['github']: + continue # Skip if no GitHub username + + github_lower = c['github'].lower() + + if github_lower in seen_github: + # Merge contribution types + seen_github[github_lower]['contributions'].update(c['types']) + # Keep higher commit count name + if c['commits'] > seen_github[github_lower].get('_commits', 0): + seen_github[github_lower]['name'] = c['name'] + seen_github[github_lower]['_commits'] = c['commits'] + else: + seen_github[github_lower] = { + "login": c['github'], + "name": c['name'], + "avatar_url": f"https://avatars.githubusercontent.com/{c['github']}", + "profile": f"https://github.com/{c['github']}", + "contributions": set(c['types']), + "_commits": c['commits'] + } + + # Convert sets to sorted lists and remove internal fields + contributors = [] + for entry in seen_github.values(): + contributors.append({ + "login": entry['login'], + "name": entry['name'], + "avatar_url": entry['avatar_url'], + "profile": entry['profile'], + "contributions": sorted(list(entry['contributions'])) + }) + + # Sort by number of contribution types (most active first) + contributors.sort(key=lambda x: len(x['contributions']), reverse=True) + + return { + "project": data['project'], + "contributors": contributors + } + + +def update_allcontributorsrc(project_name: str, contributors: list[dict], dry_run: bool = True) -> bool: + """Update the .all-contributorsrc file for a project.""" + rc_path = Path(PROJECTS[project_name]) / ".all-contributorsrc" + + if not rc_path.exists(): + print(f"Warning: {rc_path} does not exist", file=__import__('sys').stderr) + return False + + with open(rc_path, 'r') as f: + rc_data = json.load(f) + + # Merge new contributors with existing + existing_logins = {c['login'].lower() for c in rc_data.get('contributors', [])} + + added = [] + for new_contrib in contributors: + if new_contrib['login'].lower() not in existing_logins: + rc_data.setdefault('contributors', []).append(new_contrib) + added.append(new_contrib['login']) + existing_logins.add(new_contrib['login'].lower()) + + if dry_run: + print(f"\n[DRY RUN] Would add {len(added)} contributors to {rc_path}:") + for login in added: + print(f" - @{login}") + return True + + # Write updated file + with open(rc_path, 'w') as f: + json.dump(rc_data, f, indent=4) + + print(f"Updated {rc_path} with {len(added)} new contributors") + return True + + +def main(): + parser = argparse.ArgumentParser(description="Scan git history for contributors") + parser.add_argument("--project", choices=list(PROJECTS.keys()), help="Scan specific project") + parser.add_argument("--output", choices=["json", "table", "rc"], default="table", help="Output format") + parser.add_argument("--min-commits", type=int, default=1, help="Minimum commits to include") + parser.add_argument("--update", action="store_true", help="Update .all-contributorsrc files") + parser.add_argument("--dry-run", action="store_true", help="Show what would be updated without writing") + args = parser.parse_args() + + # Determine which projects to scan + if args.project: + projects = {args.project: PROJECTS[args.project]} + else: + projects = PROJECTS + + results = [] + + for name, path in projects.items(): + print(f"Scanning {name}...", file=__import__('sys').stderr) + data = analyze_project(name, path) + + # Filter by minimum commits + data['contributors'] = [c for c in data['contributors'] if c['commits'] >= args.min_commits] + data['total_contributors'] = len(data['contributors']) + + results.append(data) + + # Update mode + if args.update or args.dry_run: + for data in results: + rc_data = format_as_allcontributorsrc(data) + update_allcontributorsrc( + data['project'], + rc_data['contributors'], + dry_run=args.dry_run or not args.update + ) + return + + # Output results + if args.output == "json": + print(json.dumps(results, indent=2)) + elif args.output == "rc": + for data in results: + rc_data = format_as_allcontributorsrc(data) + print(f"\n=== {data['project']}/.all-contributorsrc contributors ===") + print(json.dumps(rc_data['contributors'], indent=2)) + else: # table + for data in results: + print(format_as_table(data)) + + +if __name__ == "__main__": + main() From 0430c856390f4635c2346fd84d25323b7aa2b547 Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Tue, 20 Jan 2026 13:48:55 -0500 Subject: [PATCH 3/8] Populate contributors from git history - Scanned git history for each project folder - Added historical contributors to .all-contributorsrc files - Generated README contributor tables with emoji badges - Added generate_readme_tables.py script for future updates Contributors added: - Book: profvjreddi, Mjrovai, GabrielAmazonas, hzeljko - Kits: profvjreddi - Labs: profvjreddi - TinyTorch: AmirAlasady, profvjreddi, kai4avaya, minhdang26403, didier-durand, karthikdani, jettythek --- .../contributors/generate_readme_tables.py | 165 ++++++++++++++++++ book/.all-contributorsrc | 56 +++++- book/README.md | 10 ++ kits/.all-contributorsrc | 23 ++- kits/README.md | 7 + labs/.all-contributorsrc | 20 ++- labs/README.md | 7 + tinytorch/.all-contributorsrc | 81 ++++++++- tinytorch/README.md | 8 +- 9 files changed, 364 insertions(+), 13 deletions(-) create mode 100755 .github/workflows/contributors/generate_readme_tables.py diff --git a/.github/workflows/contributors/generate_readme_tables.py b/.github/workflows/contributors/generate_readme_tables.py new file mode 100755 index 000000000..9a8d24d38 --- /dev/null +++ b/.github/workflows/contributors/generate_readme_tables.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python3 +""" +Generate All Contributors tables for README files. + +This script reads .all-contributorsrc files and generates the HTML tables +that go in the README.md files. + +Usage: + python generate_readme_tables.py [--project PROJECT] [--update] +""" + +import json +import re +import argparse +from pathlib import Path + +PROJECTS = { + "book": "book/", + "kits": "kits/", + "labs": "labs/", + "tinytorch": "tinytorch/", +} + +# Emoji mapping for contribution types +EMOJI_KEY = { + "bug": "πŸ›", + "code": "πŸ’»", + "doc": "πŸ“–", + "design": "🎨", + "ideas": "πŸ’‘", + "review": "πŸ‘€", + "test": "πŸ§ͺ", + "tool": "πŸ”§", + "translation": "🌍", + "tutorial": "βœ…", + "video": "πŸ“Ή", + "question": "πŸ’¬", + "maintenance": "🚧", + "infra": "πŸš‡", + "platform": "πŸ“¦", + "projectManagement": "πŸ“†", + "research": "πŸ”¬", +} + + +def generate_contributor_cell(contributor: dict, image_size: int = 80) -> str: + """Generate HTML for a single contributor cell.""" + login = contributor['login'] + name = contributor.get('name', login) + avatar_url = contributor.get('avatar_url', f"https://avatars.githubusercontent.com/{login}") + profile = contributor.get('profile', f"https://github.com/{login}") + contributions = contributor.get('contributions', []) + + # Generate emoji badges + badges = " ".join(EMOJI_KEY.get(c, c) for c in contributions) + + return f'''{name}
{name}

{badges}''' + + +def generate_table(contributors: list[dict], per_line: int = 7, image_size: int = 80) -> str: + """Generate the full HTML table for contributors.""" + if not contributors: + return "" + + lines = ["", " "] + + for i in range(0, len(contributors), per_line): + row = contributors[i:i + per_line] + lines.append(" ") + for contributor in row: + lines.append(" " + generate_contributor_cell(contributor, image_size)) + lines.append(" ") + + lines.append(" ") + lines.append("
") + + return "\n".join(lines) + + +def update_readme(project_path: str, table_html: str) -> bool: + """Update the README.md with the new contributors table.""" + readme_path = Path(project_path) / "README.md" + + if not readme_path.exists(): + print(f"Warning: {readme_path} does not exist") + return False + + with open(readme_path, 'r') as f: + content = f.read() + + # Pattern to match the ALL-CONTRIBUTORS-LIST section + pattern = r'().*?()' + + if not re.search(pattern, content, re.DOTALL): + print(f"Warning: No ALL-CONTRIBUTORS-LIST markers found in {readme_path}") + return False + + # Build replacement content + replacement = f'''\\1 + + +{table_html} + + + + +\\2''' + + new_content = re.sub(pattern, replacement, content, flags=re.DOTALL) + + with open(readme_path, 'w') as f: + f.write(new_content) + + return True + + +def process_project(project_name: str, project_path: str, update: bool = False) -> None: + """Process a single project.""" + rc_path = Path(project_path) / ".all-contributorsrc" + + if not rc_path.exists(): + print(f"Skipping {project_name}: no .all-contributorsrc found") + return + + with open(rc_path, 'r') as f: + rc_data = json.load(f) + + contributors = rc_data.get('contributors', []) + per_line = rc_data.get('contributorsPerLine', 7) + image_size = rc_data.get('imageSize', 80) + + if not contributors: + print(f"{project_name}: No contributors to display") + return + + table_html = generate_table(contributors, per_line, image_size) + + print(f"\n=== {project_name} ({len(contributors)} contributors) ===") + + if update: + if update_readme(project_path, table_html): + print(f"Updated {project_path}README.md") + else: + print(f"Failed to update {project_path}README.md") + else: + print(table_html) + + +def main(): + parser = argparse.ArgumentParser(description="Generate All Contributors tables") + parser.add_argument("--project", choices=list(PROJECTS.keys()), help="Process specific project") + parser.add_argument("--update", action="store_true", help="Update README files") + args = parser.parse_args() + + if args.project: + projects = {args.project: PROJECTS[args.project]} + else: + projects = PROJECTS + + for name, path in projects.items(): + process_project(name, path, args.update) + + +if __name__ == "__main__": + main() diff --git a/book/.all-contributorsrc b/book/.all-contributorsrc index 45f638b2d..b16008584 100644 --- a/book/.all-contributorsrc +++ b/book/.all-contributorsrc @@ -3,12 +3,62 @@ "projectOwner": "harvard-edge", "repoType": "github", "repoHost": "https://github.com", - "files": ["README.md"], + "files": [ + "README.md" + ], "imageSize": 80, "commit": false, "commitConvention": "angular", "contributorsPerLine": 7, "linkToUsage": false, "skipCi": true, - "contributors": [] -} + "contributors": [ + { + "login": "profvjreddi", + "name": "Vijay Janapa Reddi", + "avatar_url": "https://avatars.githubusercontent.com/profvjreddi", + "profile": "https://github.com/profvjreddi", + "contributions": [ + "bug", + "code", + "design", + "doc", + "ideas", + "review", + "test", + "tool" + ] + }, + { + "login": "Mjrovai", + "name": "Marcelo Rovai", + "avatar_url": "https://avatars.githubusercontent.com/Mjrovai", + "profile": "https://github.com/Mjrovai", + "contributions": [ + "code", + "design", + "test" + ] + }, + { + "login": "GabrielAmazonas", + "name": "Gabriel Amazonas", + "avatar_url": "https://avatars.githubusercontent.com/GabrielAmazonas", + "profile": "https://github.com/GabrielAmazonas", + "contributions": [ + "bug", + "doc", + "ideas" + ] + }, + { + "login": "hzeljko", + "name": "Zeljko Hrcek", + "avatar_url": "https://avatars.githubusercontent.com/hzeljko", + "profile": "https://github.com/hzeljko", + "contributions": [ + "code" + ] + } + ] +} \ No newline at end of file diff --git a/book/README.md b/book/README.md index 8d4d3c3bc..27d7cb2ae 100644 --- a/book/README.md +++ b/book/README.md @@ -163,6 +163,16 @@ Thanks to these wonderful people who helped improve the book ([emoji key](https: + + + + + + + + + +
Vijay Janapa Reddi
Vijay Janapa Reddi

πŸ› πŸ’» 🎨 πŸ“– πŸ’‘ πŸ‘€ πŸ§ͺ πŸ”§
Marcelo Rovai
Marcelo Rovai

πŸ’» 🎨 πŸ§ͺ
Gabriel Amazonas
Gabriel Amazonas

πŸ› πŸ“– πŸ’‘
Zeljko Hrcek
Zeljko Hrcek

πŸ’»
diff --git a/kits/.all-contributorsrc b/kits/.all-contributorsrc index 4d47483db..452b383cc 100644 --- a/kits/.all-contributorsrc +++ b/kits/.all-contributorsrc @@ -3,12 +3,29 @@ "projectOwner": "harvard-edge", "repoType": "github", "repoHost": "https://github.com", - "files": ["README.md"], + "files": [ + "README.md" + ], "imageSize": 80, "commit": false, "commitConvention": "angular", "contributorsPerLine": 7, "linkToUsage": false, "skipCi": true, - "contributors": [] -} + "contributors": [ + { + "login": "profvjreddi", + "name": "Vijay Janapa Reddi", + "avatar_url": "https://avatars.githubusercontent.com/profvjreddi", + "profile": "https://github.com/profvjreddi", + "contributions": [ + "bug", + "code", + "design", + "doc", + "test", + "tool" + ] + } + ] +} \ No newline at end of file diff --git a/kits/README.md b/kits/README.md index e013939a7..8cb9c3499 100644 --- a/kits/README.md +++ b/kits/README.md @@ -139,6 +139,13 @@ Thanks to these wonderful people who helped improve the hardware kits ([emoji ke + + + + + + +
Vijay Janapa Reddi
Vijay Janapa Reddi

πŸ› πŸ’» 🎨 πŸ“– πŸ§ͺ πŸ”§
diff --git a/labs/.all-contributorsrc b/labs/.all-contributorsrc index f96500ff7..85424273f 100644 --- a/labs/.all-contributorsrc +++ b/labs/.all-contributorsrc @@ -3,12 +3,26 @@ "projectOwner": "harvard-edge", "repoType": "github", "repoHost": "https://github.com", - "files": ["README.md"], + "files": [ + "README.md" + ], "imageSize": 80, "commit": false, "commitConvention": "angular", "contributorsPerLine": 7, "linkToUsage": false, "skipCi": true, - "contributors": [] -} + "contributors": [ + { + "login": "profvjreddi", + "name": "Vijay Janapa Reddi", + "avatar_url": "https://avatars.githubusercontent.com/profvjreddi", + "profile": "https://github.com/profvjreddi", + "contributions": [ + "code", + "design", + "doc" + ] + } + ] +} \ No newline at end of file diff --git a/labs/README.md b/labs/README.md index e1cef90f9..68d74ae24 100644 --- a/labs/README.md +++ b/labs/README.md @@ -74,6 +74,13 @@ Thanks to these wonderful people who helped build the labs ([emoji key](https:// + + + + + + +
Vijay Janapa Reddi
Vijay Janapa Reddi

πŸ’» 🎨 πŸ“–
diff --git a/tinytorch/.all-contributorsrc b/tinytorch/.all-contributorsrc index 55d0852c0..693edbfd0 100644 --- a/tinytorch/.all-contributorsrc +++ b/tinytorch/.all-contributorsrc @@ -3,7 +3,9 @@ "projectOwner": "harvard-edge", "repoType": "github", "repoHost": "https://github.com", - "files": ["README.md"], + "files": [ + "README.md" + ], "imageSize": 80, "commit": false, "commitConvention": "angular", @@ -16,7 +18,80 @@ "name": "Amir Alasady", "avatar_url": "https://avatars.githubusercontent.com/AmirAlasady", "profile": "https://github.com/AmirAlasady", - "contributions": ["bug"] + "contributions": [ + "bug" + ] + }, + { + "login": "profvjreddi", + "name": "Vijay Janapa Reddi", + "avatar_url": "https://avatars.githubusercontent.com/profvjreddi", + "profile": "https://github.com/profvjreddi", + "contributions": [ + "bug", + "code", + "design", + "doc", + "ideas", + "review", + "test", + "tool" + ] + }, + { + "login": "kai4avaya", + "name": "kai", + "avatar_url": "https://avatars.githubusercontent.com/kai4avaya", + "profile": "https://github.com/kai4avaya", + "contributions": [ + "bug", + "code", + "design", + "doc", + "test" + ] + }, + { + "login": "minhdang26403", + "name": "Dang Truong", + "avatar_url": "https://avatars.githubusercontent.com/minhdang26403", + "profile": "https://github.com/minhdang26403", + "contributions": [ + "bug", + "code", + "doc", + "test" + ] + }, + { + "login": "didier-durand", + "name": "Didier Durand", + "avatar_url": "https://avatars.githubusercontent.com/didier-durand", + "profile": "https://github.com/didier-durand", + "contributions": [ + "bug", + "code", + "doc" + ] + }, + { + "login": "karthikdani", + "name": "Karthik Dani", + "avatar_url": "https://avatars.githubusercontent.com/karthikdani", + "profile": "https://github.com/karthikdani", + "contributions": [ + "bug", + "code" + ] + }, + { + "login": "jettythek", + "name": "jettythek", + "avatar_url": "https://avatars.githubusercontent.com/jettythek", + "profile": "https://github.com/jettythek", + "contributions": [ + "code" + ] } ] -} +} \ No newline at end of file diff --git a/tinytorch/README.md b/tinytorch/README.md index eac2cc755..5cac62bd9 100644 --- a/tinytorch/README.md +++ b/tinytorch/README.md @@ -265,7 +265,13 @@ Thanks to these wonderful people who helped improve TinyTorch ([emoji key](https - + + + + + + +
Amir Alasady
Amir Alasady

πŸ›
Amir Alasady
Amir Alasady

πŸ›
Vijay Janapa Reddi
Vijay Janapa Reddi

πŸ› πŸ’» 🎨 πŸ“– πŸ’‘ πŸ‘€ πŸ§ͺ πŸ”§
kai
kai

πŸ› πŸ’» 🎨 πŸ“– πŸ§ͺ
Dang Truong
Dang Truong

πŸ› πŸ’» πŸ“– πŸ§ͺ
Didier Durand
Didier Durand

πŸ› πŸ’» πŸ“–
Karthik Dani
Karthik Dani

πŸ› πŸ’»
jettythek
jettythek

πŸ’»
From 8f740b82226fa02a486487cf47546f09e2c8372c Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Tue, 20 Jan 2026 13:53:54 -0500 Subject: [PATCH 4/8] Add all book contributors from main config Migrated 99 contributors from the main .all-contributorsrc to the book-specific config. These are all the people who contributed to the ML Systems Book project. Total book contributors: 103 --- book/.all-contributorsrc | 891 +++++++++++++++++++++++++++++++++++++++ book/README.md | 127 ++++++ 2 files changed, 1018 insertions(+) diff --git a/book/.all-contributorsrc b/book/.all-contributorsrc index b16008584..addf5e7ff 100644 --- a/book/.all-contributorsrc +++ b/book/.all-contributorsrc @@ -59,6 +59,897 @@ "contributions": [ "code" ] + }, + { + "login": "jasonjabbour", + "name": "Jason Jabbour", + "avatar_url": "https://avatars.githubusercontent.com/jasonjabbour", + "profile": "https://github.com/jasonjabbour", + "contributions": [ + "doc" + ] + }, + { + "login": "kai4avaya", + "name": "Kai Kleinbard", + "avatar_url": "https://avatars.githubusercontent.com/kai4avaya", + "profile": "https://github.com/kai4avaya", + "contributions": [ + "doc" + ] + }, + { + "login": "uchendui", + "name": "Ikechukwu Uchendu", + "avatar_url": "https://avatars.githubusercontent.com/uchendui", + "profile": "https://github.com/uchendui", + "contributions": [ + "doc" + ] + }, + { + "login": "Naeemkh", + "name": "Naeem Khoshnevis", + "avatar_url": "https://avatars.githubusercontent.com/Naeemkh", + "profile": "https://github.com/Naeemkh", + "contributions": [ + "doc" + ] + }, + { + "login": "Sara-Khosravi", + "name": "Sara Khosravi", + "avatar_url": "https://avatars.githubusercontent.com/Sara-Khosravi", + "profile": "https://github.com/Sara-Khosravi", + "contributions": [ + "doc" + ] + }, + { + "login": "V0XNIHILI", + "name": "Douwe den Blanken", + "avatar_url": "https://avatars.githubusercontent.com/V0XNIHILI", + "profile": "https://github.com/V0XNIHILI", + "contributions": [ + "doc" + ] + }, + { + "login": "18jeffreyma", + "name": "Jeffrey Ma", + "avatar_url": "https://avatars.githubusercontent.com/18jeffreyma", + "profile": "https://github.com/18jeffreyma", + "contributions": [ + "doc" + ] + }, + { + "login": "didier-durand", + "name": "Didier Durand", + "avatar_url": "https://avatars.githubusercontent.com/didier-durand", + "profile": "https://github.com/didier-durand", + "contributions": [ + "doc" + ] + }, + { + "login": "shanzehbatool", + "name": "shanzehbatool", + "avatar_url": "https://avatars.githubusercontent.com/shanzehbatool", + "profile": "https://github.com/shanzehbatool", + "contributions": [ + "doc" + ] + }, + { + "login": "eliasab16", + "name": "Elias", + "avatar_url": "https://avatars.githubusercontent.com/eliasab16", + "profile": "https://github.com/eliasab16", + "contributions": [ + "doc" + ] + }, + { + "login": "JaredP94", + "name": "Jared Ping", + "avatar_url": "https://avatars.githubusercontent.com/JaredP94", + "profile": "https://github.com/JaredP94", + "contributions": [ + "doc" + ] + }, + { + "login": "ishapira1", + "name": "Itai Shapira", + "avatar_url": "https://avatars.githubusercontent.com/ishapira1", + "profile": "https://github.com/ishapira1", + "contributions": [ + "doc" + ] + }, + { + "login": "Maximilian Lam", + "name": "Maximilian Lam", + "avatar_url": "https://www.gravatar.com/avatar/8863743b4f26c1a20e730fcf7ebc3bc0?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "jaysonzlin", + "name": "Jayson Lin", + "avatar_url": "https://avatars.githubusercontent.com/jaysonzlin", + "profile": "https://github.com/jaysonzlin", + "contributions": [ + "doc" + ] + }, + { + "login": "sophiacho1", + "name": "Sophia Cho", + "avatar_url": "https://avatars.githubusercontent.com/sophiacho1", + "profile": "https://github.com/sophiacho1", + "contributions": [ + "doc" + ] + }, + { + "login": "andreamurillomtz", + "name": "Andrea", + "avatar_url": "https://avatars.githubusercontent.com/andreamurillomtz", + "profile": "https://github.com/andreamurillomtz", + "contributions": [ + "doc" + ] + }, + { + "login": "alxrod", + "name": "Alex Rodriguez", + "avatar_url": "https://avatars.githubusercontent.com/alxrod", + "profile": "https://github.com/alxrod", + "contributions": [ + "doc" + ] + }, + { + "login": "korneelf1", + "name": "Korneel Van den Berghe", + "avatar_url": "https://avatars.githubusercontent.com/korneelf1", + "profile": "https://github.com/korneelf1", + "contributions": [ + "doc" + ] + }, + { + "login": "foundingnimo", + "name": "Nimo", + "avatar_url": "https://avatars.githubusercontent.com/foundingnimo", + "profile": "https://github.com/foundingnimo", + "contributions": [ + "doc" + ] + }, + { + "login": "colbybanbury", + "name": "Colby Banbury", + "avatar_url": "https://avatars.githubusercontent.com/colbybanbury", + "profile": "https://github.com/colbybanbury", + "contributions": [ + "doc" + ] + }, + { + "login": "zishenwan", + "name": "Zishen Wan", + "avatar_url": "https://avatars.githubusercontent.com/zishenwan", + "profile": "https://github.com/zishenwan", + "contributions": [ + "doc" + ] + }, + { + "login": "mmaz", + "name": "Mark Mazumder", + "avatar_url": "https://avatars.githubusercontent.com/mmaz", + "profile": "https://github.com/mmaz", + "contributions": [ + "doc" + ] + }, + { + "login": "ma3mool", + "name": "Abdulrahman Mahmoud", + "avatar_url": "https://avatars.githubusercontent.com/ma3mool", + "profile": "https://github.com/ma3mool", + "contributions": [ + "doc" + ] + }, + { + "login": "DivyaAmirtharaj", + "name": "Divya Amirtharaj", + "avatar_url": "https://avatars.githubusercontent.com/DivyaAmirtharaj", + "profile": "https://github.com/DivyaAmirtharaj", + "contributions": [ + "doc" + ] + }, + { + "login": "srivatsankrishnan", + "name": "Srivatsan Krishnan", + "avatar_url": "https://avatars.githubusercontent.com/srivatsankrishnan", + "profile": "https://github.com/srivatsankrishnan", + "contributions": [ + "doc" + ] + }, + { + "login": "arnaumarin", + "name": "marin-llobet", + "avatar_url": "https://avatars.githubusercontent.com/arnaumarin", + "profile": "https://github.com/arnaumarin", + "contributions": [ + "doc" + ] + }, + { + "login": "aptl26", + "name": "Aghyad Deeb", + "avatar_url": "https://avatars.githubusercontent.com/aptl26", + "profile": "https://github.com/aptl26", + "contributions": [ + "doc" + ] + }, + { + "login": "James-QiuHaoran", + "name": "Haoran Qiu", + "avatar_url": "https://avatars.githubusercontent.com/James-QiuHaoran", + "profile": "https://github.com/James-QiuHaoran", + "contributions": [ + "doc" + ] + }, + { + "login": "Ekhao", + "name": "Emil Njor", + "avatar_url": "https://avatars.githubusercontent.com/Ekhao", + "profile": "https://github.com/Ekhao", + "contributions": [ + "doc" + ] + }, + { + "login": "ELSuitorHarvard", + "name": "ELSuitorHarvard", + "avatar_url": "https://avatars.githubusercontent.com/ELSuitorHarvard", + "profile": "https://github.com/ELSuitorHarvard", + "contributions": [ + "doc" + ] + }, + { + "login": "kaiM0ves", + "name": "kaiM0ves", + "avatar_url": "https://avatars.githubusercontent.com/kaiM0ves", + "profile": "https://github.com/kaiM0ves", + "contributions": [ + "doc" + ] + }, + { + "login": "oishib", + "name": "oishib", + "avatar_url": "https://avatars.githubusercontent.com/oishib", + "profile": "https://github.com/oishib", + "contributions": [ + "doc" + ] + }, + { + "login": "jared-ni", + "name": "Jared Ni", + "avatar_url": "https://avatars.githubusercontent.com/jared-ni", + "profile": "https://github.com/jared-ni", + "contributions": [ + "doc" + ] + }, + { + "login": "AditiR-42", + "name": "Aditi Raju", + "avatar_url": "https://avatars.githubusercontent.com/AditiR-42", + "profile": "https://github.com/AditiR-42", + "contributions": [ + "doc" + ] + }, + { + "login": "MichaelSchnebly", + "name": "Michael Schnebly", + "avatar_url": "https://avatars.githubusercontent.com/MichaelSchnebly", + "profile": "https://github.com/MichaelSchnebly", + "contributions": [ + "doc" + ] + }, + { + "login": "VThuong99", + "name": "Thuong Duong", + "avatar_url": "https://avatars.githubusercontent.com/VThuong99", + "profile": "https://github.com/VThuong99", + "contributions": [ + "doc" + ] + }, + { + "login": "leo47007", + "name": "Yu-Shun Hsiao", + "avatar_url": "https://avatars.githubusercontent.com/leo47007", + "profile": "https://github.com/leo47007", + "contributions": [ + "doc" + ] + }, + { + "login": "BaeHenryS", + "name": "Henry Bae", + "avatar_url": "https://avatars.githubusercontent.com/BaeHenryS", + "profile": "https://github.com/BaeHenryS", + "contributions": [ + "doc" + ] + }, + { + "login": "eimlav", + "name": "Eimhin Laverty", + "avatar_url": "https://avatars.githubusercontent.com/eimlav", + "profile": "https://github.com/eimlav", + "contributions": [ + "doc" + ] + }, + { + "login": "jaywonchung", + "name": "Jae-Won Chung", + "avatar_url": "https://avatars.githubusercontent.com/jaywonchung", + "profile": "https://github.com/jaywonchung", + "contributions": [ + "doc" + ] + }, + { + "login": "ShvetankPrakash", + "name": "Shvetank Prakash", + "avatar_url": "https://avatars.githubusercontent.com/ShvetankPrakash", + "profile": "https://github.com/ShvetankPrakash", + "contributions": [ + "doc" + ] + }, + { + "login": "marcozennaro", + "name": "Marco Zennaro", + "avatar_url": "https://avatars.githubusercontent.com/marcozennaro", + "profile": "https://github.com/marcozennaro", + "contributions": [ + "doc" + ] + }, + { + "login": "aryatschand", + "name": "Arya Tschand", + "avatar_url": "https://avatars.githubusercontent.com/aryatschand", + "profile": "https://github.com/aryatschand", + "contributions": [ + "doc" + ] + }, + { + "login": "arbass22", + "name": "Andrew Bass", + "avatar_url": "https://avatars.githubusercontent.com/arbass22", + "profile": "https://github.com/arbass22", + "contributions": [ + "doc" + ] + }, + { + "login": "pongtr", + "name": "Pong Trairatvorakul", + "avatar_url": "https://avatars.githubusercontent.com/pongtr", + "profile": "https://github.com/pongtr", + "contributions": [ + "doc" + ] + }, + { + "login": "euranofshin", + "name": "Eura Nofshin", + "avatar_url": "https://avatars.githubusercontent.com/euranofshin", + "profile": "https://github.com/euranofshin", + "contributions": [ + "doc" + ] + }, + { + "login": "Matthew Stewart", + "name": "Matthew Stewart", + "avatar_url": "https://www.gravatar.com/avatar/0c931fcfd03cd548d44c90602dd773ba?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "Emeka Ezike", + "name": "Emeka Ezike", + "avatar_url": "https://www.gravatar.com/avatar/af39c27c6090c50a1921a9b6366e81cc?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "jianqingdu", + "name": "jianqingdu", + "avatar_url": "https://avatars.githubusercontent.com/jianqingdu", + "profile": "https://github.com/jianqingdu", + "contributions": [ + "doc" + ] + }, + { + "login": "jzhou1318", + "name": "Jennifer Zhou", + "avatar_url": "https://avatars.githubusercontent.com/jzhou1318", + "profile": "https://github.com/jzhou1318", + "contributions": [ + "doc" + ] + }, + { + "login": "vitasam", + "name": "The Random DIY", + "avatar_url": "https://avatars.githubusercontent.com/vitasam", + "profile": "https://github.com/vitasam", + "contributions": [ + "doc" + ] + }, + { + "login": "Fatima Shah", + "name": "Fatima Shah", + "avatar_url": "https://www.gravatar.com/avatar/468ef35acc69f3266efd700992daa369?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "BrunoScaglione", + "name": "Bruno Scaglione", + "avatar_url": "https://avatars.githubusercontent.com/BrunoScaglione", + "profile": "https://github.com/BrunoScaglione", + "contributions": [ + "doc" + ] + }, + { + "login": "Allen-Kuang", + "name": "Allen-Kuang", + "avatar_url": "https://avatars.githubusercontent.com/Allen-Kuang", + "profile": "https://github.com/Allen-Kuang", + "contributions": [ + "doc" + ] + }, + { + "login": "Tess314", + "name": "Tess314", + "avatar_url": "https://www.gravatar.com/avatar/4ad8cdf19eb3b666ace97d3eedb19278?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "taunoe", + "name": "Tauno Erik", + "avatar_url": "https://avatars.githubusercontent.com/taunoe", + "profile": "https://github.com/taunoe", + "contributions": [ + "doc" + ] + }, + { + "login": "gnodipac886", + "name": "gnodipac886", + "avatar_url": "https://avatars.githubusercontent.com/gnodipac886", + "profile": "https://github.com/gnodipac886", + "contributions": [ + "doc" + ] + }, + { + "login": "serco425", + "name": "Sercan Ayg\u00fcn", + "avatar_url": "https://avatars.githubusercontent.com/serco425", + "profile": "https://github.com/serco425", + "contributions": [ + "doc" + ] + }, + { + "login": "TheHiddenLayer", + "name": "TheHiddenLayer", + "avatar_url": "https://avatars.githubusercontent.com/TheHiddenLayer", + "profile": "https://github.com/TheHiddenLayer", + "contributions": [ + "doc" + ] + }, + { + "login": "Gjain234", + "name": "Gauri Jain", + "avatar_url": "https://avatars.githubusercontent.com/Gjain234", + "profile": "https://github.com/Gjain234", + "contributions": [ + "doc" + ] + }, + { + "login": "FinAminToastCrunch", + "name": "Fin Amin", + "avatar_url": "https://avatars.githubusercontent.com/FinAminToastCrunch", + "profile": "https://github.com/FinAminToastCrunch", + "contributions": [ + "doc" + ] + }, + { + "login": "alex-oesterling", + "name": "Alex Oesterling", + "avatar_url": "https://avatars.githubusercontent.com/alex-oesterling", + "profile": "https://github.com/alex-oesterling", + "contributions": [ + "doc" + ] + }, + { + "login": "AbenezerKb", + "name": "Abenezer Angamo", + "avatar_url": "https://avatars.githubusercontent.com/AbenezerKb", + "profile": "https://github.com/AbenezerKb", + "contributions": [ + "doc" + ] + }, + { + "login": "BravoBaldo", + "name": "Baldassarre Cesarano", + "avatar_url": "https://avatars.githubusercontent.com/BravoBaldo", + "profile": "https://github.com/BravoBaldo", + "contributions": [ + "doc" + ] + }, + { + "login": "KarthikDani", + "name": "Karthik Dani", + "avatar_url": "https://avatars.githubusercontent.com/KarthikDani", + "profile": "https://github.com/KarthikDani", + "contributions": [ + "doc" + ] + }, + { + "login": "Jahnic-kb", + "name": "Jahnic Beck", + "avatar_url": "https://avatars.githubusercontent.com/Jahnic-kb", + "profile": "https://github.com/Jahnic-kb", + "contributions": [ + "doc" + ] + }, + { + "login": "aethernavshulkraven-allain", + "name": "\u0905\u0930\u0928\u0935 \u0936\u0941\u0915\u094d\u0932\u093e | Arnav Shukla", + "avatar_url": "https://avatars.githubusercontent.com/aethernavshulkraven-allain", + "profile": "https://github.com/aethernavshulkraven-allain", + "contributions": [ + "doc" + ] + }, + { + "login": "RinZ27", + "name": "Rin", + "avatar_url": "https://avatars.githubusercontent.com/RinZ27", + "profile": "https://github.com/RinZ27", + "contributions": [ + "doc" + ] + }, + { + "login": "bilgeacun", + "name": "Bilge Acun", + "avatar_url": "https://avatars.githubusercontent.com/bilgeacun", + "profile": "https://github.com/bilgeacun", + "contributions": [ + "doc" + ] + }, + { + "login": "atcheng2", + "name": "Andy Cheng", + "avatar_url": "https://avatars.githubusercontent.com/atcheng2", + "profile": "https://github.com/atcheng2", + "contributions": [ + "doc" + ] + }, + { + "login": "arighosh05", + "name": "Aritra Ghosh", + "avatar_url": "https://avatars.githubusercontent.com/arighosh05", + "profile": "https://github.com/arighosh05", + "contributions": [ + "doc" + ] + }, + { + "login": "abigailswallow", + "name": "abigailswallow", + "avatar_url": "https://avatars.githubusercontent.com/abigailswallow", + "profile": "https://github.com/abigailswallow", + "contributions": [ + "doc" + ] + }, + { + "login": "YangZhou1997", + "name": "Yang Zhou", + "avatar_url": "https://avatars.githubusercontent.com/YangZhou1997", + "profile": "https://github.com/YangZhou1997", + "contributions": [ + "doc" + ] + }, + { + "login": "XaicuL", + "name": "JEON HYUNJUN(Luciano)", + "avatar_url": "https://avatars.githubusercontent.com/XaicuL", + "profile": "https://github.com/XaicuL", + "contributions": [ + "doc" + ] + }, + { + "login": "emmanuel2406", + "name": "Emmanuel Rassou", + "avatar_url": "https://avatars.githubusercontent.com/emmanuel2406", + "profile": "https://github.com/emmanuel2406", + "contributions": [ + "doc" + ] + }, + { + "login": "jasonlyik", + "name": "Jason Yik", + "avatar_url": "https://avatars.githubusercontent.com/jasonlyik", + "profile": "https://github.com/jasonlyik", + "contributions": [ + "doc" + ] + }, + { + "login": "jessicaquaye", + "name": "Jessica Quaye", + "avatar_url": "https://avatars.githubusercontent.com/jessicaquaye", + "profile": "https://github.com/jessicaquaye", + "contributions": [ + "doc" + ] + }, + { + "login": "cursoragent", + "name": "Cursor Agent", + "avatar_url": "https://avatars.githubusercontent.com/cursoragent", + "profile": "https://github.com/cursoragent", + "contributions": [ + "doc" + ] + }, + { + "login": "happyappledog", + "name": "happyappledog", + "avatar_url": "https://avatars.githubusercontent.com/happyappledog", + "profile": "https://github.com/happyappledog", + "contributions": [ + "doc" + ] + }, + { + "login": "snuggs", + "name": "Snuggs", + "avatar_url": "https://avatars.githubusercontent.com/snuggs", + "profile": "https://github.com/snuggs", + "contributions": [ + "doc" + ] + }, + { + "login": "swilcock0", + "name": "Sam Wilcock", + "avatar_url": "https://avatars.githubusercontent.com/swilcock0", + "profile": "https://github.com/swilcock0", + "contributions": [ + "doc" + ] + }, + { + "login": "sjohri20", + "name": "Shreya Johri", + "avatar_url": "https://avatars.githubusercontent.com/sjohri20", + "profile": "https://github.com/sjohri20", + "contributions": [ + "doc" + ] + }, + { + "login": "skmur", + "name": "Sonia Murthy", + "avatar_url": "https://avatars.githubusercontent.com/skmur", + "profile": "https://github.com/skmur", + "contributions": [ + "doc" + ] + }, + { + "login": "Costin-Andrei Oncescu", + "name": "Costin-Andrei Oncescu", + "avatar_url": "https://www.gravatar.com/avatar/fc4f3460cdfb9365ab59bdeafb06413e?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "formlsysbookissue", + "name": "formlsysbookissue", + "avatar_url": "https://www.gravatar.com/avatar/0d6b8616427d8b19d425c9808692e347?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "Annie Laurie Cook", + "name": "Annie Laurie Cook", + "avatar_url": "https://www.gravatar.com/avatar/7cd8d5dfd83071f23979019d97655dc5?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "Parampreet Singh", + "name": "Parampreet Singh", + "avatar_url": "https://www.gravatar.com/avatar/5aa037840c0ca11ee42784ed4843c655?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "Vijay Edupuganti", + "name": "Vijay Edupuganti", + "avatar_url": "https://www.gravatar.com/avatar/b15b6e0e9adf58099905c1a0fd474cb9?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "Jothi Ramaswamy", + "name": "Jothi Ramaswamy", + "avatar_url": "https://www.gravatar.com/avatar/f88052cca4f401d9b0f43aed0a53434a?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "Batur Arslan", + "name": "Batur Arslan", + "avatar_url": "https://www.gravatar.com/avatar/35a8d9ffd03f05e79a2c6ce6206a56f2?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "Curren Iyer", + "name": "Curren Iyer", + "avatar_url": "https://www.gravatar.com/avatar/bd53d146aa888548c8db4da02bf81e7a?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "Edward Jin", + "name": "Edward Jin", + "avatar_url": "https://www.gravatar.com/avatar/8d8410338458e08bd5e4b96f58e1c217?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "Tess Watt", + "name": "Tess Watt", + "avatar_url": "https://www.gravatar.com/avatar/28c6123d2c9f75578d3ccdedb0df3d11?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "bluebaer7", + "name": "bluebaer7", + "avatar_url": "https://www.gravatar.com/avatar/ef139181fe00190f21730f6912532e9e?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "yanjingl", + "name": "yanjingl", + "avatar_url": "https://www.gravatar.com/avatar/f5d58ba6aa9b00189d4c018d370e8f43?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "a-saraf", + "name": "a-saraf", + "avatar_url": "https://www.gravatar.com/avatar/a5a47df988ab1720dd706062e523ca32?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "songhan", + "name": "songhan", + "avatar_url": "https://www.gravatar.com/avatar/c2dc311aa8122d5f5f061e1db14682b1?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "jvijay", + "name": "jvijay", + "avatar_url": "https://www.gravatar.com/avatar/4814aad67982ab07a69006a1ce9d2a72?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] + }, + { + "login": "Zishen", + "name": "Zishen", + "avatar_url": "https://www.gravatar.com/avatar/43b1feff77c8a95fd581774fb8ec891f?d=identicon&s=100", + "profile": "https://github.com/harvard-edge/cs249r_book/graphs/contributors", + "contributions": [ + "doc" + ] } ] } \ No newline at end of file diff --git a/book/README.md b/book/README.md index 27d7cb2ae..9517c65c1 100644 --- a/book/README.md +++ b/book/README.md @@ -170,6 +170,133 @@ Thanks to these wonderful people who helped improve the book ([emoji key](https: Marcelo Rovai
Marcelo Rovai

πŸ’» 🎨 πŸ§ͺ Gabriel Amazonas
Gabriel Amazonas

πŸ› πŸ“– πŸ’‘ Zeljko Hrcek
Zeljko Hrcek

πŸ’» + Jason Jabbour
Jason Jabbour

πŸ“– + Kai Kleinbard
Kai Kleinbard

πŸ“– + Ikechukwu Uchendu
Ikechukwu Uchendu

πŸ“– + + + Naeem Khoshnevis
Naeem Khoshnevis

πŸ“– + Sara Khosravi
Sara Khosravi

πŸ“– + Douwe den Blanken
Douwe den Blanken

πŸ“– + Jeffrey Ma
Jeffrey Ma

πŸ“– + Didier Durand
Didier Durand

πŸ“– + shanzehbatool
shanzehbatool

πŸ“– + Elias
Elias

πŸ“– + + + Jared Ping
Jared Ping

πŸ“– + Itai Shapira
Itai Shapira

πŸ“– + Maximilian Lam
Maximilian Lam

πŸ“– + Jayson Lin
Jayson Lin

πŸ“– + Sophia Cho
Sophia Cho

πŸ“– + Andrea
Andrea

πŸ“– + Alex Rodriguez
Alex Rodriguez

πŸ“– + + + Korneel Van den Berghe
Korneel Van den Berghe

πŸ“– + Nimo
Nimo

πŸ“– + Colby Banbury
Colby Banbury

πŸ“– + Zishen Wan
Zishen Wan

πŸ“– + Mark Mazumder
Mark Mazumder

πŸ“– + Abdulrahman Mahmoud
Abdulrahman Mahmoud

πŸ“– + Divya Amirtharaj
Divya Amirtharaj

πŸ“– + + + Srivatsan Krishnan
Srivatsan Krishnan

πŸ“– + marin-llobet
marin-llobet

πŸ“– + Aghyad Deeb
Aghyad Deeb

πŸ“– + Haoran Qiu
Haoran Qiu

πŸ“– + Emil Njor
Emil Njor

πŸ“– + ELSuitorHarvard
ELSuitorHarvard

πŸ“– + kaiM0ves
kaiM0ves

πŸ“– + + + oishib
oishib

πŸ“– + Jared Ni
Jared Ni

πŸ“– + Aditi Raju
Aditi Raju

πŸ“– + Michael Schnebly
Michael Schnebly

πŸ“– + Thuong Duong
Thuong Duong

πŸ“– + Yu-Shun Hsiao
Yu-Shun Hsiao

πŸ“– + Henry Bae
Henry Bae

πŸ“– + + + Eimhin Laverty
Eimhin Laverty

πŸ“– + Jae-Won Chung
Jae-Won Chung

πŸ“– + Shvetank Prakash
Shvetank Prakash

πŸ“– + Marco Zennaro
Marco Zennaro

πŸ“– + Arya Tschand
Arya Tschand

πŸ“– + Andrew Bass
Andrew Bass

πŸ“– + Pong Trairatvorakul
Pong Trairatvorakul

πŸ“– + + + Eura Nofshin
Eura Nofshin

πŸ“– + Matthew Stewart
Matthew Stewart

πŸ“– + Emeka Ezike
Emeka Ezike

πŸ“– + jianqingdu
jianqingdu

πŸ“– + Jennifer Zhou
Jennifer Zhou

πŸ“– + The Random DIY
The Random DIY

πŸ“– + Fatima Shah
Fatima Shah

πŸ“– + + + Bruno Scaglione
Bruno Scaglione

πŸ“– + Allen-Kuang
Allen-Kuang

πŸ“– + Tess314
Tess314

πŸ“– + Tauno Erik
Tauno Erik

πŸ“– + gnodipac886
gnodipac886

πŸ“– + Sercan AygΓΌn
Sercan AygΓΌn

πŸ“– + TheHiddenLayer
TheHiddenLayer

πŸ“– + + + Gauri Jain
Gauri Jain

πŸ“– + Fin Amin
Fin Amin

πŸ“– + Alex Oesterling
Alex Oesterling

πŸ“– + Abenezer Angamo
Abenezer Angamo

πŸ“– + Baldassarre Cesarano
Baldassarre Cesarano

πŸ“– + Karthik Dani
Karthik Dani

πŸ“– + Jahnic Beck
Jahnic Beck

πŸ“– + + + ΰ€…ΰ€°ΰ€¨ΰ€΅ ΰ€Άΰ₯ΰ€•ΰ₯ΰ€²ΰ€Ύ | Arnav Shukla
ΰ€…ΰ€°ΰ€¨ΰ€΅ ΰ€Άΰ₯ΰ€•ΰ₯ΰ€²ΰ€Ύ | Arnav Shukla

πŸ“– + Rin
Rin

πŸ“– + Bilge Acun
Bilge Acun

πŸ“– + Andy Cheng
Andy Cheng

πŸ“– + Aritra Ghosh
Aritra Ghosh

πŸ“– + abigailswallow
abigailswallow

πŸ“– + Yang Zhou
Yang Zhou

πŸ“– + + + JEON HYUNJUN(Luciano)
JEON HYUNJUN(Luciano)

πŸ“– + Emmanuel Rassou
Emmanuel Rassou

πŸ“– + Jason Yik
Jason Yik

πŸ“– + Jessica Quaye
Jessica Quaye

πŸ“– + Cursor Agent
Cursor Agent

πŸ“– + happyappledog
happyappledog

πŸ“– + Snuggs
Snuggs

πŸ“– + + + Sam Wilcock
Sam Wilcock

πŸ“– + Shreya Johri
Shreya Johri

πŸ“– + Sonia Murthy
Sonia Murthy

πŸ“– + Costin-Andrei Oncescu
Costin-Andrei Oncescu

πŸ“– + formlsysbookissue
formlsysbookissue

πŸ“– + Annie Laurie Cook
Annie Laurie Cook

πŸ“– + Parampreet Singh
Parampreet Singh

πŸ“– + + + Vijay Edupuganti
Vijay Edupuganti

πŸ“– + Jothi Ramaswamy
Jothi Ramaswamy

πŸ“– + Batur Arslan
Batur Arslan

πŸ“– + Curren Iyer
Curren Iyer

πŸ“– + Edward Jin
Edward Jin

πŸ“– + Tess Watt
Tess Watt

πŸ“– + bluebaer7
bluebaer7

πŸ“– + + + yanjingl
yanjingl

πŸ“– + a-saraf
a-saraf

πŸ“– + songhan
songhan

πŸ“– + jvijay
jvijay

πŸ“– + Zishen
Zishen

πŸ“– From a59a169a7f47a20098b9a6b6ecbc1848b080ea34 Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Wed, 21 Jan 2026 19:21:47 -0500 Subject: [PATCH 5/8] Add sectioned contributor system with per-project tracking - Rename workflow to update-contributors.yml (more generic name) - Add generate_main_readme.py to create sectioned contributor table - Update main README with sections: Book, TinyTorch, Kits, Labs - Add contribution type badges (emojis) to contributor entries - Add Marcelo Rovai to kits contributors - Update workflow to handle all project contributor files --- .../workflows/book-update-contributors.yml | 75 ----- .../contributors/generate_main_readme.py | 245 +++++++++++++++ .github/workflows/update-contributors.yml | 106 +++++++ README.md | 295 +++++++++++------- book/.all-contributorsrc | 47 ++- book/README.md | 59 ++-- kits/.all-contributorsrc | 12 + kits/README.md | 8 +- 8 files changed, 589 insertions(+), 258 deletions(-) delete mode 100644 .github/workflows/book-update-contributors.yml create mode 100644 .github/workflows/contributors/generate_main_readme.py create mode 100644 .github/workflows/update-contributors.yml diff --git a/.github/workflows/book-update-contributors.yml b/.github/workflows/book-update-contributors.yml deleted file mode 100644 index e42ddfc37..000000000 --- a/.github/workflows/book-update-contributors.yml +++ /dev/null @@ -1,75 +0,0 @@ -name: 'πŸ“š Book Update Contributors' - -on: - workflow_call: - workflow_dispatch: - -# ============================================================================= -# PATH CONFIGURATION - Uses GitHub Repository Variables (Settings > Variables) -# ============================================================================= -# MLSysBook content lives under book/ to accommodate TinyTorch at root -# Use ${{ vars.BOOK_ROOT }}, ${{ vars.BOOK_QUARTO }}, etc. in workflow steps -# Variables: BOOK_ROOT, BOOK_DOCKER, BOOK_TOOLS, BOOK_QUARTO, BOOK_DEPS - -jobs: - update-contributors: - name: Update Contributors List - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup Python - uses: actions/setup-python@v4 - with: - python-version: '3.11' - cache: 'pip' - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r ${{ vars.BOOK_DEPS }}/requirements.txt - pip install PyGithub>=1.55 - - - name: Configure Git - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email "github-actions[bot]@users.noreply.github.com" - - - name: Update contributors (script) - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: python ${{ github.workspace }}/.github/workflows/contributors/update_contributors.py - - - name: Update contributors (cli) - run: npx --yes all-contributors-cli generate - - - name: Check for changes - id: update - run: | - if git status .all-contributorsrc README.md ${{ vars.BOOK_QUARTO }}/contents/frontmatter/acknowledgements/acknowledgements.qmd --porcelain | grep .; then - echo "changes_made=true" >> $GITHUB_OUTPUT - else - echo "changes_made=false" >> $GITHUB_OUTPUT - fi - - - name: Commit Changes - if: steps.update.outputs.changes_made == 'true' - run: | - BRANCH_NAME=${GITHUB_HEAD_REF:-$(git rev-parse --abbrev-ref HEAD)} - - git add .all-contributorsrc README.md ${{ vars.BOOK_QUARTO }}/contents/frontmatter/acknowledgements/acknowledgements.qmd - git commit -m "Update contributors list [skip ci]" - git pull --rebase origin "$BRANCH_NAME" - git push origin "$BRANCH_NAME" - - - name: Report Status - run: | - if [ "${{ steps.update.outputs.changes_made }}" = "true" ]; then - echo "βœ… Contributors list has been updated" - else - echo "ℹ️ No changes were needed for contributors list" - fi diff --git a/.github/workflows/contributors/generate_main_readme.py b/.github/workflows/contributors/generate_main_readme.py new file mode 100644 index 000000000..78166a1f9 --- /dev/null +++ b/.github/workflows/contributors/generate_main_readme.py @@ -0,0 +1,245 @@ +#!/usr/bin/env python3 +""" +Generate the main README.md contributor section from all project configs. + +This script reads the .all-contributorsrc files from each project +(book, tinytorch, kits, labs) and generates a sectioned contributor +table for the main README.md. + +Usage: + python generate_main_readme.py [--dry-run] +""" + +import json +import re +import sys +from pathlib import Path + +# Contribution type to emoji mapping +CONTRIBUTION_EMOJIS = { + "bug": "πŸ›", + "code": "πŸ’»", + "design": "🎨", + "doc": "πŸ“–", + "ideas": "πŸ’‘", + "review": "πŸ‘€", + "test": "πŸ§ͺ", + "tool": "πŸ”§", + "tutorial": "βœ…", + "maintenance": "🚧", + "infra": "πŸš‡", + "question": "πŸ’¬", + "translation": "🌍", + "content": "πŸ–‹", + "example": "πŸ’‘", + "security": "πŸ”", + "financial": "πŸ’΅", + "fundingFinding": "πŸ”", + "eventOrganizing": "πŸ“‹", + "talk": "πŸ“’", + "video": "πŸ“Ή", + "audio": "πŸ”Š", + "data": "πŸ”£", + "platform": "πŸ“¦", + "projectManagement": "πŸ“†", + "mentoring": "πŸ§‘β€πŸ«", + "plugin": "πŸ”Œ", + "userTesting": "πŸ““", + "a11y": "♿️", + "business": "πŸ’Ό", + "research": "πŸ”¬", + "promotion": "πŸ“£", +} + + +def load_config(path: Path) -> dict: + """Load a .all-contributorsrc file.""" + if not path.exists(): + return {"contributors": []} + with open(path) as f: + return json.load(f) + + +def generate_contributor_cell(contributor: dict, show_badges: bool = True) -> str: + """Generate HTML for a single contributor cell.""" + login = contributor.get("login", "") + name = contributor.get("name", login) + avatar_url = contributor.get("avatar_url", "") + profile = contributor.get("profile", f"https://github.com/{login}") + contributions = contributor.get("contributions", []) + + # Generate badge string + badges = "" + if show_badges and contributions: + badges = " ".join(CONTRIBUTION_EMOJIS.get(c, "") for c in contributions) + badges = f"
{badges}" if badges.strip() else "" + + return f''' {name}
{name}
{badges}''' + + +def generate_contributor_table(contributors: list, show_badges: bool = True) -> str: + """Generate an HTML table for contributors.""" + if not contributors: + return "

Coming soon!

" + + rows = [] + row_cells = [] + + for i, contributor in enumerate(contributors): + row_cells.append(generate_contributor_cell(contributor, show_badges)) + + # 7 contributors per row + if len(row_cells) == 7: + rows.append(" \n" + "\n".join(row_cells) + "\n ") + row_cells = [] + + # Add remaining cells + if row_cells: + rows.append(" \n" + "\n".join(row_cells) + "\n ") + + return f''' + +{chr(10).join(rows)} + +
''' + + +def generate_sectioned_contributors(repo_root: Path) -> str: + """Generate the full sectioned contributor section showing ALL contributors.""" + # Load all configs + book_config = load_config(repo_root / "book" / ".all-contributorsrc") + tinytorch_config = load_config(repo_root / "tinytorch" / ".all-contributorsrc") + kits_config = load_config(repo_root / "kits" / ".all-contributorsrc") + labs_config = load_config(repo_root / "labs" / ".all-contributorsrc") + + book_contributors = book_config.get("contributors", []) + tinytorch_contributors = tinytorch_config.get("contributors", []) + kits_contributors = kits_config.get("contributors", []) + labs_contributors = labs_config.get("contributors", []) + + # Count contributors + book_count = len(book_contributors) + tinytorch_count = len(tinytorch_contributors) + kits_count = len(kits_contributors) + labs_count = len(labs_contributors) + + # Generate tables - show ALL contributors + book_table = generate_contributor_table(book_contributors) + tinytorch_table = generate_contributor_table(tinytorch_contributors) + kits_table = generate_contributor_table(kits_contributors) + labs_table = generate_contributor_table(labs_contributors) + + return f'''## Contributors + +Thanks goes to these wonderful people who have contributed to making this resource better for everyone ([emoji key](https://allcontributors.org/docs/en/emoji-key)): + +### πŸ“– Textbook Contributors ({book_count}) + + + + +{book_table} + + + + + +--- + +### πŸ”₯ TinyTorch Contributors ({tinytorch_count}) + + + + +{tinytorch_table} + + + + + +--- + +### πŸ› οΈ Hardware Kits Contributors ({kits_count}) + + + + +{kits_table} + + + + + +--- + +### πŸ§ͺ Labs Contributors ({labs_count}) + + + + +{labs_table} + + + + + +--- + +**Recognize a contributor:** Comment on any issue or PR: +``` +@all-contributors please add @username for doc, code, bug, or ideas +```''' + + +def update_readme(repo_root: Path, dry_run: bool = False) -> bool: + """Update the main README.md with sectioned contributors.""" + readme_path = repo_root / "README.md" + + if not readme_path.exists(): + print(f"ERROR: README.md not found at {readme_path}") + return False + + content = readme_path.read_text() + + # Generate new contributor section + new_section = generate_sectioned_contributors(repo_root) + + # Pattern to match the entire Contributors section + # From "## Contributors" to just before the next "---" followed by a div or end of file + pattern = r'## Contributors\n.*?(?=\n---\n\n
|\Z)' + + if not re.search(pattern, content, re.DOTALL): + print("ERROR: Could not find Contributors section in README.md") + return False + + # Replace the section + new_content = re.sub(pattern, new_section, content, flags=re.DOTALL) + + if dry_run: + print("=== DRY RUN - Would update README.md with: ===") + print(new_section[:2000] + "..." if len(new_section) > 2000 else new_section) + return True + + readme_path.write_text(new_content) + print(f"Updated {readme_path}") + return True + + +def main(): + dry_run = "--dry-run" in sys.argv + + # Find repo root (this script is in .github/workflows/contributors/) + script_dir = Path(__file__).parent + repo_root = script_dir.parent.parent.parent + + # Verify we're in the right place + if not (repo_root / "README.md").exists(): + print(f"ERROR: Cannot find README.md in {repo_root}") + sys.exit(1) + + success = update_readme(repo_root, dry_run) + sys.exit(0 if success else 1) + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/update-contributors.yml b/.github/workflows/update-contributors.yml new file mode 100644 index 000000000..86c8cfbce --- /dev/null +++ b/.github/workflows/update-contributors.yml @@ -0,0 +1,106 @@ +name: 'πŸ‘₯ Update Contributors' + +on: + workflow_call: + workflow_dispatch: + +# ============================================================================= +# CONTRIBUTOR UPDATE WORKFLOW +# ============================================================================= +# Updates contributor lists across all projects: +# - Root .all-contributorsrc (from GitHub commit history) +# - Main README.md (sectioned by project: Book, TinyTorch, Kits, Labs) +# - Per-project README.md files (book/, tinytorch/, kits/, labs/) +# +# Each project has its own .all-contributorsrc that feeds into the main README. +# ============================================================================= + +jobs: + update-contributors: + name: Update Contributors List + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + cache: 'pip' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r ${{ vars.BOOK_DEPS }}/requirements.txt + pip install PyGithub>=1.55 + + - name: Configure Git + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + + - name: Update root contributors config + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: python ${{ github.workspace }}/.github/workflows/contributors/update_contributors.py + + - name: Generate sectioned main README + run: python ${{ github.workspace }}/.github/workflows/contributors/generate_main_readme.py + + - name: Generate per-project README tables + run: | + # Generate tables for each project README from their configs + python ${{ github.workspace }}/.github/workflows/contributors/generate_readme_tables.py --update 2>/dev/null || true + + - name: Check for changes + id: update + run: | + FILES_TO_CHECK=( + ".all-contributorsrc" + "README.md" + "book/.all-contributorsrc" + "book/README.md" + "tinytorch/.all-contributorsrc" + "tinytorch/README.md" + "kits/.all-contributorsrc" + "kits/README.md" + "labs/.all-contributorsrc" + "labs/README.md" + "${{ vars.BOOK_QUARTO }}/contents/frontmatter/acknowledgements/acknowledgements.qmd" + ) + + if git status "${FILES_TO_CHECK[@]}" --porcelain 2>/dev/null | grep .; then + echo "changes_made=true" >> $GITHUB_OUTPUT + else + echo "changes_made=false" >> $GITHUB_OUTPUT + fi + + - name: Commit Changes + if: steps.update.outputs.changes_made == 'true' + run: | + BRANCH_NAME=${GITHUB_HEAD_REF:-$(git rev-parse --abbrev-ref HEAD)} + + # Add all contributor-related files + git add -A .all-contributorsrc README.md \ + book/.all-contributorsrc book/README.md \ + tinytorch/.all-contributorsrc tinytorch/README.md \ + kits/.all-contributorsrc kits/README.md \ + labs/.all-contributorsrc labs/README.md \ + ${{ vars.BOOK_QUARTO }}/contents/frontmatter/acknowledgements/acknowledgements.qmd \ + 2>/dev/null || true + + git commit -m "Update contributors list [skip ci]" + git pull --rebase origin "$BRANCH_NAME" + git push origin "$BRANCH_NAME" + + - name: Report Status + run: | + if [ "${{ steps.update.outputs.changes_made }}" = "true" ]; then + echo "βœ… Contributors list has been updated" + else + echo "ℹ️ No changes were needed for contributors list" + fi diff --git a/README.md b/README.md index cb1da79de..5c078f49c 100644 --- a/README.md +++ b/README.md @@ -287,167 +287,224 @@ The textbook content (chapters, figures, explanations) is educational material t ## Contributors -Thanks goes to these wonderful people who have contributed to making this resource better for everyone: +Thanks goes to these wonderful people who have contributed to making this resource better for everyone ([emoji key](https://allcontributors.org/docs/en/emoji-key)): - +### πŸ“– Textbook Contributors (102) + + - - - - - + + + + + + + - - - - - + + + + + + + - - - - - + + + + + + + - - - - - + + + + + + + - - - - - + + + + + + + - - - - - + + + + + + + - - - - - + + + + + + + - - - - - + + + + + + + - - - - - + + + + + + + - - - - - + + + + + + + - - - - - + + + + + + + - - - - - + + + + + + + - - - - - + + + + + + + - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + +
Vijay Janapa Reddi
Vijay Janapa Reddi

Zeljko Hrcek
Zeljko Hrcek

Marcelo Rovai
Marcelo Rovai

Jason Jabbour
Jason Jabbour

Kai Kleinbard
Kai Kleinbard

Vijay Janapa Reddi
Vijay Janapa Reddi

πŸ› πŸ’» 🎨 πŸ“– πŸ’‘ πŸ‘€ πŸ§ͺ πŸ”§
Marcelo Rovai
Marcelo Rovai

πŸ’» 🎨 πŸ§ͺ
Gabriel Amazonas
Gabriel Amazonas

πŸ› πŸ“– πŸ’‘
Zeljko Hrcek
Zeljko Hrcek

πŸ’»
Jason Jabbour
Jason Jabbour

πŸ“–
Ikechukwu Uchendu
Ikechukwu Uchendu

πŸ“–
Naeem Khoshnevis
Naeem Khoshnevis

πŸ“–
Ikechukwu Uchendu
Ikechukwu Uchendu

Naeem Khoshnevis
Naeem Khoshnevis

Sara Khosravi
Sara Khosravi

Douwe den Blanken
Douwe den Blanken

Jeffrey Ma
Jeffrey Ma

Sara Khosravi
Sara Khosravi

πŸ“–
Douwe den Blanken
Douwe den Blanken

πŸ“–
Jeffrey Ma
Jeffrey Ma

πŸ“–
shanzehbatool
shanzehbatool

πŸ“–
Elias
Elias

πŸ“–
Jared Ping
Jared Ping

πŸ“–
Itai Shapira
Itai Shapira

πŸ“–
Didier Durand
Didier Durand

shanzehbatool
shanzehbatool

Elias
Elias

Jared Ping
Jared Ping

Itai Shapira
Itai Shapira

Maximilian Lam
Maximilian Lam

πŸ“–
Jayson Lin
Jayson Lin

πŸ“–
Sophia Cho
Sophia Cho

πŸ“–
Andrea
Andrea

πŸ“–
Alex Rodriguez
Alex Rodriguez

πŸ“–
Korneel Van den Berghe
Korneel Van den Berghe

πŸ“–
Nimo
Nimo

πŸ“–
Maximilian Lam
Maximilian Lam

Jayson Lin
Jayson Lin

Sophia Cho
Sophia Cho

Andrea
Andrea

Alex Rodriguez
Alex Rodriguez

Colby Banbury
Colby Banbury

πŸ“–
Zishen Wan
Zishen Wan

πŸ“–
Mark Mazumder
Mark Mazumder

πŸ“–
Abdulrahman Mahmoud
Abdulrahman Mahmoud

πŸ“–
Divya Amirtharaj
Divya Amirtharaj

πŸ“–
Srivatsan Krishnan
Srivatsan Krishnan

πŸ“–
marin-llobet
marin-llobet

πŸ“–
Korneel Van den Berghe
Korneel Van den Berghe

Nimo
Nimo

Colby Banbury
Colby Banbury

Zishen Wan
Zishen Wan

Gabriel Amazonas
Gabriel Amazonas

Aghyad Deeb
Aghyad Deeb

πŸ“–
Haoran Qiu
Haoran Qiu

πŸ“–
Emil Njor
Emil Njor

πŸ“–
ELSuitorHarvard
ELSuitorHarvard

πŸ“–
kaiM0ves
kaiM0ves

πŸ“–
oishib
oishib

πŸ“–
Jared Ni
Jared Ni

πŸ“–
Mark Mazumder
Mark Mazumder

Abdulrahman Mahmoud
Abdulrahman Mahmoud

Divya Amirtharaj
Divya Amirtharaj

Srivatsan Krishnan
Srivatsan Krishnan

marin-llobet
marin-llobet

Aditi Raju
Aditi Raju

πŸ“–
Michael Schnebly
Michael Schnebly

πŸ“–
Thuong Duong
Thuong Duong

πŸ“–
Yu-Shun Hsiao
Yu-Shun Hsiao

πŸ“–
Henry Bae
Henry Bae

πŸ“–
Eimhin Laverty
Eimhin Laverty

πŸ“–
Jae-Won Chung
Jae-Won Chung

πŸ“–
Aghyad Deeb
Aghyad Deeb

Haoran Qiu
Haoran Qiu

Emil Njor
Emil Njor

ELSuitorHarvard
ELSuitorHarvard

kaiM0ves
kaiM0ves

Shvetank Prakash
Shvetank Prakash

πŸ“–
Marco Zennaro
Marco Zennaro

πŸ“–
Arya Tschand
Arya Tschand

πŸ“–
Andrew Bass
Andrew Bass

πŸ“–
Pong Trairatvorakul
Pong Trairatvorakul

πŸ“–
Eura Nofshin
Eura Nofshin

πŸ“–
Matthew Stewart
Matthew Stewart

πŸ“–
oishib
oishib

Jared Ni
Jared Ni

Aditi Raju
Aditi Raju

Michael Schnebly
Michael Schnebly

Thuong Duong
Thuong Duong

Emeka Ezike
Emeka Ezike

πŸ“–
jianqingdu
jianqingdu

πŸ“–
Jennifer Zhou
Jennifer Zhou

πŸ“–
The Random DIY
The Random DIY

πŸ“–
Fatima Shah
Fatima Shah

πŸ“–
Bruno Scaglione
Bruno Scaglione

πŸ“–
Allen-Kuang
Allen-Kuang

πŸ“–
Yu-Shun Hsiao
Yu-Shun Hsiao

Henry Bae
Henry Bae

Eimhin Laverty
Eimhin Laverty

Jae-Won Chung
Jae-Won Chung

Shvetank Prakash
Shvetank Prakash

Tess314
Tess314

πŸ“–
Tauno Erik
Tauno Erik

πŸ“–
gnodipac886
gnodipac886

πŸ“–
Sercan AygΓΌn
Sercan AygΓΌn

πŸ“–
TheHiddenLayer
TheHiddenLayer

πŸ“–
Gauri Jain
Gauri Jain

πŸ“–
Fin Amin
Fin Amin

πŸ“–
Marco Zennaro
Marco Zennaro

Arya Tschand
Arya Tschand

Andrew Bass
Andrew Bass

Pong Trairatvorakul
Pong Trairatvorakul

Eura Nofshin
Eura Nofshin

Alex Oesterling
Alex Oesterling

πŸ“–
Abenezer Angamo
Abenezer Angamo

πŸ“–
Baldassarre Cesarano
Baldassarre Cesarano

πŸ“–
Jahnic Beck
Jahnic Beck

πŸ“–
ΰ€…ΰ€°ΰ€¨ΰ€΅ ΰ€Άΰ₯ΰ€•ΰ₯ΰ€²ΰ€Ύ | Arnav Shukla
ΰ€…ΰ€°ΰ€¨ΰ€΅ ΰ€Άΰ₯ΰ€•ΰ₯ΰ€²ΰ€Ύ | Arnav Shukla

πŸ“–
Rin
Rin

πŸ“–
Bilge Acun
Bilge Acun

πŸ“–
Matthew Stewart
Matthew Stewart

Emeka Ezike
Emeka Ezike

jianqingdu
jianqingdu

Jennifer Zhou
Jennifer Zhou

The Random DIY
The Random DIY

Andy Cheng
Andy Cheng

πŸ“–
Aritra Ghosh
Aritra Ghosh

πŸ“–
abigailswallow
abigailswallow

πŸ“–
Yang Zhou
Yang Zhou

πŸ“–
JEON HYUNJUN(Luciano)
JEON HYUNJUN(Luciano)

πŸ“–
Emmanuel Rassou
Emmanuel Rassou

πŸ“–
Jason Yik
Jason Yik

πŸ“–
Fatima Shah
Fatima Shah

Bruno Scaglione
Bruno Scaglione

Allen-Kuang
Allen-Kuang

Tess314
Tess314

Tauno Erik
Tauno Erik

Jessica Quaye
Jessica Quaye

πŸ“–
Cursor Agent
Cursor Agent

πŸ“–
happyappledog
happyappledog

πŸ“–
Snuggs
Snuggs

πŸ“–
Sam Wilcock
Sam Wilcock

πŸ“–
Shreya Johri
Shreya Johri

πŸ“–
Sonia Murthy
Sonia Murthy

πŸ“–
gnodipac886
gnodipac886

Sercan AygΓΌn
Sercan AygΓΌn

TheHiddenLayer
TheHiddenLayer

Gauri Jain
Gauri Jain

Fin Amin
Fin Amin

Costin-Andrei Oncescu
Costin-Andrei Oncescu

πŸ“–
formlsysbookissue
formlsysbookissue

πŸ“–
Annie Laurie Cook
Annie Laurie Cook

πŸ“–
Parampreet Singh
Parampreet Singh

πŸ“–
Vijay Edupuganti
Vijay Edupuganti

πŸ“–
Jothi Ramaswamy
Jothi Ramaswamy

πŸ“–
Batur Arslan
Batur Arslan

πŸ“–
Alex Oesterling
Alex Oesterling

Abenezer Angamo
Abenezer Angamo

Baldassarre Cesarano
Baldassarre Cesarano

Karthik Dani
Karthik Dani

Jahnic Beck
Jahnic Beck

Curren Iyer
Curren Iyer

πŸ“–
Edward Jin
Edward Jin

πŸ“–
Tess Watt
Tess Watt

πŸ“–
bluebaer7
bluebaer7

πŸ“–
yanjingl
yanjingl

πŸ“–
a-saraf
a-saraf

πŸ“–
songhan
songhan

πŸ“–
ΰ€…ΰ€°ΰ€¨ΰ€΅ ΰ€Άΰ₯ΰ€•ΰ₯ΰ€²ΰ€Ύ | Arnav Shukla
ΰ€…ΰ€°ΰ€¨ΰ€΅ ΰ€Άΰ₯ΰ€•ΰ₯ΰ€²ΰ€Ύ | Arnav Shukla

Rin
Rin

Bilge Acun
Bilge Acun

Andy Cheng
Andy Cheng

Aritra Ghosh
Aritra Ghosh

abigailswallow
abigailswallow

Yang Zhou
Yang Zhou

JEON HYUNJUN(Luciano)
JEON HYUNJUN(Luciano)

Emmanuel Rassou
Emmanuel Rassou

Jason Yik
Jason Yik

Jessica Quaye
Jessica Quaye

Cursor Agent
Cursor Agent

happyappledog
happyappledog

Snuggs
Snuggs

Sam Wilcock
Sam Wilcock

Shreya Johri
Shreya Johri

Sonia Murthy
Sonia Murthy

Costin-Andrei Oncescu
Costin-Andrei Oncescu

formlsysbookissue
formlsysbookissue

Annie Laurie Cook
Annie Laurie Cook

Parampreet Singh
Parampreet Singh

Vijay Edupuganti
Vijay Edupuganti

Jothi Ramaswamy
Jothi Ramaswamy

Batur Arslan
Batur Arslan

Curren Iyer
Curren Iyer

Fatima Shah
Fatima Shah

Edward Jin
Edward Jin

Tess Watt
Tess Watt

bluebaer7
bluebaer7

yanjingl
yanjingl

a-saraf
a-saraf

songhan
songhan

jvijay
jvijay

Zishen
Zishen

jvijay
jvijay

πŸ“–
Zishen
Zishen

πŸ“–
Kai Kleinbard
Kai Kleinbard

πŸ’» πŸ”§
Didier Durand
Didier Durand

πŸ“– πŸ›
+ - +--- +### πŸ”₯ TinyTorch Contributors (7) + + + + + + + + + + + + + + + + +
Amir Alasady
Amir Alasady

πŸ›
Vijay Janapa Reddi
Vijay Janapa Reddi

πŸ› πŸ’» 🎨 πŸ“– πŸ’‘ πŸ‘€ πŸ§ͺ πŸ”§
kai
kai

πŸ› πŸ’» 🎨 πŸ“– πŸ§ͺ
Dang Truong
Dang Truong

πŸ› πŸ’» πŸ“– πŸ§ͺ
Didier Durand
Didier Durand

πŸ› πŸ’» πŸ“–
Karthik Dani
Karthik Dani

πŸ› πŸ’»
jettythek
jettythek

πŸ’»
+ + + + + +--- + +### πŸ› οΈ Hardware Kits Contributors (2) + + + + + + + + + + + +
Marcelo Rovai
Marcelo Rovai

πŸ“– πŸ’» 🎨 βœ…
Vijay Janapa Reddi
Vijay Janapa Reddi

πŸ› πŸ’» 🎨 πŸ“– πŸ§ͺ πŸ”§
+ + + + + +--- + +### πŸ§ͺ Labs Contributors (1) + + + + + + + + + + +
Vijay Janapa Reddi
Vijay Janapa Reddi

πŸ’» 🎨 πŸ“–
+ + + + + +--- + +**Recognize a contributor:** Comment on any issue or PR: +``` +@all-contributors please add @username for doc, code, bug, or ideas +``` ---
diff --git a/book/.all-contributorsrc b/book/.all-contributorsrc index addf5e7ff..297ac6ac4 100644 --- a/book/.all-contributorsrc +++ b/book/.all-contributorsrc @@ -69,15 +69,6 @@ "doc" ] }, - { - "login": "kai4avaya", - "name": "Kai Kleinbard", - "avatar_url": "https://avatars.githubusercontent.com/kai4avaya", - "profile": "https://github.com/kai4avaya", - "contributions": [ - "doc" - ] - }, { "login": "uchendui", "name": "Ikechukwu Uchendu", @@ -123,15 +114,6 @@ "doc" ] }, - { - "login": "didier-durand", - "name": "Didier Durand", - "avatar_url": "https://avatars.githubusercontent.com/didier-durand", - "profile": "https://github.com/didier-durand", - "contributions": [ - "doc" - ] - }, { "login": "shanzehbatool", "name": "shanzehbatool", @@ -636,15 +618,6 @@ "doc" ] }, - { - "login": "KarthikDani", - "name": "Karthik Dani", - "avatar_url": "https://avatars.githubusercontent.com/KarthikDani", - "profile": "https://github.com/KarthikDani", - "contributions": [ - "doc" - ] - }, { "login": "Jahnic-kb", "name": "Jahnic Beck", @@ -950,6 +923,26 @@ "contributions": [ "doc" ] + }, + { + "login": "kai4avaya", + "name": "Kai Kleinbard", + "avatar_url": "https://avatars.githubusercontent.com/kai4avaya", + "profile": "https://github.com/kai4avaya", + "contributions": [ + "code", + "tool" + ] + }, + { + "login": "didier-durand", + "name": "Didier Durand", + "avatar_url": "https://avatars.githubusercontent.com/didier-durand", + "profile": "https://github.com/didier-durand", + "contributions": [ + "doc", + "bug" + ] } ] } \ No newline at end of file diff --git a/book/README.md b/book/README.md index 9517c65c1..da712ced0 100644 --- a/book/README.md +++ b/book/README.md @@ -171,132 +171,131 @@ Thanks to these wonderful people who helped improve the book ([emoji key](https: Gabriel Amazonas
Gabriel Amazonas

πŸ› πŸ“– πŸ’‘ Zeljko Hrcek
Zeljko Hrcek

πŸ’» Jason Jabbour
Jason Jabbour

πŸ“– - Kai Kleinbard
Kai Kleinbard

πŸ“– Ikechukwu Uchendu
Ikechukwu Uchendu

πŸ“– + Naeem Khoshnevis
Naeem Khoshnevis

πŸ“– - Naeem Khoshnevis
Naeem Khoshnevis

πŸ“– Sara Khosravi
Sara Khosravi

πŸ“– Douwe den Blanken
Douwe den Blanken

πŸ“– Jeffrey Ma
Jeffrey Ma

πŸ“– - Didier Durand
Didier Durand

πŸ“– shanzehbatool
shanzehbatool

πŸ“– Elias
Elias

πŸ“– - - Jared Ping
Jared Ping

πŸ“– Itai Shapira
Itai Shapira

πŸ“– + + Maximilian Lam
Maximilian Lam

πŸ“– Jayson Lin
Jayson Lin

πŸ“– Sophia Cho
Sophia Cho

πŸ“– Andrea
Andrea

πŸ“– Alex Rodriguez
Alex Rodriguez

πŸ“– - - Korneel Van den Berghe
Korneel Van den Berghe

πŸ“– Nimo
Nimo

πŸ“– + + Colby Banbury
Colby Banbury

πŸ“– Zishen Wan
Zishen Wan

πŸ“– Mark Mazumder
Mark Mazumder

πŸ“– Abdulrahman Mahmoud
Abdulrahman Mahmoud

πŸ“– Divya Amirtharaj
Divya Amirtharaj

πŸ“– - - Srivatsan Krishnan
Srivatsan Krishnan

πŸ“– marin-llobet
marin-llobet

πŸ“– + + Aghyad Deeb
Aghyad Deeb

πŸ“– Haoran Qiu
Haoran Qiu

πŸ“– Emil Njor
Emil Njor

πŸ“– ELSuitorHarvard
ELSuitorHarvard

πŸ“– kaiM0ves
kaiM0ves

πŸ“– - - oishib
oishib

πŸ“– Jared Ni
Jared Ni

πŸ“– + + Aditi Raju
Aditi Raju

πŸ“– Michael Schnebly
Michael Schnebly

πŸ“– Thuong Duong
Thuong Duong

πŸ“– Yu-Shun Hsiao
Yu-Shun Hsiao

πŸ“– Henry Bae
Henry Bae

πŸ“– - - Eimhin Laverty
Eimhin Laverty

πŸ“– Jae-Won Chung
Jae-Won Chung

πŸ“– + + Shvetank Prakash
Shvetank Prakash

πŸ“– Marco Zennaro
Marco Zennaro

πŸ“– Arya Tschand
Arya Tschand

πŸ“– Andrew Bass
Andrew Bass

πŸ“– Pong Trairatvorakul
Pong Trairatvorakul

πŸ“– - - Eura Nofshin
Eura Nofshin

πŸ“– Matthew Stewart
Matthew Stewart

πŸ“– + + Emeka Ezike
Emeka Ezike

πŸ“– jianqingdu
jianqingdu

πŸ“– Jennifer Zhou
Jennifer Zhou

πŸ“– The Random DIY
The Random DIY

πŸ“– Fatima Shah
Fatima Shah

πŸ“– - - Bruno Scaglione
Bruno Scaglione

πŸ“– Allen-Kuang
Allen-Kuang

πŸ“– + + Tess314
Tess314

πŸ“– Tauno Erik
Tauno Erik

πŸ“– gnodipac886
gnodipac886

πŸ“– Sercan AygΓΌn
Sercan AygΓΌn

πŸ“– TheHiddenLayer
TheHiddenLayer

πŸ“– - - Gauri Jain
Gauri Jain

πŸ“– Fin Amin
Fin Amin

πŸ“– + + Alex Oesterling
Alex Oesterling

πŸ“– Abenezer Angamo
Abenezer Angamo

πŸ“– Baldassarre Cesarano
Baldassarre Cesarano

πŸ“– - Karthik Dani
Karthik Dani

πŸ“– Jahnic Beck
Jahnic Beck

πŸ“– - - ΰ€…ΰ€°ΰ€¨ΰ€΅ ΰ€Άΰ₯ΰ€•ΰ₯ΰ€²ΰ€Ύ | Arnav Shukla
ΰ€…ΰ€°ΰ€¨ΰ€΅ ΰ€Άΰ₯ΰ€•ΰ₯ΰ€²ΰ€Ύ | Arnav Shukla

πŸ“– Rin
Rin

πŸ“– Bilge Acun
Bilge Acun

πŸ“– + + Andy Cheng
Andy Cheng

πŸ“– Aritra Ghosh
Aritra Ghosh

πŸ“– abigailswallow
abigailswallow

πŸ“– Yang Zhou
Yang Zhou

πŸ“– - - JEON HYUNJUN(Luciano)
JEON HYUNJUN(Luciano)

πŸ“– Emmanuel Rassou
Emmanuel Rassou

πŸ“– Jason Yik
Jason Yik

πŸ“– + + Jessica Quaye
Jessica Quaye

πŸ“– Cursor Agent
Cursor Agent

πŸ“– happyappledog
happyappledog

πŸ“– Snuggs
Snuggs

πŸ“– - - Sam Wilcock
Sam Wilcock

πŸ“– Shreya Johri
Shreya Johri

πŸ“– Sonia Murthy
Sonia Murthy

πŸ“– + + Costin-Andrei Oncescu
Costin-Andrei Oncescu

πŸ“– formlsysbookissue
formlsysbookissue

πŸ“– Annie Laurie Cook
Annie Laurie Cook

πŸ“– Parampreet Singh
Parampreet Singh

πŸ“– - - Vijay Edupuganti
Vijay Edupuganti

πŸ“– Jothi Ramaswamy
Jothi Ramaswamy

πŸ“– Batur Arslan
Batur Arslan

πŸ“– + + Curren Iyer
Curren Iyer

πŸ“– Edward Jin
Edward Jin

πŸ“– Tess Watt
Tess Watt

πŸ“– bluebaer7
bluebaer7

πŸ“– - - yanjingl
yanjingl

πŸ“– a-saraf
a-saraf

πŸ“– songhan
songhan

πŸ“– + + jvijay
jvijay

πŸ“– Zishen
Zishen

πŸ“– + Kai Kleinbard
Kai Kleinbard

πŸ’» πŸ”§ + Didier Durand
Didier Durand

πŸ“– πŸ› diff --git a/kits/.all-contributorsrc b/kits/.all-contributorsrc index 452b383cc..c9a44482a 100644 --- a/kits/.all-contributorsrc +++ b/kits/.all-contributorsrc @@ -13,6 +13,18 @@ "linkToUsage": false, "skipCi": true, "contributors": [ + { + "login": "Mjrovai", + "name": "Marcelo Rovai", + "avatar_url": "https://avatars.githubusercontent.com/Mjrovai", + "profile": "https://github.com/Mjrovai", + "contributions": [ + "doc", + "code", + "design", + "tutorial" + ] + }, { "login": "profvjreddi", "name": "Vijay Janapa Reddi", diff --git a/kits/README.md b/kits/README.md index 8cb9c3499..d70c1e3a8 100644 --- a/kits/README.md +++ b/kits/README.md @@ -142,6 +142,7 @@ Thanks to these wonderful people who helped improve the hardware kits ([emoji ke + @@ -159,13 +160,6 @@ Thanks to these wonderful people who helped improve the hardware kits ([emoji ke --- -## Authors - -- **Marcelo Rovai** - Primary author -- **Vijay Janapa Reddi** - Harvard University - ---- - ## License Content is licensed under **Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International** (CC BY-NC-SA 4.0). From 87160dfc17c25bbf08e72d7ce96680ad352dab1f Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Wed, 21 Jan 2026 19:22:53 -0500 Subject: [PATCH 6/8] Fix generate_readme_tables.py to use repo root from script location --- .../workflows/contributors/generate_readme_tables.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/contributors/generate_readme_tables.py b/.github/workflows/contributors/generate_readme_tables.py index 9a8d24d38..363649f4b 100755 --- a/.github/workflows/contributors/generate_readme_tables.py +++ b/.github/workflows/contributors/generate_readme_tables.py @@ -151,14 +151,18 @@ def main(): parser.add_argument("--project", choices=list(PROJECTS.keys()), help="Process specific project") parser.add_argument("--update", action="store_true", help="Update README files") args = parser.parse_args() - + + # Find repo root (this script is in .github/workflows/contributors/) + script_dir = Path(__file__).parent + repo_root = script_dir.parent.parent.parent + if args.project: projects = {args.project: PROJECTS[args.project]} else: projects = PROJECTS - - for name, path in projects.items(): - process_project(name, path, args.update) + + for name, rel_path in projects.items(): + process_project(name, str(repo_root / rel_path), args.update) if __name__ == "__main__": From d4b87a6b4e1ddf7d95f11c0a9d9e58fbaf03e3a7 Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Wed, 21 Jan 2026 19:25:58 -0500 Subject: [PATCH 7/8] Add automatic trigger when contributor configs change --- .github/workflows/update-contributors.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/update-contributors.yml b/.github/workflows/update-contributors.yml index 86c8cfbce..5eb76b05d 100644 --- a/.github/workflows/update-contributors.yml +++ b/.github/workflows/update-contributors.yml @@ -3,6 +3,14 @@ name: 'πŸ‘₯ Update Contributors' on: workflow_call: workflow_dispatch: + push: + branches: [dev, main] + paths: + - '.all-contributorsrc' + - 'book/.all-contributorsrc' + - 'tinytorch/.all-contributorsrc' + - 'kits/.all-contributorsrc' + - 'labs/.all-contributorsrc' # ============================================================================= # CONTRIBUTOR UPDATE WORKFLOW From 930b7371c3b95126efdb0334b8db82402428c3c5 Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Wed, 21 Jan 2026 19:27:37 -0500 Subject: [PATCH 8/8] Add comprehensive documentation for contributor system --- .github/workflows/contributors/README.md | 149 ++++++++++++++++++ .../contributors/update_contributors.py | 24 +++ .github/workflows/update-contributors.yml | 41 +++-- 3 files changed, 203 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/contributors/README.md diff --git a/.github/workflows/contributors/README.md b/.github/workflows/contributors/README.md new file mode 100644 index 000000000..decccca14 --- /dev/null +++ b/.github/workflows/contributors/README.md @@ -0,0 +1,149 @@ +# Contributor Management Scripts + +This folder contains scripts for managing contributor recognition across the repository. + +## Overview + +The contributor system tracks contributions to four projects: +- **book/** - ML Systems textbook +- **tinytorch/** - Educational ML framework +- **kits/** - Hardware kits +- **labs/** - Lab exercises + +Each project has its own `.all-contributorsrc` file, and the main `README.md` displays all contributors in organized sections. + +## Scripts + +### `update_contributors.py` + +Updates the root `.all-contributorsrc` from GitHub API. + +```bash +# Requires GITHUB_TOKEN environment variable +python update_contributors.py +``` + +**What it does:** +- Queries GitHub API for all repository contributors +- Resolves git emails to GitHub usernames +- Generates gravatar URLs for non-GitHub contributors +- Merges new contributors with existing entries + +### `generate_main_readme.py` + +Generates the sectioned contributor table in the main `README.md`. + +```bash +python generate_main_readme.py [--dry-run] +``` + +**What it does:** +- Reads all four project `.all-contributorsrc` files +- Generates HTML tables with contributor avatars and badges +- Updates the Contributors section in `README.md` +- Creates sections: Book, TinyTorch, Kits, Labs + +### `generate_readme_tables.py` + +Updates per-project README files with contributor tables. + +```bash +python generate_readme_tables.py [--project PROJECT] [--update] +``` + +**Options:** +- `--project`: Process only one project (book, tinytorch, kits, labs) +- `--update`: Actually update the README files (without this, just prints) + +**What it does:** +- Reads each project's `.all-contributorsrc` +- Generates HTML contributor tables +- Updates the `` section in each project's README + +### `scan_contributors.py` + +Scans git history to discover contributors (manual/one-time use). + +```bash +python scan_contributors.py [--project PROJECT] [--output FORMAT] [--update] +``` + +**Options:** +- `--project`: Scan only one project +- `--output`: Output format (table, json, rc) +- `--update`: Update `.all-contributorsrc` files directly +- `--dry-run`: Preview changes without writing + +**What it does:** +- Analyzes git commit history per project folder +- Categorizes contributions (code, doc, bug, etc.) from commit messages +- Maps git emails to GitHub usernames +- Filters out bots and AI tools + +## Workflow Integration + +The `update-contributors.yml` workflow runs these scripts automatically: + +``` +Trigger: Push to dev/main with .all-contributorsrc changes + OR manual dispatch + +Steps: +1. update_contributors.py β†’ Update root config from GitHub API +2. generate_main_readme.py β†’ Rebuild main README sections +3. generate_readme_tables.py β†’ Update per-project READMEs +4. Commit and push changes +``` + +## Adding Contributors + +### Method 1: Bot Command (Recommended) + +Comment on any issue or PR: +``` +@all-contributors please add @username for doc, code, bug, or ideas +``` + +### Method 2: Manual Edit + +1. Edit the appropriate `.all-contributorsrc` file +2. Add entry with: login, name, avatar_url, contributions +3. Run the workflow or scripts manually + +## Contribution Types + +| Type | Emoji | Description | +|------|-------|-------------| +| bug | πŸ› | Bug reports | +| code | πŸ’» | Code contributions | +| doc | πŸ“– | Documentation | +| design | 🎨 | Design work | +| ideas | πŸ’‘ | Ideas and suggestions | +| review | πŸ‘€ | Code review | +| test | πŸ§ͺ | Testing | +| tool | πŸ”§ | Tools and infrastructure | +| tutorial | βœ… | Tutorials | +| maintenance | 🚧 | Maintenance | + +See [All Contributors emoji key](https://allcontributors.org/docs/en/emoji-key) for full list. + +## File Structure + +``` +.github/workflows/ +β”œβ”€β”€ update-contributors.yml # Workflow definition +└── contributors/ + β”œβ”€β”€ README.md # This file + β”œβ”€β”€ requirements.txt # Python dependencies + β”œβ”€β”€ update_contributors.py # GitHub API updater + β”œβ”€β”€ generate_main_readme.py # Main README generator + β”œβ”€β”€ generate_readme_tables.py # Per-project README generator + └── scan_contributors.py # Git history scanner + +Project configs: +β”œβ”€β”€ .all-contributorsrc # Root config (legacy) +β”œβ”€β”€ book/.all-contributorsrc # Book contributors +β”œβ”€β”€ tinytorch/.all-contributorsrc # TinyTorch contributors +β”œβ”€β”€ kits/.all-contributorsrc # Kits contributors +└── labs/.all-contributorsrc # Labs contributors +``` diff --git a/.github/workflows/contributors/update_contributors.py b/.github/workflows/contributors/update_contributors.py index 86def97f4..6a73fc469 100644 --- a/.github/workflows/contributors/update_contributors.py +++ b/.github/workflows/contributors/update_contributors.py @@ -1,3 +1,27 @@ +#!/usr/bin/env python3 +""" +Update contributors from GitHub API. + +This script queries the GitHub API to find all contributors to the repository +and updates the root .all-contributorsrc file with their information. + +Features: +- Fetches contributors from GitHub commit history +- Resolves email addresses to GitHub usernames +- Generates gravatar URLs for contributors without GitHub avatars +- Excludes bots and specified users +- Merges new contributors with existing ones + +Usage: + python update_contributors.py + +Environment variables: + GITHUB_TOKEN: Required. GitHub personal access token for API access. + +Note: This script updates the ROOT .all-contributorsrc file only. +For per-project configs, use scan_contributors.py instead. +""" + import os import json import random diff --git a/.github/workflows/update-contributors.yml b/.github/workflows/update-contributors.yml index 5eb76b05d..a33e0e5ae 100644 --- a/.github/workflows/update-contributors.yml +++ b/.github/workflows/update-contributors.yml @@ -1,5 +1,35 @@ name: 'πŸ‘₯ Update Contributors' +# ============================================================================= +# CONTRIBUTOR UPDATE WORKFLOW +# ============================================================================= +# Automatically updates contributor recognition across all projects. +# +# TRIGGERS: +# - push: When any .all-contributorsrc file changes on dev or main +# - workflow_dispatch: Manual trigger from Actions UI +# - workflow_call: Called by other workflows +# +# WHAT IT DOES: +# 1. Updates root .all-contributorsrc from GitHub API +# 2. Generates sectioned contributor tables in main README.md +# 3. Updates per-project README.md files (book, tinytorch, kits, labs) +# 4. Commits and pushes changes automatically +# +# ADDING CONTRIBUTORS: +# Option 1: Comment on any issue/PR with: +# @all-contributors please add @username for doc, code, bug, ideas +# Option 2: Manually edit the .all-contributorsrc file for the project +# +# SCRIPTS (in .github/workflows/contributors/): +# - update_contributors.py : Fetches contributors from GitHub API +# - generate_main_readme.py : Builds sectioned main README +# - generate_readme_tables.py : Updates per-project READMEs +# - scan_contributors.py : Scans git history (manual use) +# +# See .github/workflows/contributors/README.md for full documentation. +# ============================================================================= + on: workflow_call: workflow_dispatch: @@ -12,17 +42,6 @@ on: - 'kits/.all-contributorsrc' - 'labs/.all-contributorsrc' -# ============================================================================= -# CONTRIBUTOR UPDATE WORKFLOW -# ============================================================================= -# Updates contributor lists across all projects: -# - Root .all-contributorsrc (from GitHub commit history) -# - Main README.md (sectioned by project: Book, TinyTorch, Kits, Labs) -# - Per-project README.md files (book/, tinytorch/, kits/, labs/) -# -# Each project has its own .all-contributorsrc that feeds into the main README. -# ============================================================================= - jobs: update-contributors: name: Update Contributors List
Marcelo Rovai
Marcelo Rovai

πŸ“– πŸ’» 🎨 βœ…
Vijay Janapa Reddi
Vijay Janapa Reddi

πŸ› πŸ’» 🎨 πŸ“– πŸ§ͺ πŸ”§