Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exclude users by name from triggering an event as a push event #1135

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ properties([
branchFilterType: "NameBasedFilter",
includeBranchesSpec: "release/qat",
excludeBranchesSpec: "",
userNameFilterType: "All",
]
])
])
Expand Down Expand Up @@ -482,7 +483,12 @@ Triggers may be filtered based on the branch name, i.e. the build will only be a

**Note:** This functionality requires access to GitLab and a git repository url already saved in the project configuration. In other words, when creating a new project, the configuration needs to be saved *once* before being able to add branch filters. For Pipeline jobs, the configuration must be saved *and* the job must be run once before the list is populated.

### Build when tags are pushed
## User name filtering
Triggers may be filtered based on the user name, i.e. the build will only be allowed for users not listed in excluded user names. On the project configuration page, when you configure the GitLab trigger, you can choose 'Filter users by name'.' Filter by name takes comma-separated lists of user names to exclude from triggering a build.

**Note:** This functionality requires access to GitLab and a git repository url already saved in the project configuration. In other words, when creating a new project, the configuration needs to be saved *once* before being able to add branch filters. For Pipeline jobs, the configuration must be saved *and* the job must be run once before the list is populated.

## Build when tags are pushed
In order to build when a new tag is pushed:
1. In the GitLab webhook configuration, add 'Tag push events'
2. In the job configuration under 'Source code management':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
import com.dabsquared.gitlabjenkins.trigger.filter.MergeRequestLabelFilter;
import com.dabsquared.gitlabjenkins.trigger.filter.MergeRequestLabelFilterConfig;
import com.dabsquared.gitlabjenkins.trigger.filter.MergeRequestLabelFilterFactory;
import com.dabsquared.gitlabjenkins.trigger.filter.UserNameFilter;
import com.dabsquared.gitlabjenkins.trigger.filter.UserNameFilterFactory;
import com.dabsquared.gitlabjenkins.trigger.filter.UserNameFilterType;
import com.dabsquared.gitlabjenkins.trigger.handler.merge.MergeRequestHookTriggerHandler;
import com.dabsquared.gitlabjenkins.trigger.handler.note.NoteHookTriggerHandler;
import com.dabsquared.gitlabjenkins.trigger.handler.pipeline.PipelineHookTriggerHandler;
Expand Down Expand Up @@ -63,6 +66,7 @@
import java.util.Collection;

import static com.dabsquared.gitlabjenkins.trigger.filter.BranchFilterConfig.BranchFilterConfigBuilder.branchFilterConfig;
import static com.dabsquared.gitlabjenkins.trigger.filter.UserNameFilterConfig.UserNameFilterConfigBuilder.userNameFilterConfig;
import static com.dabsquared.gitlabjenkins.trigger.handler.merge.MergeRequestHookTriggerHandlerFactory.newMergeRequestHookTriggerHandler;
import static com.dabsquared.gitlabjenkins.trigger.handler.note.NoteHookTriggerHandlerFactory.newNoteHookTriggerHandler;
import static com.dabsquared.gitlabjenkins.trigger.handler.pipeline.PipelineHookTriggerHandlerFactory.newPipelineHookTriggerHandler;
Expand Down Expand Up @@ -97,18 +101,23 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> implements MergeReques
private transient boolean addCiMessage;
private transient boolean addVoteOnMergeRequest;
private transient boolean allowAllBranches = false;
private transient boolean allowAllUserNames = false;
private transient String branchFilterName;
private BranchFilterType branchFilterType;
protected final String userNameFilterName;
private UserNameFilterType userNameFilterType;
private String includeBranchesSpec;
private String excludeBranchesSpec;
private String sourceBranchRegex;
private String targetBranchRegex;
protected final String excludeUserNamesSpec;
private MergeRequestLabelFilterConfig mergeRequestLabelFilterConfig;
private volatile Secret secretToken;
private String pendingBuildName;
private boolean cancelPendingBuildsOnUpdate;

private transient BranchFilter branchFilter;
private transient UserNameFilter userNameFilter;
private transient PushHookTriggerHandler pushHookTriggerHandler;
private transient MergeRequestHookTriggerHandler mergeRequestHookTriggerHandler;
private transient NoteHookTriggerHandler noteHookTriggerHandler;
Expand All @@ -128,7 +137,9 @@ public GitLabPushTrigger(boolean triggerOnPush, boolean triggerToBranchDeleteReq
boolean acceptMergeRequestOnSuccess, BranchFilterType branchFilterType,
String includeBranchesSpec, String excludeBranchesSpec, String sourceBranchRegex, String targetBranchRegex,
MergeRequestLabelFilterConfig mergeRequestLabelFilterConfig, String secretToken, boolean triggerOnPipelineEvent,
boolean triggerOnApprovedMergeRequest, String pendingBuildName, boolean cancelPendingBuildsOnUpdate) {
boolean triggerOnApprovedMergeRequest, String pendingBuildName, boolean cancelPendingBuildsOnUpdate, UserNameFilterType userNameFilterType,
String excludeUserNamesSpec
) {
this.triggerOnPush = triggerOnPush;
this.triggerToBranchDeleteRequest = triggerToBranchDeleteRequest;
this.triggerOnMergeRequest = triggerOnMergeRequest;
Expand All @@ -147,10 +158,12 @@ public GitLabPushTrigger(boolean triggerOnPush, boolean triggerToBranchDeleteReq
this.addCiMessage = addCiMessage;
this.addVoteOnMergeRequest = addVoteOnMergeRequest;
this.branchFilterType = branchFilterType;
this.userNameFilterType = userNameFilterType;
this.includeBranchesSpec = includeBranchesSpec;
this.excludeBranchesSpec = excludeBranchesSpec;
this.sourceBranchRegex = sourceBranchRegex;
this.targetBranchRegex = targetBranchRegex;
this.excludeUserNamesSpec = excludeUserNamesSpec;
this.acceptMergeRequestOnSuccess = acceptMergeRequestOnSuccess;
this.mergeRequestLabelFilterConfig = mergeRequestLabelFilterConfig;
this.secretToken = Secret.fromString(secretToken);
Expand All @@ -160,6 +173,7 @@ public GitLabPushTrigger(boolean triggerOnPush, boolean triggerToBranchDeleteReq

initializeTriggerHandler();
initializeBranchFilter();
initializeUserNameFilter();
initializeMergeRequestLabelFilter();
}

Expand Down Expand Up @@ -286,6 +300,10 @@ public BranchFilterType getBranchFilterType() {
return branchFilterType;
}

public UserNameFilterType getUserNameFilterType() {
return userNameFilterType;
}

public String getIncludeBranchesSpec() {
return includeBranchesSpec;
}
Expand All @@ -302,6 +320,10 @@ public String getTargetBranchRegex() {
return targetBranchRegex;
}

public String getExcludeUserNamesSpec() {
return excludeUserNamesSpec;
}

public MergeRequestLabelFilterConfig getMergeRequestLabelFilterConfig() {
return mergeRequestLabelFilterConfig;
}
Expand Down Expand Up @@ -409,11 +431,21 @@ public void setBranchFilterName(String branchFilterName) {
this.branchFilterName = branchFilterName;
}

@DataBoundSetter
public void setUserNameFilterName(String userNameFilterName) {
this.userNameFilterName = userNameFilterName;
}

@DataBoundSetter
public void setBranchFilterType(BranchFilterType branchFilterType) {
this.branchFilterType = branchFilterType;
}

@DataBoundSetter
public void setUserNameFilterType(UserNameFilterType userNameFilterType) {
this.userNameFilterType = userNameFilterType;
}

@DataBoundSetter
public void setIncludeBranchesSpec(String includeBranchesSpec) {
this.includeBranchesSpec = includeBranchesSpec;
Expand All @@ -424,6 +456,11 @@ public void setExcludeBranchesSpec(String excludeBranchesSpec) {
this.excludeBranchesSpec = excludeBranchesSpec;
}

@DataBoundSetter
public void setExcludeUserNamesSpec(String excludeUserNamesSpec) {
this.excludeUserNamesSpec = excludeUserNamesSpec;
}

@DataBoundSetter
public void setSourceBranchRegex(String sourceBranchRegex) {
this.sourceBranchRegex = sourceBranchRegex;
Expand Down Expand Up @@ -475,7 +512,10 @@ public void onPost(final PushHook hook) {
if (pushHookTriggerHandler == null) {
initializeTriggerHandler();
}
pushHookTriggerHandler.handle(job, hook, ciSkip, branchFilter, mergeRequestLabelFilter);
if (userNameFilter == null) {
initializeUserNameFilter();
}
pushHookTriggerHandler.handle(job, hook, ciSkip, branchFilter, mergeRequestLabelFilter, userNameFilter);
}

// executes when the Trigger receives a merge request
Expand All @@ -489,7 +529,10 @@ public void onPost(final MergeRequestHook hook) {
if (mergeRequestHookTriggerHandler == null) {
initializeTriggerHandler();
}
mergeRequestHookTriggerHandler.handle(job, hook, ciSkip, branchFilter, mergeRequestLabelFilter);
if (userNameFilter == null) {
initializeUserNameFilter();
}
mergeRequestHookTriggerHandler.handle(job, hook, ciSkip, branchFilter, mergeRequestLabelFilter, userNameFilter);
}

// executes when the Trigger receives a note request
Expand All @@ -503,7 +546,10 @@ public void onPost(final NoteHook hook) {
if (noteHookTriggerHandler == null) {
initializeTriggerHandler();
}
noteHookTriggerHandler.handle(job, hook, ciSkip, branchFilter, mergeRequestLabelFilter);
if (userNameFilter == null) {
initializeUserNameFilter();
}
noteHookTriggerHandler.handle(job, hook, ciSkip, branchFilter, mergeRequestLabelFilter, userNameFilter);
}

// executes when the Trigger receives a pipeline event
Expand All @@ -514,7 +560,10 @@ public void onPost(final PipelineHook hook) {
if (pipelineTriggerHandler == null) {
initializeTriggerHandler();
}
pipelineTriggerHandler.handle(job, hook, ciSkip, branchFilter, mergeRequestLabelFilter);
if (userNameFilter == null) {
initializeUserNameFilter();
}
pipelineTriggerHandler.handle(job, hook, ciSkip, branchFilter, mergeRequestLabelFilter, userNameFilter);
}

private void initializeTriggerHandler() {
Expand All @@ -537,13 +586,24 @@ private void initializeMergeRequestLabelFilter() {
mergeRequestLabelFilter = MergeRequestLabelFilterFactory.newMergeRequestLabelFilter(mergeRequestLabelFilterConfig);
}

private void initializeUserNameFilter() {
userNameFilter = UserNameFilterFactory.newUserNameFilter(userNameFilterConfig()
.withExcludeUserNamesSpec(excludeUserNamesSpec)
.build(userNameFilterType)
);
}

@Override
protected Object readResolve() throws ObjectStreamException {
if (branchFilterType == null) {
branchFilterType = StringUtils.isNotBlank(branchFilterName) ? BranchFilterType.valueOf(branchFilterName) : BranchFilterType.All;
}
if (userNameFilterType == null) {
userNameFilterType = StringUtils.isNotBlank(userNameFilterName) ? UserNameFilterType.valueOf(userNameFilterName) : UserNameFilterType.All;
}
initializeTriggerHandler();
initializeBranchFilter();
initializeUserNameFilter();
initializeMergeRequestLabelFilter();
return super.readResolve();
}
Expand Down Expand Up @@ -642,7 +702,6 @@ public AutoCompletionCandidates doAutoCompleteIncludeBranchesSpec(@AncestorInPat
public AutoCompletionCandidates doAutoCompleteExcludeBranchesSpec(@AncestorInPath final Job<?, ?> job, @QueryParameter final String value) {
return ProjectBranchesProvider.instance().doAutoCompleteBranchesSpec(job, value);
}

public FormValidation doCheckIncludeBranchesSpec(@AncestorInPath final Job<?, ?> project, @QueryParameter final String value) {
return ProjectBranchesProvider.instance().doCheckBranchesSpec(project, value);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.dabsquared.gitlabjenkins.trigger.filter;

/**
* @author Robin Müller
*/
class AllUserNamesFilter implements UserNameFilter {
@Override
public boolean isUserNameAllowed(String userName) {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.dabsquared.gitlabjenkins.trigger.filter;

import com.google.common.base.Splitter;
import org.springframework.util.AntPathMatcher;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;



/**
* @author jean flores
*/
class UserNameBasedFilter implements UserNameFilter {
private static final Logger LOGGER = Logger.getLogger(UserNameBasedFilter.class.getName());


private final List<String> excludedUserNames;

public UserNameBasedFilter(String excludedUserNames) {
this.excludedUserNames = convert(excludedUserNames);
}
@Override
public boolean isUserNameAllowed(String userName) {
return hasNoUserNameSpecs() || isUserNameNotExcluded(userName);
}

private boolean hasNoUserNameSpecs() {
return excludedUserNames.isEmpty();
}

private boolean isUserNameNotExcluded(String userName) {
AntPathMatcher matcher = new AntPathMatcher();
for (String excludePattern : excludedUserNames) {
LOGGER.log(Level.INFO, "excludedUserNames");
LOGGER.log(Level.INFO, excludePattern);
LOGGER.log(Level.INFO, userName);
if (matcher.match(excludePattern, userName)) {
return false;
}
}
return true;
}

private List<String> convert(String commaSeparatedString) {
if (commaSeparatedString == null)
return Collections.EMPTY_LIST;

ArrayList<String> result = new ArrayList<>();
for (String s : Splitter.on(',').omitEmptyStrings().trimResults().split(commaSeparatedString)) {
result.add(s);
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.dabsquared.gitlabjenkins.trigger.filter;

/**
* @author Robin Müller
*/
public interface UserNameFilter {

boolean isUserNameAllowed(String userName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.dabsquared.gitlabjenkins.trigger.filter;

/**
* @author jean flores
*/
public final class UserNameFilterConfig {

private final UserNameFilterType type;
private final String excludeUserNamesSpec;

private UserNameFilterConfig(UserNameFilterType type, String excludeUserNamesSpec) {
this.type = type;
this.excludeUserNamesSpec = excludeUserNamesSpec;
}

public UserNameFilterType getType() {
return type;
}

String getExcludeUserNamesSpec() {
return excludeUserNamesSpec;
}

public static class UserNameFilterConfigBuilder {
private String excludeUserNamesSpec;

public static UserNameFilterConfigBuilder userNameFilterConfig() {
return new UserNameFilterConfigBuilder();
}

public UserNameFilterConfigBuilder withExcludeUserNamesSpec(String excludeUserNamesSpec) {
this.excludeUserNamesSpec = excludeUserNamesSpec;
return this;
}

public UserNameFilterConfig build(UserNameFilterType type) {
return new UserNameFilterConfig(type, excludeUserNamesSpec);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.dabsquared.gitlabjenkins.trigger.filter;

/**
* @author jean flores
*/
public final class UserNameFilterFactory {

private UserNameFilterFactory() { }

public static UserNameFilter newUserNameFilter(UserNameFilterConfig config) {

if(config == null)
return new AllUserNamesFilter();

switch (config.getType()) {
case NameBasedFilter:
return new UserNameBasedFilter(config.getExcludeUserNamesSpec());
default:
return new AllUserNamesFilter();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.dabsquared.gitlabjenkins.trigger.filter;

/**
* @author jean flores
*/
public enum UserNameFilterType {
All,
NameBasedFilter
}
Loading