aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBjörn Dahlgren <bjorn@dahlgren.at>2015-11-26 17:27:10 +0100
committerBjörn Dahlgren <bjorn@dahlgren.at>2015-12-07 02:31:34 +0100
commit620a2215e275e124836327ba1e6a153d07615af2 (patch)
tree1354f73ce87bf6061a647eb58f5ed60308dfe1d6 /src
parentd002e0b758c1907c2d4963a2b9e556177e05ab03 (diff)
downloadbbprb-620a2215e275e124836327ba1e6a153d07615af2.tar.gz
Use new Build Status instead of commenting on pull requests
News: http://blog.bitbucket.org/2015/11/18/introducing-the-build-status-api-for-bitbucket-cloud/ API: https://confluence.atlassian.com/bitbucket/buildstatus-resource-779295267.html
Diffstat (limited to 'src')
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java14
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuilds.java11
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketCause.java7
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java109
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java48
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/BuildState.java10
-rw-r--r--src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/config.jelly6
-rw-r--r--src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/help-ciKey.html4
-rw-r--r--src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/help-ciName.html1
9 files changed, 102 insertions, 108 deletions
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java
index 879facb..247bd67 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java
@@ -28,6 +28,8 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
private final String password;
private final String repositoryOwner;
private final String repositoryName;
+ private final String ciKey;
+ private final String ciName;
private final String ciSkipPhrases;
private final boolean checkDestinationCommit;
private final boolean approveIfSuccess;
@@ -45,6 +47,8 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
String password,
String repositoryOwner,
String repositoryName,
+ String ciKey,
+ String ciName,
String ciSkipPhrases,
boolean checkDestinationCommit,
boolean approveIfSuccess
@@ -56,6 +60,8 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
this.password = password;
this.repositoryOwner = repositoryOwner;
this.repositoryName = repositoryName;
+ this.ciKey = ciKey;
+ this.ciName = ciName;
this.ciSkipPhrases = ciSkipPhrases;
this.checkDestinationCommit = checkDestinationCommit;
this.approveIfSuccess = approveIfSuccess;
@@ -85,6 +91,14 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
return repositoryName;
}
+ public String getCiKey() {
+ return ciKey;
+ }
+
+ public String getCiName() {
+ return ciName;
+ }
+
public String getCiSkipPhrases() {
return ciSkipPhrases;
}
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuilds.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuilds.java
index 45e1873..3e8e84b 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuilds.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuilds.java
@@ -1,5 +1,6 @@
package bitbucketpullrequestbuilder.bitbucketpullrequestbuilder;
+import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.BuildState;
import hudson.model.AbstractBuild;
import hudson.model.Cause;
import hudson.model.Result;
@@ -51,13 +52,13 @@ public class BitbucketBuilds {
String rootUrl = Jenkins.getInstance().getRootUrl();
String buildUrl = "";
if (rootUrl == null) {
- buildUrl = " PLEASE SET JENKINS ROOT URL FROM GLOBAL CONFIGURATION " + build.getUrl();
- }
- else {
+ logger.warning("PLEASE SET JENKINS ROOT URL IN GLOBAL CONFIGURATION FOR BUILD STATE REPORTING");
+ } else {
buildUrl = rootUrl + build.getUrl();
+ BuildState state = result == Result.SUCCESS ? BuildState.SUCCESSFUL : BuildState.FAILED;
+ repository.setBuildStatus(cause, state, buildUrl);
}
- repository.deletePullRequestComment(cause.getPullRequestId(), cause.getBuildStartCommentId());
- repository.postFinishedComment(cause.getPullRequestId(), cause.getSourceCommitHash(), cause.getDestinationCommitHash(), result == Result.SUCCESS, buildUrl);
+
if ( this.trigger.getApproveIfSuccess() && result == Result.SUCCESS ) {
this.repository.postPullRequestApproval(cause.getPullRequestId());
}
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketCause.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketCause.java
index 01e6cd1..e233371 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketCause.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketCause.java
@@ -16,7 +16,6 @@ public class BitbucketCause extends Cause {
private final String pullRequestTitle;
private final String sourceCommitHash;
private final String destinationCommitHash;
- private final String buildStartCommentId;
public static final String BITBUCKET_URL = "https://bitbucket.org/";
public BitbucketCause(String sourceBranch,
@@ -28,8 +27,7 @@ public class BitbucketCause extends Cause {
String destinationRepositoryName,
String pullRequestTitle,
String sourceCommitHash,
- String destinationCommitHash,
- String buildStartCommentId) {
+ String destinationCommitHash) {
this.sourceBranch = sourceBranch;
this.targetBranch = targetBranch;
this.repositoryOwner = repositoryOwner;
@@ -40,7 +38,6 @@ public class BitbucketCause extends Cause {
this.pullRequestTitle = pullRequestTitle;
this.sourceCommitHash = sourceCommitHash;
this.destinationCommitHash = destinationCommitHash;
- this.buildStartCommentId = buildStartCommentId;
}
public String getSourceBranch() {
@@ -79,8 +76,6 @@ public class BitbucketCause extends Cause {
public String getDestinationCommitHash() { return destinationCommitHash; }
- public String getBuildStartCommentId() { return buildStartCommentId; }
-
@Override
public String getShortDescription() {
String description = "<a href=\"" + BITBUCKET_URL + this.getDestinationRepositoryOwner() + "/";
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
index bdf5d7c..dd0f5e5 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketRepository.java
@@ -5,28 +5,20 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.ApiClient;
+import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.BuildState;
import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.Pullrequest;
+import jenkins.model.Jenkins;
/**
* Created by nishio
*/
public class BitbucketRepository {
private static final Logger logger = Logger.getLogger(BitbucketRepository.class.getName());
- public static final String BUILD_START_MARKER = "[*BuildStarted* **%s**] %s into %s";
- public static final String BUILD_FINISH_MARKER = "[*BuildFinished* **%s**] %s into %s";
+ private static final String BUILD_DESCRIPTION = "%s: %s into %s";
+ private static final String BUILD_REQUEST_MARKER = "test this please";
- public static final String BUILD_START_REGEX = "\\[\\*BuildStarted\\* \\*\\*%s\\*\\*\\] ([0-9a-fA-F]+) into ([0-9a-fA-F]+)";
- public static final String BUILD_FINISH_REGEX = "\\[\\*BuildFinished\\* \\*\\*%s\\*\\*\\] ([0-9a-fA-F]+) into ([0-9a-fA-F]+)";
-
- public static final String BUILD_FINISH_SENTENCE = BUILD_FINISH_MARKER + " \n\n **%s** - %s";
- public static final String BUILD_REQUEST_MARKER = "test this please";
-
- public static final String BUILD_SUCCESS_COMMENT = "SUCCESS";
- public static final String BUILD_FAILURE_COMMENT = "FAILURE";
private String projectPath;
private BitbucketPullRequestsBuilder builder;
private BitbucketBuildTrigger trigger;
@@ -43,7 +35,10 @@ public class BitbucketRepository {
trigger.getUsername(),
trigger.getPassword(),
trigger.getRepositoryOwner(),
- trigger.getRepositoryName());
+ trigger.getRepositoryName(),
+ trigger.getCiKey(),
+ trigger.getCiName()
+ );
}
public Collection<Pullrequest> getTargetPullRequests() {
@@ -58,17 +53,8 @@ public class BitbucketRepository {
return targetPullRequests;
}
- public String postBuildStartCommentTo(Pullrequest pullRequest) {
- String sourceCommit = pullRequest.getSource().getCommit().getHash();
- String destinationCommit = pullRequest.getDestination().getCommit().getHash();
- String comment = String.format(BUILD_START_MARKER, builder.getProject().getDisplayName(), sourceCommit, destinationCommit);
- Pullrequest.Comment commentResponse = this.client.postPullRequestComment(pullRequest.getId(), comment);
- return commentResponse.getId().toString();
- }
-
public void addFutureBuildTasks(Collection<Pullrequest> pullRequests) {
for(Pullrequest pullRequest : pullRequests) {
- String commentId = postBuildStartCommentTo(pullRequest);
if ( this.trigger.getApproveIfSuccess() ) {
deletePullRequestApproval(pullRequest.getId());
}
@@ -82,24 +68,26 @@ public class BitbucketRepository {
pullRequest.getDestination().getRepository().getRepositoryName(),
pullRequest.getTitle(),
pullRequest.getSource().getCommit().getHash(),
- pullRequest.getDestination().getCommit().getHash(),
- commentId);
+ pullRequest.getDestination().getCommit().getHash());
+ setBuildStatus(cause, BuildState.INPROGRESS, Jenkins.getInstance().getRootUrl());
this.builder.getTrigger().startJob(cause);
}
}
- public void deletePullRequestComment(String pullRequestId, String commentId) {
- this.client.deletePullRequestComment(pullRequestId,commentId);
- }
+ public void setBuildStatus(BitbucketCause cause, BuildState state, String buildUrl) {
+ String comment = null;
+ String sourceCommit = cause.getSourceCommitHash();
+ String owner = cause.getRepositoryOwner();
+ String repository = cause.getRepositoryName();
+ String destinationBranch = cause.getTargetBranch();
- public void postFinishedComment(String pullRequestId, String sourceCommit, String destinationCommit, boolean success, String buildUrl) {
- String message = BUILD_FAILURE_COMMENT;
- if (success){
- message = BUILD_SUCCESS_COMMENT;
+ logger.info("setBuildStatus " + state + " for commit: " + sourceCommit + " with url " + buildUrl);
+
+ if (state == BuildState.FAILED || state == BuildState.SUCCESSFUL) {
+ comment = String.format(BUILD_DESCRIPTION, builder.getProject().getDisplayName(), sourceCommit, destinationBranch);
}
- String comment = String.format(BUILD_FINISH_SENTENCE, builder.getProject().getDisplayName(), sourceCommit, destinationCommit, message, buildUrl);
- this.client.postPullRequestComment(pullRequestId, comment);
+ this.client.setBuildStatus(owner, repository, sourceCommit, state, buildUrl, comment);
}
public void deletePullRequestApproval(String pullRequestId) {
@@ -111,19 +99,16 @@ public class BitbucketRepository {
}
private boolean isBuildTarget(Pullrequest pullRequest) {
-
- boolean shouldBuild = true;
if (pullRequest.getState() != null && pullRequest.getState().equals("OPEN")) {
if (isSkipBuild(pullRequest.getTitle())) {
return false;
}
- String sourceCommit = pullRequest.getSource().getCommit().getHash();
-
+ Pullrequest.Revision source = pullRequest.getSource();
+ String sourceCommit = source.getCommit().getHash();
Pullrequest.Revision destination = pullRequest.getDestination();
String owner = destination.getRepository().getOwnerName();
String repositoryName = destination.getRepository().getRepositoryName();
- String destinationCommit = destination.getCommit().getHash();
String id = pullRequest.getId();
List<Pullrequest.Comment> comments = client.getPullRequestComments(owner, repositoryName, id);
@@ -137,47 +122,23 @@ public class BitbucketRepository {
continue;
}
- //These will match any start or finish message -- need to check commits
- String project_build_start = String.format(BUILD_START_REGEX, builder.getProject().getDisplayName());
- String project_build_finished = String.format(BUILD_FINISH_REGEX, builder.getProject().getDisplayName());
- Matcher startMatcher = Pattern.compile(project_build_start, Pattern.CASE_INSENSITIVE).matcher(content);
- Matcher finishMatcher = Pattern.compile(project_build_finished, Pattern.CASE_INSENSITIVE).matcher(content);
-
- if (startMatcher.find() ||
- finishMatcher.find()) {
-
- String sourceCommitMatch;
- String destinationCommitMatch;
-
- if (startMatcher.find(0)) {
- sourceCommitMatch = startMatcher.group(1);
- destinationCommitMatch = startMatcher.group(2);
- } else {
- sourceCommitMatch = finishMatcher.group(1);
- destinationCommitMatch = finishMatcher.group(2);
- }
-
- //first check source commit -- if it doesn't match, just move on. If it does, investigate further.
- if (sourceCommitMatch.equalsIgnoreCase(sourceCommit)) {
- // if we're checking destination commits, and if this doesn't match, then move on.
- if (this.trigger.getCheckDestinationCommit()
- && (!destinationCommitMatch.equalsIgnoreCase(destinationCommit))) {
- continue;
- }
-
- shouldBuild = false;
- break;
- }
- }
-
if (content.contains(BUILD_REQUEST_MARKER.toLowerCase())) {
- shouldBuild = true;
- break;
+ return true;
}
}
}
+
+ Pullrequest.Repository sourceRepository = source.getRepository();
+
+ if (this.client.hasBuildStatus(sourceRepository.getOwnerName(), sourceRepository.getRepositoryName(), sourceCommit)) {
+ logger.info("Commit " + sourceCommit + " has already been processed");
+ return false;
+ }
+
+ return true;
}
- return shouldBuild;
+
+ return false;
}
private boolean isSkipBuild(String pullRequestTitle) {
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
index 713a061..c8f1818 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
@@ -9,7 +9,6 @@ import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import java.io.IOException;
-import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
@@ -23,17 +22,20 @@ import hudson.ProxyConfiguration;
*/
public class ApiClient {
private static final Logger logger = Logger.getLogger(ApiClient.class.getName());
- private static final String BITBUCKET_HOST = "bitbucket.org";
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 String owner;
private String repositoryName;
private Credentials credentials;
+ private String key;
+ private String name;
- public ApiClient(String username, String password, String owner, String repositoryName) {
+ public ApiClient(String username, String password, String owner, String repositoryName, String key, String name) {
this.credentials = new UsernamePasswordCredentials(username, password);
this.owner = owner;
this.repositoryName = repositoryName;
+ this.key = key;
+ this.name = name;
}
public List<Pullrequest> getPullRequests() {
@@ -54,26 +56,22 @@ public class ApiClient {
return Collections.EMPTY_LIST;
}
- public void deletePullRequestComment(String pullRequestId, String commentId) {
- String path = V1_API_BASE_URL + this.owner + "/" + this.repositoryName + "/pullrequests/" + pullRequestId + "/comments/" + commentId;
- //https://bitbucket.org/api/1.0/repositories/{accountname}/{repo_slug}/pullrequests/{pull_request_id}/comments/{comment_id}
- delete(path);
+ public boolean hasBuildStatus(String owner, String repositoryName, String revision) {
+ String url = v2(owner, repositoryName, "/commit/" + revision + "/statuses/build/" + this.key);
+ return get(url).contains("\"state\"");
}
-
- public Pullrequest.Comment postPullRequestComment(String pullRequestId, String comment) {
- try {
- String response = post(
- v1("/pullrequests/" + pullRequestId + "/comments"),
- new NameValuePair[]{ new NameValuePair("content", comment) });
- return parse(response, Pullrequest.Comment.class);
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- return null;
+ public void setBuildStatus(String owner, String repositoryName, String revision, BuildState state, String buildUrl, String comment) {
+ String url = v2(owner, repositoryName, "/commit/" + revision + "/statuses/build");
+ NameValuePair[] data = new NameValuePair[]{
+ new NameValuePair("description", comment),
+ new NameValuePair("key", this.key),
+ new NameValuePair("name", this.name),
+ new NameValuePair("state", state.toString()),
+ new NameValuePair("url", buildUrl),
+ };
+ logger.info("POST state " + state + " to " + url);
+ post(url, data);
}
public void deletePullRequestApproval(String pullRequestId) {
@@ -115,8 +113,12 @@ public class ApiClient {
return V1_API_BASE_URL + this.owner + "/" + this.repositoryName + url;
}
- private String v2(String url) {
- return V2_API_BASE_URL + this.owner + "/" + this.repositoryName + url;
+ private String v2(String path) {
+ return v2(this.owner, this.repositoryName, path);
+ }
+
+ private String v2(String owner, String repositoryName, String path) {
+ return V2_API_BASE_URL + owner + "/" + repositoryName + path;
}
private String get(String path) {
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/BuildState.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/BuildState.java
new file mode 100644
index 0000000..e5c15ef
--- /dev/null
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/BuildState.java
@@ -0,0 +1,10 @@
+package bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket;
+
+/**
+ * Valid build states for a pull request
+ *
+ * @see https://confluence.atlassian.com/bitbucket/buildstatus-resource-779295267.html
+ */
+public enum BuildState {
+ FAILED, INPROGRESS, SUCCESSFUL
+}
diff --git a/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/config.jelly b/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/config.jelly
index 0eee781..82ab08c 100644
--- a/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/config.jelly
+++ b/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/config.jelly
@@ -14,6 +14,12 @@
<f:entry title="RepositoryName" field="repositoryName">
<f:textbox />
</f:entry>
+ <f:entry title="CI Identifier" field="ciKey">
+ <f:textbox default="jenkins" />
+ </f:entry>
+ <f:entry title="CI Name" field="ciName">
+ <f:textbox default="Jenkins" />
+ </f:entry>
<f:entry title="CI Skip Phrases" field="ciSkipPhrases">
<f:textbox />
</f:entry>
diff --git a/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/help-ciKey.html b/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/help-ciKey.html
new file mode 100644
index 0000000..97696b6
--- /dev/null
+++ b/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/help-ciKey.html
@@ -0,0 +1,4 @@
+The identifier needs to be unique among your Jenkins jobs related to this repo.
+This identifier is used to decide whether a commit is already built by this job and to set status for a newly built commit.
+If the value is changed rebuilds may occur and multiple statuses might show on an existing pull request.
+The value is not shown for end users of Bitbucket.
diff --git a/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/help-ciName.html b/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/help-ciName.html
new file mode 100644
index 0000000..32f248d
--- /dev/null
+++ b/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/help-ciName.html
@@ -0,0 +1 @@
+This value is the name of the current job when showing build statuses for a pull request.