@@ -166,14 +166,16 @@ export class GithubApp {
166
166
try {
167
167
const installationId = ctx . payload . installation ?. id ;
168
168
const cloneURL = ctx . payload . repository . clone_url ;
169
- const owner = installationId && ( await this . findProjectOwner ( cloneURL ) || ( await this . findInstallationOwner ( installationId ) ) ) ;
170
- if ( ! owner ) {
171
- log . info ( `Did not find user for installation. Probably an incomplete app installation.` , { repo : ctx . payload . repository , installationId } ) ;
169
+ const installationOwner = installationId ? await this . findInstallationOwner ( installationId ) : undefined ;
170
+ const project = await this . projectDB . findProjectByCloneUrl ( cloneURL ) ;
171
+ const user = await this . selectUserForPrebuild ( installationOwner , project ) ;
172
+ if ( ! user ) {
173
+ log . info ( `Did not find user for installation. Probably an incomplete app installation.` , { repo : ctx . payload . repository , installationId, project } ) ;
172
174
return ;
173
175
}
174
- const logCtx : LogContext = { userId : owner . user . id } ;
176
+ const logCtx : LogContext = { userId : user . id } ;
175
177
176
- if ( ! ! owner . user . blocked ) {
178
+ if ( ! ! user . blocked ) {
177
179
log . info ( logCtx , `Blocked user tried to start prebuild` , { repo : ctx . payload . repository } ) ;
178
180
return ;
179
181
}
@@ -190,15 +192,15 @@ export class GithubApp {
190
192
const contextURL = `${ repo . html_url } /tree/${ branch } ` ;
191
193
span . setTag ( 'contextURL' , contextURL ) ;
192
194
193
- let config = await this . prebuildManager . fetchConfig ( { span } , owner . user , contextURL ) ;
195
+ let config = await this . prebuildManager . fetchConfig ( { span } , user , contextURL ) ;
194
196
const runPrebuild = this . appRules . shouldRunPrebuild ( config , branch == repo . default_branch , false , false ) ;
195
197
if ( ! runPrebuild ) {
196
198
const reason = `Not running prebuild, the user did not enable it for this context` ;
197
199
log . debug ( logCtx , reason , { contextURL } ) ;
198
200
span . log ( { "not-running" : reason , "config" : config } ) ;
199
201
return ;
200
202
}
201
- const { user , project } = owner ;
203
+
202
204
this . prebuildManager . startPrebuild ( { span } , { user, contextURL, cloneURL : repo . clone_url , commit : pl . after , branch, project} )
203
205
. catch ( err => log . error ( logCtx , "Error while starting prebuild" , err , { contextURL } ) ) ;
204
206
} catch ( e ) {
@@ -225,17 +227,19 @@ export class GithubApp {
225
227
try {
226
228
const installationId = ctx . payload . installation ?. id ;
227
229
const cloneURL = ctx . payload . repository . clone_url ;
228
- const owner = installationId && ( await this . findProjectOwner ( cloneURL ) || ( await this . findInstallationOwner ( installationId ) ) ) ;
229
- if ( ! owner ) {
230
- log . info ( "Did not find user for installation. Probably an incomplete app installation." , { repo : ctx . payload . repository , installationId } ) ;
230
+ const installationOwner = installationId ? await this . findInstallationOwner ( installationId ) : undefined ;
231
+ const project = await this . projectDB . findProjectByCloneUrl ( cloneURL ) ;
232
+ const user = await this . selectUserForPrebuild ( installationOwner , project ) ;
233
+ if ( ! user ) {
234
+ log . info ( "Did not find user for installation. Probably an incomplete app installation." , { repo : ctx . payload . repository , installationId, project } ) ;
231
235
return ;
232
236
}
233
237
234
238
const pr = ctx . payload . pull_request ;
235
239
const contextURL = pr . html_url ;
236
- const config = await this . prebuildManager . fetchConfig ( { span } , owner . user , contextURL ) ;
240
+ const config = await this . prebuildManager . fetchConfig ( { span } , user , contextURL ) ;
237
241
238
- const prebuildStartPromise = this . onPrStartPrebuild ( { span } , config , owner , ctx ) ;
242
+ const prebuildStartPromise = this . onPrStartPrebuild ( { span } , ctx , config , user , project ) ;
239
243
this . onPrAddCheck ( { span } , config , ctx , prebuildStartPromise ) . catch ( ( ) => { /** ignore */ } ) ;
240
244
this . onPrAddBadge ( config , ctx ) ;
241
245
this . onPrAddComment ( config , ctx ) . catch ( ( ) => { /** ignore */ } ) ;
@@ -282,8 +286,7 @@ export class GithubApp {
282
286
}
283
287
}
284
288
285
- protected onPrStartPrebuild ( tracecContext : TraceContext , config : WorkspaceConfig | undefined , owner : { user : User , project ?: Project } , ctx : Context < 'pull_request.opened' | 'pull_request.synchronize' | 'pull_request.reopened' > ) : Promise < StartPrebuildResult > | undefined {
286
- const { user, project } = owner ;
289
+ protected onPrStartPrebuild ( tracecContext : TraceContext , ctx : Context < 'pull_request.opened' | 'pull_request.synchronize' | 'pull_request.reopened' > , config : WorkspaceConfig | undefined , user : User , project ?: Project ) : Promise < StartPrebuildResult > | undefined {
287
290
const pr = ctx . payload . pull_request ;
288
291
const pr_head = pr . head ;
289
292
const contextURL = pr . html_url ;
@@ -298,7 +301,7 @@ export class GithubApp {
298
301
prebuildStartPromise . catch ( err => log . error ( err , "Error while starting prebuild" , { contextURL } ) ) ;
299
302
return prebuildStartPromise ;
300
303
} else {
301
- log . debug ( { userId : owner . user . id } , `Not running prebuild, the user did not enable it for this context` , { contextURL, owner } ) ;
304
+ log . debug ( { userId : user . id } , `Not running prebuild, the user did not enable it for this context` , { contextURL, user , project } ) ;
302
305
return ;
303
306
}
304
307
}
@@ -349,24 +352,44 @@ export class GithubApp {
349
352
return this . config . hostUrl . with ( { pathname : '/button/open-in-gitpod.svg' } ) . toString ( ) ;
350
353
}
351
354
352
- protected async findProjectOwner ( cloneURL : string ) : Promise < { user : User , project ?: Project } | undefined > {
353
- // Project mode
354
- //
355
- const project = await this . projectDB . findProjectByCloneUrl ( cloneURL ) ;
356
- if ( project ) {
357
- const owner = ! ! project . userId
358
- ? { userId : project . userId }
359
- : ( await this . teamDB . findMembersByTeam ( project . teamId || '' ) ) . filter ( m => m . role === "owner" ) [ 0 ] ;
360
- if ( owner ) {
361
- const user = await this . userDB . findUserById ( owner . userId ) ;
362
- if ( user ) {
363
- return { user, project}
364
- }
355
+ /**
356
+ * Finds the relevant user account to create a prebuild with.
357
+ *
358
+ * First it tries to find the installer of the GitHub App installation
359
+ * among the members of the project team. As a fallback, it tries so pick
360
+ * any of the team members which also has a github.com connection.
361
+ *
362
+ * For projects under a personal account, it simply returns the installer.
363
+ *
364
+ * @param installationOwner given user account of the GitHub App installation
365
+ * @param project the project associated with the `cloneURL`
366
+ * @returns a promise that resolves to a `User` or undefined
367
+ */
368
+ protected async selectUserForPrebuild ( installationOwner ?: User , project ?: Project ) : Promise < User | undefined > {
369
+ if ( ! project ) {
370
+ return installationOwner ;
371
+ }
372
+ if ( ! project . teamId ) {
373
+ return installationOwner ;
374
+ }
375
+ const teamMembers = await this . teamDB . findMembersByTeam ( project . teamId ) ;
376
+ if ( ! ! installationOwner && teamMembers . some ( t => t . userId === installationOwner . id ) ) {
377
+ return installationOwner ;
378
+ }
379
+ for ( const teamMember of teamMembers ) {
380
+ const user = await this . userDB . findUserById ( teamMember . userId ) ;
381
+ if ( user && user . identities . some ( i => i . authProviderId === "Public-GitHub" ) ) {
382
+ return user ;
365
383
}
366
384
}
367
385
}
368
386
369
- protected async findInstallationOwner ( installationId : number ) : Promise < { user : User , project ?: Project } | undefined > {
387
+ /**
388
+ *
389
+ * @param installationId read from webhook event
390
+ * @returns the user account of the GitHub App installation
391
+ */
392
+ protected async findInstallationOwner ( installationId : number ) : Promise < User | undefined > {
370
393
// Legacy mode
371
394
//
372
395
const installation = await this . appInstallationDB . findInstallation ( "github" , String ( installationId ) ) ;
@@ -380,7 +403,7 @@ export class GithubApp {
380
403
return ;
381
404
}
382
405
383
- return { user } ;
406
+ return user ;
384
407
}
385
408
}
386
409
0 commit comments