Merge pull request #693 from ttsalonen/pending-build-status-for-pipelines
Pending status for pipelines and possibility to cancel pending builds on merge request updates
This commit is contained in:
commit
f73144fa9b
5
pom.xml
5
pom.xml
|
@ -162,6 +162,11 @@
|
|||
<artifactId>workflow-step-api</artifactId>
|
||||
<version>1.15</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||
<artifactId>workflow-job</artifactId>
|
||||
<version>1.15</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins</groupId>
|
||||
<artifactId>credentials</artifactId>
|
||||
|
|
|
@ -100,6 +100,8 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
|
|||
private String targetBranchRegex;
|
||||
private MergeRequestLabelFilterConfig mergeRequestLabelFilterConfig;
|
||||
private volatile Secret secretToken;
|
||||
private String pendingBuildName;
|
||||
private boolean cancelPendingBuildsOnUpdate;
|
||||
|
||||
private transient BranchFilter branchFilter;
|
||||
private transient PushHookTriggerHandler pushHookTriggerHandler;
|
||||
|
@ -120,8 +122,8 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
|
|||
boolean setBuildDescription, boolean addNoteOnMergeRequest, boolean addCiMessage, boolean addVoteOnMergeRequest,
|
||||
boolean acceptMergeRequestOnSuccess, BranchFilterType branchFilterType,
|
||||
String includeBranchesSpec, String excludeBranchesSpec, String targetBranchRegex,
|
||||
MergeRequestLabelFilterConfig mergeRequestLabelFilterConfig, String secretToken, boolean triggerOnPipelineEvent,
|
||||
boolean triggerOnApprovedMergeRequest) {
|
||||
MergeRequestLabelFilterConfig mergeRequestLabelFilterConfig, String secretToken, boolean triggerOnPipelineEvent,
|
||||
boolean triggerOnApprovedMergeRequest, String pendingBuildName, boolean cancelPendingBuildsOnUpdate) {
|
||||
this.triggerOnPush = triggerOnPush;
|
||||
this.triggerOnMergeRequest = triggerOnMergeRequest;
|
||||
this.triggerOnAcceptedMergeRequest = triggerOnAcceptedMergeRequest;
|
||||
|
@ -144,6 +146,8 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
|
|||
this.mergeRequestLabelFilterConfig = mergeRequestLabelFilterConfig;
|
||||
this.secretToken = Secret.fromString(secretToken);
|
||||
this.triggerOnApprovedMergeRequest = triggerOnApprovedMergeRequest;
|
||||
this.pendingBuildName = pendingBuildName;
|
||||
this.cancelPendingBuildsOnUpdate = cancelPendingBuildsOnUpdate;
|
||||
|
||||
initializeTriggerHandler();
|
||||
initializeBranchFilter();
|
||||
|
@ -273,6 +277,14 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
|
|||
return secretToken == null ? null : secretToken.getPlainText();
|
||||
}
|
||||
|
||||
public String getPendingBuildName() {
|
||||
return pendingBuildName;
|
||||
}
|
||||
|
||||
public boolean getCancelPendingBuildsOnUpdate() {
|
||||
return this.cancelPendingBuildsOnUpdate;
|
||||
}
|
||||
|
||||
@DataBoundSetter
|
||||
public void setTriggerOnPush(boolean triggerOnPush) {
|
||||
this.triggerOnPush = triggerOnPush;
|
||||
|
@ -388,6 +400,16 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
|
|||
this.triggerOnPipelineEvent = triggerOnPipelineEvent;
|
||||
}
|
||||
|
||||
@DataBoundSetter
|
||||
public void setPendingBuildName(String pendingBuildName) {
|
||||
this.pendingBuildName = pendingBuildName;
|
||||
}
|
||||
|
||||
@DataBoundSetter
|
||||
public void setCancelPendingBuildsOnUpdate(boolean cancelPendingBuildsOnUpdate) {
|
||||
this.cancelPendingBuildsOnUpdate = cancelPendingBuildsOnUpdate;
|
||||
}
|
||||
|
||||
// executes when the Trigger receives a push request
|
||||
public void onPost(final PushHook hook) {
|
||||
if (branchFilter == null) {
|
||||
|
@ -438,7 +460,7 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
|
|||
private void initializeTriggerHandler() {
|
||||
mergeRequestHookTriggerHandler = newMergeRequestHookTriggerHandler(triggerOnMergeRequest,
|
||||
triggerOnAcceptedMergeRequest, triggerOnClosedMergeRequest, triggerOpenMergeRequestOnPush,
|
||||
skipWorkInProgressMergeRequest, triggerOnApprovedMergeRequest);
|
||||
skipWorkInProgressMergeRequest, triggerOnApprovedMergeRequest, cancelPendingBuildsOnUpdate);
|
||||
noteHookTriggerHandler = newNoteHookTriggerHandler(triggerOnNoteRequest, noteRegex);
|
||||
pushHookTriggerHandler = newPushHookTriggerHandler(triggerOnPush, triggerOpenMergeRequestOnPush, skipWorkInProgressMergeRequest);
|
||||
pipelineTriggerHandler = newPipelineHookTriggerHandler(triggerOnPipelineEvent);
|
||||
|
|
|
@ -6,23 +6,22 @@ import com.dabsquared.gitlabjenkins.connection.GitLabConnectionProperty;
|
|||
import com.dabsquared.gitlabjenkins.gitlab.api.GitLabClient;
|
||||
import com.dabsquared.gitlabjenkins.gitlab.api.model.BuildState;
|
||||
import com.dabsquared.gitlabjenkins.gitlab.hook.model.WebHook;
|
||||
import com.dabsquared.gitlabjenkins.publisher.GitLabCommitStatusPublisher;
|
||||
import com.dabsquared.gitlabjenkins.trigger.exception.NoRevisionToBuildException;
|
||||
import com.dabsquared.gitlabjenkins.trigger.filter.BranchFilter;
|
||||
import com.dabsquared.gitlabjenkins.trigger.filter.MergeRequestLabelFilter;
|
||||
import com.dabsquared.gitlabjenkins.util.LoggerUtil;
|
||||
import hudson.model.AbstractProject;
|
||||
import hudson.model.Action;
|
||||
import hudson.model.CauseAction;
|
||||
import hudson.model.Job;
|
||||
import hudson.plugins.git.GitSCM;
|
||||
import hudson.plugins.git.RevisionParameterAction;
|
||||
import hudson.scm.SCM;
|
||||
import jenkins.model.Jenkins;
|
||||
import jenkins.model.ParameterizedJobMixIn;
|
||||
import jenkins.triggers.SCMTriggerItem;
|
||||
import net.karneim.pojobuilder.GeneratePojoBuilder;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.eclipse.jgit.transport.URIish;
|
||||
import org.jenkinsci.plugins.displayurlapi.DisplayURLProvider;
|
||||
|
||||
import javax.ws.rs.ProcessingException;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
|
@ -37,6 +36,7 @@ import java.util.logging.Logger;
|
|||
public abstract class AbstractWebHookTriggerHandler<H extends WebHook> implements WebHookTriggerHandler<H> {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(AbstractWebHookTriggerHandler.class.getName());
|
||||
protected PendingBuildsHandler pendingBuildsHandler = new PendingBuildsHandler();
|
||||
|
||||
@Override
|
||||
public void handle(Job<?, ?> job, H hook, boolean ciSkip, BranchFilter branchFilter, MergeRequestLabelFilter mergeRequestLabelFilter) {
|
||||
|
@ -48,6 +48,7 @@ public abstract class AbstractWebHookTriggerHandler<H extends WebHook> implement
|
|||
String targetBranch = getTargetBranch(hook);
|
||||
if (branchFilter.isBranchAllowed(targetBranch)) {
|
||||
LOGGER.log(Level.INFO, "{0} triggered for {1}.", LoggerUtil.toArray(job.getFullName(), getTriggerType()));
|
||||
cancelPendingBuildsIfNecessary(job, hook);
|
||||
setCommitStatusPendingIfNecessary(job, hook);
|
||||
scheduleBuild(job, createActions(job, hook));
|
||||
} else {
|
||||
|
@ -60,19 +61,17 @@ public abstract class AbstractWebHookTriggerHandler<H extends WebHook> implement
|
|||
protected abstract boolean isCiSkip(H hook);
|
||||
|
||||
private void setCommitStatusPendingIfNecessary(Job<?, ?> job, H hook) {
|
||||
if (job instanceof AbstractProject && ((AbstractProject) job).getPublishersList().get(GitLabCommitStatusPublisher.class) != null) {
|
||||
GitLabCommitStatusPublisher publisher =
|
||||
(GitLabCommitStatusPublisher) ((AbstractProject) job).getPublishersList().get(GitLabCommitStatusPublisher.class);
|
||||
String buildName = PendingBuildsHandler.resolvePendingBuildName(job);
|
||||
if (StringUtils.isNotBlank(buildName)) {
|
||||
GitLabClient client = job.getProperty(GitLabConnectionProperty.class).getClient();
|
||||
BuildStatusUpdate buildStatusUpdate = retrieveBuildStatusUpdate(hook);
|
||||
try {
|
||||
if (client == null) {
|
||||
LOGGER.log(Level.SEVERE, "No GitLab connection configured");
|
||||
} else {
|
||||
String targetUrl =
|
||||
Jenkins.getInstance().getRootUrl() + job.getUrl() + job.getNextBuildNumber() + "/";
|
||||
String targetUrl = DisplayURLProvider.get().getJobURL(job);
|
||||
client.changeBuildStatus(buildStatusUpdate.getProjectId(), buildStatusUpdate.getSha(),
|
||||
BuildState.pending, buildStatusUpdate.getRef(), publisher.getName(), targetUrl, BuildState.pending.name());
|
||||
BuildState.pending, buildStatusUpdate.getRef(), buildName, targetUrl, BuildState.pending.name());
|
||||
}
|
||||
} catch (WebApplicationException | ProcessingException e) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to set build state to pending", e);
|
||||
|
@ -94,6 +93,8 @@ public abstract class AbstractWebHookTriggerHandler<H extends WebHook> implement
|
|||
return actions.toArray(new Action[actions.size()]);
|
||||
}
|
||||
|
||||
protected void cancelPendingBuildsIfNecessary(Job<?, ?> job, H hook) {}
|
||||
|
||||
protected abstract CauseData retrieveCauseData(H hook);
|
||||
|
||||
protected abstract String getTargetBranch(H hook);
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
package com.dabsquared.gitlabjenkins.trigger.handler;
|
||||
|
||||
import com.dabsquared.gitlabjenkins.GitLabPushTrigger;
|
||||
import com.dabsquared.gitlabjenkins.cause.CauseData;
|
||||
import com.dabsquared.gitlabjenkins.cause.GitLabWebHookCause;
|
||||
import com.dabsquared.gitlabjenkins.connection.GitLabConnectionProperty;
|
||||
import com.dabsquared.gitlabjenkins.gitlab.api.GitLabClient;
|
||||
import com.dabsquared.gitlabjenkins.gitlab.api.model.BuildState;
|
||||
import com.dabsquared.gitlabjenkins.publisher.GitLabCommitStatusPublisher;
|
||||
import com.dabsquared.gitlabjenkins.util.LoggerUtil;
|
||||
import hudson.model.AbstractProject;
|
||||
import hudson.model.Cause;
|
||||
import hudson.model.Job;
|
||||
import hudson.model.Queue;
|
||||
import jenkins.model.Jenkins;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.jenkinsci.plugins.displayurlapi.DisplayURLProvider;
|
||||
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class PendingBuildsHandler {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(PendingBuildsHandler.class.getName());
|
||||
|
||||
public void cancelPendingBuilds(Job<?, ?> job, Integer projectId, String branch) {
|
||||
Queue queue = Jenkins.getInstance().getQueue();
|
||||
for (Queue.Item item : queue.getItems()) {
|
||||
if (!job.getName().equals(item.task.getName())) {
|
||||
continue;
|
||||
}
|
||||
GitLabWebHookCause queueItemGitLabWebHookCause = getGitLabWebHookCauseData(item);
|
||||
if (queueItemGitLabWebHookCause == null) {
|
||||
continue;
|
||||
}
|
||||
CauseData queueItemCauseData = queueItemGitLabWebHookCause.getData();
|
||||
if (!projectId.equals(queueItemCauseData.getSourceProjectId())) {
|
||||
continue;
|
||||
}
|
||||
if (branch.equals(queueItemCauseData.getBranch())) {
|
||||
cancel(item, queue, branch);
|
||||
setCommitStatusCancelledIfNecessary(queueItemCauseData, job);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private GitLabWebHookCause getGitLabWebHookCauseData(Queue.Item item) {
|
||||
for (Cause cause : item.getCauses()) {
|
||||
if (cause instanceof GitLabWebHookCause) {
|
||||
return (GitLabWebHookCause) cause;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void cancel(Queue.Item item, Queue queue, String branch) {
|
||||
try {
|
||||
LOGGER.log(Level.INFO, "Cancelling job {0} for branch {1}", LoggerUtil.toArray(item.task.getName(), branch));
|
||||
queue.cancel(item);
|
||||
} catch (Exception e) {
|
||||
LOGGER.log(Level.SEVERE, "Error cancelling queued build", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setCommitStatusCancelledIfNecessary(CauseData causeData, Job<?, ?> job) {
|
||||
String buildName = resolvePendingBuildName(job);
|
||||
if (StringUtils.isBlank(buildName)) {
|
||||
return;
|
||||
}
|
||||
String targetUrl = DisplayURLProvider.get().getJobURL(job);
|
||||
GitLabClient client = job.getProperty(GitLabConnectionProperty.class).getClient();
|
||||
try {
|
||||
client.changeBuildStatus(causeData.getSourceProjectId(), causeData.getLastCommit(), BuildState.canceled,
|
||||
causeData.getSourceBranch(), buildName, targetUrl, BuildState.canceled.name());
|
||||
} catch (Exception e) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to set build state to pending", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String resolvePendingBuildName(Job<?, ?> job) {
|
||||
if (job instanceof AbstractProject) {
|
||||
GitLabCommitStatusPublisher publisher =
|
||||
(GitLabCommitStatusPublisher) ((AbstractProject) job).getPublishersList().get(GitLabCommitStatusPublisher.class);
|
||||
if (publisher != null) {
|
||||
return publisher.getName();
|
||||
}
|
||||
} else if (job instanceof WorkflowJob) {
|
||||
GitLabPushTrigger trigger = GitLabPushTrigger.getFromJob(job);
|
||||
if (trigger != null) {
|
||||
return trigger.getPendingBuildName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -21,11 +21,12 @@ public final class MergeRequestHookTriggerHandlerFactory {
|
|||
boolean triggerOnClosedMergeRequest,
|
||||
TriggerOpenMergeRequest triggerOpenMergeRequest,
|
||||
boolean skipWorkInProgressMergeRequest,
|
||||
boolean triggerOnApprovedMergeRequest) {
|
||||
boolean triggerOnApprovedMergeRequest,
|
||||
boolean cancelPendingBuildsOnUpdate) {
|
||||
if (triggerOnMergeRequest || triggerOnAcceptedMergeRequest || triggerOnClosedMergeRequest || triggerOpenMergeRequest != TriggerOpenMergeRequest.never || triggerOnApprovedMergeRequest) {
|
||||
return new MergeRequestHookTriggerHandlerImpl(retrieveAllowedStates(triggerOnMergeRequest, triggerOnAcceptedMergeRequest, triggerOnClosedMergeRequest, triggerOpenMergeRequest),
|
||||
retrieveAllowedActions(triggerOnApprovedMergeRequest),
|
||||
skipWorkInProgressMergeRequest);
|
||||
skipWorkInProgressMergeRequest, cancelPendingBuildsOnUpdate);
|
||||
} else {
|
||||
return new NopMergeRequestHookTriggerHandler();
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.dabsquared.gitlabjenkins.trigger.filter.BranchFilter;
|
|||
import com.dabsquared.gitlabjenkins.trigger.filter.MergeRequestLabelFilter;
|
||||
import com.dabsquared.gitlabjenkins.trigger.handler.AbstractWebHookTriggerHandler;
|
||||
import com.dabsquared.gitlabjenkins.util.BuildUtil;
|
||||
import com.dabsquared.gitlabjenkins.trigger.handler.PendingBuildsHandler;
|
||||
import hudson.model.Job;
|
||||
import hudson.model.Run;
|
||||
import hudson.plugins.git.GitSCM;
|
||||
|
@ -39,15 +40,17 @@ class MergeRequestHookTriggerHandlerImpl extends AbstractWebHookTriggerHandler<M
|
|||
private final Collection<State> allowedStates;
|
||||
private final boolean skipWorkInProgressMergeRequest;
|
||||
private final Collection<Action> allowedActions;
|
||||
private final boolean cancelPendingBuildsOnUpdate;
|
||||
|
||||
MergeRequestHookTriggerHandlerImpl(Collection<State> allowedStates, boolean skipWorkInProgressMergeRequest) {
|
||||
this(allowedStates, EnumSet.allOf(Action.class),skipWorkInProgressMergeRequest);
|
||||
MergeRequestHookTriggerHandlerImpl(Collection<State> allowedStates, boolean skipWorkInProgressMergeRequest, boolean cancelPendingBuildsOnUpdate) {
|
||||
this(allowedStates, EnumSet.allOf(Action.class), skipWorkInProgressMergeRequest, cancelPendingBuildsOnUpdate);
|
||||
}
|
||||
|
||||
MergeRequestHookTriggerHandlerImpl(Collection<State> allowedStates, Collection<Action> allowedActions, boolean skipWorkInProgressMergeRequest) {
|
||||
MergeRequestHookTriggerHandlerImpl(Collection<State> allowedStates, Collection<Action> allowedActions, boolean skipWorkInProgressMergeRequest, boolean cancelPendingBuildsOnUpdate) {
|
||||
this.allowedStates = allowedStates;
|
||||
this.allowedActions = allowedActions;
|
||||
this.skipWorkInProgressMergeRequest = skipWorkInProgressMergeRequest;
|
||||
this.cancelPendingBuildsOnUpdate = cancelPendingBuildsOnUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -77,6 +80,17 @@ class MergeRequestHookTriggerHandlerImpl extends AbstractWebHookTriggerHandler<M
|
|||
&& hook.getObjectAttributes().getDescription().contains("[ci-skip]");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cancelPendingBuildsIfNecessary(Job<?, ?> job, MergeRequestHook hook) {
|
||||
if (!this.cancelPendingBuildsOnUpdate) {
|
||||
return;
|
||||
}
|
||||
if (!hook.getObjectAttributes().getAction().equals(Action.update)) {
|
||||
return;
|
||||
}
|
||||
this.pendingBuildsHandler.cancelPendingBuilds(job, hook.getObjectAttributes().getSourceProjectId(), hook.getObjectAttributes().getSourceBranch());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTargetBranch(MergeRequestHook hook) {
|
||||
return hook.getObjectAttributes() == null ? null : hook.getObjectAttributes().getTargetBranch();
|
||||
|
|
|
@ -12,20 +12,20 @@ import com.dabsquared.gitlabjenkins.gitlab.api.model.MergeRequest;
|
|||
import com.dabsquared.gitlabjenkins.gitlab.api.model.Project;
|
||||
import com.dabsquared.gitlabjenkins.gitlab.hook.model.PushHook;
|
||||
import com.dabsquared.gitlabjenkins.gitlab.hook.model.State;
|
||||
import com.dabsquared.gitlabjenkins.publisher.GitLabCommitStatusPublisher;
|
||||
import com.dabsquared.gitlabjenkins.trigger.filter.BranchFilter;
|
||||
import com.dabsquared.gitlabjenkins.trigger.filter.MergeRequestLabelFilter;
|
||||
import com.dabsquared.gitlabjenkins.util.LoggerUtil;
|
||||
import hudson.model.AbstractProject;
|
||||
import com.dabsquared.gitlabjenkins.trigger.handler.PendingBuildsHandler;
|
||||
import hudson.model.Action;
|
||||
import hudson.model.CauseAction;
|
||||
import hudson.model.Job;
|
||||
import hudson.plugins.git.RevisionParameterAction;
|
||||
import hudson.triggers.Trigger;
|
||||
import jenkins.model.Jenkins;
|
||||
import jenkins.model.ParameterizedJobMixIn;
|
||||
import jenkins.model.ParameterizedJobMixIn.ParameterizedJob;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.eclipse.jgit.transport.URIish;
|
||||
import org.jenkinsci.plugins.displayurlapi.DisplayURLProvider;
|
||||
|
||||
import javax.ws.rs.ProcessingException;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
|
@ -72,7 +72,7 @@ class OpenMergeRequestPushHookTriggerHandler implements PushHookTriggerHandler {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
LOGGER.log(Level.FINE, "Not a ParameterizedJob: {0}",LoggerUtil.toArray(job.getClass().getName()));
|
||||
}
|
||||
|
@ -114,7 +114,6 @@ class OpenMergeRequestPushHookTriggerHandler implements PushHookTriggerHandler {
|
|||
Project project = client.getProject(mergeRequest.getSourceProjectId().toString());
|
||||
String commit = branch.getCommit().getId();
|
||||
setCommitStatusPendingIfNecessary(job, mergeRequest.getSourceProjectId(), commit, branch.getName());
|
||||
|
||||
List<Action> actions = Arrays.<Action>asList(new CauseAction(new GitLabWebHookCause(retrieveCauseData(hook, project, mergeRequest, branch))),
|
||||
new RevisionParameterAction(commit, retrieveUrIish(hook)));
|
||||
scheduleBuild(job, actions.toArray(new Action[actions.size()]));
|
||||
|
@ -153,13 +152,12 @@ class OpenMergeRequestPushHookTriggerHandler implements PushHookTriggerHandler {
|
|||
}
|
||||
|
||||
private void setCommitStatusPendingIfNecessary(Job<?, ?> job, Integer projectId, String commit, String ref) {
|
||||
if (job instanceof AbstractProject && ((AbstractProject) job).getPublishersList().get(GitLabCommitStatusPublisher.class) != null) {
|
||||
GitLabCommitStatusPublisher publisher =
|
||||
(GitLabCommitStatusPublisher) ((AbstractProject) job).getPublishersList().get(GitLabCommitStatusPublisher.class);
|
||||
String buildName = PendingBuildsHandler.resolvePendingBuildName(job);
|
||||
if (StringUtils.isNotBlank(buildName)) {
|
||||
GitLabClient client = job.getProperty(GitLabConnectionProperty.class).getClient();
|
||||
try {
|
||||
String targetUrl = Jenkins.getInstance().getRootUrl() + job.getUrl() + job.getNextBuildNumber() + "/";
|
||||
client.changeBuildStatus(projectId, commit, BuildState.pending, ref, publisher.getName(), targetUrl, BuildState.pending.name());
|
||||
String targetUrl = DisplayURLProvider.get().getJobURL(job);
|
||||
client.changeBuildStatus(projectId, commit, BuildState.pending, ref, buildName, targetUrl, BuildState.pending.name());
|
||||
} catch (WebApplicationException | ProcessingException e) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to set build state to pending", e);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,12 @@
|
|||
<f:entry title="Build on successful pipeline events" field="triggerOnPipelineEvent">
|
||||
<f:checkbox default="false"/>
|
||||
</f:entry>
|
||||
<f:entry title="Pending build name for pipeline" help="/plugin/gitlab-plugin/help/help-pendingBuildName.html">
|
||||
<f:textbox field="pendingBuildName"/>
|
||||
</f:entry>
|
||||
<f:entry title="Cancel pending merge request builds on update" field="cancelPendingBuildsOnUpdate">
|
||||
<f:checkbox default="false"/>
|
||||
</f:entry>
|
||||
|
||||
<f:entry title="Allowed branches">
|
||||
<table>
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<div>
|
||||
<div>
|
||||
<p>Applicable only for pipelines.</p>
|
||||
<p>When filled, a 'pending' build status with the given build name is published to Gitlab when the pipeline is
|
||||
triggered. Further status updates should be defined in pipeline steps.</p>
|
||||
<p>For other types of jobs the build name is taken from 'Publish build status to Gitlab commit' post-build action.</p>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,219 @@
|
|||
package com.dabsquared.gitlabjenkins.trigger.handler;
|
||||
|
||||
import com.dabsquared.gitlabjenkins.GitLabPushTrigger;
|
||||
import com.dabsquared.gitlabjenkins.connection.GitLabConnectionProperty;
|
||||
import com.dabsquared.gitlabjenkins.gitlab.api.GitLabClient;
|
||||
import com.dabsquared.gitlabjenkins.gitlab.api.model.BuildState;
|
||||
import com.dabsquared.gitlabjenkins.gitlab.hook.model.*;
|
||||
import com.dabsquared.gitlabjenkins.gitlab.hook.model.builder.generated.*;
|
||||
import com.dabsquared.gitlabjenkins.publisher.GitLabCommitStatusPublisher;
|
||||
import com.dabsquared.gitlabjenkins.trigger.filter.BranchFilterType;
|
||||
import hudson.model.FreeStyleProject;
|
||||
import hudson.model.ItemGroup;
|
||||
import hudson.model.Project;
|
||||
import hudson.model.Queue;
|
||||
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.jvnet.hudson.test.JenkinsRule;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static com.dabsquared.gitlabjenkins.gitlab.hook.model.builder.generated.CommitBuilder.commit;
|
||||
import static com.dabsquared.gitlabjenkins.gitlab.hook.model.builder.generated.MergeRequestObjectAttributesBuilder.mergeRequestObjectAttributes;
|
||||
import static com.dabsquared.gitlabjenkins.gitlab.hook.model.builder.generated.UserBuilder.user;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class PendingBuildsHandlerTest {
|
||||
|
||||
private static final String GITLAB_BUILD_NAME = "Jenkins";
|
||||
|
||||
@ClassRule
|
||||
public static JenkinsRule jenkins = new JenkinsRule();
|
||||
|
||||
@Mock
|
||||
private GitLabClient gitLabClient;
|
||||
|
||||
@Mock
|
||||
private GitLabConnectionProperty gitLabConnectionProperty;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
when(gitLabConnectionProperty.getClient()).thenReturn(gitLabClient);
|
||||
}
|
||||
|
||||
@After
|
||||
public void clearQueue() {
|
||||
Queue queue = jenkins.getInstance().getQueue();
|
||||
for (Queue.Item item : queue.getItems()) {
|
||||
queue.cancel(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void projectCanBeConfiguredToSendPendingBuildStatusWhenTriggered() throws IOException {
|
||||
Project project = freestyleProject("freestyleProject1", new GitLabCommitStatusPublisher(GITLAB_BUILD_NAME, false));
|
||||
|
||||
GitLabPushTrigger gitLabPushTrigger = gitLabPushTrigger(project);
|
||||
|
||||
gitLabPushTrigger.onPost(pushHook(1, "branch1", "commit1"));
|
||||
|
||||
verify(gitLabClient).changeBuildStatus(eq(1), eq("commit1"), eq(BuildState.pending), eq("branch1"), eq(GITLAB_BUILD_NAME),
|
||||
contains("/freestyleProject1/"), eq(BuildState.pending.name()));
|
||||
verifyNoMoreInteractions(gitLabClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void workflowJobCanConfiguredToSendToPendingBuildStatusWhenTriggered() throws IOException {
|
||||
WorkflowJob workflowJob = workflowJob();
|
||||
|
||||
GitLabPushTrigger gitLabPushTrigger = gitLabPushTrigger(workflowJob);
|
||||
gitLabPushTrigger.setPendingBuildName(GITLAB_BUILD_NAME);
|
||||
|
||||
gitLabPushTrigger.onPost(mergeRequestHook(1, "branch1", "commit1"));
|
||||
|
||||
verify(gitLabClient).changeBuildStatus(eq(1), eq("commit1"), eq(BuildState.pending), eq("branch1"), eq(GITLAB_BUILD_NAME),
|
||||
contains("/workflowJob/"), eq(BuildState.pending.name()));
|
||||
verifyNoMoreInteractions(gitLabClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queuedMergeRequestBuildsCanBeCancelledOnMergeRequestUpdate() throws IOException {
|
||||
Project project = freestyleProject("project1", new GitLabCommitStatusPublisher(GITLAB_BUILD_NAME, false));
|
||||
|
||||
GitLabPushTrigger gitLabPushTrigger = gitLabPushTrigger(project);
|
||||
gitLabPushTrigger.setCancelPendingBuildsOnUpdate(true);
|
||||
|
||||
assertThat(jenkins.getInstance().getQueue().getItems().length, is(0));
|
||||
|
||||
gitLabPushTrigger.onPost(mergeRequestHook(1, "sourceBranch", "commit1")); // Will be cancelled
|
||||
gitLabPushTrigger.onPost(mergeRequestHook(1, "sourceBranch", "commit2")); // Will be cancelled
|
||||
gitLabPushTrigger.onPost(mergeRequestHook(1, "sourceBranch", "commit3"));
|
||||
gitLabPushTrigger.onPost(mergeRequestHook(1, "anotherBranch", "commit4"));
|
||||
gitLabPushTrigger.onPost(mergeRequestHook(2, "sourceBranch", "commit5"));
|
||||
|
||||
verify(gitLabClient).changeBuildStatus(eq(1), eq("commit1"), eq(BuildState.canceled), eq("sourceBranch"),
|
||||
eq("Jenkins"), contains("project1"), eq(BuildState.canceled.name()));
|
||||
verify(gitLabClient).changeBuildStatus(eq(1), eq("commit2"), eq(BuildState.canceled), eq("sourceBranch"),
|
||||
eq("Jenkins"), contains("project1"), eq(BuildState.canceled.name()));
|
||||
|
||||
assertThat(jenkins.getInstance().getQueue().getItems().length, is(3));
|
||||
}
|
||||
|
||||
private GitLabPushTrigger gitLabPushTrigger(Project project) throws IOException {
|
||||
GitLabPushTrigger gitLabPushTrigger = gitLabPushTrigger();
|
||||
project.addTrigger(gitLabPushTrigger);
|
||||
gitLabPushTrigger.start(project,true);
|
||||
return gitLabPushTrigger;
|
||||
}
|
||||
|
||||
private GitLabPushTrigger gitLabPushTrigger(WorkflowJob workflowJob) {
|
||||
GitLabPushTrigger gitLabPushTrigger = gitLabPushTrigger();
|
||||
workflowJob.addTrigger(gitLabPushTrigger);
|
||||
gitLabPushTrigger.start(workflowJob,true);
|
||||
return gitLabPushTrigger;
|
||||
}
|
||||
|
||||
private GitLabPushTrigger gitLabPushTrigger() {
|
||||
GitLabPushTrigger gitLabPushTrigger = new GitLabPushTrigger();
|
||||
gitLabPushTrigger.setTriggerOnPush(true);
|
||||
gitLabPushTrigger.setTriggerOnMergeRequest(true);
|
||||
gitLabPushTrigger.setPendingBuildName(GITLAB_BUILD_NAME);
|
||||
gitLabPushTrigger.setBranchFilterType(BranchFilterType.NameBasedFilter);
|
||||
gitLabPushTrigger.setBranchFilterName("");
|
||||
return gitLabPushTrigger;
|
||||
}
|
||||
|
||||
private MergeRequestHook mergeRequestHook(int projectId, String branch, String commitId) {
|
||||
return MergeRequestHookBuilder.mergeRequestHook()
|
||||
.withObjectAttributes(mergeRequestObjectAttributes()
|
||||
.withAction(Action.update)
|
||||
.withState(State.updated)
|
||||
.withIid(1)
|
||||
.withTitle("test")
|
||||
.withTargetProjectId(1)
|
||||
.withTargetBranch("targetBranch")
|
||||
.withSourceBranch(branch)
|
||||
.withSourceProjectId(projectId)
|
||||
.withLastCommit(commit().withAuthor(user().withName("author").build()).withId(commitId).build())
|
||||
.withSource(ProjectBuilder.project()
|
||||
.withName("test")
|
||||
.withNamespace("test-namespace")
|
||||
.withHomepage("https://gitlab.org/test")
|
||||
.withUrl("git@gitlab.org:test.git")
|
||||
.withSshUrl("git@gitlab.org:test.git")
|
||||
.withHttpUrl("https://gitlab.org/test.git")
|
||||
.build())
|
||||
.withTarget(ProjectBuilder.project()
|
||||
.withName("test")
|
||||
.withNamespace("test-namespace")
|
||||
.withHomepage("https://gitlab.org/test")
|
||||
.withUrl("git@gitlab.org:test.git")
|
||||
.withSshUrl("git@gitlab.org:test.git")
|
||||
.withHttpUrl("https://gitlab.org/test.git")
|
||||
.build())
|
||||
.build())
|
||||
.withProject(ProjectBuilder.project()
|
||||
.withWebUrl("https://gitlab.org/test.git")
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
}
|
||||
|
||||
private PushHook pushHook(int projectId, String branch, String commitId) {
|
||||
User user = new UserBuilder()
|
||||
.withName("username")
|
||||
.build();
|
||||
|
||||
Repository repository = new RepositoryBuilder()
|
||||
.withName("repository")
|
||||
.withGitSshUrl("sshUrl")
|
||||
.withGitHttpUrl("httpUrl")
|
||||
.build();
|
||||
|
||||
return new PushHookBuilder()
|
||||
.withProjectId(projectId)
|
||||
.withRef(branch)
|
||||
.withAfter(commitId)
|
||||
.withRepository(new Repository())
|
||||
.withProject(ProjectBuilder.project().withNamespace("namespace").build())
|
||||
.withCommits(Arrays.asList(CommitBuilder.commit().withId(commitId).withAuthor(user).build()))
|
||||
.withRepository(repository)
|
||||
.withObjectKind("push")
|
||||
.withUserName("username")
|
||||
.build();
|
||||
}
|
||||
|
||||
private Project freestyleProject(String name, GitLabCommitStatusPublisher gitLabCommitStatusPublisher) throws IOException {
|
||||
FreeStyleProject project = jenkins.createFreeStyleProject(name);
|
||||
project.setQuietPeriod(5000);
|
||||
project.getPublishersList().add(gitLabCommitStatusPublisher);
|
||||
project.addProperty(gitLabConnectionProperty);
|
||||
return project;
|
||||
}
|
||||
|
||||
private WorkflowJob workflowJob() throws IOException {
|
||||
ItemGroup itemGroup = mock(ItemGroup.class);
|
||||
when(itemGroup.getFullName()).thenReturn("parent");
|
||||
when(itemGroup.getUrlChildPrefix()).thenReturn("prefix");
|
||||
|
||||
WorkflowJob workflowJob = new WorkflowJob(itemGroup, "workflowJob");
|
||||
when(itemGroup.getRootDirFor(workflowJob)).thenReturn(new File("work"));
|
||||
|
||||
workflowJob.addProperty(gitLabConnectionProperty);
|
||||
workflowJob.setQuietPeriod(5000);
|
||||
workflowJob.onCreatedFromScratch();
|
||||
return workflowJob;
|
||||
}
|
||||
}
|
|
@ -69,7 +69,7 @@ public class MergeRequestHookTriggerHandlerImplTest {
|
|||
}
|
||||
});
|
||||
project.setQuietPeriod(0);
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(Arrays.asList(State.opened, State.reopened), false);
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(Arrays.asList(State.opened, State.reopened), false, false);
|
||||
mergeRequestHookTriggerHandler.handle(project, mergeRequestHook()
|
||||
.withObjectAttributes(mergeRequestObjectAttributes().withDescription("[ci-skip]").build())
|
||||
.build(), true, BranchFilterFactory.newBranchFilter(branchFilterConfig().build(BranchFilterType.All)),
|
||||
|
@ -81,7 +81,7 @@ public class MergeRequestHookTriggerHandlerImplTest {
|
|||
|
||||
@Test
|
||||
public void mergeRequest_build() throws IOException, InterruptedException, GitAPIException, ExecutionException {
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(Arrays.asList(State.opened, State.reopened), false);
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(Arrays.asList(State.opened, State.reopened), false, false);
|
||||
OneShotEvent buildTriggered = doHandle(mergeRequestHookTriggerHandler, State.opened);
|
||||
|
||||
assertThat(buildTriggered.isSignaled(), is(true));
|
||||
|
@ -89,7 +89,7 @@ public class MergeRequestHookTriggerHandlerImplTest {
|
|||
|
||||
@Test
|
||||
public void mergeRequest_build_when_accepted() throws IOException, InterruptedException, GitAPIException, ExecutionException {
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(Arrays.asList(State.merged), false);
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(Arrays.asList(State.merged), false, false);
|
||||
OneShotEvent buildTriggered = doHandle(mergeRequestHookTriggerHandler, State.merged);
|
||||
|
||||
assertThat(buildTriggered.isSignaled(), is(true));
|
||||
|
@ -97,7 +97,7 @@ public class MergeRequestHookTriggerHandlerImplTest {
|
|||
|
||||
@Test
|
||||
public void mergeRequest_build_when_closed() throws IOException, InterruptedException, GitAPIException, ExecutionException {
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(Arrays.asList(State.closed), false);
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(Arrays.asList(State.closed), false, false);
|
||||
OneShotEvent buildTriggered = doHandle(mergeRequestHookTriggerHandler, State.closed);
|
||||
|
||||
assertThat(buildTriggered.isSignaled(), is(true));
|
||||
|
@ -105,7 +105,7 @@ public class MergeRequestHookTriggerHandlerImplTest {
|
|||
|
||||
@Test
|
||||
public void mergeRequest_do_not_build_when_accepted() throws IOException, InterruptedException, GitAPIException, ExecutionException {
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(Arrays.asList(State.opened, State.updated), false);
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(Arrays.asList(State.opened, State.updated), false, false);
|
||||
OneShotEvent buildTriggered = doHandle(mergeRequestHookTriggerHandler, State.merged);
|
||||
|
||||
assertThat(buildTriggered.isSignaled(), is(false));
|
||||
|
@ -113,7 +113,7 @@ public class MergeRequestHookTriggerHandlerImplTest {
|
|||
|
||||
@Test
|
||||
public void mergeRequest_do_not_build_when_closed() throws IOException, InterruptedException, GitAPIException, ExecutionException {
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(Arrays.asList(State.opened, State.updated), false);
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(Arrays.asList(State.opened, State.updated), false, false);
|
||||
OneShotEvent buildTriggered = doHandle(mergeRequestHookTriggerHandler, State.closed);
|
||||
|
||||
assertThat(buildTriggered.isSignaled(), is(false));
|
||||
|
@ -121,7 +121,8 @@ public class MergeRequestHookTriggerHandlerImplTest {
|
|||
|
||||
@Test
|
||||
public void mergeRequest_build_when_approved() throws IOException, InterruptedException, GitAPIException, ExecutionException {
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(EnumSet.allOf(State.class), EnumSet.of(Action.approved), false);
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(EnumSet.allOf(State.class), EnumSet.of(Action.approved), false, false);
|
||||
|
||||
OneShotEvent buildTriggered = doHandle(mergeRequestHookTriggerHandler, Action.approved);
|
||||
|
||||
assertThat(buildTriggered.isSignaled(), is(true));
|
||||
|
@ -129,7 +130,7 @@ public class MergeRequestHookTriggerHandlerImplTest {
|
|||
|
||||
@Test
|
||||
public void mergeRequest_do_not_build_when_when_approved() throws Exception {
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(EnumSet.allOf(State.class), EnumSet.of(Action.update), false);
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(EnumSet.allOf(State.class), EnumSet.of(Action.update), false, false);
|
||||
OneShotEvent buildTriggered = doHandle(mergeRequestHookTriggerHandler, defaultMergeRequestObjectAttributes().withState(State.opened).withAction(Action.approved));
|
||||
|
||||
assertThat(buildTriggered.isSignaled(), is (false));
|
||||
|
@ -148,11 +149,11 @@ public class MergeRequestHookTriggerHandlerImplTest {
|
|||
|
||||
private void mergeRequest_build_only_when_approved(Action action)
|
||||
throws GitAPIException, IOException, InterruptedException {
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(EnumSet.allOf(State.class), EnumSet.of(Action.approved), false);
|
||||
MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler = new MergeRequestHookTriggerHandlerImpl(EnumSet.allOf(State.class), EnumSet.of(Action.approved), false, false);
|
||||
OneShotEvent buildTriggered = doHandle(mergeRequestHookTriggerHandler, action);
|
||||
|
||||
assertThat(buildTriggered.isSignaled(), is(false));
|
||||
}
|
||||
}
|
||||
|
||||
private OneShotEvent doHandle(MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler, Action action) throws GitAPIException, IOException, InterruptedException {
|
||||
return doHandle(mergeRequestHookTriggerHandler, defaultMergeRequestObjectAttributes().withAction(action));
|
||||
|
|
Loading…
Reference in New Issue