aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOlivier Bellemare <bitbucket@xob.ca>2016-10-27 10:49:17 -0400
committerOlivier Bellemare <bitbucket@xob.ca>2016-10-27 10:49:17 -0400
commita6374a41b6ad80ca586a606823f6b22f5c5c4193 (patch)
tree69e1a234ca3bb1cf2ef4071fc5315bc1f6b506fa /src
parent37d5d42e056d5faff0bbed119115a4cbe7c4e016 (diff)
downloadbbprb-a6374a41b6ad80ca586a606823f6b22f5c5c4193.tar.gz
Add option to cancel outdated builds when a pull request is updated
Diffstat (limited to 'src')
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java64
-rw-r--r--src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/config.jelly3
-rw-r--r--src/test/java/BitbucketBuildRepositoryTest.java12
3 files changed, 72 insertions, 7 deletions
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java
index aedfb91..90de6b5 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java
@@ -7,20 +7,26 @@ import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredenti
import com.cloudbees.plugins.credentials.common.UsernamePasswordCredentials;
import hudson.Extension;
import hudson.model.*;
+import hudson.model.Queue;
import hudson.model.queue.QueueTaskFuture;
import hudson.plugins.git.RevisionParameterAction;
import hudson.triggers.Trigger;
import hudson.triggers.TriggerDescriptor;
import hudson.util.ListBoxModel;
+import jenkins.model.Jenkins;
import net.sf.json.JSONObject;
+import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import static com.cloudbees.plugins.credentials.CredentialsMatchers.instanceOf;
@@ -43,11 +49,12 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
private final String ciSkipPhrases;
private final boolean checkDestinationCommit;
private final boolean approveIfSuccess;
+ private final boolean cancelOutdatedJobs;
transient private BitbucketPullRequestsBuilder bitbucketPullRequestsBuilder;
@Extension
- public static final BitbucketBuildTriggerDescriptor descriptor = new BitbucketBuildTriggerDescriptor();
+ public static final BitbucketBuildTriggerDescriptor descriptor = new BitbucketBuildTriggerDescriptor();
@DataBoundConstructor
public BitbucketBuildTrigger(
@@ -64,7 +71,8 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
String ciName,
String ciSkipPhrases,
boolean checkDestinationCommit,
- boolean approveIfSuccess
+ boolean approveIfSuccess,
+ boolean cancelOutdatedJobs
) throws ANTLRException {
super(cron);
this.projectPath = projectPath;
@@ -81,6 +89,7 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
this.ciSkipPhrases = ciSkipPhrases;
this.checkDestinationCommit = checkDestinationCommit;
this.approveIfSuccess = approveIfSuccess;
+ this.cancelOutdatedJobs = cancelOutdatedJobs;
}
public String getProjectPath() {
@@ -114,7 +123,7 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
public String getBranchesFilter() {
return branchesFilter;
}
-
+
public boolean getBranchesFilterBySCMIncludes() {
return branchesFilterBySCMIncludes;
}
@@ -139,6 +148,10 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
return approveIfSuccess;
}
+ public boolean getCancelOutdatedJobs() {
+ return cancelOutdatedJobs;
+ }
+
@Override
public void start(AbstractProject<?, ?> project, boolean newInstance) {
try {
@@ -164,9 +177,54 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
public QueueTaskFuture<?> startJob(BitbucketCause cause) {
Map<String, ParameterValue> values = this.getDefaultParameters();
+
+ if (getCancelOutdatedJobs()) {
+ cancelPreviousJobsInQueueThatMatch(cause);
+ abortRunningJobsThatMatch(cause);
+ }
+
return this.job.scheduleBuild2(0, cause, new ParametersAction(new ArrayList(values.values())), new RevisionParameterAction(cause.getSourceCommitHash()));
}
+ private void cancelPreviousJobsInQueueThatMatch(@Nonnull BitbucketCause bitbucketCause) {
+ logger.fine("Looking for queued jobs that match PR ID: " + bitbucketCause.getPullRequestId());
+ Queue queue = Jenkins.getInstance().getQueue();
+ for (Queue.Item item : queue.getItems()) {
+ if (hasCauseFromTheSamePullRequest(item.getCauses(), bitbucketCause)) {
+ logger.info("Canceling item in queue: " + item);
+ queue.cancel(item);
+ }
+ }
+ }
+
+ private void abortRunningJobsThatMatch(@Nonnull BitbucketCause bitbucketCause) {
+ logger.fine("Looking for running jobs that match PR ID: " + bitbucketCause.getPullRequestId());
+ for (Object o : job.getBuilds()) {
+ if (o instanceof Build) {
+ Build build = (Build) o;
+ if (build.isBuilding() && hasCauseFromTheSamePullRequest(build.getCauses(), bitbucketCause)) {
+ logger.info("Aborting build: " + build + " since PR is outdated");
+ build.getExecutor().interrupt(Result.ABORTED);
+ }
+ }
+ }
+ }
+
+ private boolean hasCauseFromTheSamePullRequest(@Nullable List<Cause> causes, @Nullable BitbucketCause pullRequestCause) {
+ if (causes != null && pullRequestCause != null) {
+ for (Cause cause : causes) {
+ if (cause instanceof BitbucketCause) {
+ BitbucketCause sc = (BitbucketCause) cause;
+ if (StringUtils.equals(sc.getPullRequestId(), pullRequestCause.getPullRequestId()) &&
+ StringUtils.equals(sc.getRepositoryName(), pullRequestCause.getRepositoryName())) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
private Map<String, ParameterValue> getDefaultParameters() {
Map<String, ParameterValue> values = new HashMap<String, ParameterValue>();
ParametersDefinitionProperty definitionProperty = this.job.getProperty(ParametersDefinitionProperty.class);
diff --git a/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/config.jelly b/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/config.jelly
index d4b23da..971954f 100644
--- a/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/config.jelly
+++ b/src/main/resources/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger/config.jelly
@@ -38,4 +38,7 @@
<f:entry title="Approve if build success?" field="approveIfSuccess">
<f:checkbox />
</f:entry>
+ <f:entry title="Cancel outdated jobs?" field="cancelOutdatedJobs">
+ <f:checkbox default="false"/>
+ </f:entry>
</j:jelly>
diff --git a/src/test/java/BitbucketBuildRepositoryTest.java b/src/test/java/BitbucketBuildRepositoryTest.java
index 953bd81..148e504 100644
--- a/src/test/java/BitbucketBuildRepositoryTest.java
+++ b/src/test/java/BitbucketBuildRepositoryTest.java
@@ -118,7 +118,8 @@ public class BitbucketBuildRepositoryTest {
"", true,
"", "", "",
true,
- true
+ true,
+ false
);
BitbucketPullRequestsBuilder builder = EasyMock.createMock(BitbucketPullRequestsBuilder.class);
@@ -148,7 +149,8 @@ public class BitbucketBuildRepositoryTest {
"", true,
"", "", "",
true,
- true
+ true,
+ false
);
BitbucketPullRequestsBuilder builder = EasyMock.createMock(BitbucketPullRequestsBuilder.class);
@@ -202,7 +204,8 @@ public class BitbucketBuildRepositoryTest {
"", true,
"jenkins", "Jenkins", "",
true,
- true
+ true,
+ false
);
BitbucketPullRequestsBuilder builder = EasyMock.createMock(BitbucketPullRequestsBuilder.class);
@@ -248,7 +251,8 @@ public class BitbucketBuildRepositoryTest {
"", true,
"jenkins-too-long-ci-key", "Jenkins", "",
true,
- true
+ true,
+ false
);
final MessageDigest MD5 = MessageDigest.getInstance("MD5");