Skip to content

Commit 2a7dbc6

Browse files
feat: add include_orgs card variable
This pull request adds experimental Organization support. Users can include stats from Organization repositories to which they are collaborators using the `include_orgs` card argument. Please be aware that because of #1852, only the first 100 repositories are used. Including organization, stats might therefore skew your results. Co-authored-by: Raymond Nook <[email protected]>
1 parent 3cb205c commit 2a7dbc6

8 files changed

+47
-16
lines changed

api/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export default async (req, res) => {
2121
show_icons,
2222
count_private,
2323
include_all_commits,
24+
include_orgs,
2425
line_height,
2526
title_color,
2627
ring_color,
@@ -52,6 +53,7 @@ export default async (req, res) => {
5253
username,
5354
parseBoolean(count_private),
5455
parseBoolean(include_all_commits),
56+
parseBoolean(include_orgs),
5557
parseArray(exclude_repo),
5658
);
5759

api/top-langs.js

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export default async (req, res) => {
2424
cache_seconds,
2525
layout,
2626
langs_count,
27+
include_orgs,
2728
exclude_repo,
2829
custom_title,
2930
locale,
@@ -43,6 +44,7 @@ export default async (req, res) => {
4344
try {
4445
const topLangs = await fetchTopLanguages(
4546
username,
47+
include_orgs,
4648
parseArray(exclude_repo),
4749
);
4850

readme.md

+2
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ You can provide multiple comma-separated values in the bg_color option to render
280280
- `hide_rank` - _(boolean)_ hides the rank and automatically resizes the card width. Default: `false`.
281281
- `show_icons` - _(boolean)_. Default: `false`.
282282
- `include_all_commits` - Count total commits instead of just the current year commits _(boolean)_. Default: `false`.
283+
- `include_orgs` - Include stats from organization repositories.
283284
- `count_private` - Count private commits _(boolean)_. Default: `false`.
284285
- `line_height` - Sets the line height between text _(number)_. Default: `25`.
285286
- `exclude_repo` - Exclude stars from specified repositories _(Comma-separated values)_. Default: `[] (blank array)`.
@@ -302,6 +303,7 @@ You can provide multiple comma-separated values in the bg_color option to render
302303
- `layout` - Switch between two available layouts `default` & `compact`. Default: `default`.
303304
- `card_width` - Set the card's width manually _(number)_. Default `300`.
304305
- `langs_count` - Show more languages on the card, between 1-10 _(number)_. Default `5`.
306+
- `include_orgs` - Include language stats from organization repositories.
305307
- `exclude_repo` - Exclude specified repositories _(Comma-separated values)_. Default: `[] (blank array)`.
306308
- `custom_title` - Sets a custom title for the card _(string)_. Default `Most Used Languages`.
307309

src/common/utils.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ const isValidHexColor = (hexColor) => {
7777
/**
7878
* Returns boolean if value is either "true" or "false" else the value as it is.
7979
*
80-
* @param {string | boolean} value The value to parse.
80+
* @param {string | boolean| undefined} value The value to parse.
8181
* @returns {boolean | undefined } The parsed value.
8282
*/
8383
const parseBoolean = (value) => {

src/fetchers/stats-fetcher.js

+23-8
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const fetcher = (variables, token) => {
2222
return request(
2323
{
2424
query: `
25-
query userInfo($login: String!) {
25+
query userInfo($login: String!, $ownerAffiliations: [RepositoryAffiliation]) {
2626
user(login: $login) {
2727
name
2828
login
@@ -45,7 +45,7 @@ const fetcher = (variables, token) => {
4545
followers {
4646
totalCount
4747
}
48-
repositories(ownerAffiliations: OWNER) {
48+
repositories(ownerAffiliations: $ownerAffiliations) {
4949
totalCount
5050
}
5151
}
@@ -70,9 +70,9 @@ const repositoriesFetcher = (variables, token) => {
7070
return request(
7171
{
7272
query: `
73-
query userInfo($login: String!, $after: String) {
73+
query userInfo($login: String!, $after: String, $ownerAffiliations: [RepositoryAffiliation]) {
7474
user(login: $login) {
75-
repositories(first: 100, ownerAffiliations: OWNER, orderBy: {direction: DESC, field: STARGAZERS}, after: $after) {
75+
repositories(first: 100, ownerAffiliations: $ownerAffiliations, orderBy: {direction: DESC, field: STARGAZERS}, after: $after) {
7676
nodes {
7777
name
7878
stargazers {
@@ -141,15 +141,21 @@ const totalCommitsFetcher = async (username) => {
141141
* Fetch all the stars for all the repositories of a given username.
142142
*
143143
* @param {string} username GitHub username.
144+
* @param {boolean} include_orgs Include stats from organization repos.
144145
* @param {array} repoToHide Repositories to hide.
145146
* @returns {Promise<number>} Total stars.
146147
*/
147-
const totalStarsFetcher = async (username, repoToHide) => {
148+
const totalStarsFetcher = async (username, include_orgs, repoToHide) => {
148149
let nodes = [];
149150
let hasNextPage = true;
150151
let endCursor = null;
151152
while (hasNextPage) {
152-
const variables = { login: username, first: 100, after: endCursor };
153+
const variables = {
154+
login: username,
155+
first: 100,
156+
after: endCursor,
157+
ownerAffiliations: include_orgs ? ["OWNER", "COLLABORATOR"] : ["OWNER"],
158+
};
153159
let res = await retryer(repositoriesFetcher, variables);
154160

155161
if (res.data.errors) {
@@ -183,12 +189,14 @@ const totalStarsFetcher = async (username, repoToHide) => {
183189
* @param {string} username GitHub username.
184190
* @param {boolean} count_private Include private contributions.
185191
* @param {boolean} include_all_commits Include all commits.
192+
* @param {boolean} include_orgs Include stats from organization repos.
186193
* @returns {Promise<import("./types").StatsData>} Stats data.
187194
*/
188195
const fetchStats = async (
189196
username,
190197
count_private = false,
191198
include_all_commits = false,
199+
include_orgs = false,
192200
exclude_repo = [],
193201
) => {
194202
if (!username) throw new MissingParamError(["username"]);
@@ -203,7 +211,10 @@ const fetchStats = async (
203211
rank: { level: "C", score: 0 },
204212
};
205213

206-
let res = await retryer(fetcher, { login: username });
214+
let res = await retryer(fetcher, {
215+
login: username,
216+
ownerAffiliations: include_orgs ? ["OWNER", "COLLABORATOR"] : ["OWNER"],
217+
});
207218

208219
// Catch GraphQL errors.
209220
if (res.data.errors) {
@@ -259,7 +270,11 @@ const fetchStats = async (
259270
stats.contributedTo = user.repositoriesContributedTo.totalCount;
260271

261272
// Retrieve stars while filtering out repositories to be hidden
262-
stats.totalStars = await totalStarsFetcher(username, repoToHide);
273+
stats.totalStars = await totalStarsFetcher(
274+
username,
275+
include_orgs,
276+
repoToHide,
277+
);
263278

264279
stats.rank = calculateRank({
265280
totalCommits: stats.totalCommits,

src/fetchers/top-languages-fetcher.js

+12-4
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ const fetcher = (variables, token) => {
1919
return request(
2020
{
2121
query: `
22-
query userInfo($login: String!) {
22+
query userInfo($login: String!, $ownerAffiliations: [RepositoryAffiliation]) {
2323
user(login: $login) {
2424
# fetch only owner repos & not forks
25-
repositories(ownerAffiliations: OWNER, isFork: false, first: 100) {
25+
repositories(ownerAffiliations: $ownerAffiliations, isFork: false, first: 100) {
2626
nodes {
2727
name
2828
languages(first: 10, orderBy: {field: SIZE, direction: DESC}) {
@@ -51,13 +51,21 @@ const fetcher = (variables, token) => {
5151
* Fetch top languages for a given username.
5252
*
5353
* @param {string} username GitHub username.
54+
* @param {boolean} include_orgs Include stats from organization repos.
5455
* @param {string[]} exclude_repo List of repositories to exclude.
5556
* @returns {Promise<import("./types").TopLangData>} Top languages data.
5657
*/
57-
const fetchTopLanguages = async (username, exclude_repo = []) => {
58+
const fetchTopLanguages = async (
59+
username,
60+
include_orgs = false,
61+
exclude_repo = [],
62+
) => {
5863
if (!username) throw new MissingParamError(["username"]);
5964

60-
const res = await retryer(fetcher, { login: username });
65+
const res = await retryer(fetcher, {
66+
login: username,
67+
ownerAffiliations: include_orgs ? ["OWNER", "COLLABORATOR"] : ["OWNER"],
68+
});
6169

6270
if (res.data.errors) {
6371
logger.error(res.data.errors);

tests/fetchStats.test.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ describe("Test fetchStats", () => {
201201
.onGet("https://api.github.com/search/commits?q=author:anuraghazra")
202202
.reply(200, { total_count: 1000 });
203203

204-
let stats = await fetchStats("anuraghazra", true, true);
204+
let stats = await fetchStats("anuraghazra", true, true, false);
205205
const rank = calculateRank({
206206
totalCommits: 1050,
207207
totalRepos: 5,
@@ -230,7 +230,9 @@ describe("Test fetchStats", () => {
230230
.onGet("https://api.github.com/search/commits?q=author:anuraghazra")
231231
.reply(200, { total_count: 1000 });
232232

233-
let stats = await fetchStats("anuraghazra", true, true, ["test-repo-1"]);
233+
let stats = await fetchStats("anuraghazra", true, true, false, [
234+
"test-repo-1",
235+
]);
234236
const rank = calculateRank({
235237
totalCommits: 1050,
236238
totalRepos: 5,

tests/fetchTopLanguages.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ describe("FetchTopLanguages", () => {
8181
it("should fetch correct language data while excluding the 'test-repo-1' repository", async () => {
8282
mock.onPost("https://api.github.com/graphql").reply(200, data_langs);
8383

84-
let repo = await fetchTopLanguages("anuraghazra", ["test-repo-1"]);
84+
let repo = await fetchTopLanguages("anuraghazra", false, ["test-repo-1"]);
8585
expect(repo).toStrictEqual({
8686
HTML: {
8787
color: "#0f0",

0 commit comments

Comments
 (0)