@stoked-ui/github 0.0.0-a.0 → 0.1.0-alpha.11.2
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/GithubBranch/GithubBranch.d.ts +12 -0
- package/GithubBranch/GithubBranch.js +177 -0
- package/GithubBranch/index.d.ts +2 -0
- package/GithubBranch/index.js +2 -0
- package/GithubBranch/package.json +6 -0
- package/GithubCalendar/GithubCalendar.d.ts +6 -2
- package/GithubCalendar/GithubCalendar.js +70 -28
- package/GithubCommit/GithubCommit.d.ts +11 -0
- package/GithubCommit/GithubCommit.js +170 -0
- package/GithubCommit/index.d.ts +2 -0
- package/GithubCommit/index.js +2 -0
- package/GithubCommit/package.json +6 -0
- package/GithubEvents/EventTypes/PullRequest/PullRequestEvent.js +1 -1
- package/GithubEvents/GithubEvents.d.ts +4 -24
- package/GithubEvents/GithubEvents.js +141 -220
- package/apiHandlers/createGithubBranchHandler.d.ts +12 -0
- package/apiHandlers/createGithubBranchHandler.js +41 -0
- package/apiHandlers/createGithubCommitHandler.d.ts +12 -0
- package/apiHandlers/createGithubCommitHandler.js +39 -0
- package/apiHandlers/createGithubContributionsHandler.d.ts +15 -0
- package/apiHandlers/createGithubContributionsHandler.js +41 -0
- package/apiHandlers/createGithubEventsHandler.d.ts +15 -0
- package/apiHandlers/createGithubEventsHandler.js +50 -0
- package/apiHandlers/getBranchCompareDetails.d.ts +9 -0
- package/apiHandlers/getBranchCompareDetails.js +29 -0
- package/apiHandlers/getCommitDetails.d.ts +8 -0
- package/apiHandlers/getCommitDetails.js +34 -0
- package/apiHandlers/getGithubContributions.d.ts +8 -0
- package/apiHandlers/getGithubContributions.js +126 -0
- package/apiHandlers/getGithubEvents.d.ts +25 -0
- package/apiHandlers/getGithubEvents.js +142 -0
- package/apiHandlers/getPullRequestDetails.js +2 -2
- package/apiHandlers/githubApi.d.ts +17 -0
- package/apiHandlers/githubApi.js +155 -0
- package/apiHandlers/index.d.ts +9 -0
- package/apiHandlers/index.js +9 -1
- package/components/GithubContributorsList.d.ts +8 -0
- package/components/GithubContributorsList.js +72 -0
- package/components/fetchGithubViewData.d.ts +1 -0
- package/components/fetchGithubViewData.js +10 -0
- package/index.d.ts +7 -3
- package/index.js +6 -4
- package/modern/GithubBranch/GithubBranch.js +177 -0
- package/modern/GithubBranch/index.js +2 -0
- package/modern/GithubCalendar/GithubCalendar.js +70 -28
- package/modern/GithubCommit/GithubCommit.js +170 -0
- package/modern/GithubCommit/index.js +2 -0
- package/modern/GithubEvents/EventTypes/PullRequest/PullRequestEvent.js +1 -1
- package/modern/GithubEvents/GithubEvents.js +141 -220
- package/modern/apiHandlers/createGithubBranchHandler.js +41 -0
- package/modern/apiHandlers/createGithubCommitHandler.js +39 -0
- package/modern/apiHandlers/createGithubContributionsHandler.js +41 -0
- package/modern/apiHandlers/createGithubEventsHandler.js +50 -0
- package/modern/apiHandlers/getBranchCompareDetails.js +29 -0
- package/modern/apiHandlers/getCommitDetails.js +34 -0
- package/modern/apiHandlers/getGithubContributions.js +126 -0
- package/modern/apiHandlers/getGithubEvents.js +142 -0
- package/modern/apiHandlers/getPullRequestDetails.js +2 -2
- package/modern/apiHandlers/githubApi.js +155 -0
- package/modern/apiHandlers/index.js +9 -1
- package/modern/components/GithubContributorsList.js +72 -0
- package/modern/components/fetchGithubViewData.js +10 -0
- package/modern/index.js +6 -4
- package/node/GithubBranch/GithubBranch.js +185 -0
- package/node/GithubBranch/index.js +9 -0
- package/node/GithubCalendar/GithubCalendar.js +70 -28
- package/node/GithubCommit/GithubCommit.js +178 -0
- package/node/GithubCommit/index.js +9 -0
- package/node/GithubEvents/EventTypes/PullRequest/PullRequestEvent.js +1 -1
- package/node/GithubEvents/GithubEvents.js +148 -223
- package/node/apiHandlers/createGithubBranchHandler.js +48 -0
- package/node/apiHandlers/createGithubCommitHandler.js +46 -0
- package/node/apiHandlers/createGithubContributionsHandler.js +48 -0
- package/node/apiHandlers/createGithubEventsHandler.js +57 -0
- package/node/apiHandlers/getBranchCompareDetails.js +35 -0
- package/node/apiHandlers/getCommitDetails.js +40 -0
- package/node/apiHandlers/getGithubContributions.js +132 -0
- package/node/apiHandlers/getGithubEvents.js +149 -0
- package/node/apiHandlers/getPullRequestDetails.js +2 -2
- package/node/apiHandlers/githubApi.js +168 -0
- package/node/apiHandlers/index.js +64 -1
- package/node/components/GithubContributorsList.js +80 -0
- package/node/components/fetchGithubViewData.js +16 -0
- package/node/index.js +77 -2
- package/package.json +2 -5
- package/stoked-ui-github-0.1.0-alpha.11.2.tgz +0 -0
- package/types/github.d.ts +75 -11
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = createGithubEventsHandler;
|
|
8
|
+
var _getGithubEvents = _interopRequireDefault(require("./getGithubEvents"));
|
|
9
|
+
function getQueryValue(value) {
|
|
10
|
+
return Array.isArray(value) ? value[0] : value;
|
|
11
|
+
}
|
|
12
|
+
function parseNumber(value, fallback) {
|
|
13
|
+
const parsed = Number(getQueryValue(value));
|
|
14
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
15
|
+
}
|
|
16
|
+
function createGithubEventsHandler(config = {}) {
|
|
17
|
+
return async function handler(req, res) {
|
|
18
|
+
if (req.method !== 'GET') {
|
|
19
|
+
var _res$setHeader;
|
|
20
|
+
(_res$setHeader = res.setHeader) == null || _res$setHeader.call(res, 'Allow', 'GET');
|
|
21
|
+
return res.status(405).json({
|
|
22
|
+
message: 'Method not allowed'
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
const githubUser = getQueryValue(req.query.username);
|
|
26
|
+
if (!githubUser) {
|
|
27
|
+
return res.status(400).json({
|
|
28
|
+
message: 'username is required'
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
const query = {
|
|
32
|
+
page: parseNumber(req.query.page, 1),
|
|
33
|
+
per_page: parseNumber(req.query.per_page, 40),
|
|
34
|
+
repo: getQueryValue(req.query.repo) || undefined,
|
|
35
|
+
action: getQueryValue(req.query.action) || undefined,
|
|
36
|
+
date: getQueryValue(req.query.date) || undefined,
|
|
37
|
+
description: getQueryValue(req.query.description) || undefined
|
|
38
|
+
};
|
|
39
|
+
try {
|
|
40
|
+
var _config$getGithubToke, _res$setHeader2;
|
|
41
|
+
const githubToken = ((_config$getGithubToke = config.getGithubToken) == null ? void 0 : _config$getGithubToke.call(config, req)) || process.env.GITHUB_TOKEN;
|
|
42
|
+
const data = await (0, _getGithubEvents.default)({
|
|
43
|
+
query,
|
|
44
|
+
githubUser,
|
|
45
|
+
githubToken
|
|
46
|
+
});
|
|
47
|
+
(_res$setHeader2 = res.setHeader) == null || _res$setHeader2.call(res, 'Cache-Control', 's-maxage=300, stale-while-revalidate=3600');
|
|
48
|
+
return res.status(200).json(data);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
51
|
+
const status = message.includes('username is required') ? 400 : 502;
|
|
52
|
+
return res.status(status).json({
|
|
53
|
+
message
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = getBranchCompareDetails;
|
|
7
|
+
var _githubApi = require("./githubApi");
|
|
8
|
+
async function getBranchCompareDetails(params) {
|
|
9
|
+
const {
|
|
10
|
+
owner,
|
|
11
|
+
repo,
|
|
12
|
+
base,
|
|
13
|
+
head
|
|
14
|
+
} = params;
|
|
15
|
+
if (!owner || !repo || !base || !head) {
|
|
16
|
+
throw new Error('Missing required parameters: owner, repo, base, head');
|
|
17
|
+
}
|
|
18
|
+
const compare = await (0, _githubApi.fetchGithubResource)(`/repos/${owner}/${repo}/compare/${encodeURIComponent(base)}...${encodeURIComponent(head)}`);
|
|
19
|
+
const commits = (compare.commits || []).map(commit => (0, _githubApi.normalizeGithubCommit)(commit));
|
|
20
|
+
const files = (compare.files || []).map(file => (0, _githubApi.normalizeGithubFile)(file));
|
|
21
|
+
return {
|
|
22
|
+
repo: `${owner}/${repo}`,
|
|
23
|
+
baseRef: base,
|
|
24
|
+
headRef: head,
|
|
25
|
+
status: compare.status || 'unknown',
|
|
26
|
+
aheadBy: compare.ahead_by || 0,
|
|
27
|
+
behindBy: compare.behind_by || 0,
|
|
28
|
+
totalCommits: compare.total_commits || commits.length,
|
|
29
|
+
url: compare.html_url || `https://github.com/${owner}/${repo}/compare/${encodeURIComponent(base)}...${encodeURIComponent(head)}`,
|
|
30
|
+
contributors: (0, _githubApi.buildGithubContributors)(compare.commits || []),
|
|
31
|
+
commits,
|
|
32
|
+
files,
|
|
33
|
+
stats: (0, _githubApi.summarizeGithubStats)(files)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = getCommitDetails;
|
|
7
|
+
var _githubApi = require("./githubApi");
|
|
8
|
+
async function getCommitDetails(params) {
|
|
9
|
+
var _commit$commit, _commit$commit2, _commit$commit3, _commit$commit4;
|
|
10
|
+
const {
|
|
11
|
+
owner,
|
|
12
|
+
repo,
|
|
13
|
+
ref
|
|
14
|
+
} = params;
|
|
15
|
+
if (!owner || !repo || !ref) {
|
|
16
|
+
throw new Error('Missing required parameters: owner, repo, ref');
|
|
17
|
+
}
|
|
18
|
+
const commit = await (0, _githubApi.fetchGithubResource)(`/repos/${owner}/${repo}/commits/${encodeURIComponent(ref)}`);
|
|
19
|
+
const files = (commit.files || []).map(file => (0, _githubApi.normalizeGithubFile)(file));
|
|
20
|
+
const commits = [(0, _githubApi.normalizeGithubCommit)(commit)];
|
|
21
|
+
const contributor = (0, _githubApi.buildGithubContributors)([commit])[0] || {
|
|
22
|
+
login: commits[0].author.login,
|
|
23
|
+
name: commits[0].author.name,
|
|
24
|
+
avatarUrl: commits[0].author.avatar,
|
|
25
|
+
contributions: 1
|
|
26
|
+
};
|
|
27
|
+
return {
|
|
28
|
+
repo: `${owner}/${repo}`,
|
|
29
|
+
ref: commit.sha || ref,
|
|
30
|
+
shortRef: (0, _githubApi.getGithubShortRef)(commit.sha || ref),
|
|
31
|
+
url: commit.html_url || `https://github.com/${owner}/${repo}/commit/${encodeURIComponent(commit.sha || ref)}`,
|
|
32
|
+
summary: (0, _githubApi.getGithubMessageSummary)(((_commit$commit = commit.commit) == null ? void 0 : _commit$commit.message) || ''),
|
|
33
|
+
message: ((_commit$commit2 = commit.commit) == null ? void 0 : _commit$commit2.message) || '',
|
|
34
|
+
committedAt: ((_commit$commit3 = commit.commit) == null || (_commit$commit3 = _commit$commit3.author) == null ? void 0 : _commit$commit3.date) || ((_commit$commit4 = commit.commit) == null || (_commit$commit4 = _commit$commit4.committer) == null ? void 0 : _commit$commit4.date) || '',
|
|
35
|
+
contributor,
|
|
36
|
+
commits,
|
|
37
|
+
files,
|
|
38
|
+
stats: (0, _githubApi.summarizeGithubStats)(files)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = getGithubContributions;
|
|
7
|
+
const CONTRIBUTION_LEVEL_MAP = {
|
|
8
|
+
NONE: 0,
|
|
9
|
+
FIRST_QUARTILE: 1,
|
|
10
|
+
SECOND_QUARTILE: 2,
|
|
11
|
+
THIRD_QUARTILE: 3,
|
|
12
|
+
FOURTH_QUARTILE: 4
|
|
13
|
+
};
|
|
14
|
+
const GITHUB_CONTRIBUTIONS_QUERY = `
|
|
15
|
+
query GithubContributions($login: String!, $from: DateTime!, $to: DateTime!) {
|
|
16
|
+
user(login: $login) {
|
|
17
|
+
contributionsCollection(from: $from, to: $to) {
|
|
18
|
+
contributionCalendar {
|
|
19
|
+
totalContributions
|
|
20
|
+
weeks {
|
|
21
|
+
contributionDays {
|
|
22
|
+
date
|
|
23
|
+
contributionCount
|
|
24
|
+
contributionLevel
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
function isValidDateInput(value) {
|
|
33
|
+
if (!value) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return !Number.isNaN(new Date(value).getTime());
|
|
37
|
+
}
|
|
38
|
+
function toDateRange(from, to) {
|
|
39
|
+
const rangeEnd = isValidDateInput(to) ? new Date(to) : new Date();
|
|
40
|
+
const rangeStart = isValidDateInput(from) ? new Date(from) : new Date(rangeEnd);
|
|
41
|
+
if (!isValidDateInput(from)) {
|
|
42
|
+
rangeStart.setFullYear(rangeEnd.getFullYear() - 1);
|
|
43
|
+
}
|
|
44
|
+
if (rangeStart > rangeEnd) {
|
|
45
|
+
throw new Error('Invalid contribution range: "from" must be before "to".');
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
from: rangeStart,
|
|
49
|
+
to: rangeEnd
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function buildContributionTotals(contributions) {
|
|
53
|
+
return contributions.reduce((acc, contribution) => {
|
|
54
|
+
const year = contribution.date.slice(0, 4);
|
|
55
|
+
acc[year] = (acc[year] || 0) + contribution.count;
|
|
56
|
+
return acc;
|
|
57
|
+
}, {});
|
|
58
|
+
}
|
|
59
|
+
function buildCountLabel(total, from, to) {
|
|
60
|
+
const fromYear = from.getFullYear();
|
|
61
|
+
const toYear = to.getFullYear();
|
|
62
|
+
if (fromYear === toYear) {
|
|
63
|
+
return `${total} contributions in ${fromYear}`;
|
|
64
|
+
}
|
|
65
|
+
return `${total} contributions from ${fromYear} to ${toYear}`;
|
|
66
|
+
}
|
|
67
|
+
async function getGithubContributions({
|
|
68
|
+
githubUser,
|
|
69
|
+
githubToken = process.env.GITHUB_TOKEN,
|
|
70
|
+
from,
|
|
71
|
+
to
|
|
72
|
+
}) {
|
|
73
|
+
var _payload$errors2, _payload$data;
|
|
74
|
+
if (!githubUser) {
|
|
75
|
+
throw new Error('Missing required parameter: githubUser');
|
|
76
|
+
}
|
|
77
|
+
if (!githubToken) {
|
|
78
|
+
throw new Error('GitHub token not configured');
|
|
79
|
+
}
|
|
80
|
+
const range = toDateRange(from, to);
|
|
81
|
+
const response = await fetch('https://api.github.com/graphql', {
|
|
82
|
+
method: 'POST',
|
|
83
|
+
headers: {
|
|
84
|
+
'Content-Type': 'application/json',
|
|
85
|
+
'User-Agent': 'stoked-ui-github-calendar',
|
|
86
|
+
Authorization: `Bearer ${githubToken}`
|
|
87
|
+
},
|
|
88
|
+
body: JSON.stringify({
|
|
89
|
+
query: GITHUB_CONTRIBUTIONS_QUERY,
|
|
90
|
+
variables: {
|
|
91
|
+
login: githubUser,
|
|
92
|
+
from: range.from.toISOString(),
|
|
93
|
+
to: range.to.toISOString()
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
});
|
|
97
|
+
const payload = await response.json();
|
|
98
|
+
if (!response.ok) {
|
|
99
|
+
var _payload$errors;
|
|
100
|
+
const message = (payload == null ? void 0 : payload.message) || (payload == null || (_payload$errors = payload.errors) == null || (_payload$errors = _payload$errors[0]) == null ? void 0 : _payload$errors.message) || `GitHub GraphQL error: ${response.status}`;
|
|
101
|
+
throw new Error(message);
|
|
102
|
+
}
|
|
103
|
+
if (payload != null && (_payload$errors2 = payload.errors) != null && _payload$errors2.length) {
|
|
104
|
+
throw new Error(payload.errors.map(error => error.message || 'Unknown GitHub GraphQL error').join('; '));
|
|
105
|
+
}
|
|
106
|
+
const calendar = payload == null || (_payload$data = payload.data) == null || (_payload$data = _payload$data.user) == null || (_payload$data = _payload$data.contributionsCollection) == null ? void 0 : _payload$data.contributionCalendar;
|
|
107
|
+
if (!calendar) {
|
|
108
|
+
throw new Error(`No contribution calendar returned for "${githubUser}".`);
|
|
109
|
+
}
|
|
110
|
+
const contributions = (calendar.weeks || []).flatMap(week => week.contributionDays || []).map(day => {
|
|
111
|
+
var _CONTRIBUTION_LEVEL_M;
|
|
112
|
+
return {
|
|
113
|
+
date: day.date,
|
|
114
|
+
count: day.contributionCount,
|
|
115
|
+
level: (_CONTRIBUTION_LEVEL_M = CONTRIBUTION_LEVEL_MAP[day.contributionLevel]) != null ? _CONTRIBUTION_LEVEL_M : 0
|
|
116
|
+
};
|
|
117
|
+
}).sort((a, b) => {
|
|
118
|
+
if (a.date < b.date) {
|
|
119
|
+
return -1;
|
|
120
|
+
}
|
|
121
|
+
if (a.date > b.date) {
|
|
122
|
+
return 1;
|
|
123
|
+
}
|
|
124
|
+
return 0;
|
|
125
|
+
});
|
|
126
|
+
const total = buildContributionTotals(contributions);
|
|
127
|
+
return {
|
|
128
|
+
total,
|
|
129
|
+
contributions,
|
|
130
|
+
countLabel: buildCountLabel(calendar.totalContributions || 0, range.from, range.to)
|
|
131
|
+
};
|
|
132
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
exports.githubEventsQuery = githubEventsQuery;
|
|
8
|
+
function parseLinkHeader(header) {
|
|
9
|
+
if (!header) return {};
|
|
10
|
+
return header.split(',').reduce((links, part) => {
|
|
11
|
+
const match = part.match(/<(.+)>;\s*rel="([\w]+)"/);
|
|
12
|
+
if (match) {
|
|
13
|
+
const [, url, rel] = match;
|
|
14
|
+
if (rel === 'next' || rel === 'last') {
|
|
15
|
+
links[rel] = url;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return links;
|
|
19
|
+
}, {});
|
|
20
|
+
}
|
|
21
|
+
async function githubEventsQuery({
|
|
22
|
+
query,
|
|
23
|
+
githubUser,
|
|
24
|
+
githubToken
|
|
25
|
+
}) {
|
|
26
|
+
try {
|
|
27
|
+
const {
|
|
28
|
+
page = query.page || 1,
|
|
29
|
+
per_page = query.per_page || 100,
|
|
30
|
+
repo,
|
|
31
|
+
action,
|
|
32
|
+
date,
|
|
33
|
+
description
|
|
34
|
+
} = query;
|
|
35
|
+
const pageNum = Number(page);
|
|
36
|
+
const perPage = Number(per_page);
|
|
37
|
+
console.log(`Fetching events for user: ${githubUser}, page: ${pageNum}, per_page: ${perPage}`);
|
|
38
|
+
let allEvents = [];
|
|
39
|
+
let hasMore = true;
|
|
40
|
+
let githubPage = 1;
|
|
41
|
+
const maxPages = 30;
|
|
42
|
+
const fetchPerPage = 100;
|
|
43
|
+
while (hasMore && githubPage <= maxPages) {
|
|
44
|
+
console.log(`Fetching page ${githubPage}...`);
|
|
45
|
+
const fetchOptions = {
|
|
46
|
+
headers: {
|
|
47
|
+
'User-Agent': 'brianstoker.com-website'
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
if (githubToken) {
|
|
51
|
+
fetchOptions.headers.Authorization = `token ${githubToken}`;
|
|
52
|
+
}
|
|
53
|
+
const queryParams = new URLSearchParams({
|
|
54
|
+
page: String(githubPage),
|
|
55
|
+
per_page: String(fetchPerPage)
|
|
56
|
+
});
|
|
57
|
+
const response = await fetch(`https://api.github.com/users/${githubUser}/events?${queryParams}`, fetchOptions);
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
const errorText = await response.text();
|
|
60
|
+
console.error(`GitHub API error: ${response.status}`, errorText);
|
|
61
|
+
throw new Error(`GitHub API error: ${response.status} - ${errorText}`);
|
|
62
|
+
}
|
|
63
|
+
const data = await response.json();
|
|
64
|
+
console.log(`Page ${githubPage}: Received ${data.length} events`);
|
|
65
|
+
if (data.length === 0) {
|
|
66
|
+
hasMore = false;
|
|
67
|
+
} else {
|
|
68
|
+
allEvents = [...allEvents, ...data];
|
|
69
|
+
console.log(`Total events so far: ${allEvents.length}`);
|
|
70
|
+
const linkHeader = response.headers.get('Link');
|
|
71
|
+
const links = parseLinkHeader(linkHeader);
|
|
72
|
+
hasMore = !!links.next;
|
|
73
|
+
githubPage++;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
allEvents = Array.from(new Map(allEvents.map(event => [event.id, event])).values());
|
|
77
|
+
console.log(`Final total events: ${allEvents.length}`);
|
|
78
|
+
let filteredEvents = allEvents;
|
|
79
|
+
if (repo) {
|
|
80
|
+
filteredEvents = filteredEvents.filter(event => event.repo.name === repo);
|
|
81
|
+
}
|
|
82
|
+
if (action) {
|
|
83
|
+
filteredEvents = filteredEvents.filter(event => event.type.replace('Event', '') === action);
|
|
84
|
+
}
|
|
85
|
+
if (date) {
|
|
86
|
+
const now = new Date();
|
|
87
|
+
let cutoffDate;
|
|
88
|
+
switch (date) {
|
|
89
|
+
case 'today':
|
|
90
|
+
cutoffDate = new Date(now.setHours(0, 0, 0, 0));
|
|
91
|
+
break;
|
|
92
|
+
case 'yesterday':
|
|
93
|
+
cutoffDate = new Date(now);
|
|
94
|
+
cutoffDate.setDate(cutoffDate.getDate() - 1);
|
|
95
|
+
cutoffDate.setHours(0, 0, 0, 0);
|
|
96
|
+
break;
|
|
97
|
+
case 'week':
|
|
98
|
+
cutoffDate = new Date(now);
|
|
99
|
+
cutoffDate.setDate(cutoffDate.getDate() - 7);
|
|
100
|
+
cutoffDate.setHours(0, 0, 0, 0);
|
|
101
|
+
break;
|
|
102
|
+
case 'month':
|
|
103
|
+
cutoffDate = new Date(now);
|
|
104
|
+
cutoffDate.setMonth(cutoffDate.getMonth() - 1);
|
|
105
|
+
cutoffDate.setHours(0, 0, 0, 0);
|
|
106
|
+
break;
|
|
107
|
+
default:
|
|
108
|
+
cutoffDate = new Date(0);
|
|
109
|
+
}
|
|
110
|
+
filteredEvents = filteredEvents.filter(event => new Date(event.created_at) >= cutoffDate);
|
|
111
|
+
}
|
|
112
|
+
if (description) {
|
|
113
|
+
filteredEvents = filteredEvents.filter(event => {
|
|
114
|
+
var _event$payload$commit, _event$payload$pull_r, _event$payload$issue, _event$payload$issue2;
|
|
115
|
+
let eventDescription = '';
|
|
116
|
+
if (event.type === 'PushEvent' && (_event$payload$commit = event.payload.commits) != null && _event$payload$commit.length) {
|
|
117
|
+
eventDescription = `Pushed ${event.payload.commits.length} commits`;
|
|
118
|
+
} else if (event.type === 'PullRequestEvent' && (_event$payload$pull_r = event.payload.pull_request) != null && _event$payload$pull_r.title) {
|
|
119
|
+
eventDescription = event.payload.pull_request.title;
|
|
120
|
+
} else if (event.type === 'IssuesEvent' && (_event$payload$issue = event.payload.issue) != null && _event$payload$issue.title) {
|
|
121
|
+
eventDescription = event.payload.issue.title;
|
|
122
|
+
} else if (event.type === 'IssueCommentEvent' && (_event$payload$issue2 = event.payload.issue) != null && _event$payload$issue2.title) {
|
|
123
|
+
eventDescription = `Commented on issue: ${event.payload.issue.title}`;
|
|
124
|
+
}
|
|
125
|
+
return eventDescription.toLowerCase().includes(description.toLowerCase());
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
const startIndex = (pageNum - 1) * perPage;
|
|
129
|
+
const endIndex = startIndex + perPage;
|
|
130
|
+
const paginatedEvents = filteredEvents.slice(startIndex, endIndex);
|
|
131
|
+
const repositories = Array.from(new Set(allEvents.map(event => event.repo.name))).sort();
|
|
132
|
+
const actionTypes = Array.from(new Set(allEvents.map(event => event.type.replace('Event', '')))).sort();
|
|
133
|
+
return {
|
|
134
|
+
events: paginatedEvents,
|
|
135
|
+
total: filteredEvents.length,
|
|
136
|
+
repositories,
|
|
137
|
+
actionTypes,
|
|
138
|
+
page: pageNum,
|
|
139
|
+
per_page: perPage,
|
|
140
|
+
total_pages: Math.ceil(filteredEvents.length / perPage),
|
|
141
|
+
total_fetched_events: allEvents.length,
|
|
142
|
+
max_pages_fetched: githubPage - 1
|
|
143
|
+
};
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error('Error fetching GitHub events:', error);
|
|
146
|
+
throw new Error(`${error instanceof Error ? error.message : String(error)}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
var _default = exports.default = githubEventsQuery;
|
|
@@ -44,7 +44,7 @@ async function getPullRequestDetails(params) {
|
|
|
44
44
|
if (githubToken) {
|
|
45
45
|
headers.Authorization = `token ${githubToken}`;
|
|
46
46
|
}
|
|
47
|
-
async
|
|
47
|
+
const fetchWithRateLimit = async url => {
|
|
48
48
|
const response = await fetch(url, {
|
|
49
49
|
headers
|
|
50
50
|
});
|
|
@@ -66,7 +66,7 @@ async function getPullRequestDetails(params) {
|
|
|
66
66
|
data: await response.json(),
|
|
67
67
|
rateLimit
|
|
68
68
|
};
|
|
69
|
-
}
|
|
69
|
+
};
|
|
70
70
|
|
|
71
71
|
// Fetch basic PR information
|
|
72
72
|
const {
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.buildGithubContributors = buildGithubContributors;
|
|
7
|
+
exports.fetchGithubResource = fetchGithubResource;
|
|
8
|
+
exports.getGithubMessageSummary = getGithubMessageSummary;
|
|
9
|
+
exports.getGithubShortRef = getGithubShortRef;
|
|
10
|
+
exports.normalizeGithubCommit = normalizeGithubCommit;
|
|
11
|
+
exports.normalizeGithubFile = normalizeGithubFile;
|
|
12
|
+
exports.parseGithubDiff = parseGithubDiff;
|
|
13
|
+
exports.summarizeGithubStats = summarizeGithubStats;
|
|
14
|
+
const GITHUB_API_BASE_URL = 'https://api.github.com';
|
|
15
|
+
const DEFAULT_DIFF_LINE_LIMIT = 24;
|
|
16
|
+
function getGithubHeaders() {
|
|
17
|
+
const githubToken = process.env.GITHUB_TOKEN;
|
|
18
|
+
const headers = {
|
|
19
|
+
'User-Agent': 'stoked-ui-github-components',
|
|
20
|
+
Accept: 'application/vnd.github+json'
|
|
21
|
+
};
|
|
22
|
+
if (githubToken) {
|
|
23
|
+
headers.Authorization = `token ${githubToken}`;
|
|
24
|
+
}
|
|
25
|
+
return headers;
|
|
26
|
+
}
|
|
27
|
+
async function fetchGithubResource(path) {
|
|
28
|
+
const response = await fetch(`${GITHUB_API_BASE_URL}${path}`, {
|
|
29
|
+
headers: getGithubHeaders()
|
|
30
|
+
});
|
|
31
|
+
const rateLimit = {
|
|
32
|
+
remaining: response.headers.get('x-ratelimit-remaining'),
|
|
33
|
+
reset: response.headers.get('x-ratelimit-reset')
|
|
34
|
+
};
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
const body = await response.text();
|
|
37
|
+
if (response.status === 403 && rateLimit.remaining === '0') {
|
|
38
|
+
const resetDate = rateLimit.reset ? new Date(Number(rateLimit.reset) * 1000).toLocaleString() : 'later';
|
|
39
|
+
throw new Error(`GitHub rate limit exceeded. Resets at ${resetDate}.`);
|
|
40
|
+
}
|
|
41
|
+
throw new Error(body || `GitHub API error: ${response.status}`);
|
|
42
|
+
}
|
|
43
|
+
return response.json();
|
|
44
|
+
}
|
|
45
|
+
function parseGithubDiff(patch, maxLines = DEFAULT_DIFF_LINE_LIMIT) {
|
|
46
|
+
if (!patch) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
const patchLines = patch.split('\n');
|
|
50
|
+
const visibleLines = patchLines.slice(0, maxLines);
|
|
51
|
+
const diffLines = visibleLines.map((line, index) => {
|
|
52
|
+
let type = 'context';
|
|
53
|
+
if (line.startsWith('+')) {
|
|
54
|
+
type = 'addition';
|
|
55
|
+
} else if (line.startsWith('-')) {
|
|
56
|
+
type = 'deletion';
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
type,
|
|
60
|
+
content: line,
|
|
61
|
+
lineNumber: index + 1
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
if (patchLines.length > maxLines) {
|
|
65
|
+
diffLines.push({
|
|
66
|
+
type: 'context',
|
|
67
|
+
content: `... ${patchLines.length - maxLines} more diff lines`,
|
|
68
|
+
lineNumber: diffLines.length + 1
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return diffLines;
|
|
72
|
+
}
|
|
73
|
+
function toFileChangeType(status) {
|
|
74
|
+
switch (status) {
|
|
75
|
+
case 'added':
|
|
76
|
+
return 'added';
|
|
77
|
+
case 'removed':
|
|
78
|
+
return 'deleted';
|
|
79
|
+
default:
|
|
80
|
+
return 'modified';
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function normalizeGithubFile(file, maxDiffLines = DEFAULT_DIFF_LINE_LIMIT) {
|
|
84
|
+
return {
|
|
85
|
+
path: file.filename || file.path || 'unknown',
|
|
86
|
+
type: toFileChangeType(file.status),
|
|
87
|
+
additions: file.additions || 0,
|
|
88
|
+
deletions: file.deletions || 0,
|
|
89
|
+
diff: file.diff || parseGithubDiff(file.patch, maxDiffLines)
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function getGithubIdentity(commit) {
|
|
93
|
+
var _commit$commit, _commit$commit2;
|
|
94
|
+
const apiAuthor = commit.author || commit.committer || {};
|
|
95
|
+
const commitAuthor = ((_commit$commit = commit.commit) == null ? void 0 : _commit$commit.author) || ((_commit$commit2 = commit.commit) == null ? void 0 : _commit$commit2.committer) || {};
|
|
96
|
+
return {
|
|
97
|
+
login: apiAuthor.login || commitAuthor.name || commitAuthor.email || commit.sha || 'unknown',
|
|
98
|
+
name: commitAuthor.name || apiAuthor.login || commitAuthor.email || 'Unknown author',
|
|
99
|
+
avatarUrl: apiAuthor.avatar_url || ''
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function normalizeGithubCommit(commit) {
|
|
103
|
+
var _commit$commit3, _commit$commit4, _commit$commit5;
|
|
104
|
+
const identity = getGithubIdentity(commit);
|
|
105
|
+
return {
|
|
106
|
+
id: commit.sha || commit.node_id || identity.login,
|
|
107
|
+
message: ((_commit$commit3 = commit.commit) == null ? void 0 : _commit$commit3.message) || '',
|
|
108
|
+
author: {
|
|
109
|
+
name: identity.name,
|
|
110
|
+
login: identity.login,
|
|
111
|
+
avatar: identity.avatarUrl
|
|
112
|
+
},
|
|
113
|
+
date: ((_commit$commit4 = commit.commit) == null || (_commit$commit4 = _commit$commit4.author) == null ? void 0 : _commit$commit4.date) || ((_commit$commit5 = commit.commit) == null || (_commit$commit5 = _commit$commit5.committer) == null ? void 0 : _commit$commit5.date) || '',
|
|
114
|
+
hash: commit.sha || '',
|
|
115
|
+
url: commit.html_url || ''
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function buildGithubContributors(commits) {
|
|
119
|
+
const contributors = new Map();
|
|
120
|
+
commits.forEach(commit => {
|
|
121
|
+
const identity = getGithubIdentity(commit);
|
|
122
|
+
const key = identity.login || identity.name;
|
|
123
|
+
const current = contributors.get(key);
|
|
124
|
+
if (current) {
|
|
125
|
+
current.contributions += 1;
|
|
126
|
+
if (!current.avatarUrl && identity.avatarUrl) {
|
|
127
|
+
current.avatarUrl = identity.avatarUrl;
|
|
128
|
+
}
|
|
129
|
+
if (current.name === 'Unknown author' && identity.name) {
|
|
130
|
+
current.name = identity.name;
|
|
131
|
+
}
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
contributors.set(key, {
|
|
135
|
+
login: identity.login,
|
|
136
|
+
name: identity.name,
|
|
137
|
+
avatarUrl: identity.avatarUrl,
|
|
138
|
+
contributions: 1
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
return Array.from(contributors.values()).sort((a, b) => {
|
|
142
|
+
if (b.contributions !== a.contributions) {
|
|
143
|
+
return b.contributions - a.contributions;
|
|
144
|
+
}
|
|
145
|
+
return a.login.localeCompare(b.login);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
function summarizeGithubStats(files) {
|
|
149
|
+
return files.reduce((stats, file) => ({
|
|
150
|
+
additions: stats.additions + file.additions,
|
|
151
|
+
deletions: stats.deletions + file.deletions,
|
|
152
|
+
changedFiles: stats.changedFiles + 1
|
|
153
|
+
}), {
|
|
154
|
+
additions: 0,
|
|
155
|
+
deletions: 0,
|
|
156
|
+
changedFiles: 0
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
function getGithubMessageSummary(message) {
|
|
160
|
+
var _message$split$;
|
|
161
|
+
return ((_message$split$ = message.split('\n')[0]) == null ? void 0 : _message$split$.trim()) || 'Untitled commit';
|
|
162
|
+
}
|
|
163
|
+
function getGithubShortRef(ref, length = 7) {
|
|
164
|
+
if (!ref) {
|
|
165
|
+
return '';
|
|
166
|
+
}
|
|
167
|
+
return ref.length > length ? ref.slice(0, length) : ref;
|
|
168
|
+
}
|
|
@@ -4,10 +4,73 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
+
Object.defineProperty(exports, "createGithubBranchHandler", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () {
|
|
10
|
+
return _createGithubBranchHandler.default;
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
Object.defineProperty(exports, "createGithubCommitHandler", {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: function () {
|
|
16
|
+
return _createGithubCommitHandler.default;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports, "createGithubContributionsHandler", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () {
|
|
22
|
+
return _createGithubContributionsHandler.default;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
Object.defineProperty(exports, "createGithubEventsHandler", {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
get: function () {
|
|
28
|
+
return _createGithubEventsHandler.default;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
Object.defineProperty(exports, "getBranchCompareDetails", {
|
|
32
|
+
enumerable: true,
|
|
33
|
+
get: function () {
|
|
34
|
+
return _getBranchCompareDetails.default;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
Object.defineProperty(exports, "getCommitDetails", {
|
|
38
|
+
enumerable: true,
|
|
39
|
+
get: function () {
|
|
40
|
+
return _getCommitDetails.default;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
Object.defineProperty(exports, "getGithubContributions", {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
get: function () {
|
|
46
|
+
return _getGithubContributions.default;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
Object.defineProperty(exports, "getGithubEvents", {
|
|
50
|
+
enumerable: true,
|
|
51
|
+
get: function () {
|
|
52
|
+
return _getGithubEvents.default;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
7
55
|
Object.defineProperty(exports, "getPullRequestDetails", {
|
|
8
56
|
enumerable: true,
|
|
9
57
|
get: function () {
|
|
10
58
|
return _getPullRequestDetails.default;
|
|
11
59
|
}
|
|
12
60
|
});
|
|
13
|
-
|
|
61
|
+
Object.defineProperty(exports, "githubEventsQuery", {
|
|
62
|
+
enumerable: true,
|
|
63
|
+
get: function () {
|
|
64
|
+
return _getGithubEvents.githubEventsQuery;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
var _createGithubBranchHandler = _interopRequireDefault(require("./createGithubBranchHandler"));
|
|
68
|
+
var _createGithubCommitHandler = _interopRequireDefault(require("./createGithubCommitHandler"));
|
|
69
|
+
var _getBranchCompareDetails = _interopRequireDefault(require("./getBranchCompareDetails"));
|
|
70
|
+
var _getCommitDetails = _interopRequireDefault(require("./getCommitDetails"));
|
|
71
|
+
var _getPullRequestDetails = _interopRequireDefault(require("./getPullRequestDetails"));
|
|
72
|
+
var _getGithubContributions = _interopRequireDefault(require("./getGithubContributions"));
|
|
73
|
+
var _createGithubContributionsHandler = _interopRequireDefault(require("./createGithubContributionsHandler"));
|
|
74
|
+
var _getGithubEvents = _interopRequireWildcard(require("./getGithubEvents"));
|
|
75
|
+
var _createGithubEventsHandler = _interopRequireDefault(require("./createGithubEventsHandler"));
|
|
76
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|