Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/update-readme.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# OSS Contributions

| Project | 🐛 Bug fixes | ✨ Features | ♻️ Refactors | 🔧 Chores | Total Merged |
| :--- | :---: | :---: | :---: | :---: | :---: |
| <a href="https://github.com/Kilo-Org/kilocode"><img src="https://github.com/Kilo-Org.png" width="24" height="24" style="vertical-align:middle;" title="Kilo Code" alt="Kilo Code"/></a> | 19 | 2 | 1 | 2 | **24** |
| Project | 🐛 Bug fixes | ✨ Features | ♻️ Refactors | ⚡ Performance | 🔧 Chores | 👷 CI | 🔨 Other | Total Merged |
| :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
| <a href="https://github.com/Kilo-Org/kilocode"><img src="https://github.com/Kilo-Org.png" width="24" height="24" style="vertical-align:middle;" title="Kilo Code" alt="Kilo Code"/></a> | 19 | 2 | 1 | 0 | 2 | 0 | 0 | **24** |
| <a href="https://github.com/HDCharts/charts"><img src="https://github.com/HDCharts.png" width="24" height="24" style="vertical-align:middle;" title="HDCharts" alt="HDCharts"/></a> | 111 | 77 | 37 | 2 | 82 | 60 | 57 | **500** |

# 2026

Expand Down
34 changes: 34 additions & 0 deletions README_DATA.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand All @@ -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
}
}
]
},
Expand Down
10 changes: 10 additions & 0 deletions oss-contributions.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
]
}
6 changes: 4 additions & 2 deletions src/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 6 additions & 0 deletions src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
}
24 changes: 20 additions & 4 deletions src/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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()))
Expand Down Expand Up @@ -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,
}