5
5
CreatePullRequestResponse ,
6
6
PullRequest ,
7
7
MergeStrategy ,
8
+ RequestError ,
8
9
} from "./github" ;
9
10
import { GithubApi } from "./github" ;
10
11
import { Git , GitRefNotFoundError } from "./git" ;
@@ -343,39 +344,69 @@ export class Backport {
343
344
this . config . pwd ,
344
345
) ;
345
346
if ( pushExitCode != 0 ) {
346
- const message = this . composeMessageForGitPushFailure (
347
- target ,
348
- pushExitCode ,
349
- ) ;
350
- console . error ( message ) ;
351
- successByTarget . set ( target , false ) ;
352
- await this . github . createComment ( {
353
- owner : workflowOwner ,
354
- repo : workflowRepo ,
355
- issue_number : pull_number ,
356
- body : message ,
357
- } ) ;
358
- continue ;
347
+ try {
348
+ // If the branch already exists, ignore the error and keep going.
349
+ console . info (
350
+ `Branch ${ branchname } may already exist, fetching it instead to recover previous run` ,
351
+ ) ;
352
+ await this . git . fetch (
353
+ branchname ,
354
+ this . config . pwd ,
355
+ 1 ,
356
+ this . getRemote ( ) ,
357
+ ) ;
358
+ console . info (
359
+ `Previous branch successfully recovered, retrying PR creation` ,
360
+ ) ;
361
+ // note that the recovered branch is not guaranteed to be up-to-date
362
+ } catch {
363
+ // Fetching the branch failed as well, so report the original push error.
364
+ const message = this . composeMessageForGitPushFailure (
365
+ target ,
366
+ pushExitCode ,
367
+ ) ;
368
+ console . error ( message ) ;
369
+ successByTarget . set ( target , false ) ;
370
+ await this . github . createComment ( {
371
+ owner : workflowOwner ,
372
+ repo : workflowRepo ,
373
+ issue_number : pull_number ,
374
+ body : message ,
375
+ } ) ;
376
+ continue ;
377
+ }
359
378
}
360
379
361
380
console . info ( `Create PR for ${ branchname } ` ) ;
362
381
const { title, body } = this . composePRContent ( target , mainpr ) ;
363
- const new_pr_response = await this . github . createPR ( {
364
- owner,
365
- repo,
366
- title,
367
- body,
368
- head : branchname ,
369
- base : target ,
370
- maintainer_can_modify : true ,
371
- draft : uncommitedShas !== null ,
372
- } ) ;
373
-
374
- if ( new_pr_response . status != 201 ) {
375
- console . error ( JSON . stringify ( new_pr_response ) ) ;
382
+ let new_pr_response : CreatePullRequestResponse ;
383
+ try {
384
+ new_pr_response = await this . github . createPR ( {
385
+ owner,
386
+ repo,
387
+ title,
388
+ body,
389
+ head : branchname ,
390
+ base : target ,
391
+ maintainer_can_modify : true ,
392
+ draft : uncommitedShas !== null ,
393
+ } ) ;
394
+ } catch ( error ) {
395
+ if ( ! ( error instanceof RequestError ) ) throw error ;
396
+
397
+ if (
398
+ error . status == 422 &&
399
+ ( error . response ?. data as any ) . errors . some ( ( err : any ) =>
400
+ err . message . startsWith ( "A pull request already exists for " ) ,
401
+ )
402
+ ) {
403
+ console . info ( `PR for ${ branchname } already exists, skipping.` ) ;
404
+ continue ;
405
+ }
406
+
407
+ console . error ( JSON . stringify ( error . response ?. data ) ) ;
376
408
successByTarget . set ( target , false ) ;
377
- const message =
378
- this . composeMessageForCreatePRFailed ( new_pr_response ) ;
409
+ const message = this . composeMessageForCreatePRFailed ( error ) ;
379
410
await this . github . createComment ( {
380
411
owner : workflowOwner ,
381
412
repo : workflowRepo ,
@@ -390,12 +421,11 @@ export class Backport {
390
421
const milestone = mainpr . milestone ?. number ;
391
422
if ( milestone ) {
392
423
console . info ( "Setting milestone to " + milestone ) ;
393
- const set_milestone_response = await this . github . setMilestone (
394
- new_pr . number ,
395
- milestone ,
396
- ) ;
397
- if ( set_milestone_response . status != 200 ) {
398
- console . error ( JSON . stringify ( set_milestone_response ) ) ;
424
+ try {
425
+ await this . github . setMilestone ( new_pr . number , milestone ) ;
426
+ } catch ( error ) {
427
+ if ( ! ( error instanceof RequestError ) ) throw error ;
428
+ console . error ( JSON . stringify ( error . response ) ) ;
399
429
}
400
430
}
401
431
}
@@ -404,16 +434,14 @@ export class Backport {
404
434
const assignees = mainpr . assignees . map ( ( label ) => label . login ) ;
405
435
if ( assignees . length > 0 ) {
406
436
console . info ( "Setting assignees " + assignees ) ;
407
- const add_assignee_response = await this . github . addAssignees (
408
- new_pr . number ,
409
- assignees ,
410
- {
437
+ try {
438
+ await this . github . addAssignees ( new_pr . number , assignees , {
411
439
owner,
412
440
repo,
413
- } ,
414
- ) ;
415
- if ( add_assignee_response . status != 201 ) {
416
- console . error ( JSON . stringify ( add_assignee_response ) ) ;
441
+ } ) ;
442
+ } catch ( error ) {
443
+ if ( ! ( error instanceof RequestError ) ) throw error ;
444
+ console . error ( JSON . stringify ( error . response ) ) ;
417
445
}
418
446
}
419
447
}
@@ -430,10 +458,11 @@ export class Backport {
430
458
pull_number : new_pr . number ,
431
459
reviewers : reviewers ,
432
460
} ;
433
- const set_reviewers_response =
461
+ try {
434
462
await this . github . requestReviewers ( reviewRequest ) ;
435
- if ( set_reviewers_response . status != 201 ) {
436
- console . error ( JSON . stringify ( set_reviewers_response ) ) ;
463
+ } catch ( error ) {
464
+ if ( ! ( error instanceof RequestError ) ) throw error ;
465
+ console . error ( JSON . stringify ( error . response ) ) ;
437
466
}
438
467
}
439
468
}
@@ -443,33 +472,29 @@ export class Backport {
443
472
...new Set ( [ ...labelsToCopy , ...this . config . add_labels ] ) ,
444
473
] ;
445
474
if ( labels . length > 0 ) {
446
- const label_response = await this . github . labelPR (
447
- new_pr . number ,
448
- labels ,
449
- {
475
+ try {
476
+ await this . github . labelPR ( new_pr . number , labels , {
450
477
owner,
451
478
repo,
452
- } ,
453
- ) ;
454
- if ( label_response . status != 200 ) {
455
- console . error ( JSON . stringify ( label_response ) ) ;
479
+ } ) ;
480
+ } catch ( error ) {
481
+ if ( ! ( error instanceof RequestError ) ) throw error ;
482
+ console . error ( JSON . stringify ( error . response ) ) ;
456
483
// The PR was still created so let's still comment on the original.
457
484
}
458
485
}
459
486
460
487
if ( this . config . add_author_as_assignee == true ) {
461
488
const author = mainpr . user . login ;
462
489
console . info ( "Setting " + author + " as assignee" ) ;
463
- const add_assignee_response = await this . github . addAssignees (
464
- new_pr . number ,
465
- [ author ] ,
466
- {
490
+ try {
491
+ await this . github . addAssignees ( new_pr . number , [ author ] , {
467
492
owner,
468
493
repo,
469
- } ,
470
- ) ;
471
- if ( add_assignee_response . status != 201 ) {
472
- console . error ( JSON . stringify ( add_assignee_response ) ) ;
494
+ } ) ;
495
+ } catch ( error ) {
496
+ if ( ! ( error instanceof RequestError ) ) throw error ;
497
+ console . error ( JSON . stringify ( error . response ) ) ;
473
498
}
474
499
}
475
500
@@ -667,11 +692,9 @@ export class Backport {
667
692
return dedent `Git push to origin failed for ${ target } with exitcode ${ exitcode } ` ;
668
693
}
669
694
670
- private composeMessageForCreatePRFailed (
671
- response : CreatePullRequestResponse ,
672
- ) : string {
695
+ private composeMessageForCreatePRFailed ( error : RequestError ) : string {
673
696
return dedent `Backport branch created but failed to create PR.
674
- Request to create PR rejected with status ${ response . status } .
697
+ Request to create PR rejected with status ${ error . status } .
675
698
676
699
(see action log for full response)` ;
677
700
}
0 commit comments