diff --git a/readme.md b/readme.md index 2760b191c38c3..d993558a76cc1 100644 --- a/readme.md +++ b/readme.md @@ -156,10 +156,10 @@ You can pass a query parameter `&hide=` to hide any specific stats with comma-se You can pass a query parameter `&show=` to show any specific additional stats with comma-separated values. -> Options: `&show=reviews,discussions_started,discussions_answered` +> Options: `&show=reviews,discussions_started,discussions_answered,prs_merged,prs_merged_percentage` ```md -![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&show=reviews) +![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&show=reviews,discussions_started,discussions_answered,prs_merged,prs_merged_percentage) ``` ### Showing icons @@ -548,7 +548,7 @@ Change the `?username=` value to your [Wakatime](https://wakatime.com) username. * Showing additional stats -![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra\&show=reviews,discussions_started,discussions_answered) +![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=anuraghazra\&show=reviews,discussions_started,discussions_answered,prs_merged,prs_merged_percentage) * Showing icons diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js index 7c5d43740c919..778e67647f342 100644 --- a/src/cards/stats-card.js +++ b/src/cards/stats-card.js @@ -28,6 +28,7 @@ const RANK_ONLY_CARD_DEFAULT_WIDTH = 290; * @param {string} createTextNodeParams.label The label to display. * @param {number} createTextNodeParams.value The value to display. * @param {string} createTextNodeParams.id The id of the stat. + * @param {string=} createTextNodeParams.unitSymbol The unit symbol of the stat. * @param {number} createTextNodeParams.index The index of the stat. * @param {boolean} createTextNodeParams.showIcons Whether to show icons. * @param {number} createTextNodeParams.shiftValuePos Number of pixels the value has to be shifted to the right. @@ -40,6 +41,7 @@ const createTextNode = ({ label, value, id, + unitSymbol, index, showIcons, shiftValuePos, @@ -69,7 +71,7 @@ const createTextNode = ({ x="${(showIcons ? 140 : 120) + shiftValuePos}" y="12.5" data-testid="${id}" - >${kValue} + >${kValue}${unitSymbol ? ` ${unitSymbol}` : ""} `; }; @@ -93,6 +95,8 @@ const renderStatsCard = (stats, options = {}) => { totalCommits, totalIssues, totalPRs, + totalPRsMerged, + mergedPRsPercentage, totalReviews, totalDiscussionsStarted, totalDiscussionsAnswered, @@ -171,6 +175,25 @@ const renderStatsCard = (stats, options = {}) => { id: "prs", }; + if (show.includes("prs_merged")) { + STATS.prs_merged = { + icon: icons.prs_merged, + label: i18n.t("statcard.prs-merged"), + value: totalPRsMerged, + id: "prs_merged", + }; + } + + if (show.includes("prs_merged_percentage")) { + STATS.prs_merged_percentage = { + icon: icons.prs_merged_percentage, + label: i18n.t("statcard.prs-merged-percentage"), + value: mergedPRsPercentage.toFixed(2), + id: "prs_merged_percentage", + unitSymbol: "%", + }; + } + if (show.includes("reviews")) { STATS.reviews = { icon: icons.reviews, @@ -235,7 +258,11 @@ const renderStatsCard = (stats, options = {}) => { .map((key, index) => // create the text nodes, and pass index so that we can calculate the line spacing createTextNode({ - ...STATS[key], + icon: STATS[key].icon, + label: STATS[key].label, + value: STATS[key].value, + id: STATS[key].id, + unitSymbol: STATS[key].unitSymbol, index, showIcons: show_icons, shiftValuePos: 79.01 + (isLongLocale ? 50 : 0), diff --git a/src/common/icons.js b/src/common/icons.js index 3f91d86658c93..d600c14f64af7 100644 --- a/src/common/icons.js +++ b/src/common/icons.js @@ -2,6 +2,8 @@ const icons = { star: ``, commits: ``, prs: ``, + prs_merged: ``, + prs_merged_percentage: ``, issues: ``, icon: ``, contribs: ``, diff --git a/src/fetchers/stats-fetcher.js b/src/fetchers/stats-fetcher.js index a1e282187a756..6cffdfdca680d 100644 --- a/src/fetchers/stats-fetcher.js +++ b/src/fetchers/stats-fetcher.js @@ -54,6 +54,9 @@ const GRAPHQL_STATS_QUERY = ` pullRequests(first: 1) { totalCount } + mergedPullRequests: pullRequests(states: MERGED) { + totalCount + } openIssues: issues(states: OPEN) { totalCount } @@ -201,6 +204,8 @@ const fetchStats = async ( const stats = { name: "", totalPRs: 0, + totalPRsMerged: 0, + mergedPRsPercentage: 0, totalReviews: 0, totalCommits: 0, totalIssues: 0, @@ -246,6 +251,9 @@ const fetchStats = async ( } stats.totalPRs = user.pullRequests.totalCount; + 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; diff --git a/src/fetchers/types.d.ts b/src/fetchers/types.d.ts index 3a86205834c12..b0cc2f4c33b05 100644 --- a/src/fetchers/types.d.ts +++ b/src/fetchers/types.d.ts @@ -18,6 +18,8 @@ export type RepositoryData = { export type StatsData = { name: string; totalPRs: number; + totalPRsMerged: number; + mergedPRsPercentage: number; totalReviews: number; totalCommits: number; totalIssues: number; diff --git a/src/translations.js b/src/translations.js index b39f17b3916ae..1ced5f69263fd 100644 --- a/src/translations.js +++ b/src/translations.js @@ -325,6 +325,66 @@ const statCardLocales = ({ name, apostrophe }) => { vi: "Tổng Số Thảo Luận Đã Trả Lời", se: "Totalt antal diskussioner besvarade", }, + "statcard.prs-merged": { + ar: "مجموع الطلبات المدمجة", + cn: "合并的 PR 总数", + "zh-tw": "合併的 PR 總數", + cs: "Celkem sloučených PR", + de: "Insgesamt zusammengeführte PRs", + en: "Total PRs Merged", + bn: "সর্বমোট PR একত্রীকৃত", + es: "PR totales fusionados", + fr: "Nombre total de PR fusionnés", + hu: "Összes egyesített PR", + it: "PR totali uniti", + ja: "マージされた PR の総数", + kr: "병합된 총 PR", + nl: "Totaal samengevoegde PR's", + "pt-pt": "Total de PRs Fundidos", + "pt-br": "Total de PRs Fundidos", + np: "कुल PRs मर्ज गरिएको", + el: "Σύνολο Συγχωνευμένων PR", + ru: "Всего объединённых pull request`ов", + "uk-ua": "Всього об'єднаних pull request`iв", + id: "Total PR Digabungkan", + my: "Jumlah PR Digabungkan", + sk: "Celkový počet zlúčených PR", + tr: "Toplam Birleştirilmiş PR", + pl: "Łącznie połączonych PR", + uz: "Birlangan PR-lar soni", + vi: "Tổng Số PR Đã Hợp Nhất", + se: "Totalt antal sammanfogade PR", + }, + "statcard.prs-merged-percentage": { + ar: "نسبة الطلبات المدمجة", + cn: "合并的 PR 百分比", + "zh-tw": "合併的 PR 百分比", + cs: "Sloučené PRs v procentech", + de: "Zusammengeführte PRs in Prozent", + en: "Merged PRs Percentage", + bn: "PR একত্রীকরণের শতাংশ", + es: "Porcentaje de PR fusionados", + fr: "Pourcentage de PR fusionnés", + hu: "Egyesített PR-k százaléka", + it: "Percentuale di PR uniti", + ja: "マージされた PR の割合", + kr: "병합된 PR의 비율", + nl: "Percentage samengevoegde PR's", + "pt-pt": "Percentagem de PRs Fundidos", + "pt-br": "Porcentagem de PRs Fundidos", + np: "PR मर्ज गरिएको प्रतिशत", + el: "Ποσοστό Συγχωνευμένων PR", + ru: "Процент объединённых pull request`ов", + "uk-ua": "Відсоток об'єднаних pull request`iв", + id: "Persentase PR Digabungkan", + my: "Peratus PR Digabungkan", + sk: "Percento zlúčených PR", + tr: "Birleştirilmiş PR Yüzdesi", + pl: "Procent połączonych PR", + uz: "Birlangan PR-lar foizi", + vi: "Tỷ Lệ PR Đã Hợp Nhất", + se: "Procent av sammanfogade PR", + }, }; }; diff --git a/tests/api.test.js b/tests/api.test.js index 3c72583cb47a0..567d2c12fd7de 100644 --- a/tests/api.test.js +++ b/tests/api.test.js @@ -13,6 +13,8 @@ const stats = { totalCommits: 200, totalIssues: 300, totalPRs: 400, + totalPRsMerged: 320, + mergedPRsPercentage: 80, totalReviews: 50, totalDiscussionsStarted: 10, totalDiscussionsAnswered: 40, @@ -41,6 +43,7 @@ const data_stats = { totalPullRequestReviewContributions: stats.totalReviews, }, pullRequests: { totalCount: stats.totalPRs }, + mergedPullRequests: { totalCount: stats.totalPRsMerged }, openIssues: { totalCount: stats.totalIssues }, closedIssues: { totalCount: 0 }, followers: { totalCount: 0 }, diff --git a/tests/fetchStats.test.js b/tests/fetchStats.test.js index 80b19bfeecc3d..6db4ef48fa677 100644 --- a/tests/fetchStats.test.js +++ b/tests/fetchStats.test.js @@ -16,6 +16,7 @@ const data_stats = { totalPullRequestReviewContributions: 50, }, pullRequests: { totalCount: 300 }, + mergedPullRequests: { totalCount: 240 }, openIssues: { totalCount: 100 }, closedIssues: { totalCount: 100 }, followers: { totalCount: 100 }, @@ -121,6 +122,8 @@ describe("Test fetchStats", () => { totalCommits: 100, totalIssues: 200, totalPRs: 300, + totalPRsMerged: 240, + mergedPRsPercentage: 80, totalReviews: 50, totalStars: 300, totalDiscussionsStarted: 10, @@ -155,6 +158,8 @@ describe("Test fetchStats", () => { totalCommits: 100, totalIssues: 200, totalPRs: 300, + totalPRsMerged: 240, + mergedPRsPercentage: 80, totalReviews: 50, totalStars: 300, totalDiscussionsStarted: 10, @@ -195,6 +200,8 @@ describe("Test fetchStats", () => { totalCommits: 1000, totalIssues: 200, totalPRs: 300, + totalPRsMerged: 240, + mergedPRsPercentage: 80, totalReviews: 50, totalStars: 300, totalDiscussionsStarted: 10, @@ -226,6 +233,8 @@ describe("Test fetchStats", () => { totalCommits: 1000, totalIssues: 200, totalPRs: 300, + totalPRsMerged: 240, + mergedPRsPercentage: 80, totalReviews: 50, totalStars: 200, totalDiscussionsStarted: 10, @@ -255,6 +264,8 @@ describe("Test fetchStats", () => { totalCommits: 100, totalIssues: 200, totalPRs: 300, + totalPRsMerged: 240, + mergedPRsPercentage: 80, totalReviews: 50, totalStars: 400, totalDiscussionsStarted: 10, @@ -284,6 +295,8 @@ describe("Test fetchStats", () => { totalCommits: 100, totalIssues: 200, totalPRs: 300, + totalPRsMerged: 240, + mergedPRsPercentage: 80, totalReviews: 50, totalStars: 300, totalDiscussionsStarted: 10, @@ -313,6 +326,8 @@ describe("Test fetchStats", () => { totalCommits: 100, totalIssues: 200, totalPRs: 300, + totalPRsMerged: 240, + mergedPRsPercentage: 80, totalReviews: 50, totalStars: 300, totalDiscussionsStarted: 10, diff --git a/tests/renderStatsCard.test.js b/tests/renderStatsCard.test.js index 174aa07310f7a..fbc02a93ca41a 100644 --- a/tests/renderStatsCard.test.js +++ b/tests/renderStatsCard.test.js @@ -18,6 +18,8 @@ const stats = { totalCommits: 200, totalIssues: 300, totalPRs: 400, + totalPRsMerged: 320, + mergedPRsPercentage: 80, totalReviews: 50, totalDiscussionsStarted: 10, totalDiscussionsAnswered: 50, @@ -52,6 +54,10 @@ describe("Test renderStatsCard", () => { expect( queryByTestId(document.body, "discussions_answered"), ).not.toBeInTheDocument(); + expect(queryByTestId(document.body, "prs_merged")).not.toBeInTheDocument(); + expect( + queryByTestId(document.body, "prs_merged_percentage"), + ).not.toBeInTheDocument(); }); it("should have proper name apostrophe", () => { @@ -85,16 +91,24 @@ describe("Test renderStatsCard", () => { expect(queryByTestId(document.body, "reviews")).toBeNull(); expect(queryByTestId(document.body, "discussions_started")).toBeNull(); expect(queryByTestId(document.body, "discussions_answered")).toBeNull(); + expect(queryByTestId(document.body, "prs_merged")).toBeNull(); + expect(queryByTestId(document.body, "prs_merged_percentage")).toBeNull(); }); it("should show additional stats", () => { document.body.innerHTML = renderStatsCard(stats, { - show: ["reviews", "discussions_started", "discussions_answered"], + show: [ + "reviews", + "discussions_started", + "discussions_answered", + "prs_merged", + "prs_merged_percentage", + ], }); expect( document.body.getElementsByTagName("svg")[0].getAttribute("height"), - ).toBe("270"); + ).toBe("320"); expect(queryByTestId(document.body, "stars")).toBeDefined(); expect(queryByTestId(document.body, "commits")).toBeDefined(); @@ -104,6 +118,8 @@ describe("Test renderStatsCard", () => { expect(queryByTestId(document.body, "reviews")).toBeDefined(); expect(queryByTestId(document.body, "discussions_started")).toBeDefined(); expect(queryByTestId(document.body, "discussions_answered")).toBeDefined(); + expect(queryByTestId(document.body, "prs_merged")).toBeDefined(); + expect(queryByTestId(document.body, "prs_merged_percentage")).toBeDefined(); }); it("should hide_rank", () => {