diff --git a/api/index.js b/api/index.js index 66c119a5e0563..c9f962da9a503 100644 --- a/api/index.js +++ b/api/index.js @@ -40,6 +40,7 @@ export default async (req, res) => { border_color, rank_icon, show, + include_transferred_repos, } = req.query; res.setHeader("Content-Type", "image/svg+xml"); @@ -100,6 +101,7 @@ export default async (req, res) => { showStats.includes("discussions_started"), showStats.includes("discussions_answered"), parseInt(commits_year, 10), + parseBoolean(include_transferred_repos), ); let cacheSeconds = clampValue( diff --git a/readme.md b/readme.md index 8d53b8f94fad6..2ab52ec40a169 100644 --- a/readme.md +++ b/readme.md @@ -158,6 +158,14 @@ You can specify a year and fetch only the commits that were made in that year by ![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&commits_year=2020) ``` +### Including transferred repositories + +If you have transferred repositories to organizations, you can include their stars in your stats by using the `&include_transferred_repos=true` parameter. This helps maintain accurate star counts for repositories that were originally created by you but have since been transferred to an organization. + +```md +![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&include_transferred_repos=true) +``` + ### Themes With inbuilt themes, you can customize the look of the card without doing any [manual customization](#customization). @@ -374,7 +382,8 @@ If we don't support your language, please consider contributing! You can find mo | `ring_color` | Color of the rank circle. | string (hex color) | `2f80ed` | | `number_format` | Switches between two available formats for displaying the card values `short` (i.e. `6.6k`) and `long` (i.e. `6626`). | enum | `short` | | `show` | Shows [additional items](#showing-additional-individual-stats) on stats card (i.e. `reviews`, `discussions_started`, `discussions_answered`, `prs_merged` or `prs_merged_percentage`). | string (comma-separated values) | `null` | -| `commits_year` | Filters and counts only commits made in the specified year | integer _(YYYY)_ | ` (one year to date)`. +| `commits_year` | Filters and counts only commits made in the specified year | integer _(YYYY)_ | ` (one year to date)` | +| `include_transferred_repos` | Includes repositories that were transferred to organizations in star count. This helps maintain star counts for repositories that were originally created by the user but have since been transferred to an organization. | boolean | `false` | > [!NOTE]\ > When hide\_rank=`true`, the minimum card width is 270 px + the title length and padding. diff --git a/src/cards/stats.js b/src/cards/stats.js index 67e71aef52114..d37608dcacb27 100644 --- a/src/cards/stats.js +++ b/src/cards/stats.js @@ -318,9 +318,9 @@ const renderStatsCard = (stats, options = {}) => { STATS.prs_merged_percentage = { icon: icons.prs_merged_percentage, label: i18n.t("statcard.prs-merged-percentage"), - value: mergedPRsPercentage.toFixed(2), + value: totalPRs === 0 ? "N/A" : mergedPRsPercentage.toFixed(2), id: "prs_merged_percentage", - unitSymbol: "%", + unitSymbol: totalPRs === 0 ? "" : "%", }; } diff --git a/src/fetchers/stats.js b/src/fetchers/stats.js index 56af97d89a041..d7b264ed7e903 100644 --- a/src/fetchers/stats.js +++ b/src/fetchers/stats.js @@ -15,8 +15,12 @@ import { dotenv.config(); // GraphQL queries. -const GRAPHQL_REPOS_FIELD = ` - repositories(first: 100, ownerAffiliations: OWNER, orderBy: {direction: DESC, field: STARGAZERS}, after: $after) { +const getReposField = (includeTransferred = false) => { + const ownerAffiliations = includeTransferred + ? "[OWNER, COLLABORATOR]" + : "OWNER"; + return ` + repositories(first: 100, ownerAffiliations: ${ownerAffiliations}, orderBy: {direction: DESC, field: STARGAZERS}, after: $after) { totalCount nodes { name @@ -30,16 +34,17 @@ const GRAPHQL_REPOS_FIELD = ` } } `; +}; -const GRAPHQL_REPOS_QUERY = ` +const getReposQuery = (includeTransferred = false) => ` query userInfo($login: String!, $after: String) { user(login: $login) { - ${GRAPHQL_REPOS_FIELD} + ${getReposField(includeTransferred)} } } `; -const GRAPHQL_STATS_QUERY = ` +const getStatsQuery = (includeTransferred = false) => ` query userInfo($login: String!, $after: String, $includeMergedPullRequests: Boolean!, $includeDiscussions: Boolean!, $includeDiscussionsAnswers: Boolean!, $startTime: DateTime = null) { user(login: $login) { name @@ -74,7 +79,7 @@ const GRAPHQL_STATS_QUERY = ` repositoryDiscussionComments(onlyAnswers: true) @include(if: $includeDiscussionsAnswers) { totalCount } - ${GRAPHQL_REPOS_FIELD} + ${getReposField(includeTransferred)} } } `; @@ -91,7 +96,10 @@ const GRAPHQL_STATS_QUERY = ` * @returns {Promise} Axios response. */ const fetcher = (variables, token) => { - const query = variables.after ? GRAPHQL_REPOS_QUERY : GRAPHQL_STATS_QUERY; + const includeTransferred = variables.includeTransferred || false; + const query = variables.after + ? getReposQuery(includeTransferred) + : getStatsQuery(includeTransferred); return request( { query, @@ -122,6 +130,7 @@ const statsFetcher = async ({ includeDiscussions, includeDiscussionsAnswers, startTime, + includeTransferred, }) => { let stats; let hasNextPage = true; @@ -135,6 +144,7 @@ const statsFetcher = async ({ includeDiscussions, includeDiscussionsAnswers, startTime, + includeTransferred, }; let res = await retryer(fetcher, variables); if (res.data.errors) { @@ -233,6 +243,7 @@ const fetchStats = async ( include_discussions = false, include_discussions_answers = false, commits_year, + include_transferred_repos = false, ) => { if (!username) { throw new MissingParamError(["username"]); @@ -259,6 +270,7 @@ const fetchStats = async ( includeDiscussions: include_discussions, includeDiscussionsAnswers: include_discussions_answers, startTime: commits_year ? `${commits_year}-01-01T00:00:00Z` : undefined, + includeTransferred: include_transferred_repos, }); // Catch GraphQL errors. @@ -297,7 +309,8 @@ const fetchStats = async ( if (include_merged_pull_requests) { stats.totalPRsMerged = user.mergedPullRequests.totalCount; stats.mergedPRsPercentage = - (user.mergedPullRequests.totalCount / user.pullRequests.totalCount) * 100; + (user.mergedPullRequests.totalCount / user.pullRequests.totalCount) * + 100 || 0; } stats.totalReviews = user.reviews.totalPullRequestReviewContributions; stats.totalIssues = user.openIssues.totalCount + user.closedIssues.totalCount;