diff --git a/.github/workflows/update-readme.yml b/.github/workflows/update-readme.yml index a571e3b..0d772b8 100644 --- a/.github/workflows/update-readme.yml +++ b/.github/workflows/update-readme.yml @@ -42,7 +42,7 @@ jobs: run: | set -e test -s README.md || { echo "README.md is empty"; exit 1; } - python3 -c "import json,sys; d=json.load(open('README_DATA.json')); sys.exit(1 if not d.get('years') else 0)" \ + python3 -c "import json,sys; d=json.load(open('README_DATA.json')); sys.exit(1 if not d.get('years') and not d.get('stats', {}).get('projects') else 0)" \ || { echo "README_DATA.json is empty or invalid"; exit 1; } - name: Commit and push changes diff --git a/README.md b/README.md index 0e0a883..1152133 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # OSS Contributions -| Project | 🐛 Bug fixes | ✨ Features | ♻️ Refactors | 🔧 Chores | Total Merged | -| :--- | :---: | :---: | :---: | :---: | :---: | -| Kilo Code | 19 | 2 | 1 | 2 | **24** | +| Project | 🐛 Bug fixes | ✨ Features | ♻️ Refactors | ⚡ Performance | 🔧 Chores | 👷 CI | 🔨 Other | Total Merged | +| :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | +| Kilo Code | 19 | 2 | 1 | 0 | 2 | 0 | 0 | **24** | +| HDCharts | 111 | 77 | 37 | 2 | 82 | 60 | 57 | **500** | # 2026 diff --git a/README_DATA.json b/README_DATA.json index b03a7fc..46fe15f 100644 --- a/README_DATA.json +++ b/README_DATA.json @@ -18,10 +18,25 @@ "label": "Refactors", "emoji": "♻️" }, + { + "category": "perf", + "label": "Performance", + "emoji": "⚡" + }, { "category": "chore", "label": "Chores", "emoji": "🔧" + }, + { + "category": "ci", + "label": "CI", + "emoji": "👷" + }, + { + "category": "other", + "label": "Other", + "emoji": "🔨" } ], "projects": [ @@ -36,6 +51,25 @@ "refactor": 1, "chore": 2 } + }, + { + "name": "HDCharts", + "repo_url": "https://github.com/HDCharts/charts", + "logo_url": "https://github.com/HDCharts.png", + "total_merged": 500, + "categories": { + "fix": 111, + "feat": 77, + "refactor": 37, + "perf": 2, + "docs": 68, + "test": 3, + "chore": 82, + "build": 2, + "ci": 60, + "revert": 1, + "other": 57 + } } ] }, diff --git a/oss-contributions.json b/oss-contributions.json index 87f5487..250b86d 100644 --- a/oss-contributions.json +++ b/oss-contributions.json @@ -20,6 +20,16 @@ "Kilo-Org/kilocode", "kilo-org/kilocode-legacy" ] + }, + { + "name": "HDCharts", + "repos": [ + "HDCharts/charts", + "HDCharts/charts-playground", + "HDCharts/charts-docs", + "HDCharts/charts-gif-recorder" + ], + "stats_only": true } ] } diff --git a/src/cli.py b/src/cli.py index 296eecd..6d51d78 100644 --- a/src/cli.py +++ b/src/cli.py @@ -25,9 +25,11 @@ def main(): print(f"Featured projects: {len(config['featured_projects'])}") data, featured_repos = fetch_from_config(config) - model = build_readme_model(data, featured_repos, config['stats_projects']) + model = build_readme_model( + data, featured_repos, config['stats_projects'], config['stats_only_repos'] + ) - if _count_contributions(model) == 0: + if _count_contributions(model) == 0 and not model['stats']['projects']: print("No contributions found; refusing to overwrite existing artifacts.") return 1 diff --git a/src/config.py b/src/config.py index a32b3cd..7cd9e9f 100644 --- a/src/config.py +++ b/src/config.py @@ -118,6 +118,12 @@ def load_config(config_file=None): # Repos that get a per-category merged-PR counter at the top of the README; an # entry may also be {"name": ..., "repos": [...]} to sum repos into one row. "stats_projects": data.get("stats_projects", []), + "stats_only_repos": [ + repo + for project in data.get("stats_projects", []) + if isinstance(project, dict) and project.get("stats_only") + for repo in project.get("repos", []) + ], # None means "whoever the gh token belongs to". "username": data.get("username"), } diff --git a/src/model.py b/src/model.py index f89d951..44f6884 100644 --- a/src/model.py +++ b/src/model.py @@ -58,13 +58,14 @@ def fetch_from_config(config): response is theirs; what is filtered here is which *repos* to keep. """ repos = config["repos"] + stats_only_repos = config.get("stats_only_repos", []) # Empty statuses list means no filtering (show all) allowed_statuses = set(config["statuses"]) or None featured = config["featured_projects"] username = config.get("username") # Config may spell a repo in any casing; GitHub answers with canonical. - tracked = {repo.lower() for repo in repos} + tracked = {repo.lower() for repo in [*repos, *stats_only_repos]} print(f"Fetching pull requests authored by {username or 'the authenticated user'}...") prs = fetch_authored_prs(username, query_states(allowed_statuses)) @@ -158,12 +159,12 @@ def build_stats(years, stats_projects): used = {c for project in projects for c in project['categories']} columns = [ {'category': c, 'label': CATEGORY_LABELS.get(c, 'Other'), 'emoji': CONVENTIONAL_EMOJI.get(c, DEFAULT_PR_EMOJI)} - for c in category_order if c in used + for c in category_order if c in used and c not in {'build', 'docs', 'revert', 'test'} ] return {'columns': columns, 'projects': projects} -def build_readme_model(contributions_by_date, featured_repos, stats_projects=()): +def build_readme_model(contributions_by_date, featured_repos, stats_projects=(), stats_only_repos=()): featured_projects = [] if featured_repos: sorted_featured = sorted(featured_repos.items(), key=lambda item: (item[1], item[0].lower())) @@ -248,10 +249,25 @@ def build_readme_model(contributions_by_date, featured_repos, stats_projects=()) years.append({'year': year, 'months': months}) + stats = build_stats(years, stats_projects) + stats_only = {repo.lower() for repo in stats_only_repos} + if stats_only: + for year in years: + visible_months = [] + for month in year['months']: + month['rows'] = [ + row for row in month['rows'] + if row['repo_name'].lower() not in stats_only + ] + if month['rows']: + visible_months.append(month) + year['months'] = visible_months + years = [year for year in years if year['months']] + return { 'title': 'OSS Contributions', 'featured_projects': featured_projects, - 'stats': build_stats(years, stats_projects), + 'stats': stats, 'years': years, 'status_legend': STATUS_LEGEND, }