Skip to content

Commit

Permalink
feat: add octokit to dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrewnt219 authored and aserputov committed Feb 2, 2022
1 parent 3c2d3d6 commit 3311a26
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 45 deletions.
86 changes: 86 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/api/status/env.local
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ PATH_PREFIX=/v1/status
WEB_URL=http://localhost
POSTS_URL=http://localhost/v1/posts
MOCK_REDIS=1
# github access token for octokit
GITHUB_TOKEN=
8 changes: 5 additions & 3 deletions src/api/status/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
},
"homepage": "https://github.com/Seneca-CDOT/telescope#readme",
"dependencies": {
"@octokit/core": "3.5.1",
"@octokit/plugin-retry": "3.0.9",
"@octokit/plugin-throttling": "3.5.2",
"@senecacdot/satellite": "^1.x",
"express": "4.17.2",
"express-handlebars": "6.0.2",
"npm-run-all": "4.1.5",
"sass": "1.45.2",
"vite": "2.7.13",
"npm-run-all": "4.1.5"

"vite": "2.7.13"
},
"engines": {
"node": ">=12.0.0"
Expand Down
79 changes: 37 additions & 42 deletions src/api/status/src/js/github-stats.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,50 @@
const { fetch } = require('@senecacdot/satellite');

const { logger } = require('@senecacdot/satellite');
const octokit = require('./octokit');
const redis = require('../redis');

const cacheTime = 60 * 10; // 10 mins of cache time

const fetchGitHubApi = (owner, repo, path) =>
fetch(`https://api.github.com/repos/${owner}/${repo}/${path}`, {
headers: { Accept: 'application/vnd.github.v3+json' },
});

const getStatsParticipation = async (owner, repo) => {
// get weekly commits for last year: https://docs.github.com/en/rest/reference/repos#get-the-weekly-commit-count
const res = await fetchGitHubApi(owner, repo, 'stats/participation');
const participationResponse = await res.json();
if (!res.ok) {
throw new Error(`[Code ${res.status}] - ${participationResponse.message}`);
}
const participationResponse = await octokit.request(
'GET /repos/{owner}/{repo}/stats/participation',
{
owner,
repo,
}
);

return {
weeklyCommits: {
commits: participationResponse.all[participationResponse.all.length - 1],
commits: participationResponse.data.all[participationResponse.data.all.length - 1],
},
yearlyCommits: {
commits: participationResponse.all.reduce((a, b) => a + b),
commits: participationResponse.data.all.reduce((a, b) => a + b),
},
};
};

const getStatsCodeFrequency = async (owner, repo) => {
// get weekly commits activity: https://docs.github.com/en/rest/reference/repos#get-the-weekly-commit-activity
const res = await fetchGitHubApi(owner, repo, 'stats/code_frequency');
const codeFrequencyResponse = await res.json();

if (!res.ok) {
throw new Error(`[Code ${res.status}] - ${codeFrequencyResponse.message}`);
}

const [, linesAdded, linesRemoved] = codeFrequencyResponse[codeFrequencyResponse.length - 1];
const codeFrequencyResponse = await octokit.request(
'GET /repos/{owner}/{repo}/stats/code_frequency',
{
owner,
repo,
}
);
const [, linesAdded, linesRemoved] =
codeFrequencyResponse.data[codeFrequencyResponse.data.length - 1];
return { weeklyCommits: { linesAdded, linesRemoved } };
};

const getCommitsInfo = async (owner, repo) => {
// get latest author from commits list: https://docs.github.com/en/rest/reference/repos#list-commits
const res = await fetchGitHubApi(owner, repo, 'commits');
const commitResponse = await res.json();

if (!res.ok) {
throw new Error(`[Code ${res.status}] - ${commitResponse.message}`);
}

const lastCommitResponse = commitResponse[0];
const commitResponse = await octokit.request('GET /repos/{owner}/{repo}/commits', {
owner,
repo,
});
const lastCommitResponse = commitResponse.data[0];

return {
avatar: lastCommitResponse.author.avatar_url || '',
Expand All @@ -63,13 +58,12 @@ const getCommitsInfo = async (owner, repo) => {

const getContributorsInfo = async (owner, repo) => {
// get total contributors: https://docs.github.com/en/rest/reference/repos#list-repository-contributors
const res = await fetchGitHubApi(owner, repo, 'contributors?per_page=1');

if (res.status >= 400) {
throw new Error(`[Code ${res.status}] - ${(await res.json()).message}`);
}

const contributorsResponse = await res.headers.get('link');
const { headers } = await octokit.request('GET /repos/{owner}/{repo}/contributors', {
owner,
repo,
per_page: 1,
});
const contributorsResponse = headers.link;
const [, totalContributors] = contributorsResponse.match(/.*"next".*&page=([0-9]*).*"last".*/);

return {
Expand All @@ -78,7 +72,6 @@ const getContributorsInfo = async (owner, repo) => {
};

module.exports = async function getGitHubData(owner, repo) {
let githubData = {};
try {
const cached = await redis.get(`github:info-${repo}`);
if (cached) {
Expand All @@ -93,16 +86,18 @@ module.exports = async function getGitHubData(owner, repo) {
getContributorsInfo(owner, repo),
]);

githubData = {
const githubData = {
weeklyCommits: { ...statsParticipation.weeklyCommits, ...statsCodeFrequency.weeklyCommits },
yearlyCommits: { ...statsParticipation.yearlyCommits },
...commitsInfo,
...contributorsInfo,
};

await redis.set(`github:info-${repo}`, JSON.stringify(githubData), 'EX', cacheTime);
} catch (err) {
console.error(err);
return githubData;
} catch (error) {
logger.warn({ error }, 'Fail to fetch github data');
}
return githubData;

return {};
};
31 changes: 31 additions & 0 deletions src/api/status/src/js/octokit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const { Octokit } = require('@octokit/core');
const { retry } = require('@octokit/plugin-retry');
const { throttling } = require('@octokit/plugin-throttling');

const MyOctokit = Octokit.plugin(retry, throttling);
const octokit = new MyOctokit({
auth: process.env.GITHUB_TOKEN,
// options for throttling plugin https://github.com/octokit/plugin-throttling.js
throttle: {
onRateLimit: (retryAfter, options, octokitClient) => {
octokitClient.log.warn(
`Request quota exhausted for request ${options.method} ${options.url}`
);

if (options.request.retryCount === 0) {
// only retries once
octokitClient.log.info(`Retrying after ${retryAfter} seconds!`);
// Return true to automatically retry the request after retryAfter seconds.
return true;
}

return false;
},
onAbuseLimit: (retryAfter, options, octokitClient) => {
// does not retry, only logs a warning
octokitClient.log.warn(`Abuse detected for request ${options.method} ${options.url}`);
},
},
});

module.exports = octokit;

0 comments on commit 3311a26

Please sign in to comment.