diff --git a/api/index.js b/api/index.js index 25e4151fab1c0..adfd33174cdbc 100644 --- a/api/index.js +++ b/api/index.js @@ -50,10 +50,15 @@ export default async (req, res) => { } try { + const showStats = parseArray(show); const stats = await fetchStats( username, parseBoolean(include_all_commits), parseArray(exclude_repo), + showStats.includes("prs_merged") || + showStats.includes("prs_merged_percentage"), + showStats.includes("discussions_started"), + showStats.includes("discussions_answered"), ); let cacheSeconds = clampValue( @@ -96,7 +101,7 @@ export default async (req, res) => { locale: locale ? locale.toLowerCase() : null, disable_animations: parseBoolean(disable_animations), rank_icon, - show: parseArray(show), + show: showStats, }), ); } catch (err) { diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js index 0f770d88a6fc2..1d6aebfcc0af8 100644 --- a/src/fetchers/stats-fetcher.js +++ b/src/fetchers/stats-fetcher.js @@ -40,7 +40,7 @@ const GRAPHQL_REPOS_QUERY = ` `; const GRAPHQL_STATS_QUERY = ` - query userInfo($login: String!, $after: String) { + query userInfo($login: String!, $after: String, $includeMergedPullRequests: Boolean!, $includeDiscussions: Boolean!, $includeDiscussionsAnswers: Boolean!) { user(login: $login) { name login @@ -54,7 +54,7 @@ const GRAPHQL_STATS_QUERY = ` pullRequests(first: 1) { totalCount } - mergedPullRequests: pullRequests(states: MERGED) { + mergedPullRequests: pullRequests(states: MERGED) @include(if: $includeMergedPullRequests) { totalCount } openIssues: issues(states: OPEN) { @@ -66,10 +66,10 @@ const GRAPHQL_STATS_QUERY = ` followers { totalCount } - repositoryDiscussions { + repositoryDiscussions @include(if: $includeDiscussions) { totalCount } - repositoryDiscussionComments(onlyAnswers: true) { + repositoryDiscussionComments(onlyAnswers: true) @include(if: $includeDiscussionsAnswers) { totalCount } ${GRAPHQL_REPOS_FIELD} @@ -104,17 +104,33 @@ const fetcher = (variables, token) => { /** * Fetch stats information for a given username. * - * @param {string} username Github username. + * @param {object} variables Fetcher variables. + * @param {string} variables.username Github username. + * @param {boolean} variables.includeMergedPullRequests Include merged pull requests. + * @param {boolean} variables.includeDiscussions Include discussions. + * @param {boolean} variables.includeDiscussionsAnswers Include discussions answers. * @returns {Promise} Axios response. * * @description This function supports multi-page fetching if the 'FETCH_MULTI_PAGE_STARS' environment variable is set to true. */ -const statsFetcher = async (username) => { +const statsFetcher = async ({ + username, + includeMergedPullRequests, + includeDiscussions, + includeDiscussionsAnswers, +}) => { let stats; let hasNextPage = true; let endCursor = null; while (hasNextPage) { - const variables = { login: username, first: 100, after: endCursor }; + const variables = { + login: username, + first: 100, + after: endCursor, + includeMergedPullRequests, + includeDiscussions, + includeDiscussionsAnswers, + }; let res = await retryer(fetcher, variables); if (res.data.errors) { return res; @@ -198,12 +214,18 @@ const totalCommitsFetcher = async (username) => { * @param {string} username GitHub username. * @param {boolean} include_all_commits Include all commits. * @param {string[]} exclude_repo Repositories to exclude. + * @param {boolean} include_merged_pull_requests Include merged pull requests. + * @param {boolean} include_discussions Include discussions. + * @param {boolean} include_discussions_answers Include discussions answers. * @returns {Promise} Stats data. */ const fetchStats = async ( username, include_all_commits = false, exclude_repo = [], + include_merged_pull_requests = false, + include_discussions = false, + include_discussions_answers = false, ) => { if (!username) { throw new MissingParamError(["username"]); @@ -224,7 +246,12 @@ const fetchStats = async ( rank: { level: "C", percentile: 100 }, }; - let res = await statsFetcher(username); + let res = await statsFetcher({ + username, + includeMergedPullRequests: include_merged_pull_requests, + includeDiscussions: include_discussions, + includeDiscussionsAnswers: include_discussions_answers, + }); // Catch GraphQL errors. if (res.data.errors) { @@ -259,14 +286,21 @@ const fetchStats = async ( } stats.totalPRs = user.pullRequests.totalCount; - stats.totalPRsMerged = user.mergedPullRequests.totalCount; - stats.mergedPRsPercentage = - (user.mergedPullRequests.totalCount / user.pullRequests.totalCount) * 100; + if (include_merged_pull_requests) { + stats.totalPRsMerged = user.mergedPullRequests.totalCount; + stats.mergedPRsPercentage = + (user.mergedPullRequests.totalCount / user.pullRequests.totalCount) * 100; + } stats.totalReviews = user.contributionsCollection.totalPullRequestReviewContributions; stats.totalIssues = user.openIssues.totalCount + user.closedIssues.totalCount; - stats.totalDiscussionsStarted = user.repositoryDiscussions.totalCount; - stats.totalDiscussionsAnswered = user.repositoryDiscussionComments.totalCount; + if (include_discussions) { + stats.totalDiscussionsStarted = user.repositoryDiscussions.totalCount; + } + if (include_discussions_answers) { + stats.totalDiscussionsAnswered = + user.repositoryDiscussionComments.totalCount; + } stats.contributedTo = user.repositoriesContributedTo.totalCount; // Retrieve stars while filtering out repositories to be hidden. diff --git a/tests/fetchStats.test.js b/tests/fetchStats.test.js index 56125d8b5c1a7..ca8d7bc37062e 100644 --- a/tests/fetchStats.test.js +++ b/tests/fetchStats.test.js @@ -122,12 +122,12 @@ describe("Test fetchStats", () => { totalCommits: 100, totalIssues: 200, totalPRs: 300, - totalPRsMerged: 240, - mergedPRsPercentage: 80, + totalPRsMerged: 0, + mergedPRsPercentage: 0, totalReviews: 50, totalStars: 300, - totalDiscussionsStarted: 10, - totalDiscussionsAnswered: 40, + totalDiscussionsStarted: 0, + totalDiscussionsAnswered: 0, rank, }); }); @@ -158,12 +158,12 @@ describe("Test fetchStats", () => { totalCommits: 100, totalIssues: 200, totalPRs: 300, - totalPRsMerged: 240, - mergedPRsPercentage: 80, + totalPRsMerged: 0, + mergedPRsPercentage: 0, totalReviews: 50, totalStars: 300, - totalDiscussionsStarted: 10, - totalDiscussionsAnswered: 40, + totalDiscussionsStarted: 0, + totalDiscussionsAnswered: 0, rank, }); }); @@ -200,12 +200,12 @@ describe("Test fetchStats", () => { totalCommits: 1000, totalIssues: 200, totalPRs: 300, - totalPRsMerged: 240, - mergedPRsPercentage: 80, + totalPRsMerged: 0, + mergedPRsPercentage: 0, totalReviews: 50, totalStars: 300, - totalDiscussionsStarted: 10, - totalDiscussionsAnswered: 40, + totalDiscussionsStarted: 0, + totalDiscussionsAnswered: 0, rank, }); }); @@ -249,12 +249,12 @@ describe("Test fetchStats", () => { totalCommits: 1000, totalIssues: 200, totalPRs: 300, - totalPRsMerged: 240, - mergedPRsPercentage: 80, + totalPRsMerged: 0, + mergedPRsPercentage: 0, totalReviews: 50, totalStars: 200, - totalDiscussionsStarted: 10, - totalDiscussionsAnswered: 40, + totalDiscussionsStarted: 0, + totalDiscussionsAnswered: 0, rank, }); }); @@ -280,12 +280,12 @@ describe("Test fetchStats", () => { totalCommits: 100, totalIssues: 200, totalPRs: 300, - totalPRsMerged: 240, - mergedPRsPercentage: 80, + totalPRsMerged: 0, + mergedPRsPercentage: 0, totalReviews: 50, totalStars: 400, - totalDiscussionsStarted: 10, - totalDiscussionsAnswered: 40, + totalDiscussionsStarted: 0, + totalDiscussionsAnswered: 0, rank, }); }); @@ -311,12 +311,12 @@ describe("Test fetchStats", () => { totalCommits: 100, totalIssues: 200, totalPRs: 300, - totalPRsMerged: 240, - mergedPRsPercentage: 80, + totalPRsMerged: 0, + mergedPRsPercentage: 0, totalReviews: 50, totalStars: 300, - totalDiscussionsStarted: 10, - totalDiscussionsAnswered: 40, + totalDiscussionsStarted: 0, + totalDiscussionsAnswered: 0, rank, }); }); @@ -336,6 +336,64 @@ describe("Test fetchStats", () => { followers: 100, }); + expect(stats).toStrictEqual({ + contributedTo: 61, + name: "Anurag Hazra", + totalCommits: 100, + totalIssues: 200, + totalPRs: 300, + totalPRsMerged: 0, + mergedPRsPercentage: 0, + totalReviews: 50, + totalStars: 300, + totalDiscussionsStarted: 0, + totalDiscussionsAnswered: 0, + rank, + }); + }); + + it("should not fetch additional stats data when it not requested", async () => { + let stats = await fetchStats("anuraghazra"); + const rank = calculateRank({ + all_commits: false, + commits: 100, + prs: 300, + reviews: 50, + issues: 200, + repos: 5, + stars: 300, + followers: 100, + }); + + expect(stats).toStrictEqual({ + contributedTo: 61, + name: "Anurag Hazra", + totalCommits: 100, + totalIssues: 200, + totalPRs: 300, + totalPRsMerged: 0, + mergedPRsPercentage: 0, + totalReviews: 50, + totalStars: 300, + totalDiscussionsStarted: 0, + totalDiscussionsAnswered: 0, + rank, + }); + }); + + it("should fetch additional stats when it requested", async () => { + let stats = await fetchStats("anuraghazra", false, [], true, true, true); + const rank = calculateRank({ + all_commits: false, + commits: 100, + prs: 300, + reviews: 50, + issues: 200, + repos: 5, + stars: 300, + followers: 100, + }); + expect(stats).toStrictEqual({ contributedTo: 61, name: "Anurag Hazra",