New feature: Add support for regex based filtering and more

Two new features were introduced:

(1) Allow branch filtering through regular expressions
(2) Use branch filtering also for Merge Request events

By making use of radioBlocks, the user is forced to choose
between allowing all branches to trigger the job and filtering
the branches by one out of two possible approaches:

* filtering by name
* filtering by regular expression

[FIXED #97]
[FIXED #142]
This commit is contained in:
Oscar Salvador Morillo Victoria 2015-12-03 14:41:09 +01:00
parent a23cad0ced
commit 4da58e696b
6 changed files with 111 additions and 43 deletions

View File

@ -34,6 +34,7 @@ import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import jenkins.model.Jenkins;
import jenkins.model.ParameterizedJobMixIn;
@ -53,6 +54,7 @@ import org.kohsuke.stapler.StaplerRequest;
import org.springframework.util.AntPathMatcher;
import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.common.base.Splitter;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
@ -83,14 +85,17 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
private boolean addNoteOnMergeRequest = true;
private boolean addCiMessage = false;
private boolean addVoteOnMergeRequest = true;
private boolean allowAllBranches = false;
private final String branchFilterName;
private final String includeBranchesSpec;
private final String excludeBranchesSpec;
private final String targetBranchRegex;
private boolean acceptMergeRequestOnSuccess = false;
@DataBoundConstructor
public GitLabPushTrigger(boolean triggerOnPush, boolean triggerOnMergeRequest, String triggerOpenMergeRequestOnPush, boolean ciSkip, boolean setBuildDescription, boolean addNoteOnMergeRequest, boolean addCiMessage, boolean addVoteOnMergeRequest, boolean acceptMergeRequestOnSuccess, boolean allowAllBranches,
String includeBranchesSpec, String excludeBranchesSpec) {
public GitLabPushTrigger(boolean triggerOnPush, boolean triggerOnMergeRequest, String triggerOpenMergeRequestOnPush,
boolean ciSkip, boolean setBuildDescription, boolean addNoteOnMergeRequest, boolean addCiMessage,
boolean addVoteOnMergeRequest, boolean acceptMergeRequestOnSuccess, String branchFilterName,
String includeBranchesSpec, String excludeBranchesSpec, String targetBranchRegex) {
this.triggerOnPush = triggerOnPush;
this.triggerOnMergeRequest = triggerOnMergeRequest;
this.triggerOpenMergeRequestOnPush = triggerOpenMergeRequestOnPush;
@ -99,9 +104,10 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
this.addNoteOnMergeRequest = addNoteOnMergeRequest;
this.addCiMessage = addCiMessage;
this.addVoteOnMergeRequest = addVoteOnMergeRequest;
this.allowAllBranches = allowAllBranches;
this.branchFilterName = branchFilterName;
this.includeBranchesSpec = includeBranchesSpec;
this.excludeBranchesSpec = excludeBranchesSpec;
this.targetBranchRegex = targetBranchRegex;
this.acceptMergeRequestOnSuccess = acceptMergeRequestOnSuccess;
}
@ -133,10 +139,6 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
return acceptMergeRequestOnSuccess;
}
public boolean getAllowAllBranches() {
return allowAllBranches;
}
public boolean getAddCiMessage() {
return addCiMessage;
}
@ -144,7 +146,19 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
public boolean getCiSkip() {
return ciSkip;
}
private boolean isBranchAllowed(final String branchName) {
private boolean isAllowedByTargetBranchRegex(String branchName) {
final String regex = this.getTargetBranchRegex();
if (StringUtils.isEmpty(regex)) {
return true;
}
final Pattern pattern = Pattern.compile(regex);
return pattern.matcher(branchName).matches();
}
private boolean isAllowedByList(final String branchName) {
final List<String> exclude = DescriptorImpl.splitBranchSpec(this.getExcludeBranchesSpec());
final List<String> include = DescriptorImpl.splitBranchSpec(this.getIncludeBranchesSpec());
if (exclude.isEmpty() && include.isEmpty()) {
@ -166,6 +180,27 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
return false;
}
private boolean isBranchAllowed(final String branchName) {
final String branchFilterName = this.getBranchFilterName();
if (branchFilterName.isEmpty()) {
// no filter is applied, allow all branches
return true;
}
if (Objects.equal(branchFilterName, "NameBasedFilter")) {
return this.isAllowedByList(branchName);
}
if (Objects.equal(branchFilterName, "RegexBasedFilter")) {
return this.isAllowedByTargetBranchRegex(branchName);
}
return false;
}
public String getBranchFilterName() { return this.branchFilterName; }
public String getIncludeBranchesSpec() {
return this.includeBranchesSpec == null ? "" : this.includeBranchesSpec;
}
@ -174,6 +209,8 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
return this.excludeBranchesSpec == null ? "" : this.excludeBranchesSpec;
}
public String getTargetBranchRegex() { return this.targetBranchRegex == null ? "" : this.targetBranchRegex; }
// executes when the Trigger receives a push request
public void onPost(final GitLabPushRequest req) {
// TODO 1.621+ use standard method
@ -184,7 +221,8 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
}
};
if (triggerOnPush && (allowAllBranches || this.isBranchAllowed(this.getSourceBranch(req)))) {
if (triggerOnPush && this.isBranchAllowed(this.getSourceBranch(req))) {
getDescriptor().queue.execute(new Runnable() {
public void run() {
@ -311,7 +349,8 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
// executes when the Trigger receives a merge request
public void onPost(final GitLabMergeRequest req) {
if (triggerOnMergeRequest) {
if (triggerOnMergeRequest && this.isBranchAllowed(req.getObjectAttribute().getTargetBranch())) {
getDescriptor().queue.execute(new Runnable() {
public void run() {
LOGGER.log(Level.INFO, "{0} triggered for merge request.", job.getName());
@ -403,7 +442,7 @@ public class GitLabPushTrigger extends Trigger<Job<?, ?>> {
});
}
}
}
private Map<String, ParameterValue> getDefaultParameters() {

View File

@ -1,47 +1,62 @@
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout"
xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<f:entry title="Build on Merge Request Events" field="triggerOnMergeRequest">
<f:checkbox default="true" />
<f:checkbox default="true"/>
</f:entry>
<f:entry title="Build on Push Events" field="triggerOnPush">
<f:checkbox default="true" />
<f:checkbox default="true"/>
</f:entry>
<f:entry title="Rebuild open Merge Requests" field="triggerOpenMergeRequestOnPush">
<f:select/>
<f:select/>
</f:entry>
<f:entry title="Enable [ci-skip]" field="ciSkip">
<f:checkbox default="true" />
<f:checkbox default="true"/>
</f:entry>
<f:entry title="Set build description to build cause (eg. Merge request or Git Push )" field="setBuildDescription">
<f:checkbox default="true" />
<f:checkbox default="true"/>
</f:entry>
<f:entry title="Add note with build status on merge requests" field="addNoteOnMergeRequest">
<f:checkbox default="true" />
<f:checkbox default="true"/>
</f:entry>
<f:entry title="Use GitLab CI features (GitLab 8.1 required!)" field="addCiMessage" help="/plugin/gitlab-plugin/help/help-gitlab8.1CI.html">
<f:checkbox default="false"/>
<f:entry title="Use GitLab CI features (GitLab 8.1 required!)" field="addCiMessage"
help="/plugin/gitlab-plugin/help/help-gitlab8.1CI.html">
<f:checkbox default="false"/>
</f:entry>
<f:entry title="Vote added to note with build status on merge requests" field="addVoteOnMergeRequest">
<f:checkbox default="true" />
<f:entry title="Vote added to note with build status on merge requests" field="addVoteOnMergeRequest">
<f:checkbox default="true"/>
</f:entry>
<f:entry title="Accept merge request on success" field="acceptMergeRequestOnSuccess">
<f:checkbox default="false" />
</f:entry>
<f:entry title="All allow all branches (Ignoring Filtered Branches)" field="allowAllBranches">
<f:checkbox default="false" />
<f:entry title="Accept merge request on success" field="acceptMergeRequestOnSuccess">
<f:checkbox default="false"/>
</f:entry>
<f:block>
<table style="margin-left:10px">
<f:optionalBlock title="Filter branches" help="/plugin/gitlab-plugin/help/help-allowedBranches.html" inline="true" checked="${not (empty(instance.includeBranchesSpec) and empty(instance.excludeBranchesSpec))}">
<f:entry title="Include">
<f:textbox field="includeBranchesSpec" autocompleteDelimChar="," />
</f:entry>
<f:entry title="Exclude">
<f:textbox field="excludeBranchesSpec" autocompleteDelimChar="," />
</f:entry>
</f:optionalBlock>
</table>
<table style="margin-left:10px">
<!--<f:section title="">-->
<f:radioBlock name="branchFilterName" value="" title="Allow all branches to trigger this job"
checked="${instance.branchFilterName == ''}"
inline="true" help="/plugin/gitlab-plugin/help/help-noBranchFiltering.html"/>
<f:radioBlock name="branchFilterName" value="NameBasedFilter" title="Filter branches by name"
checked="${instance.branchFilterName == 'NameBasedFilter'}" inline="true"
help="/plugin/gitlab-plugin/help/help-allowedBranches.html">
<f:entry title="Include">
<f:textbox field="includeBranchesSpec" autocompleteDelimChar=","/>
</f:entry>
<f:entry title="Exclude">
<f:textbox field="excludeBranchesSpec" autocompleteDelimChar=","/>
</f:entry>
</f:radioBlock>
<f:radioBlock name="branchFilterName" value="RegexBasedFilter" title="Filter branches by regex"
checked="${instance.branchFilterName == 'RegexBasedFilter'}" inline="true"
help="/plugin/gitlab-plugin/help/help-filterBranchesByRegex.html">
<f:entry title="Target Branch Regex">
<f:textbox field="targetBranchRegex"/>
</f:entry>
</f:radioBlock>
<!--</f:section> -->
</table>
</f:block>
</j:jelly>

View File

@ -1,3 +1,4 @@
<div>
Comma-separated list of source branches allowed to trigger a build from a <b>Push event</b>.
<p>Comma-separated list of source branches allowed to trigger a build from a <b>Push event</b> or a <b>Merge Request event</b>.
If both fields are left empty, all branches are allowed to trigger this job.
For <b>Merge Request events</b> only the target branch name is filtered out by the include and exclude lists.
</div>

View File

@ -0,0 +1,9 @@
<div>
<div>
<p>The target branch regex allows to limit the execution of this job to certain branches. Any branch matching the specified pattern triggers the
job. No filtering is performed if the field is left empty.</p>
<p>Examples:</p>
<pre># Allow execution for debug and release branches: (.*debug.*|.*release.*) </pre>
<pre># Ignore any branch with `Release` or `release` as subword: ^(?:(?![R|r]elease).)*$ </pre>
</div>
</div>

View File

@ -0,0 +1,3 @@
<div>
<p>All branches are allowed to trigger this job.</p>
</div>

View File

@ -111,13 +111,14 @@ public abstract class AbstractGitLabPushTriggerGitlabServerTest {
boolean addCiMessage = true;
boolean addVoteOnMergeRequest = true;
boolean acceptMergeRequestOnSuccess = false;
boolean allowAllBranches = true;
String branchFilter = null;
String includeBranchesSpec = null;
String excludeBranchesSpec = null;
String targetBranchRegex = null;
GitLabPushTrigger gitLabPushTrigger = new GitLabPushTrigger(triggerOnPush, triggerOnMergeRequest,
triggerOpenMergeRequestOnPush, ciSkip, setBuildDescription, addNoteOnMergeRequest, addCiMessage,
addVoteOnMergeRequest, acceptMergeRequestOnSuccess, allowAllBranches, includeBranchesSpec,
excludeBranchesSpec);
addVoteOnMergeRequest, acceptMergeRequestOnSuccess, branchFilter, includeBranchesSpec,
excludeBranchesSpec, targetBranchRegex);
return gitLabPushTrigger;
}