Repository: anuraghazra/github-readme-stats
Pull request #3350 (2023-10-13 10:20:59)

docs: add uptime badge
@qwerty541, @anuraghazra, this adds a small uptime badge to the readme. So that people know when the public instance is down. This should not increase the GraphQL usage since the response is already cached every 5 minutes on Vercel's side. 

vercel[bot]: [vc]: #tvSTZSCJNn6kOCvFAklHLlfz+SV4zFeOcELlsGxyVRU=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJnaXRodWItcmVhZG1lLXN0YXRzIiwicm9vdERpcmVjdG9yeSI6bnVsbCwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL2dpdGh1Yi1yZWFkbWUtc3RhdHMtdGVhbS9naXRodWItcmVhZG1lLXN0YXRzL0V6NGdvb3liaUJWTE1NMzF2QnIyQXlpTlJBdTciLCJwcmV2aWV3VXJsIjoiZ2l0aHViLXJlYWRtZS1zdGF0cy1naXQtYWRkdXB0aW1lYmFkZ2UtZ2l0aHViLXJlYWRtZS1zdGF0cy10ZWFtLnZlcmNlbC5hcHAiLCJuZXh0Q29tbWl0U3RhdHVzIjoiUEVORElORyJ9XX0=
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Updated (UTC) |
| :--- | :----- | :------ | :------ |
| **github-readme-stats** | 🔄 Building ([Inspect](https://vercel.com/github-readme-stats-team/github-readme-stats/Ez4gooybiBVLMM31vBr2AyiNRAu7)) | [Visit Preview](https://github-readme-stats-git-adduptimebadge-github-readme-stats-team.vercel.app) | Oct 13, 2023 10:21am |



Patch:
diff --git a/.eslintrc.json b/.eslintrc.json
index 2edbe53..0236a06 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -99,7 +99,7 @@
             "location": "start"
         }],
         "no-with": "warn",
-        // "radix": "warn",
+        "radix": "warn",
         // "vars-on-top": "error",
 
         // Enforces the style of wrapped functions
@@ -193,7 +193,7 @@
         // "no-continue": "off",
         // "no-inline-comments": "off",
         // "no-lonely-if": "warn",
-        // "no-mixed-spaces-and-tabs": "warn",
+        "no-mixed-spaces-and-tabs": "warn",
         "no-multiple-empty-lines": "warn",
         // "no-negated-condition": "off",
         // "no-nested-ternary": "warn",
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index da4545a..a35b0d2 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -2,9 +2,11 @@ name: "Static code analysis workflow (CodeQL)"
 
 on:
   push:
-    branches: [main]
+    branches:
+      - master
   pull_request:
-    branches: [main]
+    branches:
+      - master
 
 permissions:
   actions: read
diff --git a/api/index.js b/api/index.js
index 25e4151..adfd331 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/readme.md b/readme.md
index e0cd50b..5015e14 100644
--- a/readme.md
+++ b/readme.md
@@ -123,6 +123,8 @@ Please visit [this link](https://give.do/fundraisers/stand-beside-the-victims-of
 > [!IMPORTANT]\
 > Since the GitHub API only [allows 5k requests per hour per user account](https://docs.github.com/en/graphql/overview/resource-limitations), the public Vercel instance hosted on `https://github-readme-stats.vercel.app/api` could possibly hit the rate limiter (see [#1471](https://github.com/anuraghazra/github-readme-stats/issues/1471)). We use caching to prevent this from happening (see https://github.com/anuraghazra/github-readme-stats#common-options). You can turn off these rate limit protections by deploying [your own Vercel instance](#disable-rate-limit-protections).
 
+<img alt="Uptime Badge" src="https://img.shields.io/endpoint?url=https%3A%2F%2Fgithub-readme-stats-git-monitoring-github-readme-stats-team.vercel.app%2Fapi%2Fstatus%2Fup%3Ftype%3Dshields">
+
 # GitHub Stats Card
 
 Copy-paste this into your markdown content, and that is it. Simple!
diff --git a/src/common/utils.js b/src/common/utils.js
index 93d60cd..95d683c 100644
--- a/src/common/utils.js
+++ b/src/common/utils.js
@@ -232,7 +232,7 @@ const parseArray = (str) => {
  */
 const clampValue = (number, min, max) => {
   // @ts-ignore
-  if (Number.isNaN(parseInt(number))) {
+  if (Number.isNaN(parseInt(number, 10))) {
     return min;
   }
   return Math.max(min, Math.min(number, max));
diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js
index 0f770d8..1d6aebf 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<AxiosResponse>} 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<StatsData>} 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.


Test patch:
diff --git a/tests/fetchStats.test.js b/tests/fetchStats.test.js
index 56125d8..ca8d7bc 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",