Added tests for sending 'pending' builds status to GitLab and cancelling pending merge request builds on merge request update.

Also:
- Moved the code from PendingBuildsUtil to PendingBuildsHandler.
- Removed cancelling pending builds from OpenMergeRequestPushHookTriggerHandler. It is not needed there
because builds with same commitid are squashed anyway.
This commit is contained in:
Tommi Salonen 2017-12-27 13:29:26 +02:00
parent 4ecec17236
commit 70773f3f83
7 changed files with 238 additions and 32 deletions

View File

@ -462,7 +462,7 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
triggerOnAcceptedMergeRequest, triggerOnClosedMergeRequest, triggerOpenMergeRequestOnPush,
skipWorkInProgressMergeRequest, triggerOnApprovedMergeRequest, cancelPendingBuildsOnUpdate);
noteHookTriggerHandler = newNoteHookTriggerHandler(triggerOnNoteRequest, noteRegex);
pushHookTriggerHandler = newPushHookTriggerHandler(triggerOnPush, triggerOpenMergeRequestOnPush, skipWorkInProgressMergeRequest, cancelPendingBuildsOnUpdate);
pushHookTriggerHandler = newPushHookTriggerHandler(triggerOnPush, triggerOpenMergeRequestOnPush, skipWorkInProgressMergeRequest);
pipelineTriggerHandler = newPipelineHookTriggerHandler(triggerOnPipelineEvent);
}

View File

@ -10,7 +10,6 @@ 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 com.dabsquared.gitlabjenkins.util.PendingBuildsUtil;
import hudson.model.Action;
import hudson.model.CauseAction;
import hudson.model.Job;
@ -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) {
@ -61,7 +61,7 @@ public abstract class AbstractWebHookTriggerHandler<H extends WebHook> implement
protected abstract boolean isCiSkip(H hook);
private void setCommitStatusPendingIfNecessary(Job<?, ?> job, H hook) {
String buildName = PendingBuildsUtil.resolvePendingBuildName(job);
String buildName = PendingBuildsHandler.resolvePendingBuildName(job);
if (StringUtils.isNotBlank(buildName)) {
GitLabClient client = job.getProperty(GitLabConnectionProperty.class).getClient();
BuildStatusUpdate buildStatusUpdate = retrieveBuildStatusUpdate(hook);

View File

@ -1,4 +1,4 @@
package com.dabsquared.gitlabjenkins.util;
package com.dabsquared.gitlabjenkins.trigger.handler;
import com.dabsquared.gitlabjenkins.GitLabPushTrigger;
import com.dabsquared.gitlabjenkins.cause.CauseData;
@ -7,6 +7,7 @@ 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;
@ -18,11 +19,11 @@ import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import java.util.logging.Level;
import java.util.logging.Logger;
public class PendingBuildsUtil {
public class PendingBuildsHandler {
private static final Logger LOGGER = Logger.getLogger(PendingBuildsUtil.class.getName());
private static final Logger LOGGER = Logger.getLogger(PendingBuildsHandler.class.getName());
public static void cancelPendingBuilds(Job<?, ?> job, Integer projectId, String branch) {
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())) {
@ -43,7 +44,7 @@ public class PendingBuildsUtil {
}
}
private static GitLabWebHookCause getGitLabWebHookCauseData(Queue.Item item) {
private GitLabWebHookCause getGitLabWebHookCauseData(Queue.Item item) {
for (Cause cause : item.getCauses()) {
if (cause instanceof GitLabWebHookCause) {
return (GitLabWebHookCause) cause;
@ -52,7 +53,7 @@ public class PendingBuildsUtil {
return null;
}
private static void cancel(Queue.Item item, Queue queue, String branch) {
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);
@ -61,7 +62,7 @@ public class PendingBuildsUtil {
}
}
private static void setCommitStatusCancelledIfNecessary(CauseData causeData, Job<?, ?> job) {
private void setCommitStatusCancelledIfNecessary(CauseData causeData, Job<?, ?> job) {
String buildName = resolvePendingBuildName(job);
if (StringUtils.isBlank(buildName)) {
return;

View File

@ -12,7 +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.util.PendingBuildsUtil;
import com.dabsquared.gitlabjenkins.trigger.handler.PendingBuildsHandler;
import hudson.model.Job;
import hudson.model.Run;
import hudson.plugins.git.GitSCM;
@ -88,7 +88,7 @@ class MergeRequestHookTriggerHandlerImpl extends AbstractWebHookTriggerHandler<M
if (!hook.getObjectAttributes().getAction().equals(Action.update)) {
return;
}
PendingBuildsUtil.cancelPendingBuilds(job, hook.getObjectAttributes().getSourceProjectId(), hook.getObjectAttributes().getSourceBranch());
this.pendingBuildsHandler.cancelPendingBuilds(job, hook.getObjectAttributes().getSourceProjectId(), hook.getObjectAttributes().getSourceBranch());
}
@Override

View File

@ -15,7 +15,7 @@ import com.dabsquared.gitlabjenkins.gitlab.hook.model.State;
import com.dabsquared.gitlabjenkins.trigger.filter.BranchFilter;
import com.dabsquared.gitlabjenkins.trigger.filter.MergeRequestLabelFilter;
import com.dabsquared.gitlabjenkins.util.LoggerUtil;
import com.dabsquared.gitlabjenkins.util.PendingBuildsUtil;
import com.dabsquared.gitlabjenkins.trigger.handler.PendingBuildsHandler;
import hudson.model.Action;
import hudson.model.CauseAction;
import hudson.model.Job;
@ -47,11 +47,9 @@ class OpenMergeRequestPushHookTriggerHandler implements PushHookTriggerHandler {
private final static Logger LOGGER = Logger.getLogger(OpenMergeRequestPushHookTriggerHandler.class.getName());
private final boolean skipWorkInProgressMergeRequest;
private final boolean cancelPendingBuildsOnUpdate;
OpenMergeRequestPushHookTriggerHandler(boolean skipWorkInProgressMergeRequest, boolean cancelPendingBuildsOnUpdate) {
OpenMergeRequestPushHookTriggerHandler(boolean skipWorkInProgressMergeRequest) {
this.skipWorkInProgressMergeRequest = skipWorkInProgressMergeRequest;
this.cancelPendingBuildsOnUpdate = cancelPendingBuildsOnUpdate;
}
@Override
@ -74,7 +72,7 @@ class OpenMergeRequestPushHookTriggerHandler implements PushHookTriggerHandler {
}
}
}
} else {
LOGGER.log(Level.FINE, "Not a ParameterizedJob: {0}",LoggerUtil.toArray(job.getClass().getName()));
}
@ -116,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());
cancelPendingBuildsIfNecessary(job, mergeRequest.getSourceProjectId(), mergeRequest.getSourceBranch());
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()]));
@ -155,7 +152,7 @@ class OpenMergeRequestPushHookTriggerHandler implements PushHookTriggerHandler {
}
private void setCommitStatusPendingIfNecessary(Job<?, ?> job, Integer projectId, String commit, String ref) {
String buildName = PendingBuildsUtil.resolvePendingBuildName(job);
String buildName = PendingBuildsHandler.resolvePendingBuildName(job);
if (StringUtils.isNotBlank(buildName)) {
GitLabClient client = job.getProperty(GitLabConnectionProperty.class).getClient();
try {
@ -167,13 +164,6 @@ class OpenMergeRequestPushHookTriggerHandler implements PushHookTriggerHandler {
}
}
private void cancelPendingBuildsIfNecessary(Job<?, ?> job, Integer projectId, String branch) {
if (!this.cancelPendingBuildsOnUpdate) {
return;
}
PendingBuildsUtil.cancelPendingBuilds(job, projectId, branch);
}
private void scheduleBuild(Job<?, ?> job, Action[] actions) {
int projectBuildDelay = 0;
if (job instanceof ParameterizedJobMixIn.ParameterizedJob) {

View File

@ -14,10 +14,9 @@ public final class PushHookTriggerHandlerFactory {
public static PushHookTriggerHandler newPushHookTriggerHandler(boolean triggerOnPush,
TriggerOpenMergeRequest triggerOpenMergeRequestOnPush,
boolean skipWorkInProgressMergeRequest,
boolean cancelPendingBuildsOnUpdate) {
boolean skipWorkInProgressMergeRequest) {
if (triggerOnPush || triggerOpenMergeRequestOnPush == TriggerOpenMergeRequest.both) {
return new PushHookTriggerHandlerList(retrieveHandlers(triggerOnPush, triggerOpenMergeRequestOnPush, skipWorkInProgressMergeRequest, cancelPendingBuildsOnUpdate));
return new PushHookTriggerHandlerList(retrieveHandlers(triggerOnPush, triggerOpenMergeRequestOnPush, skipWorkInProgressMergeRequest));
} else {
return new NopPushHookTriggerHandler();
}
@ -25,14 +24,13 @@ public final class PushHookTriggerHandlerFactory {
private static List<PushHookTriggerHandler> retrieveHandlers(boolean triggerOnPush,
TriggerOpenMergeRequest triggerOpenMergeRequestOnPush,
boolean skipWorkInProgressMergeRequest,
boolean cancelPendingBuildsOnUpdate) {
boolean skipWorkInProgressMergeRequest) {
List<PushHookTriggerHandler> result = new ArrayList<>();
if (triggerOnPush) {
result.add(new PushHookTriggerHandlerImpl());
}
if (triggerOpenMergeRequestOnPush == TriggerOpenMergeRequest.both) {
result.add(new OpenMergeRequestPushHookTriggerHandler(skipWorkInProgressMergeRequest, cancelPendingBuildsOnUpdate));
result.add(new OpenMergeRequestPushHookTriggerHandler(skipWorkInProgressMergeRequest));
}
return result;
}

View File

@ -0,0 +1,217 @@
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(1, "commit1", BuildState.canceled, "sourceBranch", "Jenkins", null, BuildState.canceled.name());
verify(gitLabClient).changeBuildStatus(1, "commit2", BuildState.canceled, "sourceBranch", "Jenkins", null, 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;
}
}