55
66import * as buffer from 'buffer' ;
77import { ApolloQueryResult , DocumentNode , FetchResult , MutationOptions , NetworkStatus , QueryOptions } from 'apollo-boost' ;
8+ import LRUCache from 'lru-cache' ;
89import * as vscode from 'vscode' ;
910import { AuthenticationError , AuthProvider , GitHubServerType , isSamlError } from '../common/authentication' ;
1011import { COPILOT_ACCOUNTS , IComment , IReviewThread } from '../common/comment' ;
11- import { Disposable } from '../common/lifecycle' ;
12+ import { Disposable , disposeAll } from '../common/lifecycle' ;
1213import Logger from '../common/logger' ;
1314import { GitHubRemote , parseRemote } from '../common/remote' ;
1415import { ITelemetry } from '../common/telemetry' ;
@@ -43,6 +44,7 @@ import {
4344 RevertPullRequestResponse ,
4445 SuggestedActorsResponse ,
4546 TimelineEventsResponse ,
47+ UserResponse ,
4648 ViewerPermissionResponse ,
4749} from './graphql' ;
4850import {
@@ -57,6 +59,7 @@ import {
5759 PullRequestChecks ,
5860 PullRequestReviewRequirement ,
5961 RepoAccessAndMergeMethods ,
62+ User ,
6063} from './interface' ;
6164import { IssueModel } from './issueModel' ;
6265import { LoggingOctokit } from './loggingOctokit' ;
@@ -76,6 +79,7 @@ import {
7679 parseCombinedTimelineEvents ,
7780 parseGraphQLIssue ,
7881 parseGraphQLPullRequest ,
82+ parseGraphQLUser ,
7983 parseGraphQLViewerPermission ,
8084 parseMergeMethod ,
8185 parseMilestone ,
@@ -162,7 +166,13 @@ export class GitHubRepository extends Disposable {
162166 protected _metadata : Promise < IMetadata > | undefined ;
163167 public commentsController ?: vscode . CommentController ;
164168 public commentsHandler ?: PRCommentControllerRegistry ;
165- private _pullRequestModels = new Map < number , PullRequestModel > ( ) ;
169+ private _pullRequestModelsByNumber : LRUCache < number , { model : PullRequestModel , disposables : vscode . Disposable [ ] } > = new LRUCache ( {
170+ maxAge : 1000 * 60 * 60 * 4 /* 4 hours */ , stale : true , updateAgeOnGet : true ,
171+ dispose : ( _key , value ) => {
172+ disposeAll ( value . disposables ) ;
173+ value . model . dispose ( ) ;
174+ }
175+ } ) ;
166176 private _queriesSchema : any ;
167177 private _areQueriesLimited : boolean = false ;
168178
@@ -186,8 +196,12 @@ export class GitHubRepository extends Disposable {
186196 return this . remote . equals ( repo . remote ) ;
187197 }
188198
189- get pullRequestModels ( ) : Map < number , PullRequestModel > {
190- return this . _pullRequestModels ;
199+ getExistingPullRequestModel ( prNumber : number ) : PullRequestModel | undefined {
200+ return this . _pullRequestModelsByNumber . get ( prNumber ) ?. model ;
201+ }
202+
203+ get pullRequestModels ( ) : PullRequestModel [ ] {
204+ return Array . from ( this . _pullRequestModelsByNumber . values ( ) . map ( value => value . model ) ) ;
191205 }
192206
193207 public async ensureCommentsController ( ) : Promise < void > {
@@ -940,19 +954,26 @@ export class GitHubRepository extends Disposable {
940954 }
941955
942956 createOrUpdatePullRequestModel ( pullRequest : PullRequest ) : PullRequestModel {
943- let model = this . _pullRequestModels . get ( pullRequest . number ) ;
957+ let model = this . _pullRequestModelsByNumber . get ( pullRequest . number ) ?. model ;
944958 if ( model ) {
945959 model . update ( pullRequest ) ;
946960 } else {
947961 model = new PullRequestModel ( this . _credentialStore , this . _telemetry , this , this . remote , pullRequest ) ;
962+ const prModel = model ;
948963 model . onDidInvalidate ( ( ) => this . getPullRequest ( pullRequest . number ) ) ;
949- this . _pullRequestModels . set ( pullRequest . number , model ) ;
964+ const disposables : vscode . Disposable [ ] = [ ] ;
965+ disposables . push ( model . onDidChange ( ( ) => this . _onPullRequestModelChanged ( prModel ) ) ) ;
966+ this . _pullRequestModelsByNumber . set ( pullRequest . number , { model, disposables } ) ;
950967 this . _onDidAddPullRequest . fire ( model ) ;
951968 }
952969
953970 return model ;
954971 }
955972
973+ private _onPullRequestModelChanged ( model : PullRequestModel ) : void {
974+ this . _onDidChangePullRequests . fire ( [ model ] ) ;
975+ }
976+
956977 async createPullRequest ( params : OctokitCommon . PullsCreateParams ) : Promise < PullRequestModel > {
957978 try {
958979 Logger . debug ( `Create pull request - enter` , this . id ) ;
@@ -1233,6 +1254,27 @@ export class GitHubRepository extends Disposable {
12331254 return ret ;
12341255 }
12351256
1257+ async resolveUser ( login : string ) : Promise < User | undefined > {
1258+ Logger . debug ( `Fetch user ${ login } ` , this . id ) ;
1259+ const { query, schema } = await this . ensure ( ) ;
1260+
1261+ try {
1262+ const { data } = await query < UserResponse > ( {
1263+ query : schema . GetUser ,
1264+ variables : {
1265+ login,
1266+ } ,
1267+ } ) ;
1268+ return parseGraphQLUser ( data , this ) ;
1269+ } catch ( e ) {
1270+ // Ignore cases where the user doesn't exist
1271+ if ( ! ( e . message as ( string | undefined ) ) ?. startsWith ( 'GraphQL error: Could not resolve to a User with the login of' ) ) {
1272+ Logger . warn ( e . message ) ;
1273+ }
1274+ }
1275+ return undefined ;
1276+ }
1277+
12361278 async getAssignableUsers ( ) : Promise < IAccount [ ] > {
12371279 Logger . debug ( `Fetch assignable users - enter` , this . id ) ;
12381280 const { query, remote, schema } = await this . ensure ( ) ;
@@ -1554,9 +1596,9 @@ export class GitHubRepository extends Disposable {
15541596 return [ event . source . url , event ] ;
15551597 } ) ) ;
15561598
1557- for ( const model of this . _pullRequestModels . values ( ) ) {
1558- if ( crossRefs . has ( model . html_url ) ) {
1559- crossRefs . delete ( model . html_url ) ;
1599+ for ( const pr of this . _pullRequestModelsByNumber . values ( ) ) {
1600+ if ( crossRefs . has ( pr . model . html_url ) ) {
1601+ crossRefs . delete ( pr . model . html_url ) ;
15601602 }
15611603 }
15621604 const oldEvents = issueModel . timelineEvents ;
0 commit comments