From 8101c2fc7b6ca2b2fa1d835f2c5b2a5f159539a0 Mon Sep 17 00:00:00 2001
From: Joel Baranick <joel.baranick@ensighten.com>
Date: Wed, 21 Oct 2015 14:21:34 -0700
Subject: Support credentials by allowing UsernamePasswordCredentials to be
 picked when configuring BitbucketBuildTrigger and change BitbucketRepository
 to use the credentials when setting up the ApiClient.

---
 .../BitbucketBuildTrigger.java                     | 31 +++++++++++++---------
 .../BitbucketRepository.java                       | 19 +++++++++++--
 2 files changed, 36 insertions(+), 14 deletions(-)

(limited to 'src/main/java/bitbucketpullrequestbuilder')

diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java
index 879facb..974d3eb 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java
@@ -1,12 +1,17 @@
 package bitbucketpullrequestbuilder.bitbucketpullrequestbuilder;
 
 import antlr.ANTLRException;
+import com.cloudbees.plugins.credentials.CredentialsProvider;
+import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
+import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
+import com.cloudbees.plugins.credentials.common.UsernamePasswordCredentials;
 import hudson.Extension;
 import hudson.model.*;
 import hudson.model.queue.QueueTaskFuture;
 import hudson.plugins.git.RevisionParameterAction;
 import hudson.triggers.Trigger;
 import hudson.triggers.TriggerDescriptor;
+import hudson.util.ListBoxModel;
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.StaplerRequest;
@@ -17,6 +22,8 @@ import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import static com.cloudbees.plugins.credentials.CredentialsMatchers.instanceOf;
+
 /**
  * Created by nishio
  */
@@ -24,8 +31,7 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
     private static final Logger logger = Logger.getLogger(BitbucketBuildTrigger.class.getName());
     private final String projectPath;
     private final String cron;
-    private final String username;
-    private final String password;
+    private final String credentialsId;
     private final String repositoryOwner;
     private final String repositoryName;
     private final String ciSkipPhrases;
@@ -41,8 +47,7 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
     public BitbucketBuildTrigger(
             String projectPath,
             String cron,
-            String username,
-            String password,
+            String credentialsId,
             String repositoryOwner,
             String repositoryName,
             String ciSkipPhrases,
@@ -52,8 +57,7 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
         super(cron);
         this.projectPath = projectPath;
         this.cron = cron;
-        this.username = username;
-        this.password = password;
+        this.credentialsId = credentialsId;
         this.repositoryOwner = repositoryOwner;
         this.repositoryName = repositoryName;
         this.ciSkipPhrases = ciSkipPhrases;
@@ -69,12 +73,8 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
         return this.cron;
     }
 
-    public String getUsername() {
-        return username;
-    }
-
-    public String getPassword() {
-        return password;
+    public String getCredentialsId() {
+        return credentialsId;
     }
 
     public String getRepositoryOwner() {
@@ -180,5 +180,12 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
             save();
             return super.configure(req, json);
         }
+
+        public ListBoxModel doFillCredentialsIdItems() {
+            return new StandardListBoxModel()
+                    .withEmptySelection()
+                    .withMatching(instanceOf(UsernamePasswordCredentials.class),
+                            CredentialsProvider.lookupCredentials(StandardUsernamePasswordCredentials.class));
+        }
     }
 }
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
index bdf5d7c..8606c45 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
@@ -10,6 +10,12 @@ import java.util.regex.Pattern;
 
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.ApiClient;
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.Pullrequest;
+import com.cloudbees.plugins.credentials.CredentialsMatchers;
+import com.cloudbees.plugins.credentials.CredentialsProvider;
+import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
+import com.cloudbees.plugins.credentials.common.UsernamePasswordCredentials;
+
+import static com.cloudbees.plugins.credentials.CredentialsMatchers.instanceOf;
 
 /**
  * Created by nishio
@@ -39,9 +45,10 @@ public class BitbucketRepository {
 
     public void init() {
         trigger = this.builder.getTrigger();
+        StandardUsernamePasswordCredentials credentials = getCredentials(trigger.getCredentialsId());
         client = new ApiClient(
-                trigger.getUsername(),
-                trigger.getPassword(),
+                credentials.getUsername(),
+                credentials.getPassword().getPlainText(),
                 trigger.getRepositoryOwner(),
                 trigger.getRepositoryName());
     }
@@ -192,4 +199,12 @@ public class BitbucketRepository {
         }
         return false;
     }
+
+    private StandardUsernamePasswordCredentials getCredentials(String credentialsId) {
+        return CredentialsMatchers
+                .firstOrNull(
+                        CredentialsProvider.lookupCredentials(StandardUsernamePasswordCredentials.class),
+                        CredentialsMatchers.allOf(CredentialsMatchers.withId(credentialsId),
+                                instanceOf(UsernamePasswordCredentials.class)));
+    }
 }
-- 
cgit v1.2.3


From f2294ad4c37592d4046fd02e35439340278b09a0 Mon Sep 17 00:00:00 2001
From: Joel Baranick <joel.baranick@ensighten.com>
Date: Wed, 28 Oct 2015 12:54:10 -0700
Subject: Add support for plaintext username/password unless credentials are
 specified.

---
 .gitignore                                                 |  4 ++++
 .../bitbucketpullrequestbuilder/BitbucketBuildTrigger.java | 14 ++++++++++++++
 .../bitbucketpullrequestbuilder/BitbucketRepository.java   | 11 +++++++++--
 .../BitbucketBuildTrigger/config.jelly                     |  6 ++++++
 4 files changed, 33 insertions(+), 2 deletions(-)
 create mode 100644 .gitignore

(limited to 'src/main/java/bitbucketpullrequestbuilder')

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3c7b603
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+target
+*.iml
+.idea
+dependency-reduced-pom.xml
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java
index 974d3eb..09802af 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java
@@ -32,6 +32,8 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
     private final String projectPath;
     private final String cron;
     private final String credentialsId;
+    private final String username;
+    private final String password;
     private final String repositoryOwner;
     private final String repositoryName;
     private final String ciSkipPhrases;
@@ -48,6 +50,8 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
             String projectPath,
             String cron,
             String credentialsId,
+            String username,
+            String password,
             String repositoryOwner,
             String repositoryName,
             String ciSkipPhrases,
@@ -58,6 +62,8 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
         this.projectPath = projectPath;
         this.cron = cron;
         this.credentialsId = credentialsId;
+        this.username = username;
+        this.password = password;
         this.repositoryOwner = repositoryOwner;
         this.repositoryName = repositoryName;
         this.ciSkipPhrases = ciSkipPhrases;
@@ -77,6 +83,14 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
         return credentialsId;
     }
 
+    public String getUsername() {
+        return username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
     public String getRepositoryOwner() {
         return repositoryOwner;
     }
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
index 8606c45..fb43f12 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
@@ -45,10 +45,17 @@ public class BitbucketRepository {
 
     public void init() {
         trigger = this.builder.getTrigger();
+        String username = trigger.getUsername();
+        String password = trigger.getPassword();
         StandardUsernamePasswordCredentials credentials = getCredentials(trigger.getCredentialsId());
+        if (credentials != null) {
+            username = credentials.getUsername();
+            password = credentials.getPassword().getPlainText();
+        }
+
         client = new ApiClient(
-                credentials.getUsername(),
-                credentials.getPassword().getPlainText(),
+                username,
+                password,
                 trigger.getRepositoryOwner(),
                 trigger.getRepositoryName());
     }
diff --git a/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/config.jelly b/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/config.jelly
index df43e5a..db5ca0f 100644
--- a/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/config.jelly
+++ b/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/config.jelly
@@ -5,6 +5,12 @@
   <f:entry title="${%Credentials}" field="credentialsId">
       <c:select/>
   </f:entry>
+  <f:entry title="Bitbucket BasicAuth Username" field="username">
+    <f:textbox />
+  </f:entry>
+  <f:entry title="Bitbucket BasicAuth Password" field="password">
+    <f:password />
+  </f:entry>
   <f:entry title="RepositoryOwner" field="repositoryOwner">
     <f:textbox />
   </f:entry>
-- 
cgit v1.2.3


From 06eccb61d2aa83b9d3a7e94724a6d207011de2d4 Mon Sep 17 00:00:00 2001
From: Maxim Epishchev <epishev@garant.ru>
Date: Mon, 1 Feb 2016 18:21:01 +0300
Subject: Add tests for integration CredentialsSupport functional

By default we using username/password from original text fields (config.jelly).
If credentials ID provided in plugin settings - using them for BitBucket API auth.
---
 .../BitbucketRepository.java                       |  43 ++++--
 .../bitbucket/ApiClient.java                       |  71 +++++++---
 src/test/java/BitbucketBuildFilterTest.java        |  30 +---
 src/test/java/BitbucketBuildRepositoryTest.java    | 153 +++++++++++++++++++++
 4 files changed, 234 insertions(+), 63 deletions(-)
 create mode 100644 src/test/java/BitbucketBuildRepositoryTest.java

(limited to 'src/main/java/bitbucketpullrequestbuilder')

diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
index d8c736e..23b0607 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
@@ -23,7 +23,7 @@ import jenkins.scm.api.SCMSourceOwner;
 import jenkins.scm.api.SCMSourceOwners;
 import org.apache.commons.lang.StringUtils;
 
-static com.cloudbees.plugins.credentials.CredentialsMatchers.instanceOf;
+import static com.cloudbees.plugins.credentials.CredentialsMatchers.instanceOf;
 
 /**
  * Created by nishio
@@ -40,33 +40,46 @@ public class BitbucketRepository {
     private BitbucketPullRequestsBuilder builder;
     private BitbucketBuildTrigger trigger;
     private ApiClient client;
-
+    
     public BitbucketRepository(String projectPath, BitbucketPullRequestsBuilder builder) {
         this.projectPath = projectPath;
         this.builder = builder;
     }
 
     public void init() {
-        this.init(null);
+        this.init(null, null);
+    }
+    
+    public <T extends ApiClient.HttpClientFactory> void init(Class<T> httpFactory) {
+        this.init(null, httpFactory);
     }
     
     public void init(ApiClient client) {
+        this.init(client, null);
+    }
+    
+    public <T extends ApiClient.HttpClientFactory> void init(ApiClient client, Class<T> httpFactory) {
         this.trigger = this.builder.getTrigger();
-        String username = trigger.getUsername();
-        String password = trigger.getPassword();
-        StandardUsernamePasswordCredentials credentials = getCredentials(trigger.getCredentialsId());
-        if (credentials != null) {
-            username = credentials.getUsername();
-            password = credentials.getPassword().getPlainText();
-        }
-        this.client = (client == null) ? new ApiClient(
+        
+        if (client == null) {                      
+            String username = trigger.getUsername();
+            String password = trigger.getPassword();            
+            StandardUsernamePasswordCredentials credentials = getCredentials(trigger.getCredentialsId());
+            if (credentials != null) {
+                username = credentials.getUsername();
+                password = credentials.getPassword().getPlainText();
+            }            
+            this.client = new ApiClient(
                 username,
                 password,
                 trigger.getRepositoryOwner(),
                 trigger.getRepositoryName(),
                 trigger.getCiKey(),
-                trigger.getCiName()
-        ) : client;
+                trigger.getCiName(),
+                httpFactory
+            );
+            
+        } else this.client = client;
     }
 
     public Collection<Pullrequest> getTargetPullRequests() {
@@ -80,6 +93,10 @@ public class BitbucketRepository {
         }
         return targetPullRequests;
     }
+    
+    public ApiClient getClient() {
+      return this.client;
+    }
 
     public void addFutureBuildTasks(Collection<Pullrequest> pullRequests) {
         for(Pullrequest pullRequest : pullRequests) {
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
index e635f65..509dfaf 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
@@ -17,7 +17,6 @@ import java.util.logging.Logger;
 import jenkins.model.Jenkins;
 import hudson.ProxyConfiguration;
 import org.apache.commons.httpclient.methods.PutMethod;
-import org.apache.commons.httpclient.params.HttpMethodParams;
 import org.apache.commons.httpclient.util.EncodingUtil;
 
 /**
@@ -33,13 +32,55 @@ public class ApiClient {
     private Credentials credentials;
     private String key;
     private String name;
-
-    public ApiClient(String username, String password, String owner, String repositoryName, String key, String name) {
+    private HttpClientFactory factory;
+
+    public static class HttpClientFactory {    
+        public static final HttpClientFactory INSTANCE = new HttpClientFactory(); 
+        
+        public HttpClient getInstanceHttpClient() {
+            HttpClient client = new HttpClient();
+            if (Jenkins.getInstance() == null) return client;
+
+            ProxyConfiguration proxy = Jenkins.getInstance().proxy;
+            if (proxy == null) return client;
+
+            logger.log(Level.INFO, "Jenkins proxy: {0}:{1}", new Object[]{ proxy.name, proxy.port });
+            client.getHostConfiguration().setProxy(proxy.name, proxy.port);
+            String username = proxy.getUserName();
+            String password = proxy.getPassword();
+
+            // Consider it to be passed if username specified. Sufficient?
+            if (username != null && !"".equals(username.trim())) {
+                logger.log(Level.INFO, "Using proxy authentication (user={0})", username);
+                client.getState().setProxyCredentials(AuthScope.ANY,
+                    new UsernamePasswordCredentials(username, password));
+            }
+            
+            return client;
+        }
+    }
+    
+    public <T extends HttpClientFactory> ApiClient(
+        String username, String password, 
+        String owner, String repositoryName, 
+        String key, String name, 
+        Class<T> httpFactory
+    ) {
         this.credentials = new UsernamePasswordCredentials(username, password);
         this.owner = owner;
         this.repositoryName = repositoryName;
         this.key = key;
         this.name = name;
+        
+        try {
+            this.factory = (httpFactory != null) ? httpFactory.newInstance() : HttpClientFactory.INSTANCE;
+        } catch(InstantiationException e) {
+            logger.log(Level.WARNING, "failed new instance of {0}: {1} ", new Object[] { httpFactory.getName(), e });
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            logger.log(Level.WARNING, "failed new instance of {0}: {1} ", new Object[] { httpFactory.getName(), e });
+            e.printStackTrace();
+      }
     }
 
     public List<Pullrequest> getPullRequests() {
@@ -47,6 +88,7 @@ public class ApiClient {
             return parse(get(v2("/pullrequests/")), Pullrequest.Response.class).getPullrequests();
         } catch(Exception e) {
             logger.log(Level.WARNING, "invalid pull request response.", e);
+            e.printStackTrace();
         }
         return Collections.EMPTY_LIST;
     }
@@ -56,6 +98,7 @@ public class ApiClient {
             return parse(get(v1("/pullrequests/" + pullRequestId + "/comments")), new TypeReference<List<Pullrequest.Comment>>() {});
         } catch(Exception e) {
             logger.log(Level.WARNING, "invalid pull request response.", e);
+            e.printStackTrace();
         }
         return Collections.EMPTY_LIST;
     }
@@ -112,6 +155,7 @@ public class ApiClient {
             return parse(post(v2("/pullrequests/" + pullRequestId + "/approve"),
                 new NameValuePair[]{}), Pullrequest.Participant.class);
         } catch (IOException e) {
+            logger.log(Level.WARNING, "Invalid pull request approval response.", e);
             e.printStackTrace();
         }
         return null;
@@ -131,24 +175,7 @@ public class ApiClient {
     }
 
     private HttpClient getHttpClient() {
-        HttpClient client = new HttpClient();
-        if (Jenkins.getInstance() == null) return client;
-
-        ProxyConfiguration proxy = Jenkins.getInstance().proxy;
-        if (proxy == null) return client;
-
-        logger.info("Jenkins proxy: " + proxy.name + ":" + proxy.port);
-        client.getHostConfiguration().setProxy(proxy.name, proxy.port);
-        String username = proxy.getUserName();
-        String password = proxy.getPassword();
-
-        // Consider it to be passed if username specified. Sufficient?
-        if (username != null && !"".equals(username.trim())) {
-            logger.info("Using proxy authentication (user=" + username + ")");
-            client.getState().setProxyCredentials(AuthScope.ANY,
-                new UsernamePasswordCredentials(username, password));
-        }
-        return client;
+        return this.factory.getInstanceHttpClient();
     }
 
     private String v1(String url) {
@@ -193,8 +220,10 @@ public class ApiClient {
             client.executeMethod(req);
             return req.getResponseBodyAsString();
         } catch (HttpException e) {
+            logger.log(Level.WARNING, "Failed to send request.", e);
             e.printStackTrace();
         } catch (IOException e) {
+            logger.log(Level.WARNING, "Failed to send request.", e);
             e.printStackTrace();
         }
         return null;
diff --git a/src/test/java/BitbucketBuildFilterTest.java b/src/test/java/BitbucketBuildFilterTest.java
index 0fabfe4..9b84e73 100644
--- a/src/test/java/BitbucketBuildFilterTest.java
+++ b/src/test/java/BitbucketBuildFilterTest.java
@@ -1,8 +1,3 @@
-/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
 
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.BitbucketBuildFilter;
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.BitbucketCause;
@@ -10,9 +5,7 @@ import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.BitbucketPullRequ
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.BitbucketRepository;
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.ApiClient;
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.Pullrequest;
-import java.util.Arrays;
 import java.util.Calendar;
-import java.util.Collection;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.regex.Pattern;
@@ -25,8 +18,7 @@ import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.WithoutJenkins;
 
 /**
- *
- * @author maxvodo
+ * Tests
  */
 public class BitbucketBuildFilterTest {
   
@@ -288,24 +280,4 @@ public class BitbucketBuildFilterTest {
     for(Pullrequest.Comment comment : comments)
       assertFalse(repo.hasMyBuildTagInTTPComment(comment.getContent(), myBuildKey));
   }
-  
-  //@Test
-  @WithoutJenkins
-  public void ttpCommentTest() {    
-    ApiClient client = EasyMock.createNiceMock(ApiClient.class);
-    Collection<List<Pullrequest>> prs = new LinkedList<List<Pullrequest>>();
-    
-    prs.add(Arrays.asList(new Pullrequest[] {
-      new Pullrequest()
-    }));
-    
-    for(List<Pullrequest> pr : prs) EasyMock.expect(client.getPullRequests()).andReturn(pr).times(1);
-    BitbucketPullRequestsBuilder builder = EasyMock.createMock(BitbucketPullRequestsBuilder.class);
-    EasyMock.replay(client, builder);
-    
-    BitbucketRepository repo = new BitbucketRepository("", builder);
-    repo.init(client);
-    
-    Collection<Pullrequest> targetPRs = repo.getTargetPullRequests();
-  }
 }
diff --git a/src/test/java/BitbucketBuildRepositoryTest.java b/src/test/java/BitbucketBuildRepositoryTest.java
new file mode 100644
index 0000000..bb6de8f
--- /dev/null
+++ b/src/test/java/BitbucketBuildRepositoryTest.java
@@ -0,0 +1,153 @@
+
+import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.BitbucketBuildTrigger;
+import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.BitbucketPullRequestsBuilder;
+import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.BitbucketRepository;
+import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.ApiClient;
+import com.cloudbees.plugins.credentials.CredentialsProvider;
+import com.cloudbees.plugins.credentials.CredentialsScope;
+import com.cloudbees.plugins.credentials.CredentialsStore;
+import com.cloudbees.plugins.credentials.domains.Domain;
+import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl;
+import org.easymock.*;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import org.junit.Rule;
+import org.jvnet.hudson.test.JenkinsRule;
+import jenkins.model.Jenkins;
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpState;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.auth.AuthScope;
+import org.junit.Assert;
+
+
+interface ICredentialsInterceptor {
+  void assertCredentials(Credentials actual);
+}
+
+/**
+ * Utility class for interceptor functionality
+ * @param <T> 
+ */
+class HttpClientInterceptor<T extends ICredentialsInterceptor> extends HttpClient {  
+  
+  class CredentialsInterceptor<T extends ICredentialsInterceptor> extends HttpState {
+    private final T interceptor;
+    public CredentialsInterceptor(T interceptor) { this.interceptor = interceptor; }
+    
+    @Override
+    public synchronized void setCredentials(AuthScope authscope, Credentials credentials) {      
+      super.setCredentials(authscope, credentials);
+      this.interceptor.assertCredentials(credentials);
+      throw new AssertionError();
+    }    
+  }  
+  
+  private final T interceptor;
+  public HttpClientInterceptor(T interceptor) { this.interceptor = interceptor; }
+  
+  @Override
+  public synchronized HttpState getState() { return new CredentialsInterceptor(this.interceptor); }  
+}
+
+/**
+ * Utility class for credentials assertion
+ * Used with 
+ * @author maxvodo
+ */
+class AssertCredentials implements ICredentialsInterceptor {
+  private final Credentials expected;
+  public AssertCredentials(Credentials expected) { this.expected = expected; }
+
+  public void assertCredentials(Credentials actual) {
+    if (actual == null) assertTrue(this.expected == null); 
+                   else assertTrue(this.expected != null);        
+
+    if (actual instanceof UsernamePasswordCredentials) {
+      UsernamePasswordCredentials actual_ = (UsernamePasswordCredentials)actual,
+                                  expected_ = (UsernamePasswordCredentials)this.expected;
+      assertNotNull(expected_);
+      Assert.assertArrayEquals(new Object[] {
+        actual_.getUserName(), actual_.getPassword()
+      }, new Object[] {
+        expected_.getUserName(), expected_.getPassword()
+      });
+    }
+  }      
+}
+
+/**
+ * Tests
+ */
+public class BitbucketBuildRepositoryTest {
+
+  @Rule
+  public JenkinsRule jRule = new JenkinsRule();  
+  
+  @Test  
+  public void repositorySimpleUserPasswordTest() throws Exception {
+    BitbucketBuildTrigger trigger = new BitbucketBuildTrigger(
+      "", "@hourly",
+      "JenkinsCID",
+      "foo",
+      "bar",
+      "", "",
+      "", true,
+      "", "", "",
+      true, 
+      true
+    );
+    
+    BitbucketPullRequestsBuilder builder = EasyMock.createMock(BitbucketPullRequestsBuilder.class); 
+    EasyMock.expect(builder.getTrigger()).andReturn(trigger).anyTimes();
+    EasyMock.replay(builder);
+    
+    ApiClient.HttpClientFactory httpFactory = EasyMock.createMock(ApiClient.HttpClientFactory.class);
+    EasyMock.expect(httpFactory.getInstanceHttpClient()).andReturn(
+      new HttpClientInterceptor(new AssertCredentials(new UsernamePasswordCredentials("foo", "bar")))
+    ).anyTimes();
+    EasyMock.replay(httpFactory);            
+    
+    BitbucketRepository repo = new BitbucketRepository("", builder);
+    repo.init(httpFactory.getClass());
+    
+    try { repo.postPullRequestApproval("prId"); } catch(Error e) { assertTrue(e instanceof AssertionError); }
+  }
+  
+  @Test  
+  public void repositoryCtorWithTriggerTest() throws Exception {
+    BitbucketBuildTrigger trigger = new BitbucketBuildTrigger(
+      "", "@hourly",
+      "JenkinsCID",
+      "foo",
+      "bar",
+      "", "",
+      "", true,
+      "", "", "",
+      true, 
+      true
+    );          
+    
+    BitbucketPullRequestsBuilder builder = EasyMock.createMock(BitbucketPullRequestsBuilder.class); 
+    EasyMock.expect(builder.getTrigger()).andReturn(trigger).anyTimes();
+    EasyMock.replay(builder);
+    
+    CredentialsStore store = CredentialsProvider.lookupStores(Jenkins.getInstance()).iterator().next();
+    assertNotNull(store);
+    store.addCredentials(Domain.global(), new UsernamePasswordCredentialsImpl(
+      CredentialsScope.GLOBAL, "JenkinsCID", "description", "username", "password"
+    ));
+    
+    ApiClient.HttpClientFactory httpFactory = EasyMock.createMock(ApiClient.HttpClientFactory.class);
+    EasyMock.expect(httpFactory.getInstanceHttpClient()).andReturn(
+      new HttpClientInterceptor(new AssertCredentials(new UsernamePasswordCredentials("username", "password")))
+    ).anyTimes();
+    EasyMock.replay(httpFactory);  
+    
+    BitbucketRepository repo = new BitbucketRepository("", builder);
+    repo.init(httpFactory.getClass());        
+    
+    try { repo.postPullRequestApproval("prId"); } catch(Error e) { assertTrue(e instanceof AssertionError); }                
+  }
+}
-- 
cgit v1.2.3


From 340c1c44bad78992ec49746d3776c3cff1a96fbd Mon Sep 17 00:00:00 2001
From: Maxim Epishchev <epishev@garant.ru>
Date: Wed, 3 Feb 2016 14:34:44 +0300
Subject: Limit size "key" field in BitBucket POST API

Refactoring method ApiClient::computeAPIKey() to check maximum size of computed key.
Now field size contolled by special constant ApiClient::MAX_KEY_SIZE_BB_API.

This changes will resolve, in my opinion, issue with continuously rebuilding: method ApiClient::hasBuildStatus() fail and PR's are always trigger new builds.
---
 .../BitbucketPullRequestsBuilder.java              |  17 ++-
 .../BitbucketRepository.java                       |   4 +
 .../bitbucket/ApiClient.java                       |  32 +++++-
 src/test/java/BitbucketBuildFilterTest.java        |   9 +-
 src/test/java/BitbucketBuildRepositoryTest.java    | 115 ++++++++++++++++++++-
 5 files changed, 169 insertions(+), 8 deletions(-)

(limited to 'src/main/java/bitbucketpullrequestbuilder')

diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketPullRequestsBuilder.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketPullRequestsBuilder.java
index c5d4159..d337796 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketPullRequestsBuilder.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketPullRequestsBuilder.java
@@ -2,10 +2,15 @@ package bitbucketpullrequestbuilder.bitbucketpullrequestbuilder;
 
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.Pullrequest;
 import hudson.model.AbstractProject;
+
+import java.io.UnsupportedEncodingException;
 import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 
 import java.util.Collection;
+import java.util.logging.Level;
 import java.util.logging.Logger;
+
 import org.apache.commons.codec.binary.Hex;
 
 /**
@@ -54,12 +59,20 @@ public class BitbucketPullRequestsBuilder {
         return this.project;
     }        
     
+    /**
+     * Return MD5 hashed full project name or full project name, if MD5 hash provider inaccessible
+     * @return unique project id
+     */
     public String getProjectId() {
       try {
         final MessageDigest MD5 = MessageDigest.getInstance("MD5");
         return new String(Hex.encodeHex(MD5.digest(this.project.getFullName().getBytes("UTF-8"))));
-      } catch (Exception exc) {
-        logger.severe(exc.toString());
+      } catch (NoSuchAlgorithmException exc) {
+        logger.log(Level.WARNING, "Failed to produce hash", exc);
+        exc.printStackTrace();
+      } catch (UnsupportedEncodingException exc) {
+        logger.log(Level.WARNING, "Failed to produce hash", exc);
+        exc.printStackTrace();
       }
       return this.project.getFullName();
     }
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
index 23b0607..8439eea 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
@@ -9,18 +9,22 @@ import java.util.logging.Logger;
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.ApiClient;
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.BuildState;
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.Pullrequest;
+
 import java.util.LinkedList;
 import java.util.logging.Level;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+
 import com.cloudbees.plugins.credentials.CredentialsMatchers;
 import com.cloudbees.plugins.credentials.CredentialsProvider;
 import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
 import com.cloudbees.plugins.credentials.common.UsernamePasswordCredentials;
+
 import jenkins.model.Jenkins;
 import jenkins.scm.api.SCMSource;
 import jenkins.scm.api.SCMSourceOwner;
 import jenkins.scm.api.SCMSourceOwners;
+
 import org.apache.commons.lang.StringUtils;
 
 import static com.cloudbees.plugins.credentials.CredentialsMatchers.instanceOf;
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
index 509dfaf..047bf5a 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
@@ -16,6 +16,11 @@ import java.util.logging.Logger;
 
 import jenkins.model.Jenkins;
 import hudson.ProxyConfiguration;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import org.apache.commons.codec.binary.Hex;
 import org.apache.commons.httpclient.methods.PutMethod;
 import org.apache.commons.httpclient.util.EncodingUtil;
 
@@ -26,13 +31,15 @@ public class ApiClient {
     private static final Logger logger = Logger.getLogger(ApiClient.class.getName());
     private static final String V1_API_BASE_URL = "https://bitbucket.org/api/1.0/repositories/";
     private static final String V2_API_BASE_URL = "https://bitbucket.org/api/2.0/repositories/";
-    private static final String COMPUTED_KEY_FORMAT = "%s-%s";
+    private static final String COMPUTED_KEY_FORMAT = "%s-%s";    
     private String owner;
     private String repositoryName;
     private Credentials credentials;
     private String key;
     private String name;
     private HttpClientFactory factory;
+    
+    public static final byte MAX_KEY_SIZE_BB_API = 40;
 
     public static class HttpClientFactory {    
         public static final HttpClientFactory INSTANCE = new HttpClientFactory(); 
@@ -107,8 +114,29 @@ public class ApiClient {
       return this.name;
     }
     
+    private static MessageDigest SHA1 = null;
+    
+    /**
+     * Retrun 
+     * @param keyExPart
+     * @return key parameter for call BitBucket API 
+     */
     private String computeAPIKey(String keyExPart) {
-      return String.format(COMPUTED_KEY_FORMAT, this.key, keyExPart);
+      String computedKey = String.format(COMPUTED_KEY_FORMAT, this.key, keyExPart);
+      
+      if (computedKey.length() > MAX_KEY_SIZE_BB_API) {
+        try { 
+          if (SHA1 == null) SHA1 = MessageDigest.getInstance("SHA1"); 
+          return new String(Hex.encodeHex(SHA1.digest(computedKey.getBytes("UTF-8"))));
+        } catch(NoSuchAlgorithmException e) { 
+          logger.log(Level.WARNING, "Failed to create hash provider", e);
+          e.printStackTrace();
+        } catch (UnsupportedEncodingException e) {
+          logger.log(Level.WARNING, "Failed to create hash provider", e);
+          e.printStackTrace();
+        }
+      }      
+      return (computedKey.length() <= MAX_KEY_SIZE_BB_API) ?  computedKey : computedKey.substring(0, MAX_KEY_SIZE_BB_API);
     }
     
     public String buildStatusKey(String bsKey) {
diff --git a/src/test/java/BitbucketBuildFilterTest.java b/src/test/java/BitbucketBuildFilterTest.java
index 9b84e73..3b35dbc 100644
--- a/src/test/java/BitbucketBuildFilterTest.java
+++ b/src/test/java/BitbucketBuildFilterTest.java
@@ -5,17 +5,20 @@ import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.BitbucketPullRequ
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.BitbucketRepository;
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.ApiClient;
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.Pullrequest;
+
 import java.util.Calendar;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.regex.Pattern;
+
 import jenkins.plugins.git.AbstractGitSCMSource;
+import org.jvnet.hudson.test.JenkinsRule;
+import org.jvnet.hudson.test.WithoutJenkins;
+
 import org.easymock.*;
 import org.junit.Test;
-import static org.junit.Assert.*;
 import org.junit.Rule;
-import org.jvnet.hudson.test.JenkinsRule;
-import org.jvnet.hudson.test.WithoutJenkins;
+import static org.junit.Assert.*;
 
 /**
  * Tests
diff --git a/src/test/java/BitbucketBuildRepositoryTest.java b/src/test/java/BitbucketBuildRepositoryTest.java
index bb6de8f..5f1aca2 100644
--- a/src/test/java/BitbucketBuildRepositoryTest.java
+++ b/src/test/java/BitbucketBuildRepositoryTest.java
@@ -1,25 +1,41 @@
 
+import antlr.ANTLRException;
+
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.BitbucketBuildTrigger;
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.BitbucketPullRequestsBuilder;
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.BitbucketRepository;
 import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.ApiClient;
+
 import com.cloudbees.plugins.credentials.CredentialsProvider;
 import com.cloudbees.plugins.credentials.CredentialsScope;
 import com.cloudbees.plugins.credentials.CredentialsStore;
 import com.cloudbees.plugins.credentials.domains.Domain;
 import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.Collection;
 import org.easymock.*;
 import org.junit.Test;
 import static org.junit.Assert.*;
 import org.junit.Rule;
+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;
 import org.apache.commons.httpclient.HttpClient;
 import org.apache.commons.httpclient.HttpState;
 import org.apache.commons.httpclient.UsernamePasswordCredentials;
 import org.apache.commons.httpclient.auth.AuthScope;
-import org.junit.Assert;
 
 
 interface ICredentialsInterceptor {
@@ -150,4 +166,101 @@ public class BitbucketBuildRepositoryTest {
     
     try { repo.postPullRequestApproval("prId"); } catch(Error e) { assertTrue(e instanceof AssertionError); }                
   }
+  
+  class MD5HasherFunction implements Function<String, String> {       
+    protected final MessageDigest MD5;
+    public MD5HasherFunction(MessageDigest md5) { this.MD5 = md5; }
+    public String apply(String f) {
+      try { return new String(Hex.encodeHex(MD5.digest(f.getBytes("UTF-8")))); } catch(UnsupportedEncodingException e) { }
+      return null;
+    }
+  }
+  
+  class SHA1HasherFunction implements Function<String, String> {       
+    protected final MessageDigest SHA1;
+    public SHA1HasherFunction(MessageDigest sha1) { this.SHA1 = sha1; }
+    public String apply(String f) {
+      try { return new String(Hex.encodeHex(SHA1.digest(f.getBytes("UTF-8")))); } catch(UnsupportedEncodingException e) { }
+      return null;
+    }
+  }
+  
+  @Test  
+  @WithoutJenkins
+  public void repositoryProjectIdTest() throws ANTLRException, NoSuchAlgorithmException, UnsupportedEncodingException {
+    BitbucketBuildTrigger trigger = new BitbucketBuildTrigger(
+      "", "@hourly",
+      "JenkinsCID",
+      "foo",
+      "bar",
+      "", "",
+      "", true,
+      "jenkins", "Jenkins", "",
+      true, 
+      true
+    );
+    
+    BitbucketPullRequestsBuilder builder = EasyMock.createMock(BitbucketPullRequestsBuilder.class); 
+    EasyMock.expect(builder.getTrigger()).andReturn(trigger).anyTimes();
+    
+    final MessageDigest MD5 = MessageDigest.getInstance("MD5");
+    
+    String[] projectIds = new String[] { 
+      "one", 
+      "Second project",
+      "Project abstract 1.1",
+      "Good project, careated at " + (new java.util.Date()).toString(),      
+    };   
+    
+    Collection<String> hashedProjectIdsCollection = Collections2.transform(Arrays.asList(projectIds), new MD5HasherFunction(MD5));
+    String[] hashedPojectIds = hashedProjectIdsCollection.toArray(new String[hashedProjectIdsCollection.size()]);
+    
+    for(String projectId : hashedPojectIds) {
+      EasyMock.expect(builder.getProjectId()).andReturn(projectId).times(1);
+    }        
+    EasyMock.replay(builder);
+    
+    BitbucketRepository repo = new BitbucketRepository("", builder);
+    repo.init();       
+    
+    for(String projectId : projectIds) {
+      String hashMD5 = new String(Hex.encodeHex(MD5.digest(projectId.getBytes("UTF-8"))));
+      String buildStatusKey = repo.getClient().buildStatusKey(builder.getProjectId());
+      
+      assertTrue(buildStatusKey.length() <= ApiClient.MAX_KEY_SIZE_BB_API);
+      assertEquals(buildStatusKey, "jenkins-" + hashMD5);
+    }
+  }
+  
+  @Test  
+  @WithoutJenkins
+  public void triggerLongCIKeyTest() throws ANTLRException, NoSuchAlgorithmException {        
+    BitbucketBuildTrigger trigger = new BitbucketBuildTrigger(
+      "", "@hourly",
+      "JenkinsCID",
+      "foo",
+      "bar",
+      "", "",
+      "", true,
+      "jenkins-too-long-ci-key", "Jenkins", "",
+      true, 
+      true
+    );
+    
+    final MessageDigest MD5 = MessageDigest.getInstance("MD5");
+    final MessageDigest SHA1 = MessageDigest.getInstance("SHA1");
+    
+    BitbucketPullRequestsBuilder builder = EasyMock.createMock(BitbucketPullRequestsBuilder.class); 
+    EasyMock.expect(builder.getTrigger()).andReturn(trigger).anyTimes();
+    EasyMock.expect(builder.getProjectId()).andReturn((new MD5HasherFunction(MD5)).apply("projectId")).anyTimes();
+    EasyMock.replay(builder);       
+    
+    BitbucketRepository repo = new BitbucketRepository("", builder);
+    repo.init();
+    
+    String buildStatusKey = repo.getClient().buildStatusKey(builder.getProjectId());
+    assertTrue(buildStatusKey.length() <= ApiClient.MAX_KEY_SIZE_BB_API);
+    assertFalse(buildStatusKey.startsWith("jenkins-"));
+    assertEquals((new SHA1HasherFunction(SHA1)).apply("jenkins-too-long-ci-key" + "-" + builder.getProjectId()), buildStatusKey);
+  }
 }
-- 
cgit v1.2.3


From 4c667ab93e7e4fd57ac2b38a423447072d1606ed Mon Sep 17 00:00:00 2001
From: Maxim Epishchev <epishev@garant.ru>
Date: Thu, 4 Feb 2016 10:59:33 +0300
Subject: Allow default "none" credential in
 BitbucketRepository::getCredentials()

Using by default only username and passwords fields to provide BitBucket auth cause NullReferenceException in BitbucketRepository::getCredentials(),
because credentialsId is null. It's my fault :(
---
 .../bitbucketpullrequestbuilder/BitbucketRepository.java                 | 1 +
 1 file changed, 1 insertion(+)

(limited to 'src/main/java/bitbucketpullrequestbuilder')

diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
index 8439eea..3bc3928 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
@@ -303,6 +303,7 @@ public class BitbucketRepository {
     }
 
     private StandardUsernamePasswordCredentials getCredentials(String credentialsId) {
+        if (null == credentialsId) return null;
         return CredentialsMatchers
                 .firstOrNull(
                         CredentialsProvider.lookupCredentials(StandardUsernamePasswordCredentials.class),
-- 
cgit v1.2.3


From 85a09f7392c50531365e89e94766a9caf3cac0f1 Mon Sep 17 00:00:00 2001
From: Maxim Epishchev <epishev@garant.ru>
Date: Thu, 4 Feb 2016 11:54:42 +0300
Subject: Remove overqualified using of Class<T> as HttpClient interceptor

Constructor of ApiClient now using just <T extends HttpClientFactory> T type to make possible using of HttpClient interceptor in tests.
---
 .../bitbucketpullrequestbuilder/BitbucketRepository.java |  4 ++--
 .../bitbucketpullrequestbuilder/bitbucket/ApiClient.java | 15 +++------------
 src/test/java/BitbucketBuildRepositoryTest.java          | 16 ++++++++++------
 3 files changed, 15 insertions(+), 20 deletions(-)

(limited to 'src/main/java/bitbucketpullrequestbuilder')

diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
index 3bc3928..9b92775 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
@@ -54,7 +54,7 @@ public class BitbucketRepository {
         this.init(null, null);
     }
     
-    public <T extends ApiClient.HttpClientFactory> void init(Class<T> httpFactory) {
+    public <T extends ApiClient.HttpClientFactory> void init(T httpFactory) {
         this.init(null, httpFactory);
     }
     
@@ -62,7 +62,7 @@ public class BitbucketRepository {
         this.init(client, null);
     }
     
-    public <T extends ApiClient.HttpClientFactory> void init(ApiClient client, Class<T> httpFactory) {
+    public <T extends ApiClient.HttpClientFactory> void init(ApiClient client, T httpFactory) {
         this.trigger = this.builder.getTrigger();
         
         if (client == null) {                      
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
index 047bf5a..19bff34 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
@@ -71,23 +71,14 @@ public class ApiClient {
         String username, String password, 
         String owner, String repositoryName, 
         String key, String name, 
-        Class<T> httpFactory
+        T httpFactory
     ) {
         this.credentials = new UsernamePasswordCredentials(username, password);
         this.owner = owner;
         this.repositoryName = repositoryName;
         this.key = key;
-        this.name = name;
-        
-        try {
-            this.factory = (httpFactory != null) ? httpFactory.newInstance() : HttpClientFactory.INSTANCE;
-        } catch(InstantiationException e) {
-            logger.log(Level.WARNING, "failed new instance of {0}: {1} ", new Object[] { httpFactory.getName(), e });
-            e.printStackTrace();
-        } catch (IllegalAccessException e) {
-            logger.log(Level.WARNING, "failed new instance of {0}: {1} ", new Object[] { httpFactory.getName(), e });
-            e.printStackTrace();
-      }
+        this.name = name;        
+        this.factory = httpFactory != null ? httpFactory : HttpClientFactory.INSTANCE;
     }
 
     public List<Pullrequest> getPullRequests() {
diff --git a/src/test/java/BitbucketBuildRepositoryTest.java b/src/test/java/BitbucketBuildRepositoryTest.java
index 5f1aca2..953bd81 100644
--- a/src/test/java/BitbucketBuildRepositoryTest.java
+++ b/src/test/java/BitbucketBuildRepositoryTest.java
@@ -20,6 +20,7 @@ import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.logging.Logger;
 import org.easymock.*;
 import org.junit.Test;
 import static org.junit.Assert.*;
@@ -47,6 +48,7 @@ interface ICredentialsInterceptor {
  * @param <T> 
  */
 class HttpClientInterceptor<T extends ICredentialsInterceptor> extends HttpClient {  
+  private static final Logger logger = Logger.getLogger(HttpClientInterceptor.class.getName());
   
   class CredentialsInterceptor<T extends ICredentialsInterceptor> extends HttpState {
     private final T interceptor;
@@ -54,6 +56,7 @@ class HttpClientInterceptor<T extends ICredentialsInterceptor> extends HttpClien
     
     @Override
     public synchronized void setCredentials(AuthScope authscope, Credentials credentials) {      
+      logger.info("Inject setCredentials");
       super.setCredentials(authscope, credentials);
       this.interceptor.assertCredentials(credentials);
       throw new AssertionError();
@@ -73,10 +76,13 @@ class HttpClientInterceptor<T extends ICredentialsInterceptor> extends HttpClien
  * @author maxvodo
  */
 class AssertCredentials implements ICredentialsInterceptor {
+  private static final Logger logger = Logger.getLogger(AssertCredentials.class.getName());
+  
   private final Credentials expected;
   public AssertCredentials(Credentials expected) { this.expected = expected; }
 
   public void assertCredentials(Credentials actual) {
+    logger.info("Assert credential");
     if (actual == null) assertTrue(this.expected == null); 
                    else assertTrue(this.expected != null);        
 
@@ -119,14 +125,14 @@ public class BitbucketBuildRepositoryTest {
     EasyMock.expect(builder.getTrigger()).andReturn(trigger).anyTimes();
     EasyMock.replay(builder);
     
-    ApiClient.HttpClientFactory httpFactory = EasyMock.createMock(ApiClient.HttpClientFactory.class);
+    ApiClient.HttpClientFactory httpFactory = EasyMock.createNiceMock(ApiClient.HttpClientFactory.class);
     EasyMock.expect(httpFactory.getInstanceHttpClient()).andReturn(
       new HttpClientInterceptor(new AssertCredentials(new UsernamePasswordCredentials("foo", "bar")))
     ).anyTimes();
     EasyMock.replay(httpFactory);            
     
     BitbucketRepository repo = new BitbucketRepository("", builder);
-    repo.init(httpFactory.getClass());
+    repo.init(httpFactory);
     
     try { repo.postPullRequestApproval("prId"); } catch(Error e) { assertTrue(e instanceof AssertionError); }
   }
@@ -155,14 +161,14 @@ public class BitbucketBuildRepositoryTest {
       CredentialsScope.GLOBAL, "JenkinsCID", "description", "username", "password"
     ));
     
-    ApiClient.HttpClientFactory httpFactory = EasyMock.createMock(ApiClient.HttpClientFactory.class);
+    ApiClient.HttpClientFactory httpFactory = EasyMock.createNiceMock(ApiClient.HttpClientFactory.class);
     EasyMock.expect(httpFactory.getInstanceHttpClient()).andReturn(
       new HttpClientInterceptor(new AssertCredentials(new UsernamePasswordCredentials("username", "password")))
     ).anyTimes();
     EasyMock.replay(httpFactory);  
     
     BitbucketRepository repo = new BitbucketRepository("", builder);
-    repo.init(httpFactory.getClass());        
+    repo.init(httpFactory);        
     
     try { repo.postPullRequestApproval("prId"); } catch(Error e) { assertTrue(e instanceof AssertionError); }                
   }
@@ -186,7 +192,6 @@ public class BitbucketBuildRepositoryTest {
   }
   
   @Test  
-  @WithoutJenkins
   public void repositoryProjectIdTest() throws ANTLRException, NoSuchAlgorithmException, UnsupportedEncodingException {
     BitbucketBuildTrigger trigger = new BitbucketBuildTrigger(
       "", "@hourly",
@@ -233,7 +238,6 @@ public class BitbucketBuildRepositoryTest {
   }
   
   @Test  
-  @WithoutJenkins
   public void triggerLongCIKeyTest() throws ANTLRException, NoSuchAlgorithmException {        
     BitbucketBuildTrigger trigger = new BitbucketBuildTrigger(
       "", "@hourly",
-- 
cgit v1.2.3