diff --git a/README.md b/README.md index 4aaae77d..d41af969 100644 --- a/README.md +++ b/README.md @@ -443,6 +443,7 @@ The following behaviours apply to both `Multibranch Pipeline Jobs` and `Folder O * `Only Branches that are not also filed as MRs` - If you are discovering origin merge requests, it may not make sense to discover the same changes both as a merge request and as a branch. * `Only Branches that are filed as MRs` - This option exists to preserve legacy behaviour when upgrading from older versions of the plugin. NOTE: If you have an actual use case for this option please file a merge request against this text. + * `Only explicitly listed branches` - Only branches matching the "Branches to always include" regex are built as branches. Useful when builing only long-lived branches (e.g. `main`) and MRs (discovered separately). * `All Branches` - Ignores whether the branch is also filed as a merge request and instead discovers all branches on the origin project. * `Discover merge requests from origin` - To discover merge requests made from origin branches. diff --git a/src/main/java/io/jenkins/plugins/gitlabbranchsource/BranchDiscoveryTrait.java b/src/main/java/io/jenkins/plugins/gitlabbranchsource/BranchDiscoveryTrait.java index 8d54480e..454c6a94 100644 --- a/src/main/java/io/jenkins/plugins/gitlabbranchsource/BranchDiscoveryTrait.java +++ b/src/main/java/io/jenkins/plugins/gitlabbranchsource/BranchDiscoveryTrait.java @@ -143,6 +143,9 @@ protected void decorateContext(SCMSourceContext context) { ctx.wantOriginMRs(true); ctx.withFilter(new OnlyOriginMRBranchesSCMHeadFilter(getBranchesAlwaysIncludedRegexPattern())); break; + case 4: + ctx.withFilter(new OnlyExplicitlyListedBranchesSCMHeadFilter(getBranchesAlwaysIncludedRegexPattern())); + break; case 3: default: // we don't care if it is a MR or not, we're taking them all, no need to ask for MRs and no need @@ -204,6 +207,7 @@ public ListBoxModel doFillStrategyIdItems() { ListBoxModel result = new ListBoxModel(); result.add(Messages.BranchDiscoveryTrait_excludeMRs(), "1"); result.add(Messages.BranchDiscoveryTrait_onlyMRs(), "2"); + result.add(Messages.BranchDiscoveryTrait_onlyExplicitlyListed(), "4"); result.add(Messages.BranchDiscoveryTrait_allBranches(), "3"); return result; } @@ -249,9 +253,10 @@ public String getDisplayName() { } /** - * Filter that excludes branches that are also filed as a merge request. + * Base class for branch filters that support an always-included regex. + * Handles the common filter then delegates to {@link #isExcludedBranch} for strategy-specific logic. */ - public static class ExcludeOriginMRBranchesSCMHeadFilter extends SCMHeadFilter { + public abstract static class BranchDiscoverySCMHeadFilter extends SCMHeadFilter { /** * The compiled {@link Pattern} of the branchesAlwaysIncludedRegex. @@ -263,7 +268,7 @@ public static class ExcludeOriginMRBranchesSCMHeadFilter extends SCMHeadFilter { * * @param branchesAlwaysIncludedRegexPattern the branchesAlwaysIncludedRegexPattern. */ - public ExcludeOriginMRBranchesSCMHeadFilter(Pattern branchesAlwaysIncludedRegexPattern) { + protected BranchDiscoverySCMHeadFilter(Pattern branchesAlwaysIncludedRegexPattern) { this.branchesAlwaysIncludedRegexPattern = branchesAlwaysIncludedRegexPattern; } @@ -271,15 +276,42 @@ public ExcludeOriginMRBranchesSCMHeadFilter(Pattern branchesAlwaysIncludedRegexP * {@inheritDoc} */ @Override - public boolean isExcluded(@NonNull SCMSourceRequest request, @NonNull SCMHead head) { - if (head instanceof BranchSCMHead && request instanceof GitLabSCMSourceRequest) { - if (branchesAlwaysIncludedRegexPattern != null - && branchesAlwaysIncludedRegexPattern - .matcher(head.getName()) - .matches()) { - return false; - } + public final boolean isExcluded(@NonNull SCMSourceRequest request, @NonNull SCMHead head) { + if (!(head instanceof BranchSCMHead)) { + return false; + } + if (branchesAlwaysIncludedRegexPattern != null + && branchesAlwaysIncludedRegexPattern + .matcher(head.getName()) + .matches()) { + return false; + } + return isExcludedBranch(request, (BranchSCMHead) head); + } + + /** + * Strategy-specific exclusion logic, called only for branch heads not covered by + * the always-included regex. + * + * @param request the current SCM source request. + * @param head the branch head being evaluated. + * @return {@code true} if the branch should be excluded from discovery. + */ + protected abstract boolean isExcludedBranch(@NonNull SCMSourceRequest request, @NonNull BranchSCMHead head); + } + /** + * Filter that excludes branches that are also filed as a merge request. + */ + public static class ExcludeOriginMRBranchesSCMHeadFilter extends BranchDiscoverySCMHeadFilter { + + public ExcludeOriginMRBranchesSCMHeadFilter(Pattern branchesAlwaysIncludedRegexPattern) { + super(branchesAlwaysIncludedRegexPattern); + } + + @Override + protected boolean isExcludedBranch(@NonNull SCMSourceRequest request, @NonNull BranchSCMHead head) { + if (request instanceof GitLabSCMSourceRequest) { for (MergeRequest m : ((GitLabSCMSourceRequest) request).getMergeRequests()) { // only match if the merge request is an origin merge request if (m.getSourceProjectId().equals(m.getTargetProjectId()) @@ -295,35 +327,15 @@ public boolean isExcluded(@NonNull SCMSourceRequest request, @NonNull SCMHead he /** * Filter that excludes branches that are not also filed as a merge request. */ - public static class OnlyOriginMRBranchesSCMHeadFilter extends SCMHeadFilter { - - /** - * The compiled {@link Pattern} of the branchesAlwaysIncludedRegex. - */ - private final Pattern branchesAlwaysIncludedRegexPattern; + public static class OnlyOriginMRBranchesSCMHeadFilter extends BranchDiscoverySCMHeadFilter { - /** - * Constructor - * - * @param branchesAlwaysIncludedRegexPattern the branchesAlwaysIncludedRegexPattern. - */ public OnlyOriginMRBranchesSCMHeadFilter(Pattern branchesAlwaysIncludedRegexPattern) { - this.branchesAlwaysIncludedRegexPattern = branchesAlwaysIncludedRegexPattern; + super(branchesAlwaysIncludedRegexPattern); } - /** - * {@inheritDoc} - */ @Override - public boolean isExcluded(@NonNull SCMSourceRequest request, @NonNull SCMHead head) { - if (head instanceof BranchSCMHead && request instanceof GitLabSCMSourceRequest) { - if (branchesAlwaysIncludedRegexPattern != null - && branchesAlwaysIncludedRegexPattern - .matcher(head.getName()) - .matches()) { - return false; - } - + protected boolean isExcludedBranch(@NonNull SCMSourceRequest request, @NonNull BranchSCMHead head) { + if (request instanceof GitLabSCMSourceRequest) { for (MergeRequest m : ((GitLabSCMSourceRequest) request).getMergeRequests()) { if (m.getSourceProjectId().equals(m.getTargetProjectId()) && !m.getSourceBranch().equalsIgnoreCase(head.getName())) { @@ -334,4 +346,19 @@ public boolean isExcluded(@NonNull SCMSourceRequest request, @NonNull SCMHead he return false; } } + + /** + * Filter that excludes all branches except those matching the always-included regex. + */ + public static class OnlyExplicitlyListedBranchesSCMHeadFilter extends BranchDiscoverySCMHeadFilter { + + public OnlyExplicitlyListedBranchesSCMHeadFilter(Pattern branchesAlwaysIncludedRegexPattern) { + super(branchesAlwaysIncludedRegexPattern); + } + + @Override + protected boolean isExcludedBranch(@NonNull SCMSourceRequest request, @NonNull BranchSCMHead head) { + return true; + } + } } diff --git a/src/main/resources/io/jenkins/plugins/gitlabbranchsource/BranchDiscoveryTrait/help-strategyId.html b/src/main/resources/io/jenkins/plugins/gitlabbranchsource/BranchDiscoveryTrait/help-strategyId.html index 23b39c31..7be6fd96 100644 --- a/src/main/resources/io/jenkins/plugins/gitlabbranchsource/BranchDiscoveryTrait/help-strategyId.html +++ b/src/main/resources/io/jenkins/plugins/gitlabbranchsource/BranchDiscoveryTrait/help-strategyId.html @@ -20,5 +20,9 @@ on the origin project. +
Only explicitly listed branches
+
+ Only branches matching the "Branches to always include" regex are built as branches. +
diff --git a/src/main/resources/io/jenkins/plugins/gitlabbranchsource/Messages.properties b/src/main/resources/io/jenkins/plugins/gitlabbranchsource/Messages.properties index 633c68ee..4b47ee74 100644 --- a/src/main/resources/io/jenkins/plugins/gitlabbranchsource/Messages.properties +++ b/src/main/resources/io/jenkins/plugins/gitlabbranchsource/Messages.properties @@ -4,6 +4,7 @@ BranchDiscoveryTrait.authorityDisplayName=Trust origin branches BranchDiscoveryTrait.displayName=Discover branches BranchDiscoveryTrait.excludeMRs=Only branches that are not also filed as MRs BranchDiscoveryTrait.onlyMRs=Only branches that are also filed as MRs +BranchDiscoveryTrait.onlyExplicitlyListed=Only explicitly listed branches ExcludeArchivedRepositoriesTrait.displayName=Exclude archived repositories BuildStatusNameCustomPartTrait.displayName=Customize GitLab build status name ForkMergeRequestDiscoveryTrait.displayName=Discover merge requests from forks