@stats-forge/github-stats-forge-core 0.0.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -10
- package/build/api/api-result.d.ts +6 -7
- package/build/api/api-result.d.ts.map +1 -1
- package/build/api/api-result.js +4 -5
- package/build/api/contributed-to.d.ts +23 -0
- package/build/api/contributed-to.d.ts.map +1 -0
- package/build/api/contributed-to.js +43 -0
- package/build/api/gist.d.ts +8 -22
- package/build/api/gist.d.ts.map +1 -1
- package/build/api/gist.js +14 -36
- package/build/api/handler.d.ts +16 -0
- package/build/api/handler.d.ts.map +1 -0
- package/build/api/handler.js +29 -0
- package/build/api/index.d.ts +13 -12
- package/build/api/index.d.ts.map +1 -1
- package/build/api/index.js +1 -0
- package/build/api/params.d.ts +21 -12
- package/build/api/params.d.ts.map +1 -1
- package/build/api/params.js +41 -19
- package/build/api/pin.d.ts +11 -31
- package/build/api/pin.d.ts.map +1 -1
- package/build/api/pin.js +35 -63
- package/build/api/stats.d.ts +15 -16
- package/build/api/stats.d.ts.map +1 -1
- package/build/api/stats.js +60 -99
- package/build/api/top-langs.d.ts +13 -18
- package/build/api/top-langs.d.ts.map +1 -1
- package/build/api/top-langs.js +35 -72
- package/build/api/wakatime.d.ts +11 -17
- package/build/api/wakatime.d.ts.map +1 -1
- package/build/api/wakatime.js +27 -64
- package/build/calculateRank.d.ts +0 -9
- package/build/calculateRank.d.ts.map +1 -1
- package/build/calculateRank.js +12 -17
- package/build/cards/contributed-to.d.ts +19 -0
- package/build/cards/contributed-to.d.ts.map +1 -0
- package/build/cards/contributed-to.js +242 -0
- package/build/cards/gist.d.ts +3 -4
- package/build/cards/gist.d.ts.map +1 -1
- package/build/cards/gist.js +38 -43
- package/build/cards/options.d.ts +1 -1
- package/build/cards/repo.d.ts +14 -5
- package/build/cards/repo.d.ts.map +1 -1
- package/build/cards/repo.js +93 -103
- package/build/cards/stats.d.ts +18 -11
- package/build/cards/stats.d.ts.map +1 -1
- package/build/cards/stats.js +191 -222
- package/build/cards/top-languages.d.ts +18 -33
- package/build/cards/top-languages.d.ts.map +1 -1
- package/build/cards/top-languages.js +196 -387
- package/build/cards/wakatime.d.ts +17 -8
- package/build/cards/wakatime.d.ts.map +1 -1
- package/build/cards/wakatime.js +133 -187
- package/build/common/Card.d.ts +20 -59
- package/build/common/Card.d.ts.map +1 -1
- package/build/common/Card.js +131 -198
- package/build/common/I18n.d.ts +1 -7
- package/build/common/I18n.d.ts.map +1 -1
- package/build/common/I18n.js +7 -8
- package/build/common/brand.d.ts +76 -0
- package/build/common/brand.d.ts.map +1 -0
- package/build/common/brand.js +73 -0
- package/build/common/color.d.ts +4 -17
- package/build/common/color.d.ts.map +1 -1
- package/build/common/color.js +67 -49
- package/build/common/config.d.ts +4 -14
- package/build/common/config.d.ts.map +1 -1
- package/build/common/config.js +3 -16
- package/build/common/constants.d.ts +6 -2
- package/build/common/constants.d.ts.map +1 -1
- package/build/common/constants.js +5 -1
- package/build/common/date.d.ts +50 -5
- package/build/common/date.d.ts.map +1 -1
- package/build/common/date.js +104 -4
- package/build/common/emojiMap.d.ts +8 -0
- package/build/common/emojiMap.d.ts.map +1 -0
- package/build/common/emojiMap.js +10 -0
- package/build/common/emojiMap.json +1915 -0
- package/build/common/error.d.ts +1 -10
- package/build/common/error.d.ts.map +1 -1
- package/build/common/error.js +1 -10
- package/build/common/fmt.d.ts +3 -15
- package/build/common/fmt.d.ts.map +1 -1
- package/build/common/fmt.js +7 -35
- package/build/common/http.d.ts +2 -7
- package/build/common/http.d.ts.map +1 -1
- package/build/common/http.js +8 -17
- package/build/common/icons.d.ts +20 -20
- package/build/common/icons.d.ts.map +1 -1
- package/build/common/icons.js +108 -67
- package/build/common/languageColors.d.ts +0 -1
- package/build/common/languageColors.d.ts.map +1 -1
- package/build/common/languageColors.js +1 -4
- package/build/common/languageColors.json +18 -2
- package/build/common/ops.d.ts +11 -17
- package/build/common/ops.d.ts.map +1 -1
- package/build/common/ops.js +22 -39
- package/build/common/render.d.ts +34 -82
- package/build/common/render.d.ts.map +1 -1
- package/build/common/render.js +225 -259
- package/build/common/retryer.d.ts +2 -7
- package/build/common/retryer.d.ts.map +1 -1
- package/build/common/retryer.js +4 -11
- package/build/fetchers/contributed-to.d.ts +62 -0
- package/build/fetchers/contributed-to.d.ts.map +1 -0
- package/build/fetchers/contributed-to.js +184 -0
- package/build/fetchers/gist.d.ts +2 -5
- package/build/fetchers/gist.d.ts.map +1 -1
- package/build/fetchers/gist.js +1 -5
- package/build/fetchers/graphql-error.d.ts +13 -0
- package/build/fetchers/graphql-error.d.ts.map +1 -0
- package/build/fetchers/graphql-error.js +29 -0
- package/build/fetchers/index.d.ts +13 -12
- package/build/fetchers/index.d.ts.map +1 -1
- package/build/fetchers/index.js +1 -0
- package/build/fetchers/repo.d.ts +2 -11
- package/build/fetchers/repo.d.ts.map +1 -1
- package/build/fetchers/repo.js +20 -33
- package/build/fetchers/stats.d.ts +16 -40
- package/build/fetchers/stats.d.ts.map +1 -1
- package/build/fetchers/stats.js +89 -271
- package/build/fetchers/top-languages.d.ts +2 -9
- package/build/fetchers/top-languages.d.ts.map +1 -1
- package/build/fetchers/top-languages.js +16 -47
- package/build/fetchers/types.d.ts +25 -1
- package/build/fetchers/types.d.ts.map +1 -1
- package/build/fetchers/wakatime.d.ts +2 -6
- package/build/fetchers/wakatime.d.ts.map +1 -1
- package/build/fetchers/wakatime.js +1 -5
- package/build/graphql/contributionsCollection.d.ts +9 -0
- package/build/graphql/contributionsCollection.d.ts.map +1 -0
- package/build/graphql/contributionsCollection.js +12 -0
- package/build/graphql/contributionsDocument.d.ts +6 -6
- package/build/graphql/contributionsDocument.d.ts.map +1 -1
- package/build/graphql/contributionsDocument.js +8 -16
- package/build/graphql/generated/contributed-to.d.ts +22 -0
- package/build/graphql/generated/contributed-to.d.ts.map +1 -0
- package/build/graphql/generated/contributed-to.js +11 -0
- package/build/graphql/generated/gist.d.ts +1 -1
- package/build/graphql/generated/repo.d.ts +1 -1
- package/build/graphql/generated/stats.d.ts +16 -4
- package/build/graphql/generated/stats.d.ts.map +1 -1
- package/build/graphql/generated/stats.js +2 -2
- package/build/graphql/generated/top-languages.d.ts +2 -2
- package/build/graphql/graphqlDocument.d.ts +1 -2
- package/build/graphql/graphqlDocument.d.ts.map +1 -1
- package/build/graphql/graphqlDocument.js +0 -1
- package/build/graphql/reposContributedToDocument.d.ts +4 -5
- package/build/graphql/reposContributedToDocument.d.ts.map +1 -1
- package/build/graphql/reposContributedToDocument.js +11 -7
- package/build/markup/css.d.ts +35 -0
- package/build/markup/css.d.ts.map +1 -0
- package/build/markup/css.js +64 -0
- package/build/markup/element.d.ts +41 -0
- package/build/markup/element.d.ts.map +1 -0
- package/build/markup/element.js +127 -0
- package/build/markup/html.d.ts +13 -0
- package/build/markup/html.d.ts.map +1 -0
- package/build/markup/html.js +27 -0
- package/build/markup/index.d.ts +9 -0
- package/build/markup/index.d.ts.map +1 -0
- package/build/markup/index.js +6 -0
- package/build/markup/serialize.d.ts +16 -0
- package/build/markup/serialize.d.ts.map +1 -0
- package/build/markup/serialize.js +17 -0
- package/build/themes/index.d.ts +332 -333
- package/build/themes/index.d.ts.map +1 -1
- package/build/themes/index.js +1 -1
- package/build/translations.d.ts +66 -7
- package/build/translations.d.ts.map +1 -1
- package/build/translations.js +686 -629
- package/package.json +17 -26
- package/src/api/api-result.ts +10 -9
- package/src/api/contributed-to.ts +84 -0
- package/src/api/gist.ts +22 -46
- package/src/api/handler.ts +42 -0
- package/src/api/index.ts +13 -12
- package/src/api/params.ts +74 -29
- package/src/api/pin.ts +38 -65
- package/src/api/stats.ts +81 -118
- package/src/api/top-langs.ts +38 -80
- package/src/api/wakatime.ts +35 -73
- package/src/calculateRank.ts +12 -23
- package/src/cards/contributed-to.ts +373 -0
- package/src/cards/gist.ts +55 -49
- package/src/cards/options.ts +1 -1
- package/src/cards/repo.ts +134 -120
- package/src/cards/stats.ts +262 -252
- package/src/cards/top-languages.ts +315 -422
- package/src/cards/wakatime.ts +207 -225
- package/src/common/Card.ts +207 -214
- package/src/common/I18n.ts +7 -8
- package/src/common/brand.ts +109 -0
- package/src/common/color.ts +80 -57
- package/src/common/config.ts +5 -18
- package/src/common/constants.ts +8 -2
- package/src/common/date.ts +135 -5
- package/src/common/emojiMap.json +1915 -0
- package/src/common/emojiMap.ts +13 -0
- package/src/common/error.ts +2 -11
- package/src/common/fmt.ts +7 -44
- package/src/common/http.ts +9 -15
- package/src/common/icons.ts +122 -42
- package/src/common/languageColors.json +18 -2
- package/src/common/languageColors.ts +1 -4
- package/src/common/ops.ts +31 -48
- package/src/common/render.ts +334 -284
- package/src/common/retryer.ts +8 -15
- package/src/fetchers/contributed-to.ts +271 -0
- package/src/fetchers/gist.ts +8 -12
- package/src/fetchers/graphql-error.ts +36 -0
- package/src/fetchers/index.ts +15 -12
- package/src/fetchers/repo.ts +27 -40
- package/src/fetchers/stats.ts +157 -366
- package/src/fetchers/top-languages.ts +27 -55
- package/src/fetchers/types.ts +27 -1
- package/src/fetchers/wakatime.ts +5 -9
- package/src/graphql/contributionsCollection.ts +18 -0
- package/src/graphql/contributionsDocument.ts +14 -19
- package/src/graphql/generated/contributed-to.ts +25 -0
- package/src/graphql/generated/gist.ts +1 -1
- package/src/graphql/generated/repo.ts +1 -1
- package/src/graphql/generated/stats.ts +21 -8
- package/src/graphql/generated/top-languages.ts +2 -2
- package/src/graphql/graphqlDocument.ts +1 -2
- package/src/graphql/queries/contributed-to.graphql +8 -0
- package/src/graphql/queries/stats.graphql +14 -2
- package/src/graphql/reposContributedToDocument.ts +16 -15
- package/src/markup/css.ts +118 -0
- package/src/markup/element.ts +246 -0
- package/src/markup/html.ts +34 -0
- package/src/markup/index.ts +9 -0
- package/src/markup/serialize.ts +27 -0
- package/src/themes/index.ts +1 -1
- package/src/translations.ts +699 -629
- package/build/cards/index.d.ts +0 -11
- package/build/cards/index.d.ts.map +0 -1
- package/build/cards/index.js +0 -7
- package/build/common/html.d.ts +0 -8
- package/build/common/html.d.ts.map +0 -1
- package/build/common/html.js +0 -14
- package/build/index.d.ts +0 -15
- package/build/index.d.ts.map +0 -1
- package/build/index.js +0 -10
- package/src/_emoji-name-map.d.ts +0 -10
- package/src/_github-username-regex.d.ts +0 -4
- package/src/cards/index.ts +0 -21
- package/src/common/html.ts +0 -17
- package/src/index.ts +0 -18
|
@@ -1,63 +1,39 @@
|
|
|
1
|
-
import type { CardConfig } from '../common/config.
|
|
2
|
-
import type { RepoUserStats, StatsData } from './types.
|
|
1
|
+
import type { CardConfig } from '../common/config.ts';
|
|
2
|
+
import type { RepoUserStats, StatsData } from './types.ts';
|
|
3
|
+
/** The flags that ask for a per-repository count, as the query names them. */
|
|
4
|
+
interface RepoUserStatsFlags {
|
|
5
|
+
include_prs_authored?: boolean | undefined;
|
|
6
|
+
include_prs_commented?: boolean | undefined;
|
|
7
|
+
include_prs_reviewed?: boolean | undefined;
|
|
8
|
+
include_issues_authored?: boolean | undefined;
|
|
9
|
+
include_issues_commented?: boolean | undefined;
|
|
10
|
+
}
|
|
3
11
|
/**
|
|
4
12
|
* Fetch the per-repository counts the REST search API answers, one request each.
|
|
5
13
|
*
|
|
6
|
-
* @param props Fetcher props.
|
|
7
|
-
* @param props.username GitHub username.
|
|
8
|
-
* @param props.repo Repositories the search is scoped to.
|
|
9
|
-
* @param props.owner Owners the search is scoped to.
|
|
10
|
-
* @param props.include_prs_authored Include count of PRs authored.
|
|
11
|
-
* @param props.include_prs_commented Include count of PRs commented.
|
|
12
|
-
* @param props.include_prs_reviewed Include count of PRs reviewed.
|
|
13
|
-
* @param props.include_issues_authored Include count of issues authored.
|
|
14
|
-
* @param props.include_issues_commented Include count of issues commented.
|
|
15
|
-
* @param config Deployment config supplying the PAT pool.
|
|
16
14
|
* @returns Only the counts that were asked for.
|
|
17
15
|
*/
|
|
18
|
-
declare const fetchRepoUserStats: ({ username, repo, owner,
|
|
16
|
+
declare const fetchRepoUserStats: ({ username, repo, owner, ...flags }: RepoUserStatsFlags & {
|
|
19
17
|
username: string;
|
|
20
18
|
repo?: Array<string>;
|
|
21
19
|
owner?: Array<string>;
|
|
22
|
-
include_prs_authored?: boolean | undefined;
|
|
23
|
-
include_prs_commented?: boolean | undefined;
|
|
24
|
-
include_prs_reviewed?: boolean | undefined;
|
|
25
|
-
include_issues_authored?: boolean | undefined;
|
|
26
|
-
include_issues_commented?: boolean | undefined;
|
|
27
20
|
}, config: CardConfig) => Promise<RepoUserStats>;
|
|
28
21
|
/**
|
|
29
22
|
* Fetch stats for a given username.
|
|
30
23
|
*
|
|
31
|
-
* @param props Fetcher props.
|
|
32
|
-
* @param props.username GitHub username.
|
|
33
|
-
* @param props.include_all_commits Include all commits.
|
|
34
|
-
* @param props.exclude_repo Repositories to exclude.
|
|
35
|
-
* @param props.include_merged_pull_requests Include merged pull requests.
|
|
36
|
-
* @param props.include_discussions Include discussions.
|
|
37
|
-
* @param props.include_discussions_answers Include discussions answers.
|
|
38
|
-
* @param props.commits_year Year to count total commits.
|
|
39
|
-
* @param props.repo Repositories to scope the REST search to.
|
|
40
|
-
* @param props.owner Owners to scope the REST search to.
|
|
41
|
-
* @param props.include_prs_authored Include count of PRs authored.
|
|
42
|
-
* @param props.include_prs_commented Include count of PRs commented.
|
|
43
|
-
* @param props.include_prs_reviewed Include count of PRs reviewed.
|
|
44
|
-
* @param props.include_issues_authored Include count of issues authored.
|
|
45
|
-
* @param props.include_issues_commented Include count of issues commented.
|
|
46
|
-
* @param props.ownerAffiliations Owner affiliations. Default: OWNER.
|
|
47
|
-
* @param props.include_contributions Include all-time contributions.
|
|
48
|
-
* @param props.include_all_time_contribs Include all-time count of repos contributed to.
|
|
49
|
-
* @param props.contribs_include_own_repos Include user-owned repos in contributed-to counts.
|
|
50
|
-
* @param config Deployment config supplying the PAT pool.
|
|
51
24
|
* @returns Stats data.
|
|
52
25
|
*/
|
|
53
|
-
declare const fetchStats: ({ username, include_all_commits, exclude_repo, include_merged_pull_requests, include_discussions, include_discussions_answers,
|
|
26
|
+
declare const fetchStats: ({ username, include_all_commits, exclude_repo, include_merged_pull_requests, include_discussions, include_discussions_answers, from, to, repo, owner, include_prs_authored, include_prs_commented, include_prs_reviewed, include_issues_authored, include_issues_commented, ownerAffiliations, include_contributions, include_all_time_contribs, contribs_include_own_repos, }: {
|
|
54
27
|
username: string | undefined;
|
|
55
28
|
include_all_commits?: boolean | undefined;
|
|
56
29
|
exclude_repo?: Array<string>;
|
|
57
30
|
include_merged_pull_requests?: boolean;
|
|
58
31
|
include_discussions?: boolean;
|
|
59
32
|
include_discussions_answers?: boolean;
|
|
60
|
-
|
|
33
|
+
/** Start of the range the commit count covers; GitHub's own last year when neither end is given. */
|
|
34
|
+
from?: Date | undefined;
|
|
35
|
+
/** End of that range. */
|
|
36
|
+
to?: Date | undefined;
|
|
61
37
|
repo?: Array<string>;
|
|
62
38
|
owner?: Array<string>;
|
|
63
39
|
include_prs_authored?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/fetchers/stats.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/fetchers/stats.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AA4BtD,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAoL3D,8EAA8E;AAC9E,UAAU,kBAAkB;IAC1B,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3C,qBAAqB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5C,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3C,uBAAuB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9C,wBAAwB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAChD;AAyBD;;;;GAIG;AACH,QAAA,MAAM,kBAAkB,wCAMnB,kBAAkB,GAAG;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACrB,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACvB,UACO,UAAU,KACjB,OAAO,CAAC,aAAa,CAWvB,CAAC;AA6CF;;;;GAIG;AACH,QAAA,MAAM,UAAU,mXAqBX;IACD,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,mBAAmB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1C,YAAY,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7B,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,oGAAoG;IACpG,IAAI,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IACxB,yBAAyB;IACzB,EAAE,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IACtB,IAAI,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACrB,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACtB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,iBAAiB,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAClC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,0BAA0B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAClD,UACO,UAAU,KACjB,OAAO,CAAC,SAAS,CAsKnB,CAAC;AAEF,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC"}
|
package/build/fetchers/stats.js
CHANGED
|
@@ -1,36 +1,27 @@
|
|
|
1
|
-
import githubUsernameRegex from 'github-username-regex';
|
|
2
1
|
import { calculateRank } from '../calculateRank.js';
|
|
3
|
-
import {
|
|
2
|
+
import { GITHUB_USERNAME_PATTERN } from '../common/constants.js';
|
|
3
|
+
import { getWidestRange, toContributionRanges, toGitHubDateTime, toRange, toYearRanges, } from '../common/date.js';
|
|
4
4
|
import { CardError, USER_NOT_FOUND } from '../common/error.js';
|
|
5
|
-
import { wrapTextMultiline } from '../common/fmt.js';
|
|
6
5
|
import { createGraphQLFetcher, httpRequest } from '../common/http.js';
|
|
7
6
|
import { logger } from '../common/log.js';
|
|
8
|
-
import { buildSearchFilter,
|
|
7
|
+
import { buildSearchFilter, parseOwnerAffiliations } from '../common/ops.js';
|
|
9
8
|
import { retryer } from '../common/retryer.js';
|
|
10
9
|
import { buildContributionsDocument } from '../graphql/contributionsDocument.js';
|
|
11
10
|
import { UserInfoDocument, UserReposDocument } from '../graphql/generated/stats.js';
|
|
12
|
-
import {
|
|
11
|
+
import { fetchReposContributedTo } from './contributed-to.js';
|
|
12
|
+
import { graphqlError } from './graphql-error.js';
|
|
13
13
|
const fetcher = createGraphQLFetcher(UserInfoDocument, 'bearer');
|
|
14
14
|
/** Fetcher for the pages after the first, which only need `repositories`. */
|
|
15
15
|
const reposFetcher = createGraphQLFetcher(UserReposDocument, 'bearer');
|
|
16
16
|
/**
|
|
17
17
|
* Fetch stats information for a given username.
|
|
18
18
|
*
|
|
19
|
-
* @param variables Fetcher variables.
|
|
20
|
-
* @param variables.username GitHub username.
|
|
21
|
-
* @param variables.includeMergedPullRequests Include merged pull requests.
|
|
22
|
-
* @param variables.includeDiscussions Include discussions.
|
|
23
|
-
* @param variables.includeDiscussionsAnswers Include discussions answers.
|
|
24
|
-
* @param variables.startTime Time to start the count of total commits.
|
|
25
|
-
* @param variables.ownerAffiliations The owner affiliations to filter by. Default: OWNER.
|
|
26
|
-
* @param variables.includeUserRepositories Whether to include the user's own repositories in the repos contributed to.
|
|
27
|
-
* @param config Deployment config supplying the PAT pool.
|
|
28
|
-
* @returns The stats response, with every fetched page's repos merged in.
|
|
29
|
-
*
|
|
30
19
|
* @description Supports multi-page fetching when the `FETCH_MULTI_PAGE_STARS`
|
|
31
20
|
* env variable is `true` or a fetch limit.
|
|
21
|
+
*
|
|
22
|
+
* @returns The stats response, with every fetched page's repos merged in.
|
|
32
23
|
*/
|
|
33
|
-
const statsFetcher = async ({ username, includeMergedPullRequests, includeDiscussions, includeDiscussionsAnswers,
|
|
24
|
+
const statsFetcher = async ({ username, includeMergedPullRequests, includeDiscussions, includeDiscussionsAnswers, commitsRange, ownerAffiliations, includeUserRepositories, }, config) => {
|
|
34
25
|
// only the first request carries the stats themselves
|
|
35
26
|
let stats = await retryer(fetcher, {
|
|
36
27
|
login: username,
|
|
@@ -38,7 +29,9 @@ const statsFetcher = async ({ username, includeMergedPullRequests, includeDiscus
|
|
|
38
29
|
includeMergedPullRequests,
|
|
39
30
|
includeDiscussions,
|
|
40
31
|
includeDiscussionsAnswers,
|
|
41
|
-
|
|
32
|
+
// both ends together: an open `to` would run the range into the next 1st of January
|
|
33
|
+
startTime: commitsRange && toGitHubDateTime(commitsRange.from),
|
|
34
|
+
endTime: commitsRange && toGitHubDateTime(commitsRange.to),
|
|
42
35
|
ownerAffiliations,
|
|
43
36
|
includeUserRepositories,
|
|
44
37
|
}, config);
|
|
@@ -69,10 +62,10 @@ const statsFetcher = async ({ username, includeMergedPullRequests, includeDiscus
|
|
|
69
62
|
}
|
|
70
63
|
pageRepositories = page.data.data.user?.repositories;
|
|
71
64
|
extraRepoNodes.push(...(pageRepositories?.nodes ?? []));
|
|
72
|
-
fetchedPages
|
|
65
|
+
fetchedPages += 1;
|
|
73
66
|
}
|
|
74
67
|
if (extraRepoNodes.length > 0) {
|
|
75
|
-
//
|
|
68
|
+
// defensive: the merge below is the only place a parsed response is mutated
|
|
76
69
|
stats = structuredClone({
|
|
77
70
|
data: stats.data,
|
|
78
71
|
statusText: stats.statusText,
|
|
@@ -84,48 +77,29 @@ const statsFetcher = async ({ username, includeMergedPullRequests, includeDiscus
|
|
|
84
77
|
/**
|
|
85
78
|
* Fetch total items count using the REST search API.
|
|
86
79
|
*
|
|
87
|
-
* @param variables Fetcher variables.
|
|
88
|
-
* @param token GitHub token.
|
|
89
|
-
* @param context What the retryer supplies each attempt.
|
|
90
|
-
* @param context.fetch Transport to send the request with.
|
|
91
|
-
* @returns The search response, carrying `total_count`.
|
|
92
|
-
*
|
|
93
80
|
* @see https://developer.github.com/v3/search/#search-commits
|
|
81
|
+
*
|
|
82
|
+
* @returns The search response, carrying `total_count`.
|
|
94
83
|
*/
|
|
95
|
-
const fetchTotalItems = (
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
method: 'GET',
|
|
104
|
-
headers: {
|
|
105
|
-
'Content-Type': 'application/json',
|
|
106
|
-
Accept: 'application/vnd.github.cloak-preview',
|
|
107
|
-
Authorization: `token ${token}`,
|
|
108
|
-
},
|
|
109
|
-
});
|
|
110
|
-
};
|
|
84
|
+
const fetchTotalItems = ({ type, filter, repo, owner }, token, { fetch }) => httpRequest(fetch, `https://api.github.com/search/${type}?per_page=1&q=${buildSearchFilter(repo, owner).replaceAll(' ', '+')}${filter}`, {
|
|
85
|
+
method: 'GET',
|
|
86
|
+
headers: {
|
|
87
|
+
'Content-Type': 'application/json',
|
|
88
|
+
Accept: 'application/vnd.github.cloak-preview',
|
|
89
|
+
Authorization: `token ${token}`,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
111
92
|
/**
|
|
112
93
|
* Fetch a total count for a given username via the REST search API.
|
|
113
94
|
*
|
|
114
|
-
* @param props Fetcher props.
|
|
115
|
-
* @param props.username GitHub username.
|
|
116
|
-
* @param props.repo Repositories the search is scoped to.
|
|
117
|
-
* @param props.owner Owners the search is scoped to.
|
|
118
|
-
* @param props.type Search endpoint to hit, `issues` or `commits`.
|
|
119
|
-
* @param props.filter Query fragment appended to the scope filter.
|
|
120
|
-
* @param config Deployment config supplying the PAT pool.
|
|
121
|
-
* @returns Total count.
|
|
122
|
-
*
|
|
123
95
|
* The GraphQL API can't return this.
|
|
124
96
|
* @see https://github.com/anuraghazra/github-readme-stats/issues/92#issuecomment-661026467
|
|
125
97
|
* @see https://github.com/anuraghazra/github-readme-stats/pull/211
|
|
98
|
+
*
|
|
99
|
+
* @returns Total count.
|
|
126
100
|
*/
|
|
127
|
-
const totalItemsFetcher = async ({ username,
|
|
128
|
-
if (!
|
|
101
|
+
const totalItemsFetcher = async ({ username, ...search }, config) => {
|
|
102
|
+
if (!GITHUB_USERNAME_PATTERN.test(username)) {
|
|
129
103
|
logger.log('Invalid username provided.');
|
|
130
104
|
throw new CardError('Invalid username provided.', {
|
|
131
105
|
code: 'invalid_param',
|
|
@@ -134,242 +108,90 @@ const totalItemsFetcher = async ({ username, repo, owner, type, filter, }, confi
|
|
|
134
108
|
}
|
|
135
109
|
let res;
|
|
136
110
|
try {
|
|
137
|
-
res = await retryer(fetchTotalItems,
|
|
111
|
+
res = await retryer(fetchTotalItems, search, config);
|
|
138
112
|
}
|
|
139
|
-
catch (
|
|
140
|
-
logger.log(
|
|
141
|
-
throw
|
|
113
|
+
catch (error) {
|
|
114
|
+
logger.log(error);
|
|
115
|
+
throw error;
|
|
142
116
|
}
|
|
143
117
|
const totalCount = res.data.total_count;
|
|
144
|
-
if (totalCount
|
|
145
|
-
logger.error(
|
|
118
|
+
if (typeof totalCount !== 'number' || Number.isNaN(totalCount)) {
|
|
119
|
+
logger.error(`GitHub error: ${JSON.stringify(res.data)}`);
|
|
146
120
|
throw new CardError('Could not fetch data from GitHub REST API.', {
|
|
147
121
|
code: 'upstream',
|
|
148
122
|
});
|
|
149
123
|
}
|
|
150
124
|
return totalCount;
|
|
151
125
|
};
|
|
126
|
+
/** Each count the REST search API answers: the flag asking for it, and the qualifiers that find it. */
|
|
127
|
+
const REPO_USER_SEARCHES = [
|
|
128
|
+
['include_prs_authored', 'totalPRsAuthored', (username) => `author:${username}+type:pr`],
|
|
129
|
+
[
|
|
130
|
+
'include_prs_commented',
|
|
131
|
+
'totalPRsCommented',
|
|
132
|
+
(username) => `commenter:${username}+-author:${username}+type:pr`,
|
|
133
|
+
],
|
|
134
|
+
[
|
|
135
|
+
'include_prs_reviewed',
|
|
136
|
+
'totalPRsReviewed',
|
|
137
|
+
(username) => `reviewed-by:${username}+-author:${username}+type:pr`,
|
|
138
|
+
],
|
|
139
|
+
['include_issues_authored', 'totalIssuesAuthored', (username) => `author:${username}+type:issue`],
|
|
140
|
+
[
|
|
141
|
+
'include_issues_commented',
|
|
142
|
+
'totalIssuesCommented',
|
|
143
|
+
(username) => `commenter:${username}+-author:${username}+type:issue`,
|
|
144
|
+
],
|
|
145
|
+
];
|
|
152
146
|
/**
|
|
153
147
|
* Fetch the per-repository counts the REST search API answers, one request each.
|
|
154
148
|
*
|
|
155
|
-
* @param props Fetcher props.
|
|
156
|
-
* @param props.username GitHub username.
|
|
157
|
-
* @param props.repo Repositories the search is scoped to.
|
|
158
|
-
* @param props.owner Owners the search is scoped to.
|
|
159
|
-
* @param props.include_prs_authored Include count of PRs authored.
|
|
160
|
-
* @param props.include_prs_commented Include count of PRs commented.
|
|
161
|
-
* @param props.include_prs_reviewed Include count of PRs reviewed.
|
|
162
|
-
* @param props.include_issues_authored Include count of issues authored.
|
|
163
|
-
* @param props.include_issues_commented Include count of issues commented.
|
|
164
|
-
* @param config Deployment config supplying the PAT pool.
|
|
165
149
|
* @returns Only the counts that were asked for.
|
|
166
150
|
*/
|
|
167
|
-
const fetchRepoUserStats = async ({ username, repo = [], owner = [],
|
|
151
|
+
const fetchRepoUserStats = async ({ username, repo = [], owner = [], ...flags }, config) => {
|
|
168
152
|
const stats = {};
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
username,
|
|
172
|
-
|
|
173
|
-
owner,
|
|
174
|
-
type: 'issues',
|
|
175
|
-
filter: `author:${username}+type:pr`,
|
|
176
|
-
}, config);
|
|
177
|
-
}
|
|
178
|
-
if (include_prs_commented) {
|
|
179
|
-
stats.totalPRsCommented = await totalItemsFetcher({
|
|
180
|
-
username,
|
|
181
|
-
repo,
|
|
182
|
-
owner,
|
|
183
|
-
type: 'issues',
|
|
184
|
-
filter: `commenter:${username}+-author:${username}+type:pr`,
|
|
185
|
-
}, config);
|
|
186
|
-
}
|
|
187
|
-
if (include_prs_reviewed) {
|
|
188
|
-
stats.totalPRsReviewed = await totalItemsFetcher({
|
|
189
|
-
username,
|
|
190
|
-
repo,
|
|
191
|
-
owner,
|
|
192
|
-
type: 'issues',
|
|
193
|
-
filter: `reviewed-by:${username}+-author:${username}+type:pr`,
|
|
194
|
-
}, config);
|
|
195
|
-
}
|
|
196
|
-
if (include_issues_authored) {
|
|
197
|
-
stats.totalIssuesAuthored = await totalItemsFetcher({
|
|
198
|
-
username,
|
|
199
|
-
repo,
|
|
200
|
-
owner,
|
|
201
|
-
type: 'issues',
|
|
202
|
-
filter: `author:${username}+type:issue`,
|
|
203
|
-
}, config);
|
|
204
|
-
}
|
|
205
|
-
if (include_issues_commented) {
|
|
206
|
-
stats.totalIssuesCommented = await totalItemsFetcher({
|
|
207
|
-
username,
|
|
208
|
-
repo,
|
|
209
|
-
owner,
|
|
210
|
-
type: 'issues',
|
|
211
|
-
filter: `commenter:${username}+-author:${username}+type:issue`,
|
|
212
|
-
}, config);
|
|
153
|
+
for (const [flag, stat, filter] of REPO_USER_SEARCHES) {
|
|
154
|
+
if (flags[flag]) {
|
|
155
|
+
stats[stat] = await totalItemsFetcher({ username, repo, owner, type: 'issues', filter: filter(username) }, config);
|
|
156
|
+
}
|
|
213
157
|
}
|
|
214
158
|
return stats;
|
|
215
159
|
};
|
|
216
160
|
/**
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
* @param errors Errors from the response envelope.
|
|
220
|
-
* @param statusText HTTP status text, used as the error type when GitHub gave a message.
|
|
221
|
-
* @param fallback Message when GitHub gave none.
|
|
222
|
-
*/
|
|
223
|
-
const graphqlError = (errors, statusText, fallback) => {
|
|
224
|
-
logger.error(errors);
|
|
225
|
-
const message = errors[0]?.message;
|
|
226
|
-
return message
|
|
227
|
-
? new CardError(wrapTextMultiline(message, 525, 12)[0] ?? '', {
|
|
228
|
-
code: 'upstream',
|
|
229
|
-
secondaryMessage: statusText,
|
|
230
|
-
})
|
|
231
|
-
: new CardError(fallback, { code: 'upstream' });
|
|
232
|
-
};
|
|
233
|
-
/**
|
|
234
|
-
* Fetch all-time contributions by building a single GraphQL query
|
|
235
|
-
* for all the given years.
|
|
161
|
+
* Sum one figure over a set of ranges, fetched as aliased fields of a single query.
|
|
236
162
|
*
|
|
237
163
|
* Whether private contributions are included depends on the user's profile settings:
|
|
238
164
|
* https://docs.github.com/en/account-and-profile/how-tos/contribution-settings/manage-visibility-settings-for-private-contributions-and-achievements#changing-the-visibility-of-your-private-contributions
|
|
165
|
+
*
|
|
166
|
+
* @returns The total over every range, and 0 when there are none.
|
|
239
167
|
*/
|
|
240
|
-
const
|
|
241
|
-
|
|
168
|
+
const sumOverRanges = async (username, ranges,
|
|
169
|
+
/** What one range contributes to the total. */
|
|
170
|
+
pick, config) => {
|
|
171
|
+
if (ranges.length === 0) {
|
|
242
172
|
return 0;
|
|
243
173
|
}
|
|
244
|
-
const contributionsFetcher = createGraphQLFetcher(buildContributionsDocument(
|
|
174
|
+
const contributionsFetcher = createGraphQLFetcher(buildContributionsDocument(ranges), 'bearer');
|
|
245
175
|
const contribRes = await retryer(contributionsFetcher, { login: username }, config);
|
|
246
176
|
if (contribRes.data.errors) {
|
|
247
177
|
throw graphqlError(contribRes.data.errors, contribRes.statusText, 'Something went wrong while trying to retrieve the contributions data using the GraphQL API.');
|
|
248
178
|
}
|
|
249
|
-
const user = contribRes.data.data
|
|
179
|
+
const { user } = contribRes.data.data;
|
|
250
180
|
if (!user) {
|
|
251
181
|
return 0;
|
|
252
182
|
}
|
|
253
183
|
let total = 0;
|
|
254
|
-
for (const
|
|
255
|
-
|
|
256
|
-
if (yearBlock?.contributionCalendar.totalContributions) {
|
|
257
|
-
total += yearBlock.contributionCalendar.totalContributions;
|
|
258
|
-
}
|
|
184
|
+
for (const block of Object.values(user)) {
|
|
185
|
+
total += pick(block);
|
|
259
186
|
}
|
|
260
187
|
return total;
|
|
261
188
|
};
|
|
262
|
-
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
263
|
-
/**
|
|
264
|
-
* Ranges per request.
|
|
265
|
-
* Each costs roughly `4 * MAX_REPOSITORIES_LIMIT` nodes,
|
|
266
|
-
* so an unchunked round of a heavily split account would breach GitHub's 500k node ceiling
|
|
267
|
-
* and lose the ranges that had already resolved along with it.
|
|
268
|
-
*/
|
|
269
|
-
const MAX_RANGES_PER_REQUEST = 100;
|
|
270
|
-
const REPOS_CONTRIBUTED_TO_ERROR = 'Something went wrong while trying to retrieve the repository contributions data using the GraphQL API.';
|
|
271
|
-
/**
|
|
272
|
-
* Count the repositories a user contributed to across every contribution year.
|
|
273
|
-
*
|
|
274
|
-
* `repositoriesContributedTo` spans at most one year,
|
|
275
|
-
* so every year is fetched as an aliased `contributionsCollection(from, to)` in one request and the repos de-duplicated.
|
|
276
|
-
* A range returning `MAX_REPOSITORIES_LIMIT` results may have more,
|
|
277
|
-
* so it is halved and requeried in the next round.
|
|
278
|
-
*
|
|
279
|
-
* Whether private contributions are included depends on the used PAT.
|
|
280
|
-
*
|
|
281
|
-
* @param canonicalUsername Username as GitHub reports it; `nameWithOwner` uses its
|
|
282
|
-
* casing, which the raw query-string username need not match.
|
|
283
|
-
* @param years Contribution years to walk.
|
|
284
|
-
* @param includeOwnRepos Whether to count the user's own repositories.
|
|
285
|
-
* @param config Deployment config supplying the PAT pool.
|
|
286
|
-
* @returns Count of repositories.
|
|
287
|
-
*/
|
|
288
|
-
const fetchAllTimeReposContributedTo = async (canonicalUsername, years, includeOwnRepos, config) => {
|
|
289
|
-
const repos = new Set();
|
|
290
|
-
let pending = years.map(getGitHubYearRange);
|
|
291
|
-
while (pending.length > 0) {
|
|
292
|
-
const nextPending = [];
|
|
293
|
-
for (const chunk of chunkArray(pending, MAX_RANGES_PER_REQUEST)) {
|
|
294
|
-
const fetcher = createGraphQLFetcher(buildReposContributedToDocument(chunk, includeOwnRepos), 'bearer');
|
|
295
|
-
const res = await retryer(fetcher, { login: canonicalUsername, maxRepositories: MAX_REPOSITORIES_LIMIT }, config);
|
|
296
|
-
if (res.data.errors) {
|
|
297
|
-
throw graphqlError(res.data.errors, res.statusText, REPOS_CONTRIBUTED_TO_ERROR);
|
|
298
|
-
}
|
|
299
|
-
const user = res.data.data.user;
|
|
300
|
-
if (!user) {
|
|
301
|
-
throw new CardError(REPOS_CONTRIBUTED_TO_ERROR, { code: 'upstream' });
|
|
302
|
-
}
|
|
303
|
-
for (const [index, range] of chunk.entries()) {
|
|
304
|
-
const rangeResponse = user[`range_${index}`];
|
|
305
|
-
if (!rangeResponse) {
|
|
306
|
-
throw new CardError(REPOS_CONTRIBUTED_TO_ERROR, {
|
|
307
|
-
code: 'upstream',
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
const lists = [
|
|
311
|
-
rangeResponse.commitContributionsByRepository,
|
|
312
|
-
rangeResponse.issueContributionsByRepository,
|
|
313
|
-
rangeResponse.pullRequestContributionsByRepository,
|
|
314
|
-
(rangeResponse.repositoryContributions?.nodes ?? []).filter((node) => node !== null),
|
|
315
|
-
];
|
|
316
|
-
const isSaturated = lists.some((list) => list.length >= MAX_REPOSITORIES_LIMIT);
|
|
317
|
-
const rangeDays = Math.round((range.to.getTime() - range.from.getTime()) / MS_PER_DAY);
|
|
318
|
-
// a range of 1 day or less can't be split any further
|
|
319
|
-
if (isSaturated && rangeDays >= 2) {
|
|
320
|
-
// every `from` sits on UTC midnight, so the split lands on a day boundary too
|
|
321
|
-
const mid = new Date(range.from.getTime() + Math.floor(rangeDays / 2) * MS_PER_DAY);
|
|
322
|
-
// GitHub only reads the date portion,
|
|
323
|
-
// so the first half ends 1 second before `mid` to keep the halves from sharing a day
|
|
324
|
-
nextPending.push({ from: range.from, to: new Date(mid.getTime() - 1000) }, { from: mid, to: range.to });
|
|
325
|
-
continue;
|
|
326
|
-
}
|
|
327
|
-
if (isSaturated) {
|
|
328
|
-
logger.log(`Range ${range.from.toISOString()} - ${range.to.toISOString()} is saturated but cannot be split further.`);
|
|
329
|
-
}
|
|
330
|
-
for (const { repository } of lists.flat()) {
|
|
331
|
-
const name = repository.nameWithOwner;
|
|
332
|
-
if (includeOwnRepos || !name.startsWith(`${canonicalUsername}/`)) {
|
|
333
|
-
repos.add(name);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
// each saturated range pushes both of its halves
|
|
339
|
-
const saturatedCount = nextPending.length / 2;
|
|
340
|
-
if (saturatedCount > 0) {
|
|
341
|
-
logger.log(`found ${saturatedCount} saturated ranges, splitting and retrying...`);
|
|
342
|
-
}
|
|
343
|
-
pending = nextPending;
|
|
344
|
-
}
|
|
345
|
-
return repos.size;
|
|
346
|
-
};
|
|
347
189
|
/**
|
|
348
190
|
* Fetch stats for a given username.
|
|
349
191
|
*
|
|
350
|
-
* @param props Fetcher props.
|
|
351
|
-
* @param props.username GitHub username.
|
|
352
|
-
* @param props.include_all_commits Include all commits.
|
|
353
|
-
* @param props.exclude_repo Repositories to exclude.
|
|
354
|
-
* @param props.include_merged_pull_requests Include merged pull requests.
|
|
355
|
-
* @param props.include_discussions Include discussions.
|
|
356
|
-
* @param props.include_discussions_answers Include discussions answers.
|
|
357
|
-
* @param props.commits_year Year to count total commits.
|
|
358
|
-
* @param props.repo Repositories to scope the REST search to.
|
|
359
|
-
* @param props.owner Owners to scope the REST search to.
|
|
360
|
-
* @param props.include_prs_authored Include count of PRs authored.
|
|
361
|
-
* @param props.include_prs_commented Include count of PRs commented.
|
|
362
|
-
* @param props.include_prs_reviewed Include count of PRs reviewed.
|
|
363
|
-
* @param props.include_issues_authored Include count of issues authored.
|
|
364
|
-
* @param props.include_issues_commented Include count of issues commented.
|
|
365
|
-
* @param props.ownerAffiliations Owner affiliations. Default: OWNER.
|
|
366
|
-
* @param props.include_contributions Include all-time contributions.
|
|
367
|
-
* @param props.include_all_time_contribs Include all-time count of repos contributed to.
|
|
368
|
-
* @param props.contribs_include_own_repos Include user-owned repos in contributed-to counts.
|
|
369
|
-
* @param config Deployment config supplying the PAT pool.
|
|
370
192
|
* @returns Stats data.
|
|
371
193
|
*/
|
|
372
|
-
const fetchStats = async ({ username, include_all_commits = false, exclude_repo = [], include_merged_pull_requests = false, include_discussions = false, include_discussions_answers = false,
|
|
194
|
+
const fetchStats = async ({ username, include_all_commits = false, exclude_repo = [], include_merged_pull_requests = false, include_discussions = false, include_discussions_answers = false, from, to, repo = [], owner = [], include_prs_authored = false, include_prs_commented = false, include_prs_reviewed = false, include_issues_authored = false, include_issues_commented = false, ownerAffiliations = [], include_contributions = false, include_all_time_contribs = false, contribs_include_own_repos = false, }, config) => {
|
|
373
195
|
if (!username) {
|
|
374
196
|
throw CardError.missingParam(['username']);
|
|
375
197
|
}
|
|
@@ -380,6 +202,7 @@ const fetchStats = async ({ username, include_all_commits = false, exclude_repo
|
|
|
380
202
|
mergedPRsPercentage: 0,
|
|
381
203
|
totalReviews: 0,
|
|
382
204
|
totalCommits: 0,
|
|
205
|
+
commitsRange: undefined,
|
|
383
206
|
totalIssues: 0,
|
|
384
207
|
totalStars: 0,
|
|
385
208
|
totalDiscussionsStarted: 0,
|
|
@@ -395,36 +218,24 @@ const fetchStats = async ({ username, include_all_commits = false, exclude_repo
|
|
|
395
218
|
rank: { level: 'C', percentile: 100 },
|
|
396
219
|
};
|
|
397
220
|
const affiliations = parseOwnerAffiliations(ownerAffiliations);
|
|
221
|
+
// neither end given leaves GitHub's trailing year in place, which `userInfo` already carries
|
|
222
|
+
const commitsRange = from === undefined && to === undefined ? undefined : toRange(from, to);
|
|
223
|
+
const commitsYearRanges = commitsRange ? toYearRanges(commitsRange) : [];
|
|
224
|
+
// one calendar year is a range `userInfo` can ask for itself; anything else is summed separately
|
|
225
|
+
const inlineRange = commitsYearRanges.length === 1 ? commitsYearRanges[0] : undefined;
|
|
398
226
|
const res = await statsFetcher({
|
|
399
227
|
username,
|
|
400
228
|
includeMergedPullRequests: include_merged_pull_requests,
|
|
401
229
|
includeDiscussions: include_discussions,
|
|
402
230
|
includeDiscussionsAnswers: include_discussions_answers,
|
|
403
|
-
|
|
404
|
-
? undefined
|
|
405
|
-
: toGitHubDateTime(getGitHubYearRange(commits_year).from),
|
|
231
|
+
commitsRange: inlineRange,
|
|
406
232
|
ownerAffiliations: affiliations,
|
|
407
233
|
includeUserRepositories: contribs_include_own_repos,
|
|
408
234
|
}, config);
|
|
409
|
-
// Catch GraphQL errors.
|
|
410
235
|
if (res.data.errors) {
|
|
411
|
-
|
|
412
|
-
const firstError = res.data.errors[0];
|
|
413
|
-
if (firstError?.type === 'NOT_FOUND') {
|
|
414
|
-
throw new CardError(firstError.message || 'Could not fetch user.', {
|
|
415
|
-
code: 'not_found',
|
|
416
|
-
secondaryMessage: USER_NOT_FOUND,
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
if (firstError?.message) {
|
|
420
|
-
throw new CardError(wrapTextMultiline(firstError.message, 525, 12)[0] ?? '', {
|
|
421
|
-
code: 'upstream',
|
|
422
|
-
secondaryMessage: res.statusText,
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
throw new CardError('Something went wrong while trying to retrieve the stats data using the GraphQL API.', { code: 'upstream' });
|
|
236
|
+
throw graphqlError(res.data.errors, res.statusText, 'Something went wrong while trying to retrieve the stats data using the GraphQL API.');
|
|
426
237
|
}
|
|
427
|
-
const user = res.data.data
|
|
238
|
+
const { user } = res.data.data;
|
|
428
239
|
if (!user) {
|
|
429
240
|
throw new CardError('Could not fetch user.', {
|
|
430
241
|
code: 'not_found',
|
|
@@ -443,7 +254,12 @@ const fetchStats = async ({ username, include_all_commits = false, exclude_repo
|
|
|
443
254
|
}, config);
|
|
444
255
|
}
|
|
445
256
|
else {
|
|
446
|
-
stats.
|
|
257
|
+
stats.commitsRange = commitsRange;
|
|
258
|
+
// an inverted range sums no years, which is no commits rather than GitHub's default year
|
|
259
|
+
stats.totalCommits =
|
|
260
|
+
commitsRange && !inlineRange
|
|
261
|
+
? await sumOverRanges(username, commitsYearRanges, (block) => block.totalCommitContributions, config)
|
|
262
|
+
: user.commits.totalCommitContributions;
|
|
447
263
|
}
|
|
448
264
|
const repoUserStats = await fetchRepoUserStats({
|
|
449
265
|
username,
|
|
@@ -471,11 +287,13 @@ const fetchStats = async ({ username, include_all_commits = false, exclude_repo
|
|
|
471
287
|
stats.totalDiscussionsAnswered = user.repositoryDiscussionComments?.totalCount ?? 0;
|
|
472
288
|
}
|
|
473
289
|
stats.contributedTo = user.repositoriesContributedTo.totalCount;
|
|
290
|
+
const contributionRanges = toContributionRanges(user.contributionsCollection.contributionYears, getWidestRange());
|
|
474
291
|
if (include_contributions) {
|
|
475
|
-
stats.totalContributions = await
|
|
292
|
+
stats.totalContributions = await sumOverRanges(username, contributionRanges, (block) => block.contributionCalendar.totalContributions, config);
|
|
476
293
|
}
|
|
477
294
|
if (include_all_time_contribs) {
|
|
478
|
-
|
|
295
|
+
const reposContributedTo = await fetchReposContributedTo(user.login, contributionRanges, contribs_include_own_repos, config);
|
|
296
|
+
stats.allTimeContributedTo = reposContributedTo.size;
|
|
479
297
|
}
|
|
480
298
|
// Retrieve stars while filtering out repositories to be hidden.
|
|
481
299
|
const allExcludedRepos = [...exclude_repo, ...config.excludeRepositories];
|
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
import type { CardConfig } from '../common/config.
|
|
2
|
-
import type { TopLangData } from './types.
|
|
1
|
+
import type { CardConfig } from '../common/config.ts';
|
|
2
|
+
import type { TopLangData } from './types.ts';
|
|
3
3
|
/**
|
|
4
4
|
* Fetch top languages for a given username.
|
|
5
5
|
*
|
|
6
|
-
* @param props Fetcher props.
|
|
7
|
-
* @param props.username GitHub username.
|
|
8
|
-
* @param props.exclude_repo List of repositories to exclude. Default: [].
|
|
9
|
-
* @param props.size_weight Weightage to be given to size.
|
|
10
|
-
* @param props.count_weight Weightage to be given to count.
|
|
11
|
-
* @param props.ownerAffiliations The owner affiliations to filter by. Default: OWNER.
|
|
12
|
-
* @param config Deployment config supplying the PAT pool.
|
|
13
6
|
* @returns Top languages data.
|
|
14
7
|
*/
|
|
15
8
|
declare const fetchTopLanguages: ({ username, exclude_repo, size_weight, count_weight, ownerAffiliations, }: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"top-languages.d.ts","sourceRoot":"","sources":["../../src/fetchers/top-languages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"top-languages.d.ts","sourceRoot":"","sources":["../../src/fetchers/top-languages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAYtD,OAAO,KAAK,EAAQ,WAAW,EAAE,MAAM,YAAY,CAAC;AAIpD;;;;GAIG;AACH,QAAA,MAAM,iBAAiB,8EAOlB;IACD,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,YAAY,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,iBAAiB,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACnC,UACO,UAAU,KACjB,OAAO,CAAC,WAAW,CAmErB,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
|