branch-remover
Version:
A small application for quickly removing unnecessary branches from GitHub.
184 lines (151 loc) • 4.79 kB
text/typescript
import { Octokit, RestEndpointMethodTypes } from '@octokit/rest';
import {
Branch,
BranchListItem,
IBranchesProvider,
} from '../../Core';
import {
Auth,
Commit,
PullRequestStatus,
} from './Types';
export class GitHubProvider implements IBranchesProvider {
private readonly _auth: Auth;
private readonly _client: Octokit;
private get owner(): string {
return this._auth.owner;
}
private get repo(): string {
return this._auth.repo;
}
public get name(): string {
return 'GitHub';
}
constructor(auth: Auth) {
Object.getOwnPropertyNames(new Auth(null, null, null)).forEach(
(x: string): void => {
if (!auth[x]) {
throw new Error(`The "${x}" property is required. The value must not be empty.`);
}
}
);
this._client = new Octokit({
auth: auth.token,
});
this._auth = auth;
this.getListBranches = this.getListBranches.bind(this);
this.removeBranch = this.removeBranch.bind(this);
this.getPullRequestStatus = this.getPullRequestStatus.bind(this);
this.getLastCommit = this.getLastCommit.bind(this);
}
public async getListBranches(): Promise<Array<BranchListItem>> {
const result = new Array<BranchListItem>();
const getList = async(page: number): Promise<Array<BranchListItem>> => {
const { data }= await this._client.repos.listBranches({
owner: this.owner,
repo: this.repo,
per_page: 100,
page,
});
return data.map<BranchListItem>(
(x): BranchListItem => {
return {
name: x.name,
lastCommitHash: x.commit.sha,
};
}
);
};
let page = 1;
let list = await getList(page);
while (list.length) {
result.push(...list);
list = await getList(++page);
}
return result;
}
public async getBranch(branchName: string, lastCommitHash?: string): Promise<Branch> {
const { data } = await this._client.search.issuesAndPullRequests({
q: `repo:${this.owner}/${this.repo} is:pr head:${branchName}` + (lastCommitHash ? ` hash:${lastCommitHash}` : ''),
sort: 'updated',
order: 'desc',
});
const additionalInfo = new Map<string, string>();
let updatedDate: Date = null;
let mergedDate: Date = null;
let merged = false;
let hasUncommittedChanges = false;
let status: PullRequestStatus;
let item: RestEndpointMethodTypes['search']['issuesAndPullRequests']['response']['data']['items'][0];
if (data.items.length) {
for (const x of data.items) {
status = await this.getPullRequestStatus(x.number);
if (status.sourceBranchName === branchName) {
item = x;
updatedDate = new Date(status.updatedDate);
hasUncommittedChanges = updatedDate > status.mergedDate;
break;
}
}
}
if (item) {
updatedDate = new Date(item.updated_at);
if (item.state === 'closed') {
merged = status.merged;
mergedDate = status.mergedDate;
}
if (item.pull_request) {
additionalInfo.set('Pull Request Url', item.pull_request.html_url);
}
} else {
const commit = await this.getLastCommit(branchName);
updatedDate = new Date(commit.date);
}
return {
name: branchName,
merged,
mergedDate,
updatedDate,
hasUncommittedChanges,
additionalInfo,
url: `https://github.com/${this._auth.owner}/${this._auth.repo}/tree/${branchName}`,
};
}
public async removeBranch(branchName: string): Promise<void> {
await this._client.git.deleteRef({
owner: this.owner,
repo: this.repo,
ref: `heads/${branchName}`,
});
}
private async getPullRequestStatus(pullRequestNumber: number): Promise<PullRequestStatus> {
const { data } = await this._client.pulls.get({
owner: this.owner,
repo: this.repo,
pull_number: pullRequestNumber,
});
return {
sourceBranchName: data.head.ref,
targetBranchName: data.base.ref,
merged: data.merged,
mergeable: data.mergeable,
mergeableState: data.mergeable_state as any,
mergedDate: data.merged_at && new Date(data.merged_at),
mergeCommitHash: data.merge_commit_sha,
closedDate: data.closed_at && new Date(data.closed_at),
updatedDate: data.updated_at && new Date(data.updated_at),
createdDate: new Date(data.created_at),
};
}
private async getLastCommit(branchName: string): Promise<Commit> {
const { data } = await this._client.repos.getCommit({
owner: this.owner,
repo: this.repo,
ref: branchName,
});
return {
hash: data.sha,
date: new Date(data.commit.committer.date),
};
}
}