@@ -957,6 +957,7 @@ public SCMSourceCriteria.Probe create(@NonNull BranchSCMHead head,
957957 branchName = "PR-" + number + "-" + strategy .name ().toLowerCase (Locale .ENGLISH );
958958 }
959959 count ++;
960+ ensureDetailedGHPullRequest (pr , listener , github , ghRepository );
960961 if (request .process (new PullRequestSCMHead (
961962 pr , branchName , strategy == ChangeRequestCheckoutStrategy .MERGE
962963 ),
@@ -981,19 +982,20 @@ public SCMSourceCriteria.Probe create(@NonNull PullRequestSCMHead head,
981982 public SCMRevision create (@ NonNull PullRequestSCMHead head ,
982983 @ Nullable Void ignored )
983984 throws IOException , InterruptedException {
985+ String prHeadHash = pr .getHead ().getSha ();
986+ String baseHash = pr .getBase ().getSha ();
987+ String mergeHash = null ;
988+
984989 switch (strategy ) {
985990 case MERGE :
986991 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 ;
993995 default :
994- return new PullRequestSCMRevision (head , pr .getBase ().getSha (),
995- pr .getHead ().getSha ());
996+ break ;
996997 }
998+ return new PullRequestSCMRevision (head , baseHash , prHeadHash , mergeHash );
997999 }
9981000 },
9991001 new MergabilityWitness (pr , strategy , listener ),
@@ -1200,7 +1202,7 @@ protected SCMRevision retrieve(@NonNull String headName, @NonNull TaskListener l
12001202 int number = Integer .parseInt (prMatcher .group (1 ));
12011203 listener .getLogger ().format ("Attempting to resolve %s as pull request %d%n" , headName , number );
12021204 try {
1203- GHPullRequest pr = ghRepository . getPullRequest (number );
1205+ GHPullRequest pr = getDetailedGHPullRequest (number , listener , github , ghRepository );
12041206 if (pr != null ) {
12051207 boolean fork = !ghRepository .getOwner ().equals (pr .getHead ().getUser ());
12061208 Set <ChangeRequestCheckoutStrategy > strategies ;
@@ -1253,32 +1255,53 @@ protected SCMRevision retrieve(@NonNull String headName, @NonNull TaskListener l
12531255 PullRequestSCMHead head = new PullRequestSCMHead (
12541256 pr , headName , strategy == ChangeRequestCheckoutStrategy .MERGE
12551257 );
1258+ String prHeadHash = pr .getHead ().getSha ();
1259+ String baseHash = pr .getBase ().getSha ();
1260+ String mergeHash = null ;
1261+
12561262 switch (strategy ) {
12571263 case MERGE :
12581264 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+
12621283 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" ,
12641285 headName ,
12651286 number ,
1266- pr .getHead ().getSha (),
1267- pr .getBase ().getSha ()
1287+ prHeadHash ,
1288+ baseHash ,
1289+ mergeHash
12681290 );
1269- return new PullRequestSCMRevision (head ,
1270- mergeRef .getObject ().getSha (),
1271- pr .getHead ().getSha ());
1291+ break ;
12721292 default :
12731293 listener .getLogger ().format (
12741294 "Resolved %s as pull request %d at revision %s%n" ,
12751295 headName ,
12761296 number ,
1277- pr . getHead (). getSha ()
1297+ prHeadHash
12781298 );
1279- return new PullRequestSCMRevision (head , pr .getBase ().getSha (),
1280- pr .getHead ().getSha ());
1299+ break ;
12811300 }
1301+ return new PullRequestSCMRevision (head ,
1302+ baseHash ,
1303+ prHeadHash ,
1304+ mergeHash );
12821305 } else {
12831306 listener .getLogger ().format (
12841307 "Could not resolve %s as pull request %d%n" ,
@@ -1438,21 +1461,32 @@ protected SCMRevision retrieve(SCMHead head, TaskListener listener) throws IOExc
14381461 Connector .checkApiRateLimit (listener , github );
14391462 String fullName = repoOwner + "/" + repository ;
14401463 ghRepository = github .getRepository (fullName );
1464+ final GHRepository ghRepository = this .ghRepository ;
14411465 repositoryUrl = ghRepository .getHtmlUrl ();
14421466 if (head instanceof PullRequestSCMHead ) {
14431467 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 ;
14471473 switch (prhead .getCheckoutStrategy ()) {
14481474 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+ }
14501485 break ;
14511486 default :
1452- baseHash = pr .getBase ().getSha ();
14531487 break ;
14541488 }
1455- return new PullRequestSCMRevision (prhead , baseHash , pr . getHead (). getSha () );
1489+ return new PullRequestSCMRevision (prhead , baseHash , prHeadHash , mergeHash );
14561490 } else if (head instanceof GitHubTagSCMHead ) {
14571491 GitHubTagSCMHead tagHead = (GitHubTagSCMHead ) head ;
14581492 GHRef tag = ghRepository .getRef ("tags/" + tagHead .getName ());
@@ -1475,6 +1509,24 @@ protected SCMRevision retrieve(SCMHead head, TaskListener listener) throws IOExc
14751509 }
14761510 }
14771511
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+
14781530 @ Override
14791531 public SCM build (SCMHead head , SCMRevision revision ) {
14801532 return new GitHubSCMBuilder (this , head , revision ).withTraits (traits ).build ();
0 commit comments