aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxim Epishchev <epishev@garant.ru>2016-02-03 14:34:44 +0300
committerMaxim Epishchev <epishev@garant.ru>2016-02-03 14:34:44 +0300
commit340c1c44bad78992ec49746d3776c3cff1a96fbd (patch)
tree722b0cc5d457a02e4e8fd283216fcec1b3e16a5b /src
parent4b880c7045ebf42974f833ffe9b11084c86c3408 (diff)
downloadbbprb-340c1c44bad78992ec49746d3776c3cff1a96fbd.tar.gz
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.
Diffstat (limited to 'src')
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketPullRequestsBuilder.java17
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java4
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java32
-rw-r--r--src/test/java/BitbucketBuildFilterTest.java9
-rw-r--r--src/test/java/BitbucketBuildRepositoryTest.java115
5 files changed, 169 insertions, 8 deletions
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);
+ }
}