aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/bitbucketpullrequestbuilder
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/bitbucketpullrequestbuilder')
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildListener.java48
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java161
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuilds.java25
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketPullRequestsBuilder.java11
-rw-r--r--src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java7
5 files changed, 162 insertions, 90 deletions
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildListener.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildListener.java
index 95931ad..9e067e7 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildListener.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildListener.java
@@ -2,8 +2,12 @@ package bitbucketpullrequestbuilder.bitbucketpullrequestbuilder;
import hudson.Extension;
import hudson.model.AbstractBuild;
+import hudson.model.Job;
+import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.model.listeners.RunListener;
+import hudson.triggers.Trigger;
+import jenkins.model.ParameterizedJobMixIn;
import javax.annotation.Nonnull;
import java.util.logging.Logger;
@@ -12,25 +16,43 @@ import java.util.logging.Logger;
* Created by nishio
*/
@Extension
-public class BitbucketBuildListener extends RunListener<AbstractBuild> {
- private static final Logger logger = Logger.getLogger(BitbucketBuildTrigger.class.getName());
+public class BitbucketBuildListener extends RunListener<Run<?, ?>> {
+ private static final Logger logger = Logger.getLogger(BitbucketBuildListener.class.getName());
@Override
- public void onStarted(AbstractBuild abstractBuild, TaskListener listener) {
- logger.info("BuildListener onStarted called.");
- BitbucketBuildTrigger trigger = BitbucketBuildTrigger.getTrigger(abstractBuild.getProject());
- if (trigger == null) {
- return;
+ public void onStarted(Run r, TaskListener listener) {
+ logger.info("BitbucketBuildListener onStarted called.");
+ BitbucketBuilds builds = builds(r);
+ if (builds != null) {
+ builds.onStarted((BitbucketCause) r.getCause(BitbucketCause.class), r);
}
- trigger.getBuilder().getBuilds().onStarted(abstractBuild);
}
@Override
- public void onCompleted(AbstractBuild abstractBuild, @Nonnull TaskListener listener) {
- BitbucketBuildTrigger trigger = BitbucketBuildTrigger.getTrigger(abstractBuild.getProject());
- if (trigger == null) {
- return;
+ public void onCompleted(Run r, @Nonnull TaskListener listener) {
+ logger.info("BitbucketBuildListener onCompleted called.");
+ BitbucketBuilds builds = builds(r);
+ if (builds != null) {
+ builds.onCompleted((BitbucketCause) r.getCause(BitbucketCause.class), r.getResult(), r.getUrl());
}
- trigger.getBuilder().getBuilds().onCompleted(abstractBuild);
}
+
+ private BitbucketBuilds builds(Run<?, ?> r) {
+ BitbucketBuildTrigger trigger = null;
+ if (r instanceof AbstractBuild) {
+ trigger = BitbucketBuildTrigger.getTrigger(((AbstractBuild) r).getProject());
+ } else {
+ Job job = r.getParent();
+ if (job instanceof ParameterizedJobMixIn.ParameterizedJob) {
+
+ for (Trigger<?> t : ((ParameterizedJobMixIn.ParameterizedJob) job).getTriggers().values()) {
+ if (t instanceof BitbucketBuildTrigger) {
+ trigger = (BitbucketBuildTrigger) t;
+ }
+ }
+ }
+ }
+ return trigger == null ? null : trigger.getBuilder().getBuilds();
+ }
+
}
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java
index 81b5603..34e12b2 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuildTrigger.java
@@ -7,27 +7,34 @@ 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 jenkins.model.ParameterizedJobMixIn;
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;
/**
* Created by nishio
*/
-public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
+public class BitbucketBuildTrigger extends Trigger<Job<?, ?>> {
private static final Logger logger = Logger.getLogger(BitbucketBuildTrigger.class.getName());
private final String projectPath;
private final String cron;
@@ -43,6 +50,7 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
private final String ciSkipPhrases;
private final boolean checkDestinationCommit;
private final boolean approveIfSuccess;
+ private final boolean cancelOutdatedJobs;
private final String commentTrigger;
transient private BitbucketPullRequestsBuilder bitbucketPullRequestsBuilder;
@@ -52,38 +60,40 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
@DataBoundConstructor
public BitbucketBuildTrigger(
- String projectPath,
- String cron,
- String credentialsId,
- String username,
- String password,
- String repositoryOwner,
- String repositoryName,
- String branchesFilter,
- boolean branchesFilterBySCMIncludes,
- String ciKey,
- String ciName,
- String ciSkipPhrases,
- boolean checkDestinationCommit,
- boolean approveIfSuccess,
- String commentTrigger
- ) throws ANTLRException {
- super(cron);
- this.projectPath = projectPath;
- this.cron = cron;
- this.credentialsId = credentialsId;
- this.username = username;
- this.password = password;
- this.repositoryOwner = repositoryOwner;
- this.repositoryName = repositoryName;
- this.branchesFilter = branchesFilter;
- this.branchesFilterBySCMIncludes = branchesFilterBySCMIncludes;
- this.ciKey = ciKey;
- this.ciName = ciName;
- this.ciSkipPhrases = ciSkipPhrases;
- this.checkDestinationCommit = checkDestinationCommit;
- this.approveIfSuccess = approveIfSuccess;
- this.commentTrigger = commentTrigger;
+ String projectPath,
+ String cron,
+ String credentialsId,
+ String username,
+ String password,
+ String repositoryOwner,
+ String repositoryName,
+ String branchesFilter,
+ boolean branchesFilterBySCMIncludes,
+ String ciKey,
+ String ciName,
+ String ciSkipPhrases,
+ boolean checkDestinationCommit,
+ boolean approveIfSuccess,
+ boolean cancelOutdatedJobs,
+ String commentTrigger
+ ) throws ANTLRException {
+ super(cron);
+ this.projectPath = projectPath;
+ this.cron = cron;
+ this.credentialsId = credentialsId;
+ this.username = username;
+ this.password = password;
+ this.repositoryOwner = repositoryOwner;
+ this.repositoryName = repositoryName;
+ this.branchesFilter = branchesFilter;
+ this.branchesFilterBySCMIncludes = branchesFilterBySCMIncludes;
+ this.ciKey = ciKey;
+ this.ciName = ciName;
+ this.ciSkipPhrases = ciSkipPhrases;
+ this.checkDestinationCommit = checkDestinationCommit;
+ this.approveIfSuccess = approveIfSuccess;
+ this.cancelOutdatedJobs = cancelOutdatedJobs;
+ this.commentTrigger = commentTrigger;
}
public String getProjectPath() {
@@ -139,17 +149,21 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
}
public boolean getApproveIfSuccess() {
- return approveIfSuccess;
+ return approveIfSuccess;
+ }
+
+ public boolean getCancelOutdatedJobs() {
+ return cancelOutdatedJobs;
}
/**
* @return a phrase that when entered in a comment will trigger a new build
*/
public String getCommentTrigger() {
- return commentTrigger;
+ return commentTrigger;
}
@Override
- public void start(AbstractProject<?, ?> project, boolean newInstance) {
+ public void start(Job<?, ?> project, boolean newInstance) {
try {
this.bitbucketPullRequestsBuilder = BitbucketPullRequestsBuilder.getBuilder();
this.bitbucketPullRequestsBuilder.setProject(project);
@@ -171,9 +185,67 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
return this.bitbucketPullRequestsBuilder;
}
+ private ParameterizedJobMixIn retrieveScheduleJob(final Job<?, ?> job) {
+ // TODO 1.621+ use standard method
+ return new ParameterizedJobMixIn() {
+ @Override
+ protected Job asJob() {
+ return job;
+ }
+ };
+ }
+
public QueueTaskFuture<?> startJob(BitbucketCause cause) {
Map<String, ParameterValue> values = this.getDefaultParameters();
- return this.job.scheduleBuild2(0, cause, new ParametersAction(new ArrayList(values.values())), new RevisionParameterAction(cause.getSourceCommitHash()));
+
+ if (getCancelOutdatedJobs()) {
+ cancelPreviousJobsInQueueThatMatch(cause);
+ abortRunningJobsThatMatch(cause);
+ }
+
+ return retrieveScheduleJob(this.job).scheduleBuild2(0,
+ new CauseAction(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() {
@@ -190,12 +262,13 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
@Override
public void run() {
- if(this.getBuilder().getProject().isDisabled()) {
- logger.info("Build Skip.");
- } else {
- this.bitbucketPullRequestsBuilder.run();
- }
- this.getDescriptor().save();
+ Job<?,?> project = this.getBuilder().getProject();
+ if (project instanceof AbstractProject && ((AbstractProject)project).isDisabled()) {
+ logger.info("Build Skip.");
+ } else {
+ this.bitbucketPullRequestsBuilder.run();
+ this.getDescriptor().save();
+ }
}
@Override
@@ -210,7 +283,7 @@ public class BitbucketBuildTrigger extends Trigger<AbstractProject<?, ?>> {
@Override
public boolean isApplicable(Item item) {
- return true;
+ return item instanceof Job && item instanceof ParameterizedJobMixIn.ParameterizedJob;
}
@Override
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuilds.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuilds.java
index ea8e892..216287d 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuilds.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketBuilds.java
@@ -1,10 +1,7 @@
package bitbucketpullrequestbuilder.bitbucketpullrequestbuilder;
import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.BuildState;
-import hudson.model.AbstractBuild;
-import hudson.model.Cause;
-import hudson.model.Result;
-import jenkins.model.Jenkins;
+import hudson.model.*;
import jenkins.model.JenkinsLocationConfiguration;
import java.io.IOException;
@@ -24,16 +21,7 @@ public class BitbucketBuilds {
this.repository = repository;
}
- public BitbucketCause getCause(AbstractBuild build) {
- Cause cause = build.getCause(BitbucketCause.class);
- if (cause == null || !(cause instanceof BitbucketCause)) {
- return null;
- }
- return (BitbucketCause) cause;
- }
-
- public void onStarted(AbstractBuild build) {
- BitbucketCause cause = this.getCause(build);
+ void onStarted(BitbucketCause cause, Run<?, ?> build) {
if (cause == null) {
return;
}
@@ -44,24 +32,21 @@ public class BitbucketBuilds {
}
}
- public void onCompleted(AbstractBuild build) {
- BitbucketCause cause = this.getCause(build);
+ void onCompleted(BitbucketCause cause, Result result, String buildUrl) {
if (cause == null) {
return;
}
- Result result = build.getResult();
JenkinsLocationConfiguration globalConfig = new JenkinsLocationConfiguration();
String rootUrl = globalConfig.getUrl();
- String buildUrl = "";
if (rootUrl == null) {
logger.warning("PLEASE SET JENKINS ROOT URL IN GLOBAL CONFIGURATION FOR BUILD STATE REPORTING");
} else {
- buildUrl = rootUrl + build.getUrl();
+ buildUrl = rootUrl + buildUrl;
BuildState state = result == Result.SUCCESS ? BuildState.SUCCESSFUL : BuildState.FAILED;
repository.setBuildStatus(cause, state, buildUrl);
}
- if ( this.trigger.getApproveIfSuccess() && result == Result.SUCCESS ) {
+ if (this.trigger.getApproveIfSuccess() && result == Result.SUCCESS) {
this.repository.postPullRequestApproval(cause.getPullRequestId());
}
}
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketPullRequestsBuilder.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketPullRequestsBuilder.java
index d337796..42fe562 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketPullRequestsBuilder.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/BitbucketPullRequestsBuilder.java
@@ -1,7 +1,6 @@
package bitbucketpullrequestbuilder.bitbucketpullrequestbuilder;
import bitbucketpullrequestbuilder.bitbucketpullrequestbuilder.bitbucket.Pullrequest;
-import hudson.model.AbstractProject;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
@@ -11,6 +10,7 @@ import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
+import hudson.model.Job;
import org.apache.commons.codec.binary.Hex;
/**
@@ -18,7 +18,7 @@ import org.apache.commons.codec.binary.Hex;
*/
public class BitbucketPullRequestsBuilder {
private static final Logger logger = Logger.getLogger(BitbucketBuildTrigger.class.getName());
- private AbstractProject<?, ?> project;
+ private Job<?, ?> project;
private BitbucketBuildTrigger trigger;
private BitbucketRepository repository;
private BitbucketBuilds builds;
@@ -47,7 +47,7 @@ public class BitbucketPullRequestsBuilder {
return this;
}
- public void setProject(AbstractProject<?, ?> project) {
+ public void setProject(Job<?, ?> project) {
this.project = project;
}
@@ -55,7 +55,7 @@ public class BitbucketPullRequestsBuilder {
this.trigger = trigger;
}
- public AbstractProject<?, ?> getProject() {
+ public Job<?, ?> getProject() {
return this.project;
}
@@ -69,12 +69,11 @@ public class BitbucketPullRequestsBuilder {
return new String(Hex.encodeHex(MD5.digest(this.project.getFullName().getBytes("UTF-8"))));
} 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();
+
}
public BitbucketBuildTrigger getTrigger() {
diff --git a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
index 759c696..0c87478 100644
--- a/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
+++ b/src/main/java/bitbucketpullrequestbuilder/bitbucketpullrequestbuilder/bitbucket/ApiClient.java
@@ -119,10 +119,8 @@ public class ApiClient {
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);
@@ -173,7 +171,6 @@ public class ApiClient {
new NameValuePair[]{}), Pullrequest.Participant.class);
} catch (IOException e) {
logger.log(Level.WARNING, "Invalid pull request approval response.", e);
- e.printStackTrace();
}
return null;
}
@@ -186,7 +183,6 @@ public class ApiClient {
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;
}
@@ -203,7 +199,6 @@ public class ApiClient {
} while (url != null);
} catch (Exception e) {
logger.log(Level.WARNING, "invalid response.", e);
- e.printStackTrace();
}
return values;
}
@@ -255,10 +250,8 @@ public class ApiClient {
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();
} finally {
req.releaseConnection();
}