11package io .jenkins .plugins .gitlabbranchsource ;
22
3+ import edu .umd .cs .findbugs .annotations .CheckForNull ;
34import edu .umd .cs .findbugs .annotations .NonNull ;
45import hudson .Extension ;
56import hudson .util .ListBoxModel ;
7+ import java .util .regex .Pattern ;
68import jenkins .scm .api .SCMHead ;
79import jenkins .scm .api .SCMHeadCategory ;
810import jenkins .scm .api .SCMHeadOrigin ;
@@ -32,20 +34,33 @@ public class BranchDiscoveryTrait extends SCMSourceTrait {
3234 */
3335 private int strategyId ;
3436
37+ /**
38+ * Regex of branches that should always be included regardless of whether a merge request exists or not.
39+ */
40+ private String branchesAlwaysIncludedRegex ;
41+
42+ /**
43+ * The compiled {@link Pattern} of the branchesAlwaysIncludedRegex.
44+ */
45+ @ CheckForNull
46+ private transient Pattern branchesAlwaysIncludedRegexPattern ;
47+
3548 /**
3649 * Constructor for stapler.
3750 *
3851 * @param strategyId the strategy id.
52+ * @param branchesAlwaysIncludedRegex the branchesAlwaysIncludedRegex.
3953 */
4054 @ DataBoundConstructor
41- public BranchDiscoveryTrait (int strategyId ) {
55+ public BranchDiscoveryTrait (int strategyId , String branchesAlwaysIncludedRegex ) {
4256 this .strategyId = strategyId ;
57+ this .branchesAlwaysIncludedRegex = branchesAlwaysIncludedRegex ;
4358 }
4459
4560 /**
4661 * Constructor for legacy code.
4762 *
48- * @param buildBranch build branches that are not filed as a MR.
63+ * @param buildBranch build branches that are not filed as a MR.
4964 * @param buildBranchWithMr build branches that are also MRs.
5065 */
5166 public BranchDiscoveryTrait (boolean buildBranch , boolean buildBranchWithMr ) {
@@ -61,6 +76,28 @@ public int getStrategyId() {
6176 return strategyId ;
6277 }
6378
79+ /**
80+ * Returns the branchesAlwaysIncludedRegex.
81+ *
82+ * @return the branchesAlwaysIncludedRegex.
83+ */
84+ public String getBranchesAlwaysIncludedRegex () {
85+ return branchesAlwaysIncludedRegex ;
86+ }
87+
88+ /**
89+ * Returns the compiled {@link Pattern} of the branchesAlwaysIncludedRegex.
90+ *
91+ * @return the branchesAlwaysIncludedRegexPattern.
92+ */
93+ public Pattern getBranchesAlwaysIncludedRegexPattern () {
94+ if (branchesAlwaysIncludedRegex != null && branchesAlwaysIncludedRegexPattern == null ) {
95+ branchesAlwaysIncludedRegexPattern = Pattern .compile (branchesAlwaysIncludedRegex );
96+ }
97+
98+ return branchesAlwaysIncludedRegexPattern ;
99+ }
100+
64101 /**
65102 * Returns {@code true} if building branches that are not filed as a MR.
66103 *
@@ -92,11 +129,11 @@ protected void decorateContext(SCMSourceContext<?, ?> context) {
92129 switch (strategyId ) {
93130 case 1 :
94131 ctx .wantOriginMRs (true );
95- ctx .withFilter (new ExcludeOriginMRBranchesSCMHeadFilter ());
132+ ctx .withFilter (new ExcludeOriginMRBranchesSCMHeadFilter (getBranchesAlwaysIncludedRegexPattern () ));
96133 break ;
97134 case 2 :
98135 ctx .wantOriginMRs (true );
99- ctx .withFilter (new OnlyOriginMRBranchesSCMHeadFilter ());
136+ ctx .withFilter (new OnlyOriginMRBranchesSCMHeadFilter (getBranchesAlwaysIncludedRegexPattern () ));
100137 break ;
101138 case 3 :
102139 default :
@@ -208,12 +245,33 @@ public String getDisplayName() {
208245 */
209246 public static class ExcludeOriginMRBranchesSCMHeadFilter extends SCMHeadFilter {
210247
248+ /**
249+ * The compiled {@link Pattern} of the branchesAlwaysIncludedRegex.
250+ */
251+ private final Pattern branchesAlwaysIncludedRegexPattern ;
252+
253+ /**
254+ * Constructor
255+ *
256+ * @param branchesAlwaysIncludedRegexPattern the branchesAlwaysIncludedRegexPattern.
257+ */
258+ public ExcludeOriginMRBranchesSCMHeadFilter (Pattern branchesAlwaysIncludedRegexPattern ) {
259+ this .branchesAlwaysIncludedRegexPattern = branchesAlwaysIncludedRegexPattern ;
260+ }
261+
211262 /**
212263 * {@inheritDoc}
213264 */
214265 @ Override
215266 public boolean isExcluded (@ NonNull SCMSourceRequest request , @ NonNull SCMHead head ) {
216267 if (head instanceof BranchSCMHead && request instanceof GitLabSCMSourceRequest ) {
268+ if (branchesAlwaysIncludedRegexPattern != null
269+ && branchesAlwaysIncludedRegexPattern
270+ .matcher (head .getName ())
271+ .matches ()) {
272+ return false ;
273+ }
274+
217275 for (MergeRequest m : ((GitLabSCMSourceRequest ) request ).getMergeRequests ()) {
218276 // only match if the merge request is an origin merge request
219277 if (m .getSourceProjectId ().equals (m .getTargetProjectId ())
@@ -231,12 +289,33 @@ public boolean isExcluded(@NonNull SCMSourceRequest request, @NonNull SCMHead he
231289 */
232290 public static class OnlyOriginMRBranchesSCMHeadFilter extends SCMHeadFilter {
233291
292+ /**
293+ * The compiled {@link Pattern} of the branchesAlwaysIncludedRegex.
294+ */
295+ private final Pattern branchesAlwaysIncludedRegexPattern ;
296+
297+ /**
298+ * Constructor
299+ *
300+ * @param branchesAlwaysIncludedRegexPattern the branchesAlwaysIncludedRegexPattern.
301+ */
302+ public OnlyOriginMRBranchesSCMHeadFilter (Pattern branchesAlwaysIncludedRegexPattern ) {
303+ this .branchesAlwaysIncludedRegexPattern = branchesAlwaysIncludedRegexPattern ;
304+ }
305+
234306 /**
235307 * {@inheritDoc}
236308 */
237309 @ Override
238310 public boolean isExcluded (@ NonNull SCMSourceRequest request , @ NonNull SCMHead head ) {
239311 if (head instanceof BranchSCMHead && request instanceof GitLabSCMSourceRequest ) {
312+ if (branchesAlwaysIncludedRegexPattern != null
313+ && branchesAlwaysIncludedRegexPattern
314+ .matcher (head .getName ())
315+ .matches ()) {
316+ return false ;
317+ }
318+
240319 for (MergeRequest m : ((GitLabSCMSourceRequest ) request ).getMergeRequests ()) {
241320 if (m .getSourceProjectId ().equals (m .getTargetProjectId ())
242321 && !m .getSourceBranch ().equalsIgnoreCase (head .getName ())) {
0 commit comments