From ee9f820ef54427a0eadc44f4e8f0d1d6e2f44ef0 Mon Sep 17 00:00:00 2001
From: Nathanial Woolls <nathanial.woolls@idmworks.com>
Date: Wed, 17 May 2017 13:00:24 -0400
Subject: Fix NullPointerException when a Pull Request's destination commit is
 NULL * see:
 https://github.com/nishio-dens/bitbucket-pullrequest-builder-plugin/issues/119
 * see:
 https://github.com/nishio-dens/bitbucket-pullrequest-builder-plugin/issues/98

---
 .../BitbucketRepository.java                       | 25 +++++--
 src/test/java/BitbucketBuildRepositoryTest.java    | 84 +++++++++++++++++++++-
 2 files changed, 103 insertions(+), 6 deletions(-)

diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
index 02d11c5..352ec04 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
@@ -291,17 +291,34 @@ public class BitbucketRepository {
     }
 
     private boolean isFilteredBuild(Pullrequest pullRequest) {
+
+        final String pullRequestId = pullRequest.getId();
+        final String pullRequestTitle = pullRequest.getTitle();
+        final String destinationRepoName = pullRequest.getDestination().getRepository().getRepositoryName();
+
+        // pullRequest.getDestination().getCommit() may return null for pull requests with merge conflicts
+        // * see: https://github.com/nishio-dens/bitbucket-pullrequest-builder-plugin/issues/119
+        // * see: https://github.com/nishio-dens/bitbucket-pullrequest-builder-plugin/issues/98
+        final String destinationCommitHash;
+        if (pullRequest.getDestination().getCommit() == null) {
+            logger.log(Level.INFO, "Pull request #{0} ''{1}'' in repo ''{2}'' has a null value for destination commit.",
+                    new Object[]{pullRequestId, pullRequestTitle, destinationRepoName});
+            destinationCommitHash = null;
+        } else {
+            destinationCommitHash = pullRequest.getDestination().getCommit().getHash();
+        }
+
         BitbucketCause cause = new BitbucketCause(
           pullRequest.getSource().getBranch().getName(),
           pullRequest.getDestination().getBranch().getName(),
           pullRequest.getSource().getRepository().getOwnerName(),
           pullRequest.getSource().getRepository().getRepositoryName(),
-          pullRequest.getId(),
+          pullRequestId,
           pullRequest.getDestination().getRepository().getOwnerName(),
-          pullRequest.getDestination().getRepository().getRepositoryName(),
-          pullRequest.getTitle(),
+          destinationRepoName,
+          pullRequestTitle,
           pullRequest.getSource().getCommit().getHash(),
-          pullRequest.getDestination().getCommit().getHash(),
+          destinationCommitHash,
           pullRequest.getAuthor().getCombinedUsername()
         );
         
diff --git a/src/test/java/BitbucketBuildRepositoryTest.java b/src/test/java/BitbucketBuildRepositoryTest.java
index f076c4d..02e58f0 100644
--- a/src/test/java/BitbucketBuildRepositoryTest.java
+++ b/src/test/java/BitbucketBuildRepositoryTest.java
@@ -6,6 +6,7 @@ import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.BitbucketPullRequ
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.BitbucketRepository;
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.ApiClient;
 
+import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.Pullrequest;
 import com.cloudbees.plugins.credentials.CredentialsProvider;
 import com.cloudbees.plugins.credentials.CredentialsScope;
 import com.cloudbees.plugins.credentials.CredentialsStore;
@@ -18,8 +19,10 @@ import com.google.common.collect.Collections2;
 import java.io.UnsupportedEncodingException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.List;
 import java.util.logging.Logger;
 import org.easymock.*;
 import org.junit.Test;
@@ -29,7 +32,6 @@ import org.junit.Assert;
 import org.jvnet.hudson.test.JenkinsRule;
 
 import jenkins.model.Jenkins;
-import org.jvnet.hudson.test.WithoutJenkins;
 
 import org.apache.commons.codec.binary.Hex;
 import org.apache.commons.httpclient.Credentials;
@@ -106,7 +108,7 @@ public class BitbucketBuildRepositoryTest {
 
   @Rule
   public JenkinsRule jRule = new JenkinsRule();  
-  
+
   @Test  
   public void repositorySimpleUserPasswordTest() throws Exception {
     BitbucketBuildTrigger trigger = new BitbucketBuildTrigger(
@@ -271,4 +273,82 @@ public class BitbucketBuildRepositoryTest {
     assertFalse(buildStatusKey.startsWith("jenkins-"));
     assertEquals((new SHA1HasherFunction(SHA1)).apply("jenkins-too-long-ci-key" + "-" + builder.getProjectId()), buildStatusKey);
   }
+
+  @Test
+  public void getTargetPullRequestsWithNullDestinationCommit() throws Exception {
+    // arrange
+
+    // setup mock BitbucketBuildTrigger
+    final BitbucketBuildTrigger trigger = EasyMock.createMock(BitbucketBuildTrigger.class);
+    EasyMock.expect(trigger.getCiSkipPhrases()).andReturn("");
+    EasyMock.expect(trigger.getBranchesFilterBySCMIncludes()).andReturn(false);
+    EasyMock.expect(trigger.getBranchesFilter()).andReturn("");
+    EasyMock.replay(trigger);
+
+    // setup mock BitbucketPullRequestsBuilder
+    final BitbucketPullRequestsBuilder builder = EasyMock.createMock(BitbucketPullRequestsBuilder.class);
+    EasyMock.expect(builder.getTrigger()).andReturn(trigger).anyTimes();
+    EasyMock.expect(builder.getProjectId()).andReturn("").anyTimes();
+    EasyMock.replay(builder);
+
+    // setup PRs to return from mock ApiClient
+    final Pullrequest pullRequest = new Pullrequest();
+
+    final Pullrequest.Repository sourceRepo = new Pullrequest.Repository();
+    sourceRepo.setFullName("Owner/Name");
+
+    final Pullrequest.Repository destRepo = new Pullrequest.Repository();
+    destRepo.setFullName("Owner/Name");
+
+    final Pullrequest.Branch sourceBranch = new Pullrequest.Branch();
+    sourceBranch.setName("Name");
+
+    final Pullrequest.Branch destBranch = new Pullrequest.Branch();
+    destBranch.setName("Name");
+
+    final Pullrequest.Commit sourceCommit = new Pullrequest.Commit();
+    sourceCommit.setHash("Hash");
+
+    final Pullrequest.Commit destCommit = null; // the crux of the test
+
+    final Pullrequest.Revision sourceRevision = new Pullrequest.Revision();
+    sourceRevision.setBranch(sourceBranch);
+    sourceRevision.setRepository(sourceRepo);
+    sourceRevision.setCommit(sourceCommit);
+
+    final Pullrequest.Revision destRevision = new Pullrequest.Revision();
+    destRevision.setBranch(destBranch);
+    destRevision.setRepository(destRepo);
+    destRevision.setCommit(destCommit);
+
+    final Pullrequest.Author author = new Pullrequest.Author();
+    author.setDisplayName("DisplayName");
+    author.setUsername("Username");
+
+    pullRequest.setSource(sourceRevision);
+    pullRequest.setDestination(destRevision);
+    pullRequest.setId("Id");
+    pullRequest.setTitle("Title");
+    pullRequest.setState("OPEN");
+    pullRequest.setAutohor(author);
+
+    final List<Pullrequest> pullRequests = new ArrayList<>(Arrays.asList(pullRequest));
+
+    // setup mock ApiClient
+    final ApiClient client = EasyMock.createNiceMock(ApiClient.class);
+    EasyMock.expect(client.getPullRequests()).andReturn(pullRequests);
+    EasyMock.replay(client);
+
+    // setup SUT
+    final BitbucketRepository repo = new BitbucketRepository("", builder);
+
+    // act
+    repo.init(client);
+
+    // assert
+    Collection<Pullrequest> targetPullRequests = repo.getTargetPullRequests();
+
+    assertEquals(pullRequests.size(), targetPullRequests.size());
+    assertEquals(pullRequest, targetPullRequests.iterator().next());
+  }
 }
-- 
cgit v1.2.3