Randell Dawson c8f6d15688
feat(tool): Add ability to view all open PRs for repos other than freeCodeCamp in the Dashboard app (#40453)
* feat: show open boilerplate prs on dashboard

fix:  rest of boilerplate server changes

fix: more

fix: other

* fix: update lib functions

* fix: retrofitted one-off scripts

* feat: added rateLimit for requests

* fix: reduce time

* fix: put limiter inside each route

* fix: make client show when rated limited

* fix: removed unused probot from app

* fix: renamed folders

* fix: consolidate config.js and constants.js

* chore: update octokit to latest version

* fix: remove invalid file

* fix: refactored update-db.js

* feat: add fcc logo

* fix: logo url

* fix: remove Home link

* fix: change link colors

* fix: added rate limiter to landing page

* fix: ran npm install in client to create package-lock.json

* fix: correct typo in doc

Co-authored-by: Nicholas Carrigan (he/him) <nhcarrigan@gmail.com>

* fix: Replace favicon, Gitter => Discord

Signed-off-by: nhcarrigan <nhcarrigan@gmail.com>

* fix: add extra linting guidance to package.json

* Ignore contributor app

Signed-off-by: nhcarrigan <nhcarrigan@gmail.com>

* fix: revert linting rules for client

* fix: add skip_preflight_check=true for tests

Co-authored-by: Kristofer Koishigawa <scissorsneedfoodtoo@gmail.com>

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
Co-authored-by: Kris Koishigawa <scissorsneedfoodtoo@gmail.com>
Co-authored-by: Nicholas Carrigan (he/him) <nhcarrigan@gmail.com>
2020-12-22 13:43:36 +09:00

174 lines
4.5 KiB
JavaScript

const { Octokit } = require('@octokit/rest');
const _cliProgress = require('cli-progress');
const {
github: { owner, secret }
} = require('../config');
const octokit = new Octokit({ auth: secret });
const { getRange, getCount } = require('./pr-stats');
/* eslint-disable camelcase */
const prsPaginate = async (
repo,
base,
method,
firstPR,
lastPR,
prPropsToGet
) => {
let methodProps = {
owner,
repo,
state: 'open',
sort: 'created',
direction: 'asc',
page: 1,
per_page: 100
};
if (base) {
methodProps = { ...methodProps, base };
}
const prFilter = (prs, first, last, prPropsToGet) => {
const filtered = [];
for (let pr of prs) {
if (pr.number >= first && pr.number <= last) {
const propsObj = prPropsToGet.reduce((obj, prop) => {
obj[prop] = pr[prop];
return obj;
}, {});
filtered.push(propsObj);
}
if (pr.number >= last) {
done = true;
return filtered;
}
}
return filtered;
};
// will be true when lastPR is seen in paginated results
let done = false;
let response = await method(methodProps);
console.log('x-ratelimit-remaining:', response.meta['x-ratelimit-remaining']);
let { data } = response;
data = prFilter(data, firstPR, lastPR, prPropsToGet);
while (octokit.hasNextPage(response) && !done) {
response = await octokit.getNextPage(response);
console.log(
'x-ratelimit-remaining:',
response.meta['x-ratelimit-remaining']
);
let dataFiltered = prFilter(response.data, firstPR, lastPR, prPropsToGet);
data = data.concat(dataFiltered);
// progressBar.increment(dataFiltered.length);
}
return data;
};
const getUserInput = async (repo, base, rangeType = '') => {
let data, firstPR, lastPR;
if (rangeType === 'all') {
data = await getRange(repo, base).then(data => data);
firstPR = data[0];
lastPR = data[1];
} else {
let [type, start, end] = process.argv.slice(2);
data = await getRange(repo, base).then(data => data);
firstPR = data[0];
lastPR = data[1];
if (type !== 'all' && type !== 'range') {
throw 'Please specify either all or range for 1st arg.';
}
if (type === 'range') {
start = parseInt(start, 10);
end = parseInt(end, 10);
if (!start || !end) {
throw 'Specify both a starting PR # (2nd arg) and ending PR # (3rd arg).';
}
if (start > end) {
throw 'Starting PR # must be less than or equal to end PR #.';
}
if (start < firstPR) {
throw `Starting PR # can not be less than first open PR # (${firstPR})`;
}
firstPR = start;
if (end > lastPR) {
throw `Ending PR # can not be greater than last open PR # (${lastPR})`;
}
lastPR = end;
}
}
// A null value for firstPR or lastPR indicates the repo had no open PRs
if (firstPR === null || lastPR === null) {
return { totalPRs: 0, firstPR, lastPR };
}
const totalPRs = await getCount(repo, base).then(data => data);
return { totalPRs, firstPR, lastPR };
};
const getPRs = async (repo, base, totalPRs, firstPR, lastPR, prPropsToGet) => {
let progressText = `Retrieve PRs (${firstPR}-${lastPR}) [{bar}] `;
progressText += '{percentage}% | Elapsed Time: {duration_formatted} ';
progressText += '| ETA: {eta_formatted}';
const getPRsBar = new _cliProgress.Bar(
{
format: progressText,
etaBuffer: 50
},
_cliProgress.Presets.shades_classic
);
// getPRsBar.start(totalPRs, 0);
let openPRs = await prsPaginate(
repo,
base,
octokit.pulls.list,
firstPR,
lastPR,
prPropsToGet,
getPRsBar
);
// getPRsBar.update(totalPRs);
// getPRsBar.stop();
console.log(`# of PRs retrieved: ${openPRs.length}`);
return { firstPR, lastPR, openPRs };
};
const filesPaginate = async (repo, number) => {
let methodProps = {
owner,
state: 'open',
sort: 'created',
direction: 'asc',
page: 1,
per_page: 100
};
if (repo) {
methodProps = { ...methodProps, repo };
}
let response = await octokit.pulls.listFiles({
number,
...methodProps
});
let { data } = response;
while (octokit.hasNextPage(response)) {
response = await octokit.getNextPage(response);
let { data: moreData } = response;
data = data.concat(moreData);
}
return data;
};
const getFiles = async (repo, number) => await filesPaginate(repo, number);
const getFilenames = async (repo, number) =>
(await getFiles(repo, number)).map(({ filename }) => filename);
module.exports = { getPRs, getUserInput, getFiles, getFilenames };