66import * as vscode from 'vscode' ;
77import { openPullRequestOnGitHub } from '../commands' ;
88import { FolderRepositoryManager } from './folderRepositoryManager' ;
9- import { GithubItemStateEnum , IAccount , isITeam , ITeam , PullRequestMergeability , reviewerId , ReviewEventEnum , ReviewState } from './interface' ;
9+ import { IAccount , ReviewEventEnum , ReviewState } from './interface' ;
1010import { PullRequestModel } from './pullRequestModel' ;
1111import { getDefaultMergeMethod } from './pullRequestOverview' ;
1212import { PullRequestView } from './pullRequestOverviewCommon' ;
13+ import { PullRequestReviewHelpers , ReviewContext } from './pullRequestReviewCommon' ;
1314import { isInCodespaces , parseReviewers } from './utils' ;
14- import { MergeArguments , PullRequest , ReviewType , SubmitReviewReply } from './views' ;
15+ import { MergeArguments , PullRequest , ReviewType } from './views' ;
1516import { IComment } from '../common/comment' ;
1617import { emojify , ensureEmojis } from '../common/emoji' ;
1718import { disposeAll } from '../common/lifecycle' ;
@@ -57,29 +58,11 @@ export class PullRequestViewProvider extends WebviewViewBase implements vscode.W
5758 }
5859
5960 private async updateBranch ( message : IRequestMessage < string > ) : Promise < void > {
60- if ( this . _folderRepositoryManager . repository . state . workingTreeChanges . length > 0 || this . _folderRepositoryManager . repository . state . indexChanges . length > 0 ) {
61- await vscode . window . showErrorMessage ( vscode . l10n . t ( 'The pull request branch cannot be updated when the there changed files in the working tree or index. Stash or commit all change and then try again.' ) , { modal : true } ) ;
62- return this . _replyMessage ( message , { } ) ;
63- }
64- const mergeSucceeded = await this . _folderRepositoryManager . tryMergeBaseIntoHead ( this . _item , true ) ;
65- if ( ! mergeSucceeded ) {
66- this . _replyMessage ( message , { } ) ;
67- }
68- // The mergability of the PR doesn't update immediately. Poll.
69- let mergability = PullRequestMergeability . Unknown ;
70- let attemptsRemaining = 5 ;
71- do {
72- mergability = ( await this . _item . getMergeability ( ) ) . mergeability ;
73- attemptsRemaining -- ;
74- await new Promise ( c => setTimeout ( c , 1000 ) ) ;
75- } while ( attemptsRemaining > 0 && mergability === PullRequestMergeability . Unknown ) ;
76-
77- const result : Partial < PullRequest > = {
78- events : await this . _item . getTimelineEvents ( ) ,
79- mergeable : mergability ,
80- } ;
81- await this . refresh ( ) ;
82- this . _replyMessage ( message , result ) ;
61+ return PullRequestReviewHelpers . updateBranch (
62+ this . getReviewContext ( ) ,
63+ message ,
64+ ( ) => this . refresh ( )
65+ ) ;
8366 }
8467
8568 protected override async _onDidReceiveMessage ( message : IRequestMessage < any > ) {
@@ -122,47 +105,11 @@ export class PullRequestViewProvider extends WebviewViewBase implements vscode.W
122105 }
123106
124107 private async checkoutDefaultBranch ( message : IRequestMessage < string > ) : Promise < void > {
125- try {
126- const defaultBranch = await this . _folderRepositoryManager . getPullRequestRepositoryDefaultBranch ( this . _item ) ;
127- const prBranch = this . _folderRepositoryManager . repository . state . HEAD ?. name ;
128- await this . _folderRepositoryManager . checkoutDefaultBranch ( defaultBranch ) ;
129- if ( prBranch ) {
130- await this . _folderRepositoryManager . cleanupAfterPullRequest ( prBranch , this . _item ) ;
131- }
132- } finally {
133- // Complete webview promise so that button becomes enabled again
134- this . _replyMessage ( message , { } ) ;
135- }
108+ return PullRequestReviewHelpers . checkoutDefaultBranch ( this . getReviewContext ( ) , message ) ;
136109 }
137110
138111 private reRequestReview ( message : IRequestMessage < string > ) : void {
139- let targetReviewer : ReviewState | undefined ;
140- const userReviewers : IAccount [ ] = [ ] ;
141- const teamReviewers : ITeam [ ] = [ ] ;
142-
143- for ( const reviewer of this . _existingReviewers ) {
144- let id = reviewer . reviewer . id ;
145- if ( id && ( ( reviewer . state === 'REQUESTED' ) || ( id === message . args ) ) ) {
146- if ( id === message . args ) {
147- targetReviewer = reviewer ;
148- }
149- }
150- }
151-
152- if ( targetReviewer && isITeam ( targetReviewer . reviewer ) ) {
153- teamReviewers . push ( targetReviewer . reviewer ) ;
154- } else if ( targetReviewer && ! isITeam ( targetReviewer . reviewer ) ) {
155- userReviewers . push ( targetReviewer . reviewer ) ;
156- }
157-
158- this . _item . requestReview ( userReviewers , teamReviewers , true ) . then ( ( ) => {
159- if ( targetReviewer ) {
160- targetReviewer . state = 'REQUESTED' ;
161- }
162- this . _replyMessage ( message , {
163- reviewers : this . _existingReviewers ,
164- } ) ;
165- } ) ;
112+ return PullRequestReviewHelpers . reRequestReview ( this . getReviewContext ( ) , message ) ;
166113 }
167114
168115 public async refresh ( ) : Promise < void > {
@@ -173,9 +120,22 @@ export class PullRequestViewProvider extends WebviewViewBase implements vscode.W
173120 }
174121
175122 private getCurrentUserReviewState ( reviewers : ReviewState [ ] , currentUser : IAccount ) : string | undefined {
176- const review = reviewers . find ( r => reviewerId ( r . reviewer ) === currentUser . login ) ;
177- // There will always be a review. If not then the PR shouldn't have been or fetched/shown for the current user
178- return review ?. state ;
123+ return PullRequestReviewHelpers . getCurrentUserReviewState ( reviewers , currentUser ) ;
124+ }
125+
126+ /**
127+ * Get the review context for helper functions
128+ */
129+ private getReviewContext ( ) : ReviewContext {
130+ return {
131+ item : this . _item ,
132+ folderRepositoryManager : this . _folderRepositoryManager ,
133+ existingReviewers : this . _existingReviewers ,
134+ postMessage : ( message : any ) => this . _postMessage ( message ) ,
135+ replyMessage : ( message : IRequestMessage < any > , response : any ) => this . _replyMessage ( message , response ) ,
136+ throwError : ( message : IRequestMessage < any > | undefined , error : string ) => this . _throwError ( message , error ) ,
137+ getTimeline : ( ) => this . _item . getTimelineEvents ( )
138+ } ;
179139 }
180140
181141 private _prDisposables : vscode . Disposable [ ] | undefined = undefined ;
@@ -346,58 +306,24 @@ export class PullRequestViewProvider extends WebviewViewBase implements vscode.W
346306 }
347307
348308 private updateReviewers ( review ?: ReviewEvent ) : void {
349- if ( review && review . state ) {
350- const existingReviewer = this . _existingReviewers . find (
351- reviewer => review . user . login === reviewerId ( reviewer . reviewer ) ,
352- ) ;
353- if ( existingReviewer ) {
354- existingReviewer . state = review . state ;
355- } else {
356- this . _existingReviewers . push ( {
357- reviewer : review . user ,
358- state : review . state ,
359- } ) ;
360- }
361- }
309+ PullRequestReviewHelpers . updateReviewers ( this . _existingReviewers , review ) ;
362310 }
363311
364312 private async doReviewCommand ( context : { body : string } , reviewType : ReviewType , action : ( body : string ) => Promise < ReviewEvent > ) {
365- const submittingMessage = {
366- command : 'pr.submitting-review' ,
367- lastReviewType : reviewType
368- } ;
369- this . _postMessage ( submittingMessage ) ;
370- try {
371- const review = await action ( context . body ) ;
372- this . updateReviewers ( review ) ;
373- const reviewMessage : SubmitReviewReply & { command : string } = {
374- command : 'pr.append-review' ,
375- events : [ ] ,
376- reviewers : this . _existingReviewers ,
377- reviewedEvent : review ,
378- } ;
379- await this . _postMessage ( reviewMessage ) ;
380- } catch ( e ) {
381- vscode . window . showErrorMessage ( vscode . l10n . t ( 'Submitting review failed. {0}' , formatError ( e ) ) ) ;
382- this . _throwError ( undefined , `${ formatError ( e ) } ` ) ;
383- this . _postMessage ( { command : 'pr.append-review' } ) ;
384- }
313+ return PullRequestReviewHelpers . doReviewCommand (
314+ this . getReviewContext ( ) ,
315+ context ,
316+ reviewType ,
317+ action
318+ ) ;
385319 }
386320
387321 private async doReviewMessage ( message : IRequestMessage < string > , action : ( body ) => Promise < ReviewEvent > ) {
388- try {
389- const review = await action ( message . args ) ;
390- this . updateReviewers ( review ) ;
391- const reviewMessage : SubmitReviewReply = {
392- events : [ ] ,
393- reviewedEvent : review ,
394- reviewers : this . _existingReviewers ,
395- } ;
396- this . _replyMessage ( message , reviewMessage ) ;
397- } catch ( e ) {
398- vscode . window . showErrorMessage ( vscode . l10n . t ( 'Submitting review failed. {0}' , formatError ( e ) ) ) ;
399- this . _throwError ( message , `${ formatError ( e ) } ` ) ;
400- }
322+ return PullRequestReviewHelpers . doReviewMessage (
323+ this . getReviewContext ( ) ,
324+ message ,
325+ action
326+ ) ;
401327 }
402328
403329 private approvePullRequest ( body : string ) : Promise < ReviewEvent > {
@@ -446,47 +372,27 @@ export class PullRequestViewProvider extends WebviewViewBase implements vscode.W
446372 }
447373
448374 private setReadyForReview ( message : IRequestMessage < Record < string , unknown > > ) : void {
449- this . _item
450- . setReadyForReview ( )
451- . then ( result => {
452- this . _replyMessage ( message , result ) ;
453- } )
454- . catch ( e => {
455- vscode . window . showErrorMessage ( vscode . l10n . t ( 'Unable to set pull request ready for review. {0}' , formatError ( e ) ) ) ;
456- this . _throwError ( message , '' ) ;
457- } ) ;
375+ return PullRequestReviewHelpers . setReadyForReview ( this . getReviewContext ( ) , message ) ;
458376 }
459377
460378 private async mergePullRequest (
461379 message : IRequestMessage < MergeArguments > ,
462380 ) : Promise < void > {
463- const { title, description, method } = message . args ;
464- const email = await this . _folderRepositoryManager . getPreferredEmail ( this . _item ) ;
465- const yes = vscode . l10n . t ( 'Yes' ) ;
466- const confirmation = await vscode . window . showInformationMessage (
467- vscode . l10n . t ( 'Merge this pull request?' ) ,
468- { modal : true } ,
469- yes ,
470- ) ;
471- if ( confirmation !== yes ) {
472- this . _replyMessage ( message , { state : GithubItemStateEnum . Open } ) ;
473- return ;
474- }
475- try {
476- const result = await this . _item . merge ( this . _folderRepositoryManager . repository , title , description , method , email ) ;
477-
478- if ( ! result . merged ) {
479- vscode . window . showErrorMessage ( vscode . l10n . t ( 'Merging pull request failed: {0}' , result ?. message ?? '' ) ) ;
381+ return PullRequestReviewHelpers . mergePullRequest (
382+ this . getReviewContext ( ) ,
383+ message ,
384+ {
385+ confirmMerge : async ( ) => {
386+ const yes = vscode . l10n . t ( 'Yes' ) ;
387+ const confirmation = await vscode . window . showInformationMessage (
388+ vscode . l10n . t ( 'Merge this pull request?' ) ,
389+ { modal : true } ,
390+ yes ,
391+ ) ;
392+ return confirmation === yes ;
393+ }
480394 }
481-
482- this . _replyMessage ( message , {
483- state : result . merged ? GithubItemStateEnum . Merged : GithubItemStateEnum . Open ,
484- } ) ;
485-
486- } catch ( e ) {
487- vscode . window . showErrorMessage ( vscode . l10n . t ( 'Unable to merge pull request. {0}' , formatError ( e ) ) ) ;
488- this . _throwError ( message , '' ) ;
489- }
395+ ) ;
490396 }
491397
492398 private _getHtmlForWebview ( ) {
0 commit comments