-
-
Notifications
You must be signed in to change notification settings - Fork 29.5k
feat: Add all-time contributions support with deduplicated repository count #4644
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
@banu4prasad is attempting to deploy a commit to the github readme stats Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds support for displaying all-time contribution statistics across a user's entire GitHub history, with automatic deduplication to count unique repositories only once even when a user has multiple contribution types (commits, issues, PRs, reviews) to the same repository.
Key Changes:
- Added
all_time_contribsquery parameter to enable fetching contributions across all years instead of just the last year - Implemented parallel fetching of contribution data using
Promise.all()with a 9-second timeout and graceful fallback - Extended cache duration for all-time stats (6 hours default vs 4 hours for standard stats)
Reviewed changes
Copilot reviewed 6 out of 8 changed files in this pull request and generated 20 comments.
Show a summary per file
| File | Description |
|---|---|
src/fetchers/all-time-contributions.js |
New module that fetches contribution years and yearly data in parallel, deduplicating repositories across all contribution types |
src/fetchers/stats.js |
Integrated all-time contributions feature with timeout protection and fallback logic; removed some logger statements |
api/index.js |
Added parameter handling for all_time_contribs and custom cache logic for longer TTL |
src/common/envs.js |
Added ALL_TIME_CONTRIBS environment variable to enable/disable the feature globally |
src/cards/stats.js |
Added conditional label rendering to show "all time" vs "last year" based on parameter |
src/cards/types.d.ts |
Added TypeScript type definition for the new all_time_contribs option |
src/translations.js |
Added statcard.contribs-alltime translation key in 48 languages |
.gitignore |
Added .DS_Store to ignore macOS system files |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 7 out of 9 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export const fetchAllTimeContributions = async (login) => { | ||
| if (!login) { | ||
| throw new MissingParamError(["login"]); | ||
| } | ||
|
|
||
| // Fetch all contribution years (uses retryer with token rotation) | ||
| const years = await fetchContributionYears(login); | ||
|
|
||
| // Count unique repositories across ALL years | ||
| const allRepos = new Set(); | ||
|
|
||
| // Fetch all years in PARALLEL for speed (each uses retryer with token rotation) | ||
| const yearDataPromises = years.map(year => fetchYearContributions(login, year)); | ||
| const yearDataResults = await Promise.all(yearDataPromises); | ||
|
|
||
| yearDataResults.forEach((yearData) => { | ||
| const addRepos = (contributions) => { | ||
| contributions?.forEach((contrib) => { | ||
| if (contrib.repository?.nameWithOwner) { | ||
| allRepos.add(contrib.repository.nameWithOwner); | ||
| } | ||
| }); | ||
| }; | ||
|
|
||
| addRepos(yearData.commitContributionsByRepository); | ||
| addRepos(yearData.issueContributionsByRepository); | ||
| addRepos(yearData.pullRequestContributionsByRepository); | ||
| addRepos(yearData.pullRequestReviewContributionsByRepository); | ||
| }); | ||
|
|
||
| return { | ||
| totalRepositoriesContributedTo: allRepos.size, | ||
| yearsAnalyzed: years.length, | ||
| }; | ||
| }; No newline at end of file |
Copilot
AI
Dec 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new fetchAllTimeContributions function and the entire all-time-contributions.js module lack test coverage. Given that this repository has comprehensive test coverage for other fetchers, tests should be added to verify the deduplication logic, error handling, and parallel fetching behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 8 out of 10 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ); | ||
| } catch (err) { | ||
| // Clear timeout on error as well | ||
| clearTimeout(timeoutId); |
Copilot
AI
Dec 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable timeoutId may be undefined when clearTimeout(timeoutId) is called in the catch block. If an error occurs before the timeout is set (e.g., in the Promise.race setup), clearTimeout will be called with undefined. While this doesn't cause an error in JavaScript, it's better to check if timeoutId is defined before clearing it for clarity and best practices.
| hide_rank: parseBoolean(hide_rank), | ||
| include_all_commits: parseBoolean(include_all_commits), | ||
| all_time_contribs: parseBoolean(all_time_contribs), | ||
| commits_year: parseInt(commits_year, 10), |
Copilot
AI
Dec 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When commits_year is undefined or not provided, parseInt(commits_year, 10) will return NaN. This should be handled the same way as in line 100 where it's conditionally parsed: commits_year ? parseInt(commits_year, 10) : undefined. The NaN value could cause unexpected behavior in the rendering logic.
| commits_year: parseInt(commits_year, 10), | |
| commits_year: commits_year ? parseInt(commits_year, 10) : undefined, |
| const stats = await fetchStats( | ||
| username, | ||
| parseBoolean(include_all_commits), | ||
| parseBoolean(all_time_contribs), | ||
| parseArray(exclude_repo), | ||
| showStats.includes("prs_merged") || | ||
| showStats.includes("prs_merged_percentage"), | ||
| showStats.includes("discussions_started"), | ||
| showStats.includes("discussions_answered"), | ||
| parseInt(commits_year, 10), | ||
| commits_year ? parseInt(commits_year, 10) : undefined, | ||
| ); |
Copilot
AI
Dec 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The integration of the all_time_contribs parameter with the existing API endpoint and stats fetcher lacks test coverage. Consider adding tests to tests/api.test.js and tests/fetchStats.test.js that verify the parameter is correctly passed through and the feature works as expected when enabled or disabled.
| @@ -0,0 +1,485 @@ | |||
| import { afterEach, beforeEach, describe, expect, it, jest } from "@jest/globals"; | |||
Copilot
AI
Dec 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused imports beforeEach, jest.
| import { afterEach, beforeEach, describe, expect, it, jest } from "@jest/globals"; | |
| import { afterEach, describe, expect, it } from "@jest/globals"; |
Summary
Adds support for displaying all-time contributions across all years on GitHub, with automatic deduplication of repositories to show accurate unique contribution counts.
Changes
all_time_contribsparameter to toggle between last year and all-time contributionsALL_TIME_CONTRIBSenvironment variable to enable/disable feature globallyUsage
Standard (last year only)
?username=YOUR_USERNAME
All-time contributions (deduplicated)
?username=YOUR_USERNAME&all_time_contribs=true
Environment Variables
ALL_TIME_CONTRIBS=true- Enable all-time contributions featurePAT_1=<github_token>- GitHub Personal Access Token withread:userscopefixes #2282