mirror of
https://github.com/bendtherules/github-delete-unused-repos.git
synced 2026-08-18 13:52:59 +00:00
Convert detection logic into class + Remove unused sample files
This commit is contained in:
@@ -1,6 +0,0 @@
|
|||||||
import { Greeter } from '../src/greeter';
|
|
||||||
|
|
||||||
test('Should greet with message', () => {
|
|
||||||
const greeter = new Greeter('friend');
|
|
||||||
expect(greeter.greet()).toBe('Bonjour, friend!');
|
|
||||||
});
|
|
||||||
@@ -2,6 +2,7 @@ import * as Octokit from '@octokit/rest';
|
|||||||
import assert = require('assert');
|
import assert = require('assert');
|
||||||
import Bottleneck from 'bottleneck';
|
import Bottleneck from 'bottleneck';
|
||||||
|
|
||||||
|
// +++ General init +++
|
||||||
const octokit = new Octokit() as OctokitMod;
|
const octokit = new Octokit() as OctokitMod;
|
||||||
|
|
||||||
// Add rate limiter
|
// Add rate limiter
|
||||||
@@ -20,6 +21,10 @@ octokit.authenticate({
|
|||||||
secret: '2228539a48032f0622d6c12a66f56253d0a30d60',
|
secret: '2228539a48032f0622d6c12a66f56253d0a30d60',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// --- End General init ---
|
||||||
|
|
||||||
|
// +++ All typescript definitions +++
|
||||||
|
|
||||||
interface RequestOptions {
|
interface RequestOptions {
|
||||||
method: string;
|
method: string;
|
||||||
url: string;
|
url: string;
|
||||||
@@ -73,7 +78,7 @@ interface ResponseWithMetaLink {
|
|||||||
|
|
||||||
interface ResponseWithDataArrayAndMeta<T>
|
interface ResponseWithDataArrayAndMeta<T>
|
||||||
extends ResponseWithDataArray<T>,
|
extends ResponseWithDataArray<T>,
|
||||||
ResponseWithMetaLink {}
|
ResponseWithMetaLink { }
|
||||||
|
|
||||||
interface ResponseFromGetUserRepo extends ResponseWithMetaLink {
|
interface ResponseFromGetUserRepo extends ResponseWithMetaLink {
|
||||||
data: RepoFromGetUserRepo[];
|
data: RepoFromGetUserRepo[];
|
||||||
@@ -163,362 +168,374 @@ interface RepoNameWithParentRepo {
|
|||||||
|
|
||||||
interface RepoNameWithBranchesAndParent
|
interface RepoNameWithBranchesAndParent
|
||||||
extends RepoNameWithBranches,
|
extends RepoNameWithBranches,
|
||||||
RepoNameWithParentRepo {}
|
RepoNameWithParentRepo { }
|
||||||
|
|
||||||
const username = 'rousan';
|
|
||||||
|
|
||||||
interface ObjectWithPerPage {
|
interface ObjectWithPerPage {
|
||||||
per_page?: number;
|
per_page?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function paginate<TFirstParam extends ObjectWithPerPage, TDataElement>(
|
// --- End all typescript definitions ---
|
||||||
method: (
|
|
||||||
args: TFirstParam
|
|
||||||
) => Promise<ResponseWithDataArrayAndMeta<TDataElement>>,
|
|
||||||
args: TFirstParam
|
|
||||||
): Promise<ResponseWithDataArray<TDataElement>> {
|
|
||||||
// Set per_page
|
|
||||||
args.per_page = 100;
|
|
||||||
|
|
||||||
let response: ResponseWithDataArrayAndMeta<TDataElement> = await method(args);
|
class GithubDetectUnusedRepos {
|
||||||
|
private username: string;
|
||||||
|
|
||||||
// Concat all data
|
constructor(username: string) {
|
||||||
let { data } = response;
|
this.username = username;
|
||||||
while (octokit.hasNextPage(response)) {
|
|
||||||
response = await octokit.getNextPage(response);
|
|
||||||
data = data.concat(response.data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
public async fetchUnusedForkedRepos() {
|
||||||
data,
|
const params: Octokit.ReposGetForUserParams = {
|
||||||
};
|
this.username,
|
||||||
}
|
};
|
||||||
|
|
||||||
async function fetchRepoNameWithBranches(
|
const repos: ResponseWithDataArray<RepoFromGetUserRepo> = await this.paginate(
|
||||||
repoName: string
|
(
|
||||||
): Promise<RepoNameWithBranches> {
|
tmpFirstParam: Octokit.ReposGetForUserParams
|
||||||
const params: Octokit.ReposGetBranchesParams = {
|
): Promise<ResponseFromGetUserRepo> => {
|
||||||
owner: username,
|
return (octokit.repos.getForUser(tmpFirstParam) as any) as Promise<
|
||||||
repo: repoName,
|
ResponseFromGetUserRepo
|
||||||
};
|
>;
|
||||||
|
},
|
||||||
|
params
|
||||||
|
);
|
||||||
|
|
||||||
const branchesResponse: ResponseWithDataArray<
|
const forkedRepoNames = repos.data
|
||||||
BranchFromGetBranches
|
.filter(repo => repo.fork)
|
||||||
> = await paginate((tmpFirstParam: Octokit.ReposGetBranchesParams): Promise<
|
.map(repo => repo.name);
|
||||||
ResponseFromGetBranches
|
|
||||||
> => {
|
|
||||||
return (octokit.repos.getBranches(tmpFirstParam) as any) as Promise<
|
|
||||||
ResponseFromGetBranches
|
|
||||||
>;
|
|
||||||
}, params);
|
|
||||||
|
|
||||||
return {
|
// tslint:disable-next-line:no-console
|
||||||
repoName,
|
console.log(forkedRepoNames);
|
||||||
branches: branchesResponse.data,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchRepoNameWithParentRepo(
|
const allPromiseRepoNameWithBranches = forkedRepoNames.map(repoName => {
|
||||||
forkedRepoName: string
|
return this.fetchRepoNameWithBranches(repoName);
|
||||||
): Promise<RepoNameWithParentRepo> {
|
});
|
||||||
const responseRepoDetails: ResponseFromGetRepo = await octokit.repos.get({
|
|
||||||
owner: username,
|
|
||||||
repo: forkedRepoName,
|
|
||||||
});
|
|
||||||
|
|
||||||
const repoDetails = responseRepoDetails.data;
|
const allPromiseRepoNameWithParentRepo = forkedRepoNames.map(
|
||||||
|
forkedRepoName => {
|
||||||
|
return this.fetchRepoNameWithParentRepo(forkedRepoName);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
const allRepoNameWithBranches = await Promise.all(
|
||||||
repoName: forkedRepoName,
|
allPromiseRepoNameWithBranches
|
||||||
parentRepo: repoDetails.parent,
|
);
|
||||||
};
|
const allRepoNameWithParentRepo = await Promise.all(
|
||||||
}
|
allPromiseRepoNameWithParentRepo
|
||||||
|
);
|
||||||
|
|
||||||
async function fetchForkBranchIsNotAhead(
|
// Both the above list (of objects) have same number of items and
|
||||||
parentRepoOwner: string,
|
// items in the same index (of both lists) have same value for repoName key.
|
||||||
parentRepoName: string,
|
|
||||||
forkedRepoOwner: string,
|
|
||||||
forkedRepoName: string,
|
|
||||||
forkedBranchName: string,
|
|
||||||
parentBranchName?: string
|
|
||||||
): Promise<boolean> {
|
|
||||||
let commitObject: ResponseFromCompareCommits;
|
|
||||||
|
|
||||||
if (parentBranchName === undefined) {
|
// So join them together into one list of objects (each object containing branches and parent repo)
|
||||||
parentBranchName = forkedBranchName;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
assert.strictEqual(
|
||||||
commitObject = ((await octokit.repos.compareCommits({
|
allRepoNameWithBranches.length,
|
||||||
// both owner and repo can be either parent or forked, for this usecase
|
allRepoNameWithParentRepo.length,
|
||||||
owner: parentRepoOwner,
|
'Length of `allRepoNameWithBranches` and `allRepoNameWithParentRepo` should be same'
|
||||||
repo: parentRepoName,
|
);
|
||||||
base: `${parentRepoOwner}:${parentBranchName}`,
|
|
||||||
head: `${forkedRepoOwner}:${forkedBranchName}`,
|
|
||||||
})) as any) as ResponseFromCompareCommits;
|
|
||||||
} catch {
|
|
||||||
const fallBackParentBranchName = 'master';
|
|
||||||
|
|
||||||
if (parentBranchName !== fallBackParentBranchName) {
|
const allRepoNameWithBranchesAndParent: RepoNameWithBranchesAndParent[] = [];
|
||||||
return fetchForkBranchIsNotAhead(
|
{
|
||||||
parentRepoOwner,
|
const tmpLength = allRepoNameWithBranches.length;
|
||||||
parentRepoName,
|
|
||||||
forkedRepoOwner,
|
for (let index = 0; index < tmpLength; index++) {
|
||||||
forkedRepoName,
|
const tmpRepoNameWithBranches = allRepoNameWithBranches[index];
|
||||||
forkedBranchName,
|
const tmpRepoNameWithParentRepo = allRepoNameWithParentRepo[index];
|
||||||
fallBackParentBranchName
|
|
||||||
|
assert.strictEqual(
|
||||||
|
tmpRepoNameWithBranches.repoName,
|
||||||
|
tmpRepoNameWithParentRepo.repoName,
|
||||||
|
'Reponame should be same for objects stored at same index in `allRepoNameWithBranches` and `allRepoNameWithParentRepo`'
|
||||||
|
);
|
||||||
|
|
||||||
|
const repoName = tmpRepoNameWithBranches.repoName;
|
||||||
|
|
||||||
|
const combinedObject: RepoNameWithBranchesAndParent = {
|
||||||
|
repoName,
|
||||||
|
branches: tmpRepoNameWithBranches.branches,
|
||||||
|
parentRepo: tmpRepoNameWithParentRepo.parentRepo,
|
||||||
|
};
|
||||||
|
|
||||||
|
allRepoNameWithBranchesAndParent.push(combinedObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const allRepoWithFlagTillStep4: RepoNameWithUnusedFlag[] = [];
|
||||||
|
|
||||||
|
{
|
||||||
|
const allPromiseRepoWithFlagFromCommit = allRepoNameWithBranchesAndParent.map(
|
||||||
|
(repoInfo: RepoNameWithBranchesAndParent) => {
|
||||||
|
return this.fetchNoneOfForkBranchesIsAhead(repoInfo);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const allPromiseRepoWithFlagFromForkContrib = allRepoNameWithBranchesAndParent.map(
|
||||||
|
({ repoName }) => {
|
||||||
|
return this.fetchUserIsNotContributor(this.username, repoName);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const allPromiseRepoWithFlagFromParentContrib = allRepoNameWithBranchesAndParent.map(
|
||||||
|
({ repoName, parentRepo }) => {
|
||||||
|
return this.fetchUserIsNotContributor(parentRepo.owner.login, repoName);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const allRepoWithFlagFromCommit: RepoNameWithUnusedFlag[] = await Promise.all(
|
||||||
|
allPromiseRepoWithFlagFromCommit
|
||||||
|
);
|
||||||
|
|
||||||
|
const allRepoWithFlagFromForkContrib: RepoNameWithUnusedFlag[] = await Promise.all(
|
||||||
|
allPromiseRepoWithFlagFromForkContrib
|
||||||
|
);
|
||||||
|
|
||||||
|
const allRepoWithFlagFromParentContrib: RepoNameWithUnusedFlag[] = await Promise.all(
|
||||||
|
allPromiseRepoWithFlagFromParentContrib
|
||||||
|
);
|
||||||
|
|
||||||
|
{
|
||||||
|
assert.strictEqual(
|
||||||
|
allRepoWithFlagFromCommit.length,
|
||||||
|
allRepoWithFlagFromForkContrib.length,
|
||||||
|
'Length of `allRepoWithFlagFromCommit` and `allRepoWithFlagFromContrib` should be same'
|
||||||
|
);
|
||||||
|
|
||||||
|
const repoCount = allRepoWithFlagFromCommit.length;
|
||||||
|
|
||||||
|
for (let index = 0; index < repoCount; index++) {
|
||||||
|
const tmpObjFromCommit = allRepoWithFlagFromCommit[index];
|
||||||
|
const tmpObjFromForkContrib = allRepoWithFlagFromForkContrib[index];
|
||||||
|
const tmpObjFromParentContrib = allRepoWithFlagFromParentContrib[index];
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
tmpObjFromCommit.repoName,
|
||||||
|
tmpObjFromForkContrib.repoName,
|
||||||
|
'Reponame from same index of `allRepoWithFlagFromCommit` and `allRepoWithFlagFromContrib` should be same'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
tmpObjFromForkContrib.repoName,
|
||||||
|
tmpObjFromParentContrib.repoName,
|
||||||
|
'Reponame from same index of `tmpObjFromForkContrib` and `tmpObjFromParentContrib` should be same'
|
||||||
|
);
|
||||||
|
|
||||||
|
const tmpRepoName = tmpObjFromCommit.repoName;
|
||||||
|
|
||||||
|
allRepoWithFlagTillStep4.push({
|
||||||
|
repoName: tmpRepoName,
|
||||||
|
unused:
|
||||||
|
tmpObjFromCommit.unused &&
|
||||||
|
tmpObjFromForkContrib.unused &&
|
||||||
|
tmpObjFromParentContrib.unused,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const unusedRepoNames = allRepoWithFlagTillStep4
|
||||||
|
.filter(tmp => tmp.unused)
|
||||||
|
.map(tmp => tmp.repoName);
|
||||||
|
|
||||||
|
return unusedRepoNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async paginate<TFirstParam extends ObjectWithPerPage, TDataElement>(
|
||||||
|
method: (
|
||||||
|
args: TFirstParam
|
||||||
|
) => Promise<ResponseWithDataArrayAndMeta<TDataElement>>,
|
||||||
|
args: TFirstParam
|
||||||
|
): Promise<ResponseWithDataArray<TDataElement>> {
|
||||||
|
// Set per_page
|
||||||
|
args.per_page = 100;
|
||||||
|
|
||||||
|
let response: ResponseWithDataArrayAndMeta<TDataElement> = await method(args);
|
||||||
|
|
||||||
|
// Concat all data
|
||||||
|
let { data } = response;
|
||||||
|
while (octokit.hasNextPage(response)) {
|
||||||
|
response = await octokit.getNextPage(response);
|
||||||
|
data = data.concat(response.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetchRepoNameWithBranches(
|
||||||
|
repoName: string
|
||||||
|
): Promise<RepoNameWithBranches> {
|
||||||
|
const params: Octokit.ReposGetBranchesParams = {
|
||||||
|
owner: this.username,
|
||||||
|
repo: repoName,
|
||||||
|
};
|
||||||
|
|
||||||
|
const branchesResponse: ResponseWithDataArray<
|
||||||
|
BranchFromGetBranches
|
||||||
|
> = await this.paginate((tmpFirstParam: Octokit.ReposGetBranchesParams): Promise<
|
||||||
|
ResponseFromGetBranches
|
||||||
|
> => {
|
||||||
|
return (octokit.repos.getBranches(tmpFirstParam) as any) as Promise<
|
||||||
|
ResponseFromGetBranches
|
||||||
|
>;
|
||||||
|
}, params);
|
||||||
|
|
||||||
|
return {
|
||||||
|
repoName,
|
||||||
|
branches: branchesResponse.data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetchRepoNameWithParentRepo(
|
||||||
|
forkedRepoName: string
|
||||||
|
): Promise<RepoNameWithParentRepo> {
|
||||||
|
const responseRepoDetails: ResponseFromGetRepo = await octokit.repos.get({
|
||||||
|
owner: this.username,
|
||||||
|
repo: forkedRepoName,
|
||||||
|
});
|
||||||
|
|
||||||
|
const repoDetails = responseRepoDetails.data;
|
||||||
|
|
||||||
|
return {
|
||||||
|
repoName: forkedRepoName,
|
||||||
|
parentRepo: repoDetails.parent,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetchForkBranchIsNotAhead(
|
||||||
|
parentRepoOwner: string,
|
||||||
|
parentRepoName: string,
|
||||||
|
forkedRepoOwner: string,
|
||||||
|
forkedRepoName: string,
|
||||||
|
forkedBranchName: string,
|
||||||
|
parentBranchName?: string
|
||||||
|
): Promise<boolean> {
|
||||||
|
let commitObject: ResponseFromCompareCommits;
|
||||||
|
|
||||||
|
if (parentBranchName === undefined) {
|
||||||
|
parentBranchName = forkedBranchName;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
commitObject = ((await octokit.repos.compareCommits({
|
||||||
|
// both owner and repo can be either parent or forked, for this usecase
|
||||||
|
owner: parentRepoOwner,
|
||||||
|
repo: parentRepoName,
|
||||||
|
base: `${parentRepoOwner}:${parentBranchName}`,
|
||||||
|
head: `${forkedRepoOwner}:${forkedBranchName}`,
|
||||||
|
})) as any) as ResponseFromCompareCommits;
|
||||||
|
} catch {
|
||||||
|
const fallBackParentBranchName = 'master';
|
||||||
|
|
||||||
|
if (parentBranchName !== fallBackParentBranchName) {
|
||||||
|
return this.fetchForkBranchIsNotAhead(
|
||||||
|
parentRepoOwner,
|
||||||
|
parentRepoName,
|
||||||
|
forkedRepoOwner,
|
||||||
|
forkedRepoName,
|
||||||
|
forkedBranchName,
|
||||||
|
fallBackParentBranchName
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commitObject.data.ahead_by === 0) {
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (commitObject.data.ahead_by === 0) {
|
// Async determine if parent repo contains all commits which are
|
||||||
return true;
|
// currently set as HEAD in each branch of the original repo
|
||||||
} else {
|
private async fetchNoneOfForkBranchesIsAhead(
|
||||||
return false;
|
repoInfo: RepoNameWithBranchesAndParent
|
||||||
}
|
): Promise<RepoNameWithUnusedFlag> {
|
||||||
}
|
const allPromiseBranchUnused = repoInfo.branches.map(tmpBranch => {
|
||||||
|
return this.fetchForkBranchIsNotAhead(
|
||||||
|
repoInfo.parentRepo.owner.login,
|
||||||
|
repoInfo.parentRepo.name,
|
||||||
|
this.username,
|
||||||
|
repoInfo.repoName,
|
||||||
|
tmpBranch.name
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// Async determine if parent repo contains all commits which are
|
const allBranchUnused = await Promise.all(allPromiseBranchUnused);
|
||||||
// currently set as HEAD in each branch of the original repo
|
|
||||||
async function fetchNoneOfForkBranchesIsAhead(
|
const everyBranchUnused = allBranchUnused.every(
|
||||||
repoInfo: RepoNameWithBranchesAndParent
|
tmpBoolean => tmpBoolean === true
|
||||||
): Promise<RepoNameWithUnusedFlag> {
|
|
||||||
const allPromiseBranchUnused = repoInfo.branches.map(tmpBranch => {
|
|
||||||
return fetchForkBranchIsNotAhead(
|
|
||||||
repoInfo.parentRepo.owner.login,
|
|
||||||
repoInfo.parentRepo.name,
|
|
||||||
username,
|
|
||||||
repoInfo.repoName,
|
|
||||||
tmpBranch.name
|
|
||||||
);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
const allBranchUnused = await Promise.all(allPromiseBranchUnused);
|
return {
|
||||||
|
repoName: repoInfo.repoName,
|
||||||
|
unused: everyBranchUnused,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const everyBranchUnused = allBranchUnused.every(
|
private async fetchUserIsNotContributor(
|
||||||
tmpBoolean => tmpBoolean === true
|
repoOwner: string,
|
||||||
);
|
repoName: string
|
||||||
|
): Promise<RepoNameWithUnusedFlag> {
|
||||||
|
const params: Octokit.ReposGetContributorsParams = {
|
||||||
|
owner: repoOwner,
|
||||||
|
repo: repoName,
|
||||||
|
anon: '0',
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
const responseFromGetContributors: ResponseWithDataArray<
|
||||||
repoName: repoInfo.repoName,
|
OwnerFromGetContributors
|
||||||
unused: everyBranchUnused,
|
> = await this.paginate(
|
||||||
};
|
async (
|
||||||
}
|
tmpFirstParam: Octokit.ReposGetContributorsParams
|
||||||
|
): Promise<ResponseWithDataArrayAndMeta<OwnerFromGetContributors>> => {
|
||||||
|
// 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>);
|
||||||
|
|
||||||
async function fetchUserIsNotContributor(
|
let dataNormalized = response.data;
|
||||||
repoOwner: string,
|
if (dataNormalized === undefined) {
|
||||||
repoName: string
|
dataNormalized = [];
|
||||||
): Promise<RepoNameWithUnusedFlag> {
|
}
|
||||||
const params: Octokit.ReposGetContributorsParams = {
|
|
||||||
owner: repoOwner,
|
|
||||||
repo: repoName,
|
|
||||||
anon: '0',
|
|
||||||
};
|
|
||||||
|
|
||||||
const responseFromGetContributors: ResponseWithDataArray<
|
const responseNormalized: ResponseWithDataArrayAndMeta<
|
||||||
OwnerFromGetContributors
|
OwnerFromGetContributors
|
||||||
> = await paginate(
|
> = {
|
||||||
async (
|
data: dataNormalized,
|
||||||
tmpFirstParam: Octokit.ReposGetContributorsParams
|
meta: response.meta,
|
||||||
): Promise<ResponseWithDataArrayAndMeta<OwnerFromGetContributors>> => {
|
};
|
||||||
// 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>);
|
|
||||||
|
|
||||||
let dataNormalized = response.data;
|
return responseNormalized;
|
||||||
if (dataNormalized === undefined) {
|
},
|
||||||
dataNormalized = [];
|
params
|
||||||
}
|
|
||||||
|
|
||||||
const responseNormalized: ResponseWithDataArrayAndMeta<
|
|
||||||
OwnerFromGetContributors
|
|
||||||
> = {
|
|
||||||
data: dataNormalized,
|
|
||||||
meta: response.meta,
|
|
||||||
};
|
|
||||||
|
|
||||||
return responseNormalized;
|
|
||||||
},
|
|
||||||
params
|
|
||||||
);
|
|
||||||
|
|
||||||
const contributors = responseFromGetContributors.data;
|
|
||||||
|
|
||||||
const matchingContributor = contributors.find(
|
|
||||||
tmpContributor => tmpContributor.login === username
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
// tslint:disable-next-line:object-literal-shorthand
|
|
||||||
repoName: repoName,
|
|
||||||
unused: matchingContributor === undefined,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function fetchUnusedForkedRepos() {
|
|
||||||
const params: Octokit.ReposGetForUserParams = {
|
|
||||||
username,
|
|
||||||
};
|
|
||||||
|
|
||||||
const repos: ResponseWithDataArray<RepoFromGetUserRepo> = await paginate(
|
|
||||||
(
|
|
||||||
tmpFirstParam: Octokit.ReposGetForUserParams
|
|
||||||
): Promise<ResponseFromGetUserRepo> => {
|
|
||||||
return (octokit.repos.getForUser(tmpFirstParam) as any) as Promise<
|
|
||||||
ResponseFromGetUserRepo
|
|
||||||
>;
|
|
||||||
},
|
|
||||||
params
|
|
||||||
);
|
|
||||||
|
|
||||||
const forkedRepoNames = repos.data
|
|
||||||
.filter(repo => repo.fork)
|
|
||||||
.map(repo => repo.name);
|
|
||||||
|
|
||||||
// tslint:disable-next-line:no-console
|
|
||||||
console.log(forkedRepoNames);
|
|
||||||
|
|
||||||
const allPromiseRepoNameWithBranches = forkedRepoNames.map(repoName => {
|
|
||||||
return fetchRepoNameWithBranches(repoName);
|
|
||||||
});
|
|
||||||
|
|
||||||
const allPromiseRepoNameWithParentRepo = forkedRepoNames.map(
|
|
||||||
forkedRepoName => {
|
|
||||||
return fetchRepoNameWithParentRepo(forkedRepoName);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const allRepoNameWithBranches = await Promise.all(
|
|
||||||
allPromiseRepoNameWithBranches
|
|
||||||
);
|
|
||||||
const allRepoNameWithParentRepo = await Promise.all(
|
|
||||||
allPromiseRepoNameWithParentRepo
|
|
||||||
);
|
|
||||||
|
|
||||||
// Both the above list (of objects) have same number of items and
|
|
||||||
// items in the same index (of both lists) have same value for repoName key.
|
|
||||||
|
|
||||||
// So join them together into one list of objects (each object containing branches and parent repo)
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
allRepoNameWithBranches.length,
|
|
||||||
allRepoNameWithParentRepo.length,
|
|
||||||
'Length of `allRepoNameWithBranches` and `allRepoNameWithParentRepo` should be same'
|
|
||||||
);
|
|
||||||
|
|
||||||
const allRepoNameWithBranchesAndParent: RepoNameWithBranchesAndParent[] = [];
|
|
||||||
{
|
|
||||||
const tmpLength = allRepoNameWithBranches.length;
|
|
||||||
|
|
||||||
for (let index = 0; index < tmpLength; index++) {
|
|
||||||
const tmpRepoNameWithBranches = allRepoNameWithBranches[index];
|
|
||||||
const tmpRepoNameWithParentRepo = allRepoNameWithParentRepo[index];
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
tmpRepoNameWithBranches.repoName,
|
|
||||||
tmpRepoNameWithParentRepo.repoName,
|
|
||||||
'Reponame should be same for objects stored at same index in `allRepoNameWithBranches` and `allRepoNameWithParentRepo`'
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const repoName = tmpRepoNameWithBranches.repoName;
|
const contributors = responseFromGetContributors.data;
|
||||||
|
|
||||||
const combinedObject: RepoNameWithBranchesAndParent = {
|
const matchingContributor = contributors.find(
|
||||||
repoName,
|
tmpContributor => tmpContributor.login === this.username
|
||||||
branches: tmpRepoNameWithBranches.branches,
|
);
|
||||||
parentRepo: tmpRepoNameWithParentRepo.parentRepo,
|
|
||||||
};
|
|
||||||
|
|
||||||
allRepoNameWithBranchesAndParent.push(combinedObject);
|
return {
|
||||||
}
|
// tslint:disable-next-line:object-literal-shorthand
|
||||||
|
repoName: repoName,
|
||||||
|
unused: matchingContributor === undefined,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const allRepoWithFlagTillStep4: RepoNameWithUnusedFlag[] = [];
|
|
||||||
|
|
||||||
{
|
|
||||||
const allPromiseRepoWithFlagFromCommit = allRepoNameWithBranchesAndParent.map(
|
|
||||||
(repoInfo: RepoNameWithBranchesAndParent) => {
|
|
||||||
return fetchNoneOfForkBranchesIsAhead(repoInfo);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const allPromiseRepoWithFlagFromForkContrib = allRepoNameWithBranchesAndParent.map(
|
|
||||||
({ repoName }) => {
|
|
||||||
return fetchUserIsNotContributor(username, repoName);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const allPromiseRepoWithFlagFromParentContrib = allRepoNameWithBranchesAndParent.map(
|
|
||||||
({ repoName, parentRepo }) => {
|
|
||||||
return fetchUserIsNotContributor(parentRepo.owner.login, repoName);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const allRepoWithFlagFromCommit: RepoNameWithUnusedFlag[] = await Promise.all(
|
|
||||||
allPromiseRepoWithFlagFromCommit
|
|
||||||
);
|
|
||||||
|
|
||||||
const allRepoWithFlagFromForkContrib: RepoNameWithUnusedFlag[] = await Promise.all(
|
|
||||||
allPromiseRepoWithFlagFromForkContrib
|
|
||||||
);
|
|
||||||
|
|
||||||
const allRepoWithFlagFromParentContrib: RepoNameWithUnusedFlag[] = await Promise.all(
|
|
||||||
allPromiseRepoWithFlagFromParentContrib
|
|
||||||
);
|
|
||||||
|
|
||||||
{
|
|
||||||
assert.strictEqual(
|
|
||||||
allRepoWithFlagFromCommit.length,
|
|
||||||
allRepoWithFlagFromForkContrib.length,
|
|
||||||
'Length of `allRepoWithFlagFromCommit` and `allRepoWithFlagFromContrib` should be same'
|
|
||||||
);
|
|
||||||
|
|
||||||
const repoCount = allRepoWithFlagFromCommit.length;
|
|
||||||
|
|
||||||
for (let index = 0; index < repoCount; index++) {
|
|
||||||
const tmpObjFromCommit = allRepoWithFlagFromCommit[index];
|
|
||||||
const tmpObjFromForkContrib = allRepoWithFlagFromForkContrib[index];
|
|
||||||
const tmpObjFromParentContrib = allRepoWithFlagFromParentContrib[index];
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
tmpObjFromCommit.repoName,
|
|
||||||
tmpObjFromForkContrib.repoName,
|
|
||||||
'Reponame from same index of `allRepoWithFlagFromCommit` and `allRepoWithFlagFromContrib` should be same'
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
tmpObjFromForkContrib.repoName,
|
|
||||||
tmpObjFromParentContrib.repoName,
|
|
||||||
'Reponame from same index of `tmpObjFromForkContrib` and `tmpObjFromParentContrib` should be same'
|
|
||||||
);
|
|
||||||
|
|
||||||
const tmpRepoName = tmpObjFromCommit.repoName;
|
|
||||||
|
|
||||||
allRepoWithFlagTillStep4.push({
|
|
||||||
repoName: tmpRepoName,
|
|
||||||
unused:
|
|
||||||
tmpObjFromCommit.unused &&
|
|
||||||
tmpObjFromForkContrib.unused &&
|
|
||||||
tmpObjFromParentContrib.unused,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const unusedRepoNames = allRepoWithFlagTillStep4
|
|
||||||
.filter(tmp => tmp.unused)
|
|
||||||
.map(tmp => tmp.repoName);
|
|
||||||
|
|
||||||
return unusedRepoNames;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function runMain() {
|
|
||||||
fetchUnusedForkedRepos().then(unusedRepoNames => {
|
|
||||||
// tslint:disable-next-line:no-console
|
export function runMain(username: string = 'bendtherules') {
|
||||||
console.log(unusedRepoNames);
|
new GithubDetectUnusedRepos(username)
|
||||||
});
|
.fetchUnusedForkedRepos()
|
||||||
|
.then(unusedRepoNames => {
|
||||||
|
// tslint:disable-next-line:no-console
|
||||||
|
console.log(unusedRepoNames);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next steps
|
// Next steps
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
export class Greeter {
|
|
||||||
private greeting: string;
|
|
||||||
|
|
||||||
constructor(message: string) {
|
|
||||||
this.greeting = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public greet(): string {
|
|
||||||
return `Bonjour, ${this.greeting}!`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
import 'babel-polyfill';
|
import 'babel-polyfill';
|
||||||
import { Greeter } from './greeter';
|
|
||||||
// tslint:disable-next-line:ordered-imports
|
// tslint:disable-next-line:ordered-imports
|
||||||
import { fetchUnusedForkedRepos, runMain } from './gh';
|
import { fetchUnusedForkedRepos, runMain } from './gh';
|
||||||
export * from './greeter';
|
|
||||||
|
|
||||||
// tslint:disable-next-line:only-arrow-functions
|
// tslint:disable-next-line:only-arrow-functions
|
||||||
(function(currentWindow: Window) {
|
(function(currentWindow: Window) {
|
||||||
@@ -13,7 +11,6 @@ export * from './greeter';
|
|||||||
|
|
||||||
// assign Greeter to global
|
// assign Greeter to global
|
||||||
const myWindow = currentWindow as any;
|
const myWindow = currentWindow as any;
|
||||||
myWindow.Greeter = Greeter;
|
|
||||||
myWindow.runMain = runMain;
|
myWindow.runMain = runMain;
|
||||||
// we can use Greeter , execute following in console
|
// we can use Greeter , execute following in console
|
||||||
// var greet = new Greeter('myName');
|
// var greet = new Greeter('myName');
|
||||||
|
|||||||
Reference in New Issue
Block a user