From 0d54b1179ab982144c9a8460db25c53709bf49dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1mer=20B=C3=A1lint?= Date: Sat, 16 Nov 2019 20:51:47 +0100 Subject: [PATCH] Added option to reuse GitSCM's excluded users list --- .../cloudbees/jenkins/GitHubPushTrigger.java | 31 ++++ .../jenkins/GitHubPushTrigger/config.groovy | 6 + .../jenkins/GitHubPushTriggerTest.java | 153 ++++++++++++++++-- 3 files changed, 177 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/cloudbees/jenkins/GitHubPushTrigger.java b/src/main/java/com/cloudbees/jenkins/GitHubPushTrigger.java index 62259c733..7e9b924a1 100644 --- a/src/main/java/com/cloudbees/jenkins/GitHubPushTrigger.java +++ b/src/main/java/com/cloudbees/jenkins/GitHubPushTrigger.java @@ -11,6 +11,9 @@ import hudson.model.Item; import hudson.model.Job; import hudson.model.Project; +import hudson.plugins.git.GitSCM; +import hudson.plugins.git.extensions.impl.UserExclusion; +import hudson.scm.SCM; import hudson.triggers.SCMTrigger; import hudson.triggers.Trigger; import hudson.triggers.TriggerDescriptor; @@ -23,6 +26,7 @@ import jenkins.scm.api.SCMEvent; import jenkins.triggers.SCMTriggerItem; import jenkins.triggers.SCMTriggerItem.SCMTriggerItems; + import org.apache.commons.jelly.XMLOutput; import org.jenkinsci.plugins.github.GitHubPlugin; import org.jenkinsci.plugins.github.admin.GitHubHookRegisterProblemMonitor; @@ -34,6 +38,7 @@ import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.Stapler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,6 +70,7 @@ * @author Kohsuke Kawaguchi */ public class GitHubPushTrigger extends Trigger> implements GitHubTrigger { + private boolean useGitExcludedUsers; @DataBoundConstructor public GitHubPushTrigger() { @@ -98,6 +104,22 @@ public void onPost(final GitHubTriggerEvent event) { if (Objects.isNull(job)) { return; // nothing to do } + if (useGitExcludedUsers) { + Set excludedUsers = null; + if (job instanceof AbstractProject) { + SCM scm = ((AbstractProject) job).getScm(); + if (scm instanceof GitSCM) { + UserExclusion exclusions = ((GitSCM) scm).getExtensions().get(UserExclusion.class); + if (exclusions != null) { + excludedUsers = exclusions.getExcludedUsersNormalized(); + } + } + } + + if (excludedUsers != null && excludedUsers.contains(event.getTriggeredByUser())) { + return; // user is excluded from triggering build + } + } Job currentJob = notNull(job, "Job can't be null"); @@ -241,6 +263,15 @@ public DescriptorImpl getDescriptor() { return (DescriptorImpl) super.getDescriptor(); } + public boolean isUseGitExcludedUsers() { + return useGitExcludedUsers; + } + + @DataBoundSetter + public void setUseGitExcludedUsers(Boolean useGitExcludedUsers) { + this.useGitExcludedUsers = useGitExcludedUsers != null ? useGitExcludedUsers : false; + } + /** * Action object for {@link Project}. Used to display the polling log. */ diff --git a/src/main/resources/com/cloudbees/jenkins/GitHubPushTrigger/config.groovy b/src/main/resources/com/cloudbees/jenkins/GitHubPushTrigger/config.groovy index c9a140f5c..29e0ff909 100644 --- a/src/main/resources/com/cloudbees/jenkins/GitHubPushTrigger/config.groovy +++ b/src/main/resources/com/cloudbees/jenkins/GitHubPushTrigger/config.groovy @@ -2,6 +2,8 @@ package com.cloudbees.jenkins.GitHubPushTrigger import com.cloudbees.jenkins.GitHubPushTrigger +def f = namespace(lib.FormTagLib); + tr { td(colspan: 4) { div(id: 'gh-hooks-warn') @@ -18,3 +20,7 @@ InlineWarning.setup({ }).start(); """) } + +f.entry() { + f.checkbox(title: _("Use Git excluded user list (\"Polling ignores commits from certain users\")"), field: "useGitExcludedUsers") +} diff --git a/src/test/java/com/cloudbees/jenkins/GitHubPushTriggerTest.java b/src/test/java/com/cloudbees/jenkins/GitHubPushTriggerTest.java index 00a529c28..236b46206 100644 --- a/src/test/java/com/cloudbees/jenkins/GitHubPushTriggerTest.java +++ b/src/test/java/com/cloudbees/jenkins/GitHubPushTriggerTest.java @@ -1,10 +1,17 @@ package com.cloudbees.jenkins; -import hudson.model.FreeStyleProject; -import hudson.plugins.git.GitSCM; -import hudson.plugins.git.util.Build; -import hudson.plugins.git.util.BuildData; -import hudson.util.FormValidation; +import static com.cloudbees.jenkins.GitHubWebHookFullTest.classpath; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.jenkinsci.plugins.github.webhook.subscriber.DefaultPushGHEventListenerTest.TRIGGERED_BY_USER_FROM_RESOURCE; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.concurrent.TimeUnit; + +import javax.inject.Inject; + import org.eclipse.jgit.lib.ObjectId; import org.jenkinsci.plugins.github.admin.GitHubHookRegisterProblemMonitor; import org.jenkinsci.plugins.github.webhook.subscriber.DefaultPushGHEventListenerTest; @@ -16,16 +23,21 @@ import org.junit.Test; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; +import org.mockito.Mockito; -import javax.inject.Inject; -import java.io.IOException; -import java.util.HashMap; -import java.util.concurrent.TimeUnit; +import com.cloudbees.jenkins.GitHubPushTrigger.DescriptorImpl; -import static com.cloudbees.jenkins.GitHubWebHookFullTest.classpath; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.jenkinsci.plugins.github.webhook.subscriber.DefaultPushGHEventListenerTest.TRIGGERED_BY_USER_FROM_RESOURCE; +import hudson.model.FreeStyleProject; +import hudson.plugins.git.GitSCM; +import hudson.plugins.git.extensions.impl.UserExclusion; +import hudson.plugins.git.util.Build; +import hudson.plugins.git.util.BuildData; +import hudson.util.FormValidation; +import hudson.util.ReflectionUtils; +import hudson.util.SequentialExecutionQueue; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.times; /** * @author lanwen (Merkushev Kirill) @@ -96,4 +108,119 @@ public void shouldReturnOkOnNoAnyProblem() throws Exception { FormValidation validation = descriptor.doCheckHookRegistered(job); assertThat("all ok", validation.kind, is(FormValidation.Kind.OK)); } + + private SequentialExecutionQueue addSpyToQueueField() { + Field queueField = ReflectionUtils.findField(DescriptorImpl.class, "queue"); + ReflectionUtils.makeAccessible(queueField); + SequentialExecutionQueue queue = (SequentialExecutionQueue)ReflectionUtils.getField(queueField, descriptor); + SequentialExecutionQueue spiedQueue = Mockito.spy(queue); + ReflectionUtils.setField(queueField, descriptor, spiedQueue); + return spiedQueue; + } + + @Test + public void shouldSkipBuildIfExclusionEnabledWithMatchingUser() throws IOException { + SequentialExecutionQueue spiedQueue = addSpyToQueueField(); + + String matchingUserName = "userName"; + FreeStyleProject project = jRule.createFreeStyleProject(); + GitHubPushTrigger trigger = new GitHubPushTrigger(); + trigger.setUseGitExcludedUsers(true); + trigger.start(project, false); + project.addTrigger(trigger); + GitSCM scm = new GitSCM("https://localhost/dummy.git"); + UserExclusion userExclusion = new UserExclusion("something" + System.lineSeparator() + + matchingUserName + System.lineSeparator() + + "somethingElse" + System.lineSeparator()); + scm.getExtensions().add(userExclusion); + project.setScm(scm); + + GitHubTriggerEvent event = GitHubTriggerEvent.create() + .withTimestamp(System.currentTimeMillis()) + .withOrigin("origin") + .withTriggeredByUser(matchingUserName) + .build(); + trigger.onPost(event); + + verify(spiedQueue, times(0)).execute(Mockito.any(Runnable.class)); + } + + @Test + public void shouldTriggerBuildIfExclusionEnabledWithNonMatchingUser() throws IOException { + SequentialExecutionQueue spiedQueue = addSpyToQueueField(); + + FreeStyleProject project = jRule.createFreeStyleProject(); + GitHubPushTrigger trigger = new GitHubPushTrigger(); + trigger.setUseGitExcludedUsers(true); + trigger.start(project, false); + project.addTrigger(trigger); + GitSCM scm = new GitSCM("https://localhost/dummy.git"); + UserExclusion userExclusion = new UserExclusion("something" + System.lineSeparator() + + "nonMatchingUserName" + System.lineSeparator() + + "somethingElse" + System.lineSeparator()); + scm.getExtensions().add(userExclusion); + project.setScm(scm); + + GitHubTriggerEvent event = GitHubTriggerEvent.create() + .withTimestamp(System.currentTimeMillis()) + .withOrigin("origin") + .withTriggeredByUser("userName") + .build(); + trigger.onPost(event); + + verify(spiedQueue).execute(Mockito.any(Runnable.class)); + } + + @Test + public void shouldTriggerBuildIfExclusionDisabledWithMatchingUser() throws IOException { + SequentialExecutionQueue spiedQueue = addSpyToQueueField(); + + String matchingUserName = "userName"; + FreeStyleProject project = jRule.createFreeStyleProject(); + GitHubPushTrigger trigger = new GitHubPushTrigger(); + trigger.setUseGitExcludedUsers(false); + trigger.start(project, false); + project.addTrigger(trigger); + GitSCM scm = new GitSCM("https://localhost/dummy.git"); + UserExclusion userExclusion = new UserExclusion("something" + System.lineSeparator() + + matchingUserName + System.lineSeparator() + + "somethingElse" + System.lineSeparator()); + scm.getExtensions().add(userExclusion); + project.setScm(scm); + + GitHubTriggerEvent event = GitHubTriggerEvent.create() + .withTimestamp(System.currentTimeMillis()) + .withOrigin("origin") + .withTriggeredByUser(matchingUserName) + .build(); + trigger.onPost(event); + + verify(spiedQueue).execute(Mockito.any(Runnable.class)); + } + + @Test + public void shouldTriggerBuildIfExclusionDisabledWithNonMatchingUser() throws IOException { + SequentialExecutionQueue spiedQueue = addSpyToQueueField(); + + FreeStyleProject project = jRule.createFreeStyleProject(); + GitHubPushTrigger trigger = new GitHubPushTrigger(); + trigger.setUseGitExcludedUsers(false); + trigger.start(project, false); + project.addTrigger(trigger); + GitSCM scm = new GitSCM("https://localhost/dummy.git"); + UserExclusion userExclusion = new UserExclusion("something" + System.lineSeparator() + + "nonMatchingUserName" + System.lineSeparator() + + "somethingElse" + System.lineSeparator()); + scm.getExtensions().add(userExclusion); + project.setScm(scm); + + GitHubTriggerEvent event = GitHubTriggerEvent.create() + .withTimestamp(System.currentTimeMillis()) + .withOrigin("origin") + .withTriggeredByUser("userName") + .build(); + trigger.onPost(event); + + verify(spiedQueue).execute(Mockito.any(Runnable.class)); + } }