@@ -957,6 +957,7 @@ public SCMSourceCriteria.Probe create(@NonNull BranchSCMHead head,
957
957
branchName = "PR-" + number + "-" + strategy .name ().toLowerCase (Locale .ENGLISH );
958
958
}
959
959
count ++;
960
+ ensureDetailedGHPullRequest (pr , listener , github , ghRepository );
960
961
if (request .process (new PullRequestSCMHead (
961
962
pr , branchName , strategy == ChangeRequestCheckoutStrategy .MERGE
962
963
),
@@ -981,19 +982,20 @@ public SCMSourceCriteria.Probe create(@NonNull PullRequestSCMHead head,
981
982
public SCMRevision create (@ NonNull PullRequestSCMHead head ,
982
983
@ Nullable Void ignored )
983
984
throws IOException , InterruptedException {
985
+ String prHeadHash = pr .getHead ().getSha ();
986
+ String baseHash = pr .getBase ().getSha ();
987
+ String mergeHash = null ;
988
+
984
989
switch (strategy ) {
985
990
case MERGE :
986
991
request .checkApiRateLimit ();
987
- GHRef mergeRef = ghRepository .getRef (
988
- "heads/" + pr .getBase ().getRef ()
989
- );
990
- return new PullRequestSCMRevision (head ,
991
- mergeRef .getObject ().getSha (),
992
- pr .getHead ().getSha ());
992
+ baseHash = ghRepository .getRef ("heads/" + pr .getBase ().getRef ()).getObject ().getSha ();
993
+ mergeHash = pr .getMergeCommitSha ();
994
+ break ;
993
995
default :
994
- return new PullRequestSCMRevision (head , pr .getBase ().getSha (),
995
- pr .getHead ().getSha ());
996
+ break ;
996
997
}
998
+ return new PullRequestSCMRevision (head , baseHash , prHeadHash , mergeHash );
997
999
}
998
1000
},
999
1001
new MergabilityWitness (pr , strategy , listener ),
@@ -1200,7 +1202,7 @@ protected SCMRevision retrieve(@NonNull String headName, @NonNull TaskListener l
1200
1202
int number = Integer .parseInt (prMatcher .group (1 ));
1201
1203
listener .getLogger ().format ("Attempting to resolve %s as pull request %d%n" , headName , number );
1202
1204
try {
1203
- GHPullRequest pr = ghRepository . getPullRequest (number );
1205
+ GHPullRequest pr = getDetailedGHPullRequest (number , listener , github , ghRepository );
1204
1206
if (pr != null ) {
1205
1207
boolean fork = !ghRepository .getOwner ().equals (pr .getHead ().getUser ());
1206
1208
Set <ChangeRequestCheckoutStrategy > strategies ;
@@ -1253,32 +1255,53 @@ protected SCMRevision retrieve(@NonNull String headName, @NonNull TaskListener l
1253
1255
PullRequestSCMHead head = new PullRequestSCMHead (
1254
1256
pr , headName , strategy == ChangeRequestCheckoutStrategy .MERGE
1255
1257
);
1258
+ String prHeadHash = pr .getHead ().getSha ();
1259
+ String baseHash = pr .getBase ().getSha ();
1260
+ String mergeHash = null ;
1261
+
1256
1262
switch (strategy ) {
1257
1263
case MERGE :
1258
1264
Connector .checkApiRateLimit (listener , github );
1259
- GHRef mergeRef = ghRepository .getRef (
1260
- "heads/" + pr .getBase ().getRef ()
1261
- );
1265
+ baseHash = ghRepository .getRef ("heads/" + head .getTarget ().getName ()).getObject ().getSha ();
1266
+ mergeHash = pr .getMergeCommitSha ();
1267
+
1268
+ if (Boolean .FALSE .equals (pr .getMergeable ())) {
1269
+ listener .getLogger ().format ("Resolved %s as pull request %d: Not mergeable.%n%n" ,
1270
+ headName ,
1271
+ number );
1272
+ return null ;
1273
+ }
1274
+ List <String > parents = ghRepository .getCommit (mergeHash ).getParentSHA1s ();
1275
+ if (parents .size () != 2 || !parents .contains (baseHash ) || !parents .contains (prHeadHash )) {
1276
+ listener .getLogger ().format ("Resolved %s as pull request %d: Merge commit does not match base and head.%n%n" ,
1277
+ headName ,
1278
+ number );
1279
+ return null ;
1280
+
1281
+ }
1282
+
1262
1283
listener .getLogger ().format (
1263
- "Resolved %s as pull request %d at revision %s merged onto %s%n" ,
1284
+ "Resolved %s as pull request %d at revision %s merged onto %s as %s %n" ,
1264
1285
headName ,
1265
1286
number ,
1266
- pr .getHead ().getSha (),
1267
- pr .getBase ().getSha ()
1287
+ prHeadHash ,
1288
+ baseHash ,
1289
+ mergeHash
1268
1290
);
1269
- return new PullRequestSCMRevision (head ,
1270
- mergeRef .getObject ().getSha (),
1271
- pr .getHead ().getSha ());
1291
+ break ;
1272
1292
default :
1273
1293
listener .getLogger ().format (
1274
1294
"Resolved %s as pull request %d at revision %s%n" ,
1275
1295
headName ,
1276
1296
number ,
1277
- pr . getHead (). getSha ()
1297
+ prHeadHash
1278
1298
);
1279
- return new PullRequestSCMRevision (head , pr .getBase ().getSha (),
1280
- pr .getHead ().getSha ());
1299
+ break ;
1281
1300
}
1301
+ return new PullRequestSCMRevision (head ,
1302
+ baseHash ,
1303
+ prHeadHash ,
1304
+ mergeHash );
1282
1305
} else {
1283
1306
listener .getLogger ().format (
1284
1307
"Could not resolve %s as pull request %d%n" ,
@@ -1438,21 +1461,32 @@ protected SCMRevision retrieve(SCMHead head, TaskListener listener) throws IOExc
1438
1461
Connector .checkApiRateLimit (listener , github );
1439
1462
String fullName = repoOwner + "/" + repository ;
1440
1463
ghRepository = github .getRepository (fullName );
1464
+ final GHRepository ghRepository = this .ghRepository ;
1441
1465
repositoryUrl = ghRepository .getHtmlUrl ();
1442
1466
if (head instanceof PullRequestSCMHead ) {
1443
1467
PullRequestSCMHead prhead = (PullRequestSCMHead ) head ;
1444
- int number = prhead .getNumber ();
1445
- GHPullRequest pr = ghRepository .getPullRequest (number );
1446
- String baseHash ;
1468
+
1469
+ GHPullRequest pr = getDetailedGHPullRequest (prhead .getNumber (), listener , github , ghRepository );
1470
+ String baseHash = pr .getBase ().getSha ();
1471
+ String prHeadHash = pr .getHead ().getSha ();
1472
+ String mergeHash = null ;
1447
1473
switch (prhead .getCheckoutStrategy ()) {
1448
1474
case MERGE :
1449
- baseHash = ghRepository .getRef ("heads/" + prhead .getTarget ().getName ()).getObject ().getSha ();
1475
+ assert (pr .getMergeable () != null );
1476
+ if (Boolean .FALSE .equals (pr .getMergeable ())) {
1477
+ throw new AbortException ("Pull request " + prhead .getNumber () + " is not mergeable." );
1478
+ }
1479
+ baseHash = ghRepository .getRef ("heads/" + pr .getBase ().getRef ()).getObject ().getSha ();
1480
+ mergeHash = pr .getMergeCommitSha ();
1481
+ List <String > parents = ghRepository .getCommit (mergeHash ).getParentSHA1s ();
1482
+ if (parents .size () != 2 || !parents .contains (baseHash ) || !parents .contains (prHeadHash )) {
1483
+ throw new AbortException ("Merge commit does not match base and head commits for pull request " + prhead .getNumber () + "." );
1484
+ }
1450
1485
break ;
1451
1486
default :
1452
- baseHash = pr .getBase ().getSha ();
1453
1487
break ;
1454
1488
}
1455
- return new PullRequestSCMRevision (prhead , baseHash , pr . getHead (). getSha () );
1489
+ return new PullRequestSCMRevision (prhead , baseHash , prHeadHash , mergeHash );
1456
1490
} else if (head instanceof GitHubTagSCMHead ) {
1457
1491
GitHubTagSCMHead tagHead = (GitHubTagSCMHead ) head ;
1458
1492
GHRef tag = ghRepository .getRef ("tags/" + tagHead .getName ());
@@ -1475,6 +1509,24 @@ protected SCMRevision retrieve(SCMHead head, TaskListener listener) throws IOExc
1475
1509
}
1476
1510
}
1477
1511
1512
+ private GHPullRequest getDetailedGHPullRequest (int number , TaskListener listener , GitHub github , GHRepository ghRepository ) throws IOException , InterruptedException {
1513
+ Connector .checkApiRateLimit (listener , github );
1514
+ GHPullRequest pr = ghRepository .getPullRequest (number );
1515
+ ensureDetailedGHPullRequest (pr , listener , github , ghRepository );
1516
+ return pr ;
1517
+ }
1518
+
1519
+ private void ensureDetailedGHPullRequest (GHPullRequest pr , TaskListener listener , GitHub github , GHRepository ghRepository ) throws IOException , InterruptedException {
1520
+ final long sleep = 1000 ;
1521
+ while (pr .getMergeableState () == null ) {
1522
+ listener .getLogger ().format (
1523
+ "Could not determine the mergability of pull request %d. Retrying...%n" ,
1524
+ pr .getNumber ());
1525
+ Thread .sleep (sleep );
1526
+ Connector .checkApiRateLimit (listener , github );
1527
+ }
1528
+ }
1529
+
1478
1530
@ Override
1479
1531
public SCM build (SCMHead head , SCMRevision revision ) {
1480
1532
return new GitHubSCMBuilder (this , head , revision ).withTraits (traits ).build ();
0 commit comments