aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder')
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildFilter.java13
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java127
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java50
3 files changed, 154 insertions, 36 deletions
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildFilter.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildFilter.java
index 1072337..c251930 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildFilter.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildFilter.java
@@ -1,9 +1,9 @@
package bitbucketpullrequestbuilder.bitbucketpullrequestbuilder;
-import hudson.ExtensionList;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.regex.Matcher;
@@ -169,12 +169,15 @@ public class BitbucketBuildFilter {
return filter.trim();
}
- public static BitbucketBuildFilter InstanceBySCM(ExtensionList<SCMSource> scmSources, String defaultFilter) {
- logger.log(Level.FINE, "Filter instance by using SCM");
+ public static BitbucketBuildFilter InstanceBySCM(Collection<SCMSource> scmSources, String defaultFilter) {
+ logger.log(Level.INFO, "Filter instance by using SCMSources list with {0} items", scmSources.size());
AbstractGitSCMSource gitscm = null;
for(SCMSource scm : scmSources) {
- gitscm = (AbstractGitSCMSource)scm;
- if (gitscm != null) break;
+ logger.log(Level.INFO, "Check {0} SCMSource ", scm.getClass());
+ if (scm instanceof AbstractGitSCMSource) {
+ gitscm = (AbstractGitSCMSource)scm;
+ break;
+ }
}
return new BitbucketBuildFilter(FilterFromGitSCMSource(gitscm, defaultFilter));
}
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
index c71cc99..6736ee9 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
@@ -9,11 +9,15 @@ 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 jenkins.model.Jenkins;
import jenkins.scm.api.SCMSource;
+import jenkins.scm.api.SCMSourceOwner;
+import jenkins.scm.api.SCMSourceOwners;
+import org.apache.commons.lang.StringUtils;
/**
* Created by nishio
@@ -22,7 +26,9 @@ public class BitbucketRepository {
private static final Logger logger = Logger.getLogger(BitbucketRepository.class.getName());
private static final String BUILD_DESCRIPTION = "%s: %s into %s";
private static final String BUILD_REQUEST_MARKER = "test this please";
- private static final String BUILD_REQUEST_MARKER_COUNTER_RX = "\\[(\\d+)]\\";
+ private static final String BUILD_REQUEST_DONE_MARKER = "ttp build flag";
+ private static final String BUILD_REQUEST_MARKER_TAG_SINGLE_RX = "\\#[\\w\\-\\d]+";
+ private static final String BUILD_REQUEST_MARKER_TAGS_RX = "\\[bid\\:\\s?(.*)\\]";
private String projectPath;
private BitbucketPullRequestsBuilder builder;
@@ -35,15 +41,19 @@ public class BitbucketRepository {
}
public void init() {
- trigger = this.builder.getTrigger();
- client = new ApiClient(
+ this.init(null);
+ }
+
+ public void init(ApiClient client) {
+ this.trigger = this.builder.getTrigger();
+ this.client = (client == null) ? new ApiClient(
trigger.getUsername(),
trigger.getPassword(),
trigger.getRepositoryOwner(),
trigger.getRepositoryName(),
trigger.getCiKey(),
trigger.getCiName()
- );
+ ) : client;
}
public Collection<Pullrequest> getTargetPullRequests() {
@@ -102,10 +112,68 @@ public class BitbucketRepository {
public void postPullRequestApproval(String pullRequestId) {
this.client.postPullRequestApproval(pullRequestId);
}
-
- private Integer extractRebuildTimesFromComment(String content) {
- Matcher matcher = Pattern.compile(BUILD_REQUEST_MARKER_COUNTER_RX).matcher(content);
- return matcher.groupCount() >= 1 ? Integer.parseInt(matcher.group(1)) : 0;
+
+ public String getMyBuildTag(String buildKey) {
+ return "#" + this.client.buildStatusKey(buildKey);
+ }
+
+ final static Pattern BUILD_TAGS_RX = Pattern.compile(BUILD_REQUEST_MARKER_TAGS_RX, Pattern.CASE_INSENSITIVE | Pattern.CANON_EQ);
+ final static Pattern SINGLE_BUILD_TAG_RX = Pattern.compile(BUILD_REQUEST_MARKER_TAG_SINGLE_RX, Pattern.CASE_INSENSITIVE | Pattern.CANON_EQ);
+ final static String CONTENT_PART_TEMPLATE = "```[bid: %s]```";
+
+ private List<String> getAvailableBuildTagsFromTTPComment(String buildTags) {
+ logger.log(Level.INFO, "Parse {0}", new Object[]{ buildTags });
+ List<String> availableBuildTags = new LinkedList<String>();
+ Matcher subBuildTagMatcher = SINGLE_BUILD_TAG_RX.matcher(buildTags);
+ while(subBuildTagMatcher.find()) availableBuildTags.add(subBuildTagMatcher.group(0).trim());
+ return availableBuildTags;
+ }
+
+ public boolean hasMyBuildTagInTTPComment(String content, String buildKey) {
+ Matcher tagsMatcher = BUILD_TAGS_RX.matcher(content);
+ if (tagsMatcher.find()) {
+ logger.log(Level.INFO, "Content {0} g[1]:{1} mykey:{2}", new Object[] { content, tagsMatcher.group(1).trim(), this.getMyBuildTag(buildKey) });
+ return this.getAvailableBuildTagsFromTTPComment(tagsMatcher.group(1).trim()).contains(this.getMyBuildTag(buildKey));
+ }
+ else return false;
+ }
+
+ private void postBuildTagInTTPComment(String pullRequestId, String content, String buildKey) {
+ logger.log(Level.INFO, "Update build tag for {0} build key", buildKey);
+ List<String> builds = this.getAvailableBuildTagsFromTTPComment(content);
+ builds.add(this.getMyBuildTag(buildKey));
+ content += " " + String.format(CONTENT_PART_TEMPLATE, StringUtils.join(builds, " "));
+ logger.log(Level.INFO, "Post comment: {0} with original content {1}", new Object[]{ content, this.client.postPullRequestComment(pullRequestId, content).getId() });
+ }
+
+ private boolean processTTPCommentBuildTags(String content, String buildKey) {
+ if (!this.isTTPCommentBuildTags(content)) return true;
+ logger.log(Level.INFO, "Processing ttp with build comment: {0}", content);
+ return !this.hasMyBuildTagInTTPComment(content, buildKey);
+ }
+
+ private boolean isTTPComment(String content) {
+ return content.toLowerCase().contains(BUILD_REQUEST_MARKER.toLowerCase());
+ }
+
+ private boolean isTTPCommentBuildTags(String content) {
+ return content.toLowerCase().contains(BUILD_REQUEST_DONE_MARKER.toLowerCase());
+ }
+
+ public List<Pullrequest.Comment> filterPullRequestComments(List<Pullrequest.Comment> comments) {
+ logger.info("Filter PullRequest Comments.");
+ Collections.sort(comments);
+ Collections.reverse(comments);
+ List<Pullrequest.Comment> filteredComments = new LinkedList<Pullrequest.Comment>();
+ for(Pullrequest.Comment comment : comments) {
+ String content = comment.getContent();
+ if (content == null || content.isEmpty()) continue;
+ boolean isTTP = this.isTTPComment(content);
+ boolean isTTPBuild = this.isTTPCommentBuildTags(content);
+ if (isTTP || isTTPBuild) filteredComments.add(comment);
+ if (isTTP) break;
+ }
+ return filteredComments;
}
private boolean isBuildTarget(Pullrequest pullRequest) {
@@ -121,41 +189,40 @@ public class BitbucketRepository {
String repositoryName = destination.getRepository().getRepositoryName();
Pullrequest.Repository sourceRepository = source.getRepository();
+ String buildKeyPart = this.builder.getProjectId();
- boolean commitAlreadyBeenProcessed = this.client.hasBuildStatus(
- sourceRepository.getOwnerName(), sourceRepository.getRepositoryName(), sourceCommit, this.builder.getProjectId()
+ final boolean commitAlreadyBeenProcessed = this.client.hasBuildStatus(
+ sourceRepository.getOwnerName(), sourceRepository.getRepositoryName(), sourceCommit, buildKeyPart
);
if (commitAlreadyBeenProcessed) logger.log(Level.INFO,
"Commit {0}#{1} has already been processed",
- new Object[]{ sourceCommit, this.builder.getProjectId() }
+ new Object[]{ sourceCommit, buildKeyPart }
);
- String id = pullRequest.getId();
+ final String id = pullRequest.getId();
List<Pullrequest.Comment> comments = client.getPullRequestComments(owner, repositoryName, id);
boolean rebuildCommentAvailable = false;
if (comments != null) {
- Collections.sort(comments);
- Collections.reverse(comments);
- for (Pullrequest.Comment comment : comments) {
+ Collection<Pullrequest.Comment> filteredComments = this.filterPullRequestComments(comments);
+ for (Pullrequest.Comment comment : filteredComments) {
String content = comment.getContent();
- if (content == null || content.isEmpty()) {
- continue;
- }
-
- if (content.contains(BUILD_REQUEST_MARKER.toLowerCase())) {
+ if (this.isTTPComment(content)) {
rebuildCommentAvailable = true;
logger.log(Level.INFO,
"Rebuild comment available for commit {0} and comment #{1}",
new Object[]{ sourceCommit, comment.getId() }
- );
- this.client.deleteComment(id, Integer.toString(comment.getId()));
- }
+ );
+ }
+ rebuildCommentAvailable &= this.processTTPCommentBuildTags(content, buildKeyPart);
+ if (!rebuildCommentAvailable) break;
}
- }
+ }
+ if (rebuildCommentAvailable) this.postBuildTagInTTPComment(id, "TTP build flag", buildKeyPart);
- logger.log(Level.INFO, "Build target? {0}", rebuildCommentAvailable || !commitAlreadyBeenProcessed);
- return rebuildCommentAvailable || !commitAlreadyBeenProcessed;
+ final boolean canBuildTarget = rebuildCommentAvailable || !commitAlreadyBeenProcessed;
+ logger.log(Level.INFO, "Build target? {0} [rebuild:{1} processed:{2}]", new Object[]{ canBuildTarget, rebuildCommentAvailable, commitAlreadyBeenProcessed});
+ return canBuildTarget;
}
return false;
@@ -188,9 +255,15 @@ public class BitbucketRepository {
pullRequest.getDestination().getCommit().getHash()
);
+ //@FIXME: Way to iterate over all available SCMSources
+ List<SCMSource> sources = new LinkedList<SCMSource>();
+ for(SCMSourceOwner owner : SCMSourceOwners.all())
+ for(SCMSource src : owner.getSCMSources())
+ sources.add(src);
+
BitbucketBuildFilter filter = !this.trigger.getBranchesFilterBySCMIncludes() ?
BitbucketBuildFilter.InstanceByString(this.trigger.getBranchesFilter()) :
- BitbucketBuildFilter.InstanceBySCM(Jenkins.getInstance().getExtensionList(SCMSource.class), this.trigger.getBranchesFilter());
+ BitbucketBuildFilter.InstanceBySCM(sources, this.trigger.getBranchesFilter());
return filter.approved(cause);
}
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
index 18ca86f..e635f65 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
@@ -16,6 +16,9 @@ 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;
/**
* Created by nishio
@@ -56,15 +59,27 @@ public class ApiClient {
}
return Collections.EMPTY_LIST;
}
+
+ public String getName() {
+ return this.name;
+ }
+
+ private String computeAPIKey(String keyExPart) {
+ return String.format(COMPUTED_KEY_FORMAT, this.key, keyExPart);
+ }
+
+ public String buildStatusKey(String bsKey) {
+ return this.computeAPIKey(bsKey);
+ }
public boolean hasBuildStatus(String owner, String repositoryName, String revision, String keyEx) {
- String url = v2(owner, repositoryName, "/commit/" + revision + "/statuses/build/" + String.format(COMPUTED_KEY_FORMAT, this.key, keyEx));
+ String url = v2(owner, repositoryName, "/commit/" + revision + "/statuses/build/" + this.computeAPIKey(keyEx));
return get(url).contains("\"state\"");
}
public void setBuildStatus(String owner, String repositoryName, String revision, BuildState state, String buildUrl, String comment, String keyEx) {
String url = v2(owner, repositoryName, "/commit/" + revision + "/statuses/build");
- String computedKey = String.format(COMPUTED_KEY_FORMAT, this.key, keyEx);
+ String computedKey = this.computeAPIKey(keyEx);
NameValuePair[] data = new NameValuePair[]{
new NameValuePair("description", comment),
new NameValuePair("key", computedKey),
@@ -81,8 +96,15 @@ public class ApiClient {
delete(v2("/pullrequests/" + pullRequestId + "/approve"));
}
- public void deleteComment(String pullRequestId, String commentId) {
- delete(v1("/pullrequests/" + pullRequestId + "/comments/" + commentId + "/"));
+ public void deletePullRequestComment(String pullRequestId, String commentId) {
+ delete(v1("/pullrequests/" + pullRequestId + "/comments/" + commentId));
+ }
+
+ public void updatePullRequestComment(String pullRequestId, String content, String commentId) {
+ NameValuePair[] data = new NameValuePair[] {
+ new NameValuePair("content", content),
+ };
+ put(v1("/pullrequests/" + pullRequestId + "/comments/" + commentId), data);
}
public Pullrequest.Participant postPullRequestApproval(String pullRequestId) {
@@ -94,6 +116,19 @@ public class ApiClient {
}
return null;
}
+
+ public Pullrequest.Comment postPullRequestComment(String pullRequestId, String content) {
+ NameValuePair[] data = new NameValuePair[] {
+ new NameValuePair("content", content),
+ };
+ try {
+ return parse(post(v1("/pullrequests/" + pullRequestId + "/comments"), data), new TypeReference<Pullrequest.Comment>() {});
+ } catch(Exception e) {
+ logger.log(Level.WARNING, "Invalid pull request comment response.", e);
+ e.printStackTrace();
+ }
+ return null;
+ }
private HttpClient getHttpClient() {
HttpClient client = new HttpClient();
@@ -142,6 +177,13 @@ public class ApiClient {
private void delete(String path) {
send(new DeleteMethod(path));
}
+
+ private void put(String path, NameValuePair[] data) {
+ PutMethod req = new PutMethod(path);
+ req.setRequestBody(EncodingUtil.formUrlEncode(data, "utf-8"));
+ req.getParams().setContentCharset("utf-8");
+ send(req);
+ }
private String send(HttpMethodBase req) {
HttpClient client = getHttpClient();