fix: total commit counts (#211)

* fix: wip fix total commit counts

* tests: added tests

* chore: remove console logs

* docs: added docs for include_all_commits

* chore: increased value offset x

* chore: added reference/links comments

* docs: updated docs
This commit is contained in:
Anurag Hazra 2020-07-31 13:37:39 +05:30 committed by GitHub
parent a4486d0327
commit 416f027fae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 117 additions and 11 deletions

View File

@ -18,6 +18,7 @@ module.exports = async (req, res) => {
hide_rank, hide_rank,
show_icons, show_icons,
count_private, count_private,
include_all_commits,
line_height, line_height,
title_color, title_color,
icon_color, icon_color,
@ -31,7 +32,11 @@ module.exports = async (req, res) => {
res.setHeader("Content-Type", "image/svg+xml"); res.setHeader("Content-Type", "image/svg+xml");
try { try {
stats = await fetchStats(username, parseBoolean(count_private)); stats = await fetchStats(
username,
parseBoolean(count_private),
parseBoolean(include_all_commits)
);
} catch (err) { } catch (err) {
return res.send( return res.send(
renderError( renderError(
@ -56,6 +61,7 @@ module.exports = async (req, res) => {
hide_title: parseBoolean(hide_title), hide_title: parseBoolean(hide_title),
hide_border: parseBoolean(hide_border), hide_border: parseBoolean(hide_border),
hide_rank: parseBoolean(hide_rank), hide_rank: parseBoolean(hide_rank),
include_all_commits: parseBoolean(include_all_commits),
line_height, line_height,
title_color, title_color,
icon_color, icon_color,

View File

@ -22,6 +22,7 @@
"dependencies": { "dependencies": {
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"emoji-name-map": "^1.2.8", "emoji-name-map": "^1.2.8",
"github-username-regex": "^1.0.0",
"word-wrap": "^1.2.3" "word-wrap": "^1.2.3"
}, },
"husky": { "husky": {

View File

@ -135,6 +135,7 @@ You can customize the appearance of your `Stats Card` or `Repo Card` however you
- `hide_title` - _(boolean)_ - `hide_title` - _(boolean)_
- `hide_rank` - _(boolean)_ - `hide_rank` - _(boolean)_
- `show_icons` - _(boolean)_ - `show_icons` - _(boolean)_
- `include_total_commits` - Count total commits instead of just the current year commits _(boolean)_
- `count_private` - Count private commits _(boolean)_ - `count_private` - Count private commits _(boolean)_
- `line_height` - Sets the line-height between text _(number)_ - `line_height` - Sets the line-height between text _(number)_
@ -235,6 +236,10 @@ You can use the `&layout=compact` option to change the card design.
![Anurag's github stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&hide=issues&show_icons=true) ![Anurag's github stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&hide=issues&show_icons=true)
- Include All Commits
![Anurag's github stats](https://github-readme-stats.vercel.app/api?username=anuraghazra&include_all_commits=true)
- Themes - Themes
Choose from any of the [default themes](#themes) Choose from any of the [default themes](#themes)

View File

@ -1,6 +1,9 @@
const { request, logger } = require("./utils"); const { request, logger } = require("./utils");
const axios = require("axios");
const retryer = require("./retryer"); const retryer = require("./retryer");
const calculateRank = require("./calculateRank"); const calculateRank = require("./calculateRank");
const githubUsernameRegex = require("github-username-regex");
require("dotenv").config(); require("dotenv").config();
const fetcher = (variables, token) => { const fetcher = (variables, token) => {
@ -46,7 +49,45 @@ const fetcher = (variables, token) => {
); );
}; };
async function fetchStats(username, count_private = false) { // https://github.com/anuraghazra/github-readme-stats/issues/92#issuecomment-661026467
// https://github.com/anuraghazra/github-readme-stats/pull/211/
const totalCommitsFetcher = async (username) => {
if (!githubUsernameRegex.test(username)) {
logger.log("Invalid username");
return 0;
}
// https://developer.github.com/v3/search/#search-commits
const fetchTotalCommits = (variables, token) => {
return axios({
method: "get",
url: `https://api.github.com/search/commits?q=author:${variables.login}`,
headers: {
"Content-Type": "application/json",
Accept: "application/vnd.github.cloak-preview",
Authorization: `bearer ${token}`,
},
});
};
try {
let res = await retryer(fetchTotalCommits, { login: username });
if (res.data.total_count) {
return res.data.total_count;
}
} catch (err) {
logger.log(err);
// just return 0 if there is something wrong so that
// we don't break the whole app
return 0;
}
};
async function fetchStats(
username,
count_private = false,
include_all_commits = false
) {
if (!username) throw Error("Invalid username"); if (!username) throw Error("Invalid username");
const stats = { const stats = {
@ -61,6 +102,11 @@ async function fetchStats(username, count_private = false) {
let res = await retryer(fetcher, { login: username }); let res = await retryer(fetcher, { login: username });
let experimental_totalCommits = 0;
if (include_all_commits) {
experimental_totalCommits = await totalCommitsFetcher(username);
}
if (res.data.errors) { if (res.data.errors) {
logger.error(res.data.errors); logger.error(res.data.errors);
throw Error(res.data.errors[0].message || "Could not fetch user"); throw Error(res.data.errors[0].message || "Could not fetch user");
@ -72,11 +118,11 @@ async function fetchStats(username, count_private = false) {
stats.name = user.name || user.login; stats.name = user.name || user.login;
stats.totalIssues = user.issues.totalCount; stats.totalIssues = user.issues.totalCount;
stats.totalCommits = contributionCount.totalCommitContributions; stats.totalCommits =
contributionCount.totalCommitContributions + experimental_totalCommits;
if (count_private) { if (count_private) {
stats.totalCommits = stats.totalCommits += contributionCount.restrictedContributionsCount;
contributionCount.totalCommitContributions +
contributionCount.restrictedContributionsCount;
} }
stats.totalPRs = user.pullRequests.totalCount; stats.totalPRs = user.pullRequests.totalCount;

View File

@ -8,7 +8,15 @@ const { getStyles } = require("./getStyles");
const icons = require("./icons"); const icons = require("./icons");
const Card = require("./Card"); const Card = require("./Card");
const createTextNode = ({ icon, label, value, id, index, showIcons }) => { const createTextNode = ({
icon,
label,
value,
id,
index,
showIcons,
shiftValuePos,
}) => {
const kValue = kFormatter(value); const kValue = kFormatter(value);
const staggerDelay = (index + 3) * 150; const staggerDelay = (index + 3) * 150;
@ -24,7 +32,12 @@ const createTextNode = ({ icon, label, value, id, index, showIcons }) => {
<g class="stagger" style="animation-delay: ${staggerDelay}ms" transform="translate(25, 0)"> <g class="stagger" style="animation-delay: ${staggerDelay}ms" transform="translate(25, 0)">
${iconSvg} ${iconSvg}
<text class="stat bold" ${labelOffset} y="12.5">${label}:</text> <text class="stat bold" ${labelOffset} y="12.5">${label}:</text>
<text class="stat" x="135" y="12.5" data-testid="${id}">${kValue}</text> <text
class="stat"
x="${shiftValuePos ? 170 : 150}"
y="12.5"
data-testid="${id}"
>${kValue}</text>
</g> </g>
`; `;
}; };
@ -45,6 +58,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
hide_title = false, hide_title = false,
hide_border = false, hide_border = false,
hide_rank = false, hide_rank = false,
include_all_commits = false,
line_height = 25, line_height = 25,
title_color, title_color,
icon_color, icon_color,
@ -74,7 +88,9 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
}, },
commits: { commits: {
icon: icons.commits, icon: icons.commits,
label: "Total Commits", label: `Total Commits${
include_all_commits ? "" : ` (${new Date().getFullYear()})`
}`,
value: totalCommits, value: totalCommits,
id: "commits", id: "commits",
}, },
@ -107,6 +123,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
...STATS[key], ...STATS[key],
index, index,
showIcons: show_icons, showIcons: show_icons,
shiftValuePos: !include_all_commits,
}) })
); );

View File

@ -9,7 +9,10 @@ const data = {
user: { user: {
name: "Anurag Hazra", name: "Anurag Hazra",
repositoriesContributedTo: { totalCount: 61 }, repositoriesContributedTo: { totalCount: 61 },
contributionsCollection: { totalCommitContributions: 100, restrictedContributionsCount: 50 }, contributionsCollection: {
totalCommitContributions: 100,
restrictedContributionsCount: 50,
},
pullRequests: { totalCount: 300 }, pullRequests: { totalCount: 300 },
issues: { totalCount: 200 }, issues: { totalCount: 200 },
followers: { totalCount: 100 }, followers: { totalCount: 100 },
@ -102,4 +105,32 @@ describe("Test fetchStats", () => {
rank, rank,
}); });
}); });
});
it("should fetch total commits", async () => {
mock.onPost("https://api.github.com/graphql").reply(200, data);
mock
.onGet("https://api.github.com/search/commits?q=author:anuraghazra")
.reply(200, { total_count: 1000 });
let stats = await fetchStats("anuraghazra", true, true);
const rank = calculateRank({
totalCommits: 1000 + 150,
totalRepos: 5,
followers: 100,
contributions: 61,
stargazers: 400,
prs: 300,
issues: 200,
});
expect(stats).toStrictEqual({
contributedTo: 61,
name: "Anurag Hazra",
totalCommits: 1000 + 150,
totalIssues: 200,
totalPRs: 300,
totalStars: 400,
rank,
});
});
});