mirror of
https://github.com/bendtherules/github-delete-unused-repos.git
synced 2026-08-18 13:52:59 +00:00
Throttle request using bottleneck
Also reformat + renames
This commit is contained in:
@@ -33,6 +33,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/rest": "^15.6.2",
|
"@octokit/rest": "^15.6.2",
|
||||||
|
"bottleneck": "^2.3.1",
|
||||||
"octonode": "^0.9.2"
|
"octonode": "^0.9.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1,26 +1,79 @@
|
|||||||
import rest = require('@octokit/rest');
|
import * as Octokit from '@octokit/rest';
|
||||||
import assert = require('assert');
|
import assert = require('assert');
|
||||||
|
import Bottleneck from 'bottleneck';
|
||||||
|
|
||||||
const octokit = new rest();
|
const octokit = new Octokit() as OctokitMod;
|
||||||
|
|
||||||
|
// Add rate limiter
|
||||||
|
const limiter = new Bottleneck({
|
||||||
|
maxConcurrent: 10,
|
||||||
|
minTime: 50,
|
||||||
|
});
|
||||||
|
|
||||||
|
const noop = () => Promise.resolve();
|
||||||
|
octokit.hook.before('request', limiter.schedule.bind(limiter, noop));
|
||||||
|
|
||||||
|
// Add key and secret for query
|
||||||
octokit.authenticate({
|
octokit.authenticate({
|
||||||
type: 'oauth',
|
type: 'oauth',
|
||||||
key: '05e5f5ec65387c49137b',
|
key: '05e5f5ec65387c49137b',
|
||||||
secret: '2228539a48032f0622d6c12a66f56253d0a30d60',
|
secret: '2228539a48032f0622d6c12a66f56253d0a30d60',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
interface RequestOptions {
|
||||||
|
method: string;
|
||||||
|
url: string;
|
||||||
|
headers: any;
|
||||||
|
query?: string;
|
||||||
|
variables?: Variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Result {
|
||||||
|
headers: {
|
||||||
|
status: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OctokitError {
|
||||||
|
code: number;
|
||||||
|
status: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OctokitMod extends Octokit {
|
||||||
|
// The following are added because Octokit does not expose the hook.error, hook.before, and hook.after methods
|
||||||
|
hook: {
|
||||||
|
error: (
|
||||||
|
when: 'request',
|
||||||
|
callback: (error: OctokitError, options: RequestOptions) => void
|
||||||
|
) => void;
|
||||||
|
before: (
|
||||||
|
when: 'request',
|
||||||
|
callback: (result: Result, options: RequestOptions) => void
|
||||||
|
) => void;
|
||||||
|
after: (
|
||||||
|
when: 'request',
|
||||||
|
callback: (result: Result, options: RequestOptions) => void
|
||||||
|
) => void;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Variables {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
interface ResponseWithDataArray<T> {
|
interface ResponseWithDataArray<T> {
|
||||||
data: T[];
|
data: T[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ResponseWithMetaLink {
|
interface ResponseWithMetaLink {
|
||||||
meta: {
|
meta: {
|
||||||
link: string
|
link: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ResponseWithDataArrayAndMeta<T> extends ResponseWithDataArray<T>, ResponseWithMetaLink {
|
interface ResponseWithDataArrayAndMeta<T>
|
||||||
|
extends ResponseWithDataArray<T>,
|
||||||
}
|
ResponseWithMetaLink {}
|
||||||
|
|
||||||
interface ResponseFromGetUserRepo extends ResponseWithMetaLink {
|
interface ResponseFromGetUserRepo extends ResponseWithMetaLink {
|
||||||
data: RepoFromGetUserRepo[];
|
data: RepoFromGetUserRepo[];
|
||||||
@@ -110,19 +163,20 @@ interface RepoNameWithParentRepo {
|
|||||||
|
|
||||||
interface RepoNameWithBranchesAndParent
|
interface RepoNameWithBranchesAndParent
|
||||||
extends RepoNameWithBranches,
|
extends RepoNameWithBranches,
|
||||||
RepoNameWithParentRepo { }
|
RepoNameWithParentRepo {}
|
||||||
|
|
||||||
const username = 'bendtherules';
|
const username = 'rousan';
|
||||||
|
|
||||||
interface ObjectWithPerPage {
|
interface ObjectWithPerPage {
|
||||||
per_page?: number;
|
per_page?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function paginate<TFirstParam extends ObjectWithPerPage, TDataElement>(
|
async function paginate<TFirstParam extends ObjectWithPerPage, TDataElement>(
|
||||||
method: (args: TFirstParam) => Promise<ResponseWithDataArrayAndMeta<TDataElement>>,
|
method: (
|
||||||
|
args: TFirstParam
|
||||||
|
) => Promise<ResponseWithDataArrayAndMeta<TDataElement>>,
|
||||||
args: TFirstParam
|
args: TFirstParam
|
||||||
): Promise<ResponseWithDataArray<TDataElement>> {
|
): Promise<ResponseWithDataArray<TDataElement>> {
|
||||||
|
|
||||||
// Set per_page
|
// Set per_page
|
||||||
args.per_page = 100;
|
args.per_page = 100;
|
||||||
|
|
||||||
@@ -136,25 +190,27 @@ async function paginate<TFirstParam extends ObjectWithPerPage, TDataElement>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data
|
data,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchRepoNameWithBranches(
|
async function fetchRepoNameWithBranches(
|
||||||
repoName: string
|
repoName: string
|
||||||
): Promise<RepoNameWithBranches> {
|
): Promise<RepoNameWithBranches> {
|
||||||
const params: rest.ReposGetBranchesParams = {
|
const params: Octokit.ReposGetBranchesParams = {
|
||||||
owner: username,
|
owner: username,
|
||||||
repo: repoName,
|
repo: repoName,
|
||||||
};
|
};
|
||||||
|
|
||||||
const branchesResponse: ResponseWithDataArray<BranchFromGetBranches> =
|
const branchesResponse: ResponseWithDataArray<
|
||||||
await paginate(
|
BranchFromGetBranches
|
||||||
(tmpFirstParam: rest.ReposGetBranchesParams): Promise<ResponseFromGetBranches> => {
|
> = await paginate((tmpFirstParam: Octokit.ReposGetBranchesParams): Promise<
|
||||||
return octokit.repos.getBranches(tmpFirstParam) as any as Promise<ResponseFromGetBranches>;
|
ResponseFromGetBranches
|
||||||
},
|
> => {
|
||||||
params
|
return (octokit.repos.getBranches(tmpFirstParam) as any) as Promise<
|
||||||
);
|
ResponseFromGetBranches
|
||||||
|
>;
|
||||||
|
}, params);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
repoName,
|
repoName,
|
||||||
@@ -254,26 +310,33 @@ async function fetchNoneOfForkBranchesIsAhead(
|
|||||||
async function fetchUserIsNotContributor(
|
async function fetchUserIsNotContributor(
|
||||||
repoName: string
|
repoName: string
|
||||||
): Promise<RepoNameWithUnusedFlag> {
|
): Promise<RepoNameWithUnusedFlag> {
|
||||||
const params: rest.ReposGetContributorsParams = {
|
const params: Octokit.ReposGetContributorsParams = {
|
||||||
owner: username,
|
owner: username,
|
||||||
repo: repoName,
|
repo: repoName,
|
||||||
anon: '0',
|
anon: '0',
|
||||||
};
|
};
|
||||||
|
|
||||||
const responseFromGetContributors: ResponseWithDataArray<OwnerFromGetContributors> =
|
const responseFromGetContributors: ResponseWithDataArray<
|
||||||
await paginate(
|
OwnerFromGetContributors
|
||||||
async (tmpFirstParam: rest.ReposGetContributorsParams): Promise<ResponseWithDataArrayAndMeta<OwnerFromGetContributors>> => {
|
> = await paginate(
|
||||||
|
async (
|
||||||
|
tmpFirstParam: Octokit.ReposGetContributorsParams
|
||||||
|
): Promise<ResponseWithDataArrayAndMeta<OwnerFromGetContributors>> => {
|
||||||
// Modify getContributors to return empty contributor data array instead of undefined for empty repos
|
// Modify getContributors to return empty contributor data array instead of undefined for empty repos
|
||||||
const response = await (octokit.repos.getContributors(tmpFirstParam) as any as Promise<ResponseFromGetContributors>);
|
const response = await ((octokit.repos.getContributors(
|
||||||
|
tmpFirstParam
|
||||||
|
) as any) as Promise<ResponseFromGetContributors>);
|
||||||
|
|
||||||
let dataNormalized = response.data;
|
let dataNormalized = response.data;
|
||||||
if (dataNormalized === undefined) {
|
if (dataNormalized === undefined) {
|
||||||
dataNormalized = [];
|
dataNormalized = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const responseNormalized: ResponseWithDataArrayAndMeta<OwnerFromGetContributors> = {
|
const responseNormalized: ResponseWithDataArrayAndMeta<
|
||||||
|
OwnerFromGetContributors
|
||||||
|
> = {
|
||||||
data: dataNormalized,
|
data: dataNormalized,
|
||||||
meta: response.meta
|
meta: response.meta,
|
||||||
};
|
};
|
||||||
|
|
||||||
return responseNormalized;
|
return responseNormalized;
|
||||||
@@ -295,14 +358,17 @@ async function fetchUserIsNotContributor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function fetchUnusedForkedRepos() {
|
async function fetchUnusedForkedRepos() {
|
||||||
const params: rest.ReposGetForUserParams = {
|
const params: Octokit.ReposGetForUserParams = {
|
||||||
username,
|
username,
|
||||||
}
|
};
|
||||||
|
|
||||||
const repos: ResponseWithDataArray<RepoFromGetUserRepo> =
|
const repos: ResponseWithDataArray<RepoFromGetUserRepo> = await paginate(
|
||||||
await paginate(
|
(
|
||||||
(tmpFirstParam: rest.ReposGetForUserParams): Promise<ResponseFromGetUserRepo> => {
|
tmpFirstParam: Octokit.ReposGetForUserParams
|
||||||
return octokit.repos.getForUser(tmpFirstParam) as any as Promise<ResponseFromGetUserRepo>;
|
): Promise<ResponseFromGetUserRepo> => {
|
||||||
|
return (octokit.repos.getForUser(tmpFirstParam) as any) as Promise<
|
||||||
|
ResponseFromGetUserRepo
|
||||||
|
>;
|
||||||
},
|
},
|
||||||
params
|
params
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -991,6 +991,10 @@ boom@2.x.x:
|
|||||||
dependencies:
|
dependencies:
|
||||||
hoek "2.x.x"
|
hoek "2.x.x"
|
||||||
|
|
||||||
|
bottleneck@^2.3.1:
|
||||||
|
version "2.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/bottleneck/-/bottleneck-2.3.1.tgz#16292092ff040ccbf2d05d0a09d69eab7b1c46bc"
|
||||||
|
|
||||||
brace-expansion@^1.1.7:
|
brace-expansion@^1.1.7:
|
||||||
version "1.1.11"
|
version "1.1.11"
|
||||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||||
|
|||||||
Reference in New Issue
Block a user