Skip to content

Conversation

@banu4prasad
Copy link

@banu4prasad banu4prasad commented Nov 8, 2025

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

  • Added all_time_contribs parameter to toggle between last year and all-time contributions
  • Deduplicated repository counting (counts each repo only once, even with multiple contribution types)
  • Increased cache duration for all-time stats.
  • Added ALL_TIME_CONTRIBS environment variable to enable/disable feature globally

Usage

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 feature
  • PAT_1=<github_token> - GitHub Personal Access Token with read:user scope

fixes #2282

Screenshot 2025-11-08 at 4 46 26 PM Screenshot 2025-11-08 at 4 40 17 PM Screenshot 2025-11-08 at 4 40 05 PM

@vercel
Copy link

vercel bot commented Nov 8, 2025

@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.

@github-actions github-actions bot added stats-card Feature, Enhancement, Fixes related to stats the stats card. card-i18n Card text translations. labels Nov 8, 2025
Copilot AI review requested due to automatic review settings December 18, 2025 06:44
Copy link
Contributor

Copilot AI left a 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_contribs query 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.

Copy link
Contributor

Copilot AI left a 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.

Comment on lines 159 to 193
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
Copy link

Copilot AI Dec 25, 2025

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.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Copilot AI left a 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);
Copy link

Copilot AI Dec 25, 2025

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.

Copilot uses AI. Check for mistakes.
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),
Copy link

Copilot AI Dec 25, 2025

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.

Suggested change
commits_year: parseInt(commits_year, 10),
commits_year: commits_year ? parseInt(commits_year, 10) : undefined,

Copilot uses AI. Check for mistakes.
Comment on lines 91 to 101
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,
);
Copy link

Copilot AI Dec 25, 2025

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.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,485 @@
import { afterEach, beforeEach, describe, expect, it, jest } from "@jest/globals";
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused imports beforeEach, jest.

Suggested change
import { afterEach, beforeEach, describe, expect, it, jest } from "@jest/globals";
import { afterEach, describe, expect, it } from "@jest/globals";

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

card-i18n Card text translations. stats-card Feature, Enhancement, Fixes related to stats the stats card.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Show all time contributed to

1 participant