import path from 'path'; import { components } from '@octokit/openapi-types'; import { RepositoryHelper } from './repository'; import { getChangedLineNumbersFromPatch } from './parseGitPatch'; type PullRequest = components['schemas']['pull-request']; type PullRequestFile = components['schemas']['diff-entry']; export class PullRequestHelper extends RepositoryHelper { protected prNumber: number; protected prQuery: { owner: string; repo: string; pull_number: number; }; protected prData: PullRequest | undefined; constructor(owner: string, repo: string, prNumber: number, octokit: unknown = undefined) { super(owner, repo, octokit); this.prNumber = prNumber; this.prQuery = { owner, repo, pull_number: prNumber, }; } async getBranchName(): Promise { return (await this.getPr()).head.ref; } async getTitle(): Promise { return (await this.getPr()).title; } async getUrl(): Promise { return (await this.getPr()).html_url; } async getReviewers(): Promise { const requestedReviewers = (await this.getPr()).requested_reviewers?.map((r) => r.login); const reviewResponse = await this.getOctokit().rest.pulls.listReviews(this.prQuery); const actualReviewers = reviewResponse.data.map((r) => r.user?.login ?? '').filter((r) => r.length > 0); return [...(requestedReviewers ?? []), ...actualReviewers]; } async getFiles(): Promise { const prResponse = await this.getOctokit().rest.pulls.listFiles(this.prQuery); return prResponse.data; } async hasQualifiedChanges(fileExtensions: string[], linesChangedThreshold: number): Promise { return ( (await this.getFiles()) .filter( (f) => !['renamed', 'removed', 'unchanged'].includes(f.status) && fileExtensions.includes(path.extname(f.filename).toLowerCase()), ) .map((f) => getChangedLineNumbersFromPatch(f.patch as string).length) .reduce((partialSum, numLines) => partialSum + numLines, 0) > linesChangedThreshold ); } async addComment(body: string): Promise { await this.getOctokit().rest.issues.createComment({ owner: this.owner, repo: this.repo, issue_number: this.prNumber, body, }); } private async getPr(): Promise { if (!this.prData) { const prInfoResponse = await this.getOctokit().rest.pulls.get(this.prQuery); if (prInfoResponse.status !== 200) { throw prInfoResponse; } this.prData = prInfoResponse.data; } return this.prData; } }