Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff292f2c0b | ||
|
|
68e7cbe8b1 | ||
|
|
54a106ce36 | ||
|
|
893c5e4df3 | ||
|
|
a4486d0327 | ||
|
|
60511778ff | ||
|
|
3b0f1b11a0 | ||
|
|
03e484b1fd | ||
|
|
9753c24625 | ||
|
|
331721945f | ||
|
|
56d424f1d4 |
+7
-1
@@ -18,6 +18,7 @@ module.exports = async (req, res) => {
|
||||
hide_rank,
|
||||
show_icons,
|
||||
count_private,
|
||||
include_all_commits,
|
||||
line_height,
|
||||
title_color,
|
||||
icon_color,
|
||||
@@ -31,7 +32,11 @@ module.exports = async (req, res) => {
|
||||
res.setHeader("Content-Type", "image/svg+xml");
|
||||
|
||||
try {
|
||||
stats = await fetchStats(username, parseBoolean(count_private));
|
||||
stats = await fetchStats(
|
||||
username,
|
||||
parseBoolean(count_private),
|
||||
parseBoolean(include_all_commits)
|
||||
);
|
||||
} catch (err) {
|
||||
return res.send(
|
||||
renderError(
|
||||
@@ -56,6 +61,7 @@ module.exports = async (req, res) => {
|
||||
hide_title: parseBoolean(hide_title),
|
||||
hide_border: parseBoolean(hide_border),
|
||||
hide_rank: parseBoolean(hide_rank),
|
||||
include_all_commits: parseBoolean(include_all_commits),
|
||||
line_height,
|
||||
title_color,
|
||||
icon_color,
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"dependencies": {
|
||||
"dotenv": "^8.2.0",
|
||||
"emoji-name-map": "^1.2.8",
|
||||
"github-username-regex": "^1.0.0",
|
||||
"word-wrap": "^1.2.3"
|
||||
},
|
||||
"husky": {
|
||||
|
||||
@@ -118,29 +118,44 @@ You can look at a preview for [all available themes](./themes/README.md) or chec
|
||||
|
||||
You can customize the appearance of your `Stats Card` or `Repo Card` however you want with URL params.
|
||||
|
||||
Customization Options:
|
||||
#### Common Options:
|
||||
|
||||
| Option | type | description | Stats Card (default) | Repo Card (default) | Top Lang Card (default) |
|
||||
| ------------- | --------- | ------------------------------------------- | -------------------- | ------------------- | ----------------------- |
|
||||
| title_color | hex color | title color | 2f80ed | 2f80ed | 2f80ed |
|
||||
| text_color | hex color | body color | 333 | 333 | 333 |
|
||||
| icon_color | hex color | icon color | 4c71f2 | 586069 | 586069 |
|
||||
| bg_color | hex color | card bg color | FFFEFE | FFFEFE | FFFEFE |
|
||||
| line_height | number | control the line-height between text | 30 | N/A | N/A |
|
||||
| hide | CSV | hides the items specified | undefined | N/A | undefined |
|
||||
| hide_rank | boolean | hides the ranking | false | N/A | N/A |
|
||||
| hide_title | boolean | hides the stats title | false | N/A | false |
|
||||
| hide_border | boolean | hides the stats card border | false | N/A | N/A |
|
||||
| show_owner | boolean | shows owner name in repo card | N/A | false | N/A |
|
||||
| show_icons | boolean | shows icons | false | N/A | N/A |
|
||||
| theme | string | sets inbuilt theme | 'default' | 'default_repocard' | 'default' |
|
||||
| cache_seconds | number | manually set custom cache control | 1800 | 1800 | 1800 |
|
||||
| count_private | boolean | counts private contributions too if enabled | false | N/A | N/A |
|
||||
| layout | string | choose a layout option | N/A | N/A | 'default' |
|
||||
| card_width | number | set the card width | N/A | N/A | 300 |
|
||||
- `title_color` - Card's title color _(hex color)_
|
||||
- `text_color` - Body text color _(hex color)_
|
||||
- `icon_color` - Icons color if available _(hex color)_
|
||||
- `bg_color` - Card's background color _(hex color)_
|
||||
- `theme` - name of the theme, choose from [all available themes](./themes/README.md)
|
||||
- `cache_seconds` - set the cache header manually _(min: 1800, max: 86400)_
|
||||
|
||||
> Note on cache: Repo cards have default cache of 30mins (1800 seconds) if the fork count & star count is less than 1k otherwise it's 2hours (7200). Also note that cache is clamped to minimum of 30min and maximum of 24hours
|
||||
|
||||
#### Stats Card Exclusive Options:
|
||||
|
||||
- `hide` - Hide's the specified items from stats _(Comma seperated values)_
|
||||
- `hide_title` - _(boolean)_
|
||||
- `hide_rank` - _(boolean)_
|
||||
- `show_icons` - _(boolean)_
|
||||
- `include_total_commits` - Count total commits instead of just the current year commits _(boolean)_
|
||||
- `count_private` - Count private commits _(boolean)_
|
||||
- `line_height` - Sets the line-height between text _(number)_
|
||||
|
||||
#### Repo Card Exclusive Options:
|
||||
|
||||
- `show_owner` - Show the owner name of the repo _(boolean)_
|
||||
|
||||
#### Language Card Exclusive Options:
|
||||
|
||||
- `hide` - Hide the languages specified from the card _(Comma seperated values)_
|
||||
- `hide_title` - _(boolean)_
|
||||
- `layout` - Switch between two available layouts `default` & `compact`
|
||||
- `card_width` - Set the card's width manually _(number)_
|
||||
|
||||
> :warning: **Important:**
|
||||
> Language names should be uri-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding)
|
||||
> (i.e: `c++` should become `c%2B%2B`, `jupyter notebook` should become `jupyter%20notebook`, etc.)
|
||||
|
||||
---
|
||||
|
||||
# GitHub Extra Pins
|
||||
|
||||
GitHub extra pins allow you to pin more than 6 repositories in your profile using a GitHub readme profile.
|
||||
@@ -189,10 +204,6 @@ You can use `?hide=language1,language2` parameter to hide individual languages.
|
||||
[](https://github.com/anuraghazra/github-readme-stats)
|
||||
```
|
||||
|
||||
> :warning: **Important:**
|
||||
> Language names should be uri-escaped, as specified in [Percent Encoding](https://en.wikipedia.org/wiki/Percent-encoding)
|
||||
> (i.e: `c++` should become `c%2B%2B`, `jupyter notebook` should become `jupyter%20notebook`, etc.)
|
||||
|
||||
### Compact Language Card Layout
|
||||
|
||||
You can use the `&layout=compact` option to change the card design.
|
||||
@@ -225,6 +236,10 @@ You can use the `&layout=compact` option to change the card design.
|
||||
|
||||

|
||||
|
||||
- Include All Commits
|
||||
|
||||

|
||||
|
||||
- Themes
|
||||
|
||||
Choose from any of the [default themes](#themes)
|
||||
|
||||
+51
-5
@@ -1,6 +1,9 @@
|
||||
const { request, logger } = require("./utils");
|
||||
const axios = require("axios");
|
||||
const retryer = require("./retryer");
|
||||
const calculateRank = require("./calculateRank");
|
||||
const githubUsernameRegex = require("github-username-regex");
|
||||
|
||||
require("dotenv").config();
|
||||
|
||||
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");
|
||||
|
||||
const stats = {
|
||||
@@ -61,6 +102,11 @@ async function fetchStats(username, count_private = false) {
|
||||
|
||||
let res = await retryer(fetcher, { login: username });
|
||||
|
||||
let experimental_totalCommits = 0;
|
||||
if (include_all_commits) {
|
||||
experimental_totalCommits = await totalCommitsFetcher(username);
|
||||
}
|
||||
|
||||
if (res.data.errors) {
|
||||
logger.error(res.data.errors);
|
||||
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.totalIssues = user.issues.totalCount;
|
||||
|
||||
stats.totalCommits = contributionCount.totalCommitContributions;
|
||||
stats.totalCommits =
|
||||
contributionCount.totalCommitContributions + experimental_totalCommits;
|
||||
|
||||
if (count_private) {
|
||||
stats.totalCommits =
|
||||
contributionCount.totalCommitContributions +
|
||||
contributionCount.restrictedContributionsCount;
|
||||
stats.totalCommits += contributionCount.restrictedContributionsCount;
|
||||
}
|
||||
|
||||
stats.totalPRs = user.pullRequests.totalCount;
|
||||
|
||||
+20
-3
@@ -8,7 +8,15 @@ const { getStyles } = require("./getStyles");
|
||||
const icons = require("./icons");
|
||||
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 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)">
|
||||
${iconSvg}
|
||||
<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>
|
||||
`;
|
||||
};
|
||||
@@ -45,6 +58,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
||||
hide_title = false,
|
||||
hide_border = false,
|
||||
hide_rank = false,
|
||||
include_all_commits = false,
|
||||
line_height = 25,
|
||||
title_color,
|
||||
icon_color,
|
||||
@@ -74,7 +88,9 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
||||
},
|
||||
commits: {
|
||||
icon: icons.commits,
|
||||
label: "Total Commits",
|
||||
label: `Total Commits${
|
||||
include_all_commits ? "" : ` (${new Date().getFullYear()})`
|
||||
}`,
|
||||
value: totalCommits,
|
||||
id: "commits",
|
||||
},
|
||||
@@ -107,6 +123,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
|
||||
...STATS[key],
|
||||
index,
|
||||
showIcons: show_icons,
|
||||
shiftValuePos: !include_all_commits,
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@@ -9,7 +9,10 @@ const data = {
|
||||
user: {
|
||||
name: "Anurag Hazra",
|
||||
repositoriesContributedTo: { totalCount: 61 },
|
||||
contributionsCollection: { totalCommitContributions: 100, restrictedContributionsCount: 50 },
|
||||
contributionsCollection: {
|
||||
totalCommitContributions: 100,
|
||||
restrictedContributionsCount: 50,
|
||||
},
|
||||
pullRequests: { totalCount: 300 },
|
||||
issues: { totalCount: 200 },
|
||||
followers: { totalCount: 100 },
|
||||
@@ -102,4 +105,32 @@ describe("Test fetchStats", () => {
|
||||
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,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user