Path: blob/main/extensions/copilot/src/extension/prompts/node/test/fixtures/pullRequestModel.summarized.ts
13406 views
1export class PullRequestModel extends IssueModel<PullRequest> implements IPullRequestModel {2async createCommentReply(3body: string,4inReplyTo: string,5isSingleComment: boolean,6commitId?: string,7): Promise<IComment | undefined> {…}89/**10* Check whether there is an existing pending review and update the context key to control what comment actions are shown.11*/12async validateDraftMode(): Promise<boolean> {…}1314private async updateDraftModeContext() {…}1516/**17* Edit an existing review comment.18* @param comment The comment to edit19* @param text The new comment text20*/21async editReviewComment(comment: IComment, text: string): Promise<IComment> {…}2223/**24* Deletes a review comment.25* @param commentId The comment id to delete26*/27async deleteReviewComment(commentId: string): Promise<void> {…}2829/**30* Get existing requests to review.31*/32async getReviewRequests(): Promise<IAccount[]> {…}3334/**35* Add reviewers to a pull request36* @param reviewers A list of GitHub logins37*/38async requestReview(reviewers: string[]): Promise<void> {…}3940/**41* Remove a review request that has not yet been completed42* @param reviewer A GitHub Login43*/44async deleteReviewRequest(reviewers: string[]): Promise<void> {…}4546async deleteAssignees(assignees: string[]): Promise<void> {…}4748private diffThreads(oldReviewThreads: IReviewThread[], newReviewThreads: IReviewThread[]): void {4950newReviewThreads.forEach(thread => {…});5152oldReviewThreads.forEach(thread => {…});5354this._onDidChangeReviewThreads.fire({55added,56changed,57removed,58});59}6061async getReviewThreads(): Promise<IReviewThread[]> {62const { remote, query, schema } = await this.githubRepository.ensure();63try {…} catch (e) {…}64}6566/**67* Get all review comments.68*/69async initializeReviewComments(): Promise<void> {70const { remote, query, schema } = await this.githubRepository.ensure();71try {…} catch (e) {…}72}7374/**75* Get a list of the commits within a pull request.76*/77async getCommits(): Promise<OctokitCommon.PullsListCommitsResponseData> {78try {…} catch (e) {…}79}8081/**82* Get all changed files within a commit83* @param commit The commit84*/85async getCommitChangedFiles(86commit: OctokitCommon.PullsListCommitsResponseData[0],87): Promise<OctokitCommon.ReposGetCommitResponseFiles> {88try {…} catch (e) {…}89}9091/**92* Gets file content for a file at the specified commit93* @param filePath The file path94* @param commit The commit95*/96async getFile(filePath: string, commit: string) {97const { octokit, remote } = await this.githubRepository.ensure();98const fileContent = await octokit.call(octokit.api.repos.getContent, {99owner: remote.owner,100repo: remote.repositoryName,101path: filePath,102ref: commit,103});104105if (Array.isArray(fileContent.data)) {…}106107const contents = (fileContent.data as any).content ?? '';108const buff = buffer.Buffer.from(contents, (fileContent.data as any).encoding);109return buff.toString();110}111112/**113* Get the timeline events of a pull request, including comments, reviews, commits, merges, deletes, and assigns.114*/115async getTimelineEvents(): Promise<TimelineEvent[]> {116Logger.debug(`Fetch timeline events of PR #${this.number} - enter`, PullRequestModel.ID);117const { query, remote, schema } = await this.githubRepository.ensure();118119try {120121const ret = data.repository.pullRequest.timelineItems.nodes;122const events = parseGraphQLTimelineEvents(ret, this.githubRepository);123124this.addReviewTimelineEventComments(events, reviewThreads);125insertNewCommitsSinceReview(events, latestReviewCommitInfo?.sha, currentUser, this.head);126127return events;128} catch (e) {129console.log(e);130return [];131}132}133134private addReviewTimelineEventComments(events: TimelineEvent[], reviewThreads: IReviewThread[]): void {135interface CommentNode extends IComment {136childComments?: CommentNode[];137}138139const reviewEvents = events.filter((e): e is CommonReviewEvent => e.event === EventType.Reviewed);140const reviewComments = reviewThreads.reduce((previous, current) => (previous as IComment[]).concat(current.comments), []);141142const reviewEventsById = reviewEvents.reduce((index, evt) => {143index[evt.id] = evt;144evt.comments = [];145return index;146}, {} as { [key: number]: CommonReviewEvent });147148const commentsById = reviewComments.reduce((index, evt) => {149index[evt.id] = evt;150return index;151}, {} as { [key: number]: CommentNode });152153const roots: CommentNode[] = [];154let i = reviewComments.length;155while (i-- > 0) {156const c: CommentNode = reviewComments[i];157if (!c.inReplyToId) {158roots.unshift(c);159continue;160}161const parent = commentsById[c.inReplyToId];162parent.childComments = parent.childComments || [];163parent.childComments = [c, ...(c.childComments || []), ...parent.childComments];164}165166roots.forEach(c => {167const review = reviewEventsById[c.pullRequestReviewId!];168if (review) {…}169});170171reviewThreads.forEach(thread => {172if (!thread.prReviewDatabaseId || !reviewEventsById[thread.prReviewDatabaseId]) {…}173const prReviewThreadEvent = reviewEventsById[thread.prReviewDatabaseId];174prReviewThreadEvent.reviewThread = {175threadId: thread.id,176canResolve: thread.viewerCanResolve,177canUnresolve: thread.viewerCanUnresolve,178isResolved: thread.isResolved179};180181});182183const pendingReview = reviewEvents.filter(r => r.state.toLowerCase() === 'pending')[0];184if (pendingReview) {185// Ensures that pending comments made in reply to other reviews are included for the pending review186pendingReview.comments = reviewComments.filter(c => c.isDraft);187}188}189190private async _getReviewRequiredCheck() {191const { query, remote, octokit, schema } = await this.githubRepository.ensure();192193const [branch, reviewStates] = await Promise.all([194octokit.call(octokit.api.repos.getBranch, { branch: this.base.ref, owner: remote.owner, repo: remote.repositoryName }),195query<LatestReviewsResponse>({196query: schema.LatestReviews,197variables: {198owner: remote.owner,199name: remote.repositoryName,200number: this.number,201}202})203]);204if (branch.data.protected && branch.data.protection.required_status_checks && branch.data.protection.required_status_checks.enforcement_level !== 'off') {205// We need to add the "review required" check manually.206return {207id: REVIEW_REQUIRED_CHECK_ID,208context: 'Branch Protection',209description: vscode.l10n.t('Other requirements have not been met.'),210state: (reviewStates.data as LatestReviewsResponse).repository.pullRequest.latestReviews.nodes.every(node => node.state !== 'CHANGES_REQUESTED') ? CheckState.Neutral : CheckState.Failure,211target_url: this.html_url212};213}214return undefined;215}216217/**218* Get the status checks of the pull request, those for the last commit.219*/220async getStatusChecks(): Promise<PullRequestChecks | undefined> {221let checks = await this.githubRepository.getStatusChecks(this.number);222223// Fun info: The checks don't include whether a review is required.224// Also, unless you're an admin on the repo, you can't just do octokit.repos.getBranchProtection225if ((this.item.mergeable === PullRequestMergeability.NotMergeable) && (!checks || checks.statuses.every(status => status.state === CheckState.Success))) {226__SELECTION_HERE__227if (reviewRequiredCheck) {228if (!checks) {229checks = {230state: CheckState.Failure,231statuses: []232};233}234checks.statuses.push(reviewRequiredCheck);235checks.state = CheckState.Failure;236}237}238239return checks;240}241242static async openDiffFromComment(243folderManager: FolderRepositoryManager,244pullRequestModel: PullRequestModel,245comment: IComment,246): Promise<void> {247const contentChanges = await pullRequestModel.getFileChangesInfo();248const change = contentChanges.find(249fileChange => fileChange.fileName === comment.path || fileChange.previousFileName === comment.path,250);251if (!change) {252throw new Error(`Can't find matching file`);253}254255const pathSegments = comment.path!.split('/');256this.openDiff(folderManager, pullRequestModel, change, pathSegments[pathSegments.length - 1]);257}258259static async openFirstDiff(260folderManager: FolderRepositoryManager,261pullRequestModel: PullRequestModel,262) {263const contentChanges = await pullRequestModel.getFileChangesInfo();264if (!contentChanges.length) {265return;266}267268const firstChange = contentChanges[0];269this.openDiff(folderManager, pullRequestModel, firstChange, firstChange.fileName);270}271272static async openDiff(273folderManager: FolderRepositoryManager,274pullRequestModel: PullRequestModel,275change: SlimFileChange | InMemFileChange,276diffTitle: string277): Promise<void> {278279280let headUri, baseUri: vscode.Uri;281if (!pullRequestModel.equals(folderManager.activePullRequest)) {…} else {…}282283vscode.commands.executeCommand(284'vscode.diff',285baseUri,286headUri,287`${diffTitle} (Pull Request)`,288{},289);290}291292private _fileChanges: Map<string, SlimFileChange | InMemFileChange> = new Map();293get fileChanges(): Map<string, SlimFileChange | InMemFileChange> {…}294295async getFileChangesInfo() {…}296297/**298* List the changed files in a pull request.299*/300private async getRawFileChangesInfo(): Promise<IRawFileChange[]> {…}301}302303304