From ff87925bd2b510f3cdf2df8ed69446ccafba959e Mon Sep 17 00:00:00 2001 From: Nikolas Falco Date: Wed, 21 May 2025 23:04:30 +0200 Subject: [PATCH] [JENKINS-75691] Add trait to include the ref spec of target branch of pull requests This could be useful if you need perform a changelog or some software need to individuate the new code for example SonarQube PR analysis. --- ...itbucketBuildStatusNotificationsTrait.java | 19 +-- .../BitbucketSCMSourceTraitDescriptor.java | 80 ++++++++++++ .../bitbucket/trait/BranchDiscoveryTrait.java | 22 +--- .../trait/DiscardOldBranchTrait.java | 14 +-- .../bitbucket/trait/DiscardOldTagTrait.java | 11 +- .../trait/ForkPullRequestDiscoveryTrait.java | 25 +--- .../OriginPullRequestDiscoveryTrait.java | 22 +--- .../PublicRepoPullRequestFilterTrait.java | 24 +--- .../PullRequestTargetBranchRefSpecTrait.java | 118 ++++++++++++++++++ .../bitbucket/trait/SSHCheckoutTrait.java | 41 +----- .../trait/ShowBitbucketAvatarTrait.java | 16 +-- .../bitbucket/trait/TagDiscoveryTrait.java | 20 +-- .../trait/WebhookConfigurationTrait.java | 19 +-- .../trait/WebhookRegistrationTrait.java | 21 +--- .../plugins/bitbucket/Messages.properties | 3 + .../config.jelly | 26 ++++ .../help.html | 26 ++++ .../PublicRepoPullRequestFilterTraitTest.java | 1 - ...llRequestTargetBranchRefSpecTraitTest.java | 67 ++++++++++ 19 files changed, 339 insertions(+), 236 deletions(-) create mode 100644 src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/BitbucketSCMSourceTraitDescriptor.java create mode 100644 src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/PullRequestTargetBranchRefSpecTrait.java create mode 100644 src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/trait/PullRequestTargetBranchRefSpecTrait/config.jelly create mode 100644 src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/trait/PullRequestTargetBranchRefSpecTrait/help.html create mode 100644 src/test/java/com/cloudbees/jenkins/plugins/bitbucket/trait/PullRequestTargetBranchRefSpecTraitTest.java diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/BitbucketBuildStatusNotificationsTrait.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/BitbucketBuildStatusNotificationsTrait.java index db9907ce5..5ba54518b 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/BitbucketBuildStatusNotificationsTrait.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/BitbucketBuildStatusNotificationsTrait.java @@ -28,10 +28,8 @@ import com.cloudbees.jenkins.plugins.bitbucket.Messages; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Extension; -import jenkins.scm.api.SCMSource; import jenkins.scm.api.trait.SCMSourceContext; import jenkins.scm.api.trait.SCMSourceTrait; -import jenkins.scm.api.trait.SCMSourceTraitDescriptor; import org.jenkinsci.Symbol; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; @@ -146,7 +144,7 @@ protected void decorateContext(SCMSourceContext context) { */ @Symbol("bitbucketBuildStatusNotifications") @Extension - public static class DescriptorImpl extends SCMSourceTraitDescriptor { + public static class DescriptorImpl extends BitbucketSCMSourceTraitDescriptor { /** * {@inheritDoc} @@ -156,20 +154,5 @@ public String getDisplayName() { return Messages.BitbucketBuildStatusNotificationsTrait_displayName(); } - /** - * {@inheritDoc} - */ - @Override - public Class getContextClass() { - return BitbucketSCMSourceContext.class; - } - - /** - * {@inheritDoc} - */ - @Override - public Class getSourceClass() { - return BitbucketSCMSource.class; - } } } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/BitbucketSCMSourceTraitDescriptor.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/BitbucketSCMSourceTraitDescriptor.java new file mode 100644 index 000000000..fc5ec2745 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/BitbucketSCMSourceTraitDescriptor.java @@ -0,0 +1,80 @@ +/* + * The MIT License + * + * Copyright (c) 2025, Falco Nikolas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.cloudbees.jenkins.plugins.bitbucket.trait; + +import com.cloudbees.jenkins.plugins.bitbucket.BitbucketGitSCMBuilder; +import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource; +import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSourceContext; +import hudson.model.Descriptor; +import hudson.plugins.git.GitSCM; +import hudson.scm.SCM; +import jenkins.scm.api.SCMSource; +import jenkins.scm.api.trait.SCMBuilder; +import jenkins.scm.api.trait.SCMSourceContext; +import jenkins.scm.api.trait.SCMSourceTrait; +import jenkins.scm.api.trait.SCMSourceTraitDescriptor; + +/** + * Abstract base class for {@link Descriptor} of {@link SCMSourceTrait} + * implementations specific for bitbucket. + * + * @since 936.3.0 + */ +abstract class BitbucketSCMSourceTraitDescriptor extends SCMSourceTraitDescriptor { + + /** + * {@inheritDoc} + */ + @SuppressWarnings("rawtypes") + @Override + public Class getContextClass() { + return BitbucketSCMSourceContext.class; + } + + /** + * {@inheritDoc} + */ + @Override + public Class getSourceClass() { + return BitbucketSCMSource.class; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("rawtypes") + @Override + public Class getBuilderClass() { + return BitbucketGitSCMBuilder.class; + } + + /** + * {@inheritDoc} + */ + @Override + public Class getScmClass() { + return GitSCM.class; + } + +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/BranchDiscoveryTrait.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/BranchDiscoveryTrait.java index 2c372c3b4..0f92db212 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/BranchDiscoveryTrait.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/BranchDiscoveryTrait.java @@ -23,7 +23,6 @@ */ package com.cloudbees.jenkins.plugins.bitbucket.trait; -import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource; import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSourceContext; import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSourceRequest; import com.cloudbees.jenkins.plugins.bitbucket.BranchSCMHead; @@ -38,14 +37,12 @@ import jenkins.scm.api.SCMHeadCategory; import jenkins.scm.api.SCMHeadOrigin; import jenkins.scm.api.SCMRevision; -import jenkins.scm.api.SCMSource; import jenkins.scm.api.trait.SCMHeadAuthority; import jenkins.scm.api.trait.SCMHeadAuthorityDescriptor; import jenkins.scm.api.trait.SCMHeadFilter; import jenkins.scm.api.trait.SCMSourceContext; import jenkins.scm.api.trait.SCMSourceRequest; import jenkins.scm.api.trait.SCMSourceTrait; -import jenkins.scm.api.trait.SCMSourceTraitDescriptor; import jenkins.scm.impl.trait.Discovery; import org.apache.commons.lang3.StringUtils; import org.jenkinsci.Symbol; @@ -158,7 +155,7 @@ public boolean includeCategory(@NonNull SCMHeadCategory category) { @Symbol("bitbucketBranchDiscovery") @Extension @Discovery - public static class DescriptorImpl extends SCMSourceTraitDescriptor { + public static class DescriptorImpl extends BitbucketSCMSourceTraitDescriptor { /** * {@inheritDoc} @@ -168,22 +165,6 @@ public String getDisplayName() { return Messages.BranchDiscoveryTrait_displayName(); } - /** - * {@inheritDoc} - */ - @Override - public Class getContextClass() { - return BitbucketSCMSourceContext.class; - } - - /** - * {@inheritDoc} - */ - @Override - public Class getSourceClass() { - return BitbucketSCMSource.class; - } - /** * Populates the strategy options. * @@ -191,7 +172,6 @@ public Class getSourceClass() { */ @NonNull @Restricted(NoExternalUse.class) - @SuppressWarnings("unused") // stapler public ListBoxModel doFillStrategyIdItems() { ListBoxModel result = new ListBoxModel(); result.add(Messages.BranchDiscoveryTrait_excludePRs(), "1"); diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/DiscardOldBranchTrait.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/DiscardOldBranchTrait.java index bb49739ed..2f355874c 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/DiscardOldBranchTrait.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/DiscardOldBranchTrait.java @@ -23,7 +23,6 @@ */ package com.cloudbees.jenkins.plugins.bitbucket.trait; -import com.cloudbees.jenkins.plugins.bitbucket.BitbucketGitSCMBuilder; import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSourceRequest; import com.cloudbees.jenkins.plugins.bitbucket.Messages; import com.cloudbees.jenkins.plugins.bitbucket.PullRequestSCMHead; @@ -35,12 +34,10 @@ import java.io.IOException; import java.time.LocalDate; import jenkins.scm.api.SCMHead; -import jenkins.scm.api.trait.SCMBuilder; import jenkins.scm.api.trait.SCMHeadFilter; import jenkins.scm.api.trait.SCMSourceContext; import jenkins.scm.api.trait.SCMSourceRequest; import jenkins.scm.api.trait.SCMSourceTrait; -import jenkins.scm.api.trait.SCMSourceTraitDescriptor; import org.jenkinsci.Symbol; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; @@ -109,11 +106,11 @@ private LocalDate asLocalDate(@NonNull long milliseconds) { */ @Symbol("bitbucketDiscardOldBranch") @Extension - public static class DescriptorImpl extends SCMSourceTraitDescriptor { + public static class DescriptorImpl extends BitbucketSCMSourceTraitDescriptor { public FormValidation doCheckKeepForDays(@QueryParameter final int keepForDays) { if (keepForDays <= 0) { - return FormValidation.error("Invalid value. Days must be greater than 0"); + return FormValidation.error(Messages.DiscardOldBranchTrait_invalidDays()); } return FormValidation.ok(); } @@ -123,13 +120,6 @@ public String getDisplayName() { return Messages.DiscardOldBranchTrait_displayName(); } - /** - * {@inheritDoc} - */ - @Override - public boolean isApplicableToBuilder(@SuppressWarnings("rawtypes") @NonNull Class builderClass) { - return BitbucketGitSCMBuilder.class.isAssignableFrom(builderClass); - } } } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/DiscardOldTagTrait.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/DiscardOldTagTrait.java index 0ab41e2a2..8cd0105a7 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/DiscardOldTagTrait.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/DiscardOldTagTrait.java @@ -23,7 +23,6 @@ */ package com.cloudbees.jenkins.plugins.bitbucket.trait; -import com.cloudbees.jenkins.plugins.bitbucket.BitbucketGitSCMBuilder; import com.cloudbees.jenkins.plugins.bitbucket.Messages; import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; @@ -33,11 +32,9 @@ import jenkins.scm.api.SCMHead; import jenkins.scm.api.SCMSource; import jenkins.scm.api.mixin.TagSCMHead; -import jenkins.scm.api.trait.SCMBuilder; import jenkins.scm.api.trait.SCMHeadPrefilter; import jenkins.scm.api.trait.SCMSourceContext; import jenkins.scm.api.trait.SCMSourceTrait; -import jenkins.scm.api.trait.SCMSourceTraitDescriptor; import org.jenkinsci.Symbol; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; @@ -96,11 +93,11 @@ private LocalDate asLocalDate(@NonNull long milliseconds) { @Symbol("bitbucketDiscardOldTag") @Extension - public static class DescriptorImpl extends SCMSourceTraitDescriptor { + public static class DescriptorImpl extends BitbucketSCMSourceTraitDescriptor { public FormValidation doCheckKeepForDays(@QueryParameter int keepForDays) { if (keepForDays <= 0) { - return FormValidation.error("Invalid value. Days must be greater than 0"); + return FormValidation.error(Messages.DiscardOldTagTrait_invalidDays()); } return FormValidation.ok(); } @@ -110,10 +107,6 @@ public String getDisplayName() { return Messages.DiscardOldTagTrait_displayName(); } - @Override - public boolean isApplicableToBuilder(@NonNull Class builderClass) { - return BitbucketGitSCMBuilder.class.isAssignableFrom(builderClass); - } } } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/ForkPullRequestDiscoveryTrait.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/ForkPullRequestDiscoveryTrait.java index d9d20dbce..04b297c8f 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/ForkPullRequestDiscoveryTrait.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/ForkPullRequestDiscoveryTrait.java @@ -23,7 +23,6 @@ */ package com.cloudbees.jenkins.plugins.bitbucket.trait; -import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource; import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSourceContext; import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSourceRequest; import com.cloudbees.jenkins.plugins.bitbucket.Messages; @@ -39,14 +38,12 @@ import jenkins.scm.api.SCMHeadCategory; import jenkins.scm.api.SCMHeadOrigin; import jenkins.scm.api.SCMRevision; -import jenkins.scm.api.SCMSource; import jenkins.scm.api.mixin.ChangeRequestCheckoutStrategy; import jenkins.scm.api.mixin.ChangeRequestSCMHead2; import jenkins.scm.api.trait.SCMHeadAuthority; import jenkins.scm.api.trait.SCMHeadAuthorityDescriptor; import jenkins.scm.api.trait.SCMSourceContext; import jenkins.scm.api.trait.SCMSourceTrait; -import jenkins.scm.api.trait.SCMSourceTraitDescriptor; import jenkins.scm.impl.ChangeRequestSCMHeadCategory; import jenkins.scm.impl.trait.Discovery; import org.apache.commons.lang3.StringUtils; @@ -166,7 +163,7 @@ public boolean includeCategory(@NonNull SCMHeadCategory category) { @Symbol("bitbucketForkDiscovery") @Extension @Discovery - public static class DescriptorImpl extends SCMSourceTraitDescriptor { + public static class DescriptorImpl extends BitbucketSCMSourceTraitDescriptor { /** * {@inheritDoc} @@ -176,22 +173,6 @@ public String getDisplayName() { return Messages.ForkPullRequestDiscoveryTrait_displayName(); } - /** - * {@inheritDoc} - */ - @Override - public Class getContextClass() { - return BitbucketSCMSourceContext.class; - } - - /** - * {@inheritDoc} - */ - @Override - public Class getSourceClass() { - return BitbucketSCMSource.class; - } - /** * Populates the strategy options. * @@ -199,7 +180,6 @@ public Class getSourceClass() { */ @NonNull @Restricted(NoExternalUse.class) - @SuppressWarnings("unused") // stapler public ListBoxModel doFillStrategyIdItems() { ListBoxModel result = new ListBoxModel(); result.add(Messages.ForkPullRequestDiscoveryTrait_mergeOnly(), "1"); @@ -213,8 +193,8 @@ public ListBoxModel doFillStrategyIdItems() { * * @return the list of appropriate {@link SCMHeadAuthorityDescriptor} instances. */ + @SuppressWarnings("unchecked") @NonNull - @SuppressWarnings("unused") // stapler public List getTrustDescriptors() { return SCMHeadAuthority._for( BitbucketSCMSourceRequest.class, @@ -230,7 +210,6 @@ public List getTrustDescriptors() { * @return the default trust for new instances of {@link ForkPullRequestDiscoveryTrait}. */ @NonNull - @SuppressWarnings("unused") // stapler public SCMHeadAuthority getDefaultTrust() { return new TrustTeamForks(); } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/OriginPullRequestDiscoveryTrait.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/OriginPullRequestDiscoveryTrait.java index ad0bffa15..b2c92d9f3 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/OriginPullRequestDiscoveryTrait.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/OriginPullRequestDiscoveryTrait.java @@ -23,7 +23,6 @@ */ package com.cloudbees.jenkins.plugins.bitbucket.trait; -import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource; import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSourceContext; import com.cloudbees.jenkins.plugins.bitbucket.Messages; import edu.umd.cs.findbugs.annotations.NonNull; @@ -34,7 +33,6 @@ import jenkins.scm.api.SCMHeadCategory; import jenkins.scm.api.SCMHeadOrigin; import jenkins.scm.api.SCMRevision; -import jenkins.scm.api.SCMSource; import jenkins.scm.api.mixin.ChangeRequestCheckoutStrategy; import jenkins.scm.api.mixin.ChangeRequestSCMHead2; import jenkins.scm.api.trait.SCMHeadAuthority; @@ -42,7 +40,6 @@ import jenkins.scm.api.trait.SCMSourceContext; import jenkins.scm.api.trait.SCMSourceRequest; import jenkins.scm.api.trait.SCMSourceTrait; -import jenkins.scm.api.trait.SCMSourceTraitDescriptor; import jenkins.scm.impl.ChangeRequestSCMHeadCategory; import jenkins.scm.impl.trait.Discovery; import org.jenkinsci.Symbol; @@ -135,7 +132,7 @@ public boolean includeCategory(@NonNull SCMHeadCategory category) { @Symbol("bitbucketPullRequestDiscovery") @Extension @Discovery - public static class DescriptorImpl extends SCMSourceTraitDescriptor { + public static class DescriptorImpl extends BitbucketSCMSourceTraitDescriptor { /** * {@inheritDoc} @@ -145,22 +142,6 @@ public String getDisplayName() { return "Discover pull requests from origin"; } - /** - * {@inheritDoc} - */ - @Override - public Class getContextClass() { - return BitbucketSCMSourceContext.class; - } - - /** - * {@inheritDoc} - */ - @Override - public Class getSourceClass() { - return BitbucketSCMSource.class; - } - /** * Populates the strategy options. * @@ -168,7 +149,6 @@ public Class getSourceClass() { */ @NonNull @Restricted(NoExternalUse.class) - @SuppressWarnings("unused") // stapler public ListBoxModel doFillStrategyIdItems() { ListBoxModel result = new ListBoxModel(); result.add(Messages.ForkPullRequestDiscoveryTrait_mergeOnly(), "1"); diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/PublicRepoPullRequestFilterTrait.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/PublicRepoPullRequestFilterTrait.java index 2d6fbd7cc..072831079 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/PublicRepoPullRequestFilterTrait.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/PublicRepoPullRequestFilterTrait.java @@ -21,18 +21,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - package com.cloudbees.jenkins.plugins.bitbucket.trait; -import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource; import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSourceContext; import com.cloudbees.jenkins.plugins.bitbucket.Messages; import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; -import jenkins.scm.api.SCMSource; import jenkins.scm.api.trait.SCMSourceContext; import jenkins.scm.api.trait.SCMSourceTrait; -import jenkins.scm.api.trait.SCMSourceTraitDescriptor; import jenkins.scm.impl.trait.Discovery; import org.jenkinsci.Symbol; import org.kohsuke.stapler.DataBoundConstructor; @@ -64,7 +60,7 @@ protected void decorateContext(SCMSourceContext context) { @Symbol("bitbucketPublicRepoPullRequestFilter") @Extension @Discovery - public static class DescriptorImpl extends SCMSourceTraitDescriptor { + public static class DescriptorImpl extends BitbucketSCMSourceTraitDescriptor { /** * {@inheritDoc} */ @@ -73,22 +69,6 @@ public static class DescriptorImpl extends SCMSourceTraitDescriptor { public String getDisplayName() { return Messages.PublicRepoPullRequestFilterTrait_displayName(); } - - /** - * {@inheritDoc} - */ - @Override - public Class getContextClass() { - return BitbucketSCMSourceContext.class; - } - - /** - * {@inheritDoc} - */ - @Override - public Class getSourceClass() { - return BitbucketSCMSource.class; - } - } + } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/PullRequestTargetBranchRefSpecTrait.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/PullRequestTargetBranchRefSpecTrait.java new file mode 100644 index 000000000..019f6d290 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/PullRequestTargetBranchRefSpecTrait.java @@ -0,0 +1,118 @@ +/* + * The MIT License + * + * Copyright (c) 2025, Falco Nikolas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.cloudbees.jenkins.plugins.bitbucket.trait; + +import com.cloudbees.jenkins.plugins.bitbucket.Messages; +import com.cloudbees.jenkins.plugins.bitbucket.PullRequestSCMHead; +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.Extension; +import hudson.plugins.git.GitSCM; +import hudson.scm.SCM; +import jenkins.plugins.git.AbstractGitSCMSource; +import jenkins.plugins.git.GitSCMBuilder; +import jenkins.plugins.git.GitSCMSourceContext; +import jenkins.scm.api.SCMHead; +import jenkins.scm.api.trait.SCMBuilder; +import jenkins.scm.api.trait.SCMSourceContext; +import jenkins.scm.api.trait.SCMSourceTrait; +import jenkins.scm.api.trait.SCMSourceTraitDescriptor; +import org.jenkinsci.Symbol; +import org.kohsuke.stapler.DataBoundConstructor; + +/** + * Exposes the target branch of pull request as ref specs of a + * {@link AbstractGitSCMSource} as a {@link SCMSourceTrait}. + * + * @author Nikolas Falco + * @since 936.2.0 + * @see Original source + */ +public class PullRequestTargetBranchRefSpecTrait extends SCMSourceTrait { + + /** + * Constructor for stapler. + */ + @DataBoundConstructor + public PullRequestTargetBranchRefSpecTrait() { + // for stapler + } + + /** + * {@inheritDoc} + */ + @Override + protected void decorateBuilder(SCMBuilder builder) { + if (builder instanceof GitSCMBuilder gitBuilder) { + SCMHead head = builder.head(); + if (head instanceof PullRequestSCMHead prHead) { + String targetBranch = prHead.getTarget().getName(); + gitBuilder.withRefSpec("+refs/heads/" + targetBranch + ":refs/remotes/@{remote}/" + targetBranch); + } + } + } + + /** + * Our descriptor. + */ + @Symbol("bitbucketPRTargetBranchRefSpec") + @Extension + public static class DescriptorImpl extends SCMSourceTraitDescriptor { + + /** + * {@inheritDoc} + */ + @NonNull + @Override + public String getDisplayName() { + return Messages.PullRequestTargetBranchRefSpecTrait_displayName(); + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("rawtypes") + @Override + public Class getBuilderClass() { + return GitSCMBuilder.class; + } + + /** + * {@inheritDoc} + */ + @Override + public Class getScmClass() { + return GitSCM.class; + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("rawtypes") + @Override + public Class getContextClass() { + return GitSCMSourceContext.class; + } + + } +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/SSHCheckoutTrait.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/SSHCheckoutTrait.java index 3718abae8..494cc593a 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/SSHCheckoutTrait.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/SSHCheckoutTrait.java @@ -25,7 +25,6 @@ import com.cloudbees.jenkins.plugins.bitbucket.BitbucketGitSCMBuilder; import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource; -import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSourceContext; import com.cloudbees.jenkins.plugins.bitbucket.Messages; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketRepositoryProtocol; import com.cloudbees.jenkins.plugins.sshcredentials.SSHUserPrivateKey; @@ -41,16 +40,12 @@ import hudson.model.Item; import hudson.model.Queue; import hudson.plugins.git.GitSCM; -import hudson.scm.SCMDescriptor; import hudson.security.ACL; import hudson.util.FormValidation; import hudson.util.ListBoxModel; import jenkins.model.Jenkins; -import jenkins.scm.api.SCMSource; import jenkins.scm.api.trait.SCMBuilder; -import jenkins.scm.api.trait.SCMSourceContext; import jenkins.scm.api.trait.SCMSourceTrait; -import jenkins.scm.api.trait.SCMSourceTraitDescriptor; import org.apache.commons.lang3.StringUtils; import org.jenkinsci.Symbol; import org.kohsuke.accmod.Restricted; @@ -117,7 +112,7 @@ protected void decorateBuilder(SCMBuilder builder) { */ @Symbol("bitbucketSshCheckout") @Extension - public static class DescriptorImpl extends SCMSourceTraitDescriptor { + public static class DescriptorImpl extends BitbucketSCMSourceTraitDescriptor { /** * {@inheritDoc} @@ -128,38 +123,6 @@ public String getDisplayName() { return Messages.SSHCheckoutTrait_displayName(); } - /** - * {@inheritDoc} - */ - @Override - public Class getContextClass() { - return BitbucketSCMSourceContext.class; - } - - /** - * {@inheritDoc} - */ - @Override - public Class getSourceClass() { - return BitbucketSCMSource.class; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isApplicableToBuilder(@NonNull Class builderClass) { - return BitbucketGitSCMBuilder.class.isAssignableFrom(builderClass); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isApplicableToSCM(@NonNull SCMDescriptor scm) { - return scm instanceof GitSCM.DescriptorImpl; - } - /** * Form completion. * @@ -169,7 +132,6 @@ public boolean isApplicableToSCM(@NonNull SCMDescriptor scm) { * @return the form items. */ @Restricted(NoExternalUse.class) - @SuppressWarnings("unused") // stapler form binding public ListBoxModel doFillCredentialsIdItems(@CheckForNull @AncestorInPath Item context, @QueryParameter String serverUrl, @QueryParameter String credentialsId) { @@ -200,7 +162,6 @@ public ListBoxModel doFillCredentialsIdItems(@CheckForNull @AncestorInPath Item * @return the validation results */ @Restricted(NoExternalUse.class) - @SuppressWarnings("unused") // stapler form binding public FormValidation doCheckCredentialsId(@CheckForNull @AncestorInPath Item context, @QueryParameter String serverUrl, @QueryParameter String value) { diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/ShowBitbucketAvatarTrait.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/ShowBitbucketAvatarTrait.java index 00fe9fa48..879bc4a54 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/ShowBitbucketAvatarTrait.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/ShowBitbucketAvatarTrait.java @@ -23,13 +23,9 @@ */ package com.cloudbees.jenkins.plugins.bitbucket.trait; -import com.cloudbees.jenkins.plugins.bitbucket.BitbucketGitSCMBuilder; import com.cloudbees.jenkins.plugins.bitbucket.Messages; -import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; -import jenkins.scm.api.trait.SCMBuilder; import jenkins.scm.api.trait.SCMSourceTrait; -import jenkins.scm.api.trait.SCMSourceTraitDescriptor; import org.jenkinsci.Symbol; import org.kohsuke.stapler.DataBoundConstructor; @@ -48,20 +44,16 @@ public ShowBitbucketAvatarTrait() { @Symbol("showBitbucketAvatar") @Extension - public static class DescriptorImpl extends SCMSourceTraitDescriptor { - - @Override - public String getDisplayName() { - return Messages.ShowBitbucketAvatarTrait_displayName(); - } + public static class DescriptorImpl extends BitbucketSCMSourceTraitDescriptor { /** * {@inheritDoc} */ @Override - public boolean isApplicableToBuilder(@SuppressWarnings("rawtypes") @NonNull Class builderClass) { - return BitbucketGitSCMBuilder.class.isAssignableFrom(builderClass); + public String getDisplayName() { + return Messages.ShowBitbucketAvatarTrait_displayName(); } + } } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/TagDiscoveryTrait.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/TagDiscoveryTrait.java index 76176cd62..6d83fa7fd 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/TagDiscoveryTrait.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/TagDiscoveryTrait.java @@ -23,7 +23,6 @@ */ package com.cloudbees.jenkins.plugins.bitbucket.trait; -import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource; import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSourceContext; import com.cloudbees.jenkins.plugins.bitbucket.BitbucketTagSCMHead; import com.cloudbees.jenkins.plugins.bitbucket.Messages; @@ -32,13 +31,11 @@ import jenkins.plugins.git.GitTagSCMRevision; import jenkins.scm.api.SCMHeadCategory; import jenkins.scm.api.SCMHeadOrigin; -import jenkins.scm.api.SCMSource; import jenkins.scm.api.trait.SCMHeadAuthority; import jenkins.scm.api.trait.SCMHeadAuthorityDescriptor; import jenkins.scm.api.trait.SCMSourceContext; import jenkins.scm.api.trait.SCMSourceRequest; import jenkins.scm.api.trait.SCMSourceTrait; -import jenkins.scm.api.trait.SCMSourceTraitDescriptor; import jenkins.scm.impl.TagSCMHeadCategory; import jenkins.scm.impl.trait.Discovery; import org.jenkinsci.Symbol; @@ -81,7 +78,7 @@ public boolean includeCategory(@NonNull SCMHeadCategory category) { @Symbol("bitbucketTagDiscovery") @Extension @Discovery - public static class DescriptorImpl extends SCMSourceTraitDescriptor { + public static class DescriptorImpl extends BitbucketSCMSourceTraitDescriptor { /** * {@inheritDoc} @@ -91,21 +88,6 @@ public String getDisplayName() { return Messages.TagDiscoveryTrait_displayName(); } - /** - * {@inheritDoc} - */ - @Override - public Class getContextClass() { - return BitbucketSCMSourceContext.class; - } - - /** - * {@inheritDoc} - */ - @Override - public Class getSourceClass() { - return BitbucketSCMSource.class; - } } /** diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/WebhookConfigurationTrait.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/WebhookConfigurationTrait.java index 950ed8ab0..d0e5095be 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/WebhookConfigurationTrait.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/WebhookConfigurationTrait.java @@ -29,10 +29,8 @@ import com.cloudbees.jenkins.plugins.bitbucket.hooks.WebhookConfiguration; import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; -import jenkins.scm.api.SCMSource; import jenkins.scm.api.trait.SCMSourceContext; import jenkins.scm.api.trait.SCMSourceTrait; -import jenkins.scm.api.trait.SCMSourceTraitDescriptor; import org.jenkinsci.Symbol; import org.kohsuke.stapler.DataBoundConstructor; @@ -90,7 +88,7 @@ protected void decorateContext(SCMSourceContext context) { */ @Symbol("bitbucketWebhookConfiguration") @Extension - public static class DescriptorImpl extends SCMSourceTraitDescriptor { + public static class DescriptorImpl extends BitbucketSCMSourceTraitDescriptor { /** * {@inheritDoc} @@ -100,20 +98,5 @@ public String getDisplayName() { return Messages.WebhookConfigurationTrait_displayName(); } - /** - * {@inheritDoc} - */ - @Override - public Class getContextClass() { - return BitbucketSCMSourceContext.class; - } - - /** - * {@inheritDoc} - */ - @Override - public Class getSourceClass() { - return BitbucketSCMSource.class; - } } } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/WebhookRegistrationTrait.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/WebhookRegistrationTrait.java index 0c56196af..655a8acb0 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/WebhookRegistrationTrait.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/trait/WebhookRegistrationTrait.java @@ -31,10 +31,8 @@ import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; import hudson.util.ListBoxModel; -import jenkins.scm.api.SCMSource; import jenkins.scm.api.trait.SCMSourceContext; import jenkins.scm.api.trait.SCMSourceTrait; -import jenkins.scm.api.trait.SCMSourceTraitDescriptor; import org.jenkinsci.Symbol; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -96,7 +94,7 @@ protected void decorateContext(SCMSourceContext context) { */ @Symbol("bitbucketWebhookRegistration") @Extension - public static class DescriptorImpl extends SCMSourceTraitDescriptor { + public static class DescriptorImpl extends BitbucketSCMSourceTraitDescriptor { /** * {@inheritDoc} @@ -106,29 +104,12 @@ public String getDisplayName() { return Messages.WebhookRegistrationTrait_displayName(); } - /** - * {@inheritDoc} - */ - @Override - public Class getContextClass() { - return BitbucketSCMSourceContext.class; - } - - /** - * {@inheritDoc} - */ - @Override - public Class getSourceClass() { - return BitbucketSCMSource.class; - } - /** * Form completion. * * @return the mode options. */ @Restricted(NoExternalUse.class) - @SuppressWarnings("unused") // stapler form binding public ListBoxModel doFillModeItems() { ListBoxModel result = new ListBoxModel(); result.add(Messages.WebhookRegistrationTrait_disableHook(), WebhookRegistration.DISABLE.toString()); diff --git a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/Messages.properties b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/Messages.properties index 72d31da89..f3fa2c6ec 100644 --- a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/Messages.properties +++ b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/Messages.properties @@ -65,5 +65,8 @@ BitbucketTagSCMHead.Pronoun=Tag TagDiscoveryTrait.authorityDisplayName=Trust origin tags BitbucketBuildStatusNotificationsTrait.displayName=Bitbucket build status notifications DiscardOldBranchTrait.displayName=Discard branch older than given days +DiscardOldBranchTrait.invalidDays=Invalid value. Days must be greater than 0 DiscardOldTagTrait.displayName=Discard tag older than given days +DiscardOldTagTrait.invalidDays=Invalid value. Days must be greater than 0 ShowBitbucketAvatarTrait.displayName=Show Bitbucket avatar images +PullRequestTargetBranchRefSpecTrait.displayName=PullRequest target branch ref spec diff --git a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/trait/PullRequestTargetBranchRefSpecTrait/config.jelly b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/trait/PullRequestTargetBranchRefSpecTrait/config.jelly new file mode 100644 index 000000000..c8ac533f6 --- /dev/null +++ b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/trait/PullRequestTargetBranchRefSpecTrait/config.jelly @@ -0,0 +1,26 @@ + + + + diff --git a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/trait/PullRequestTargetBranchRefSpecTrait/help.html b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/trait/PullRequestTargetBranchRefSpecTrait/help.html new file mode 100644 index 000000000..46164afe4 --- /dev/null +++ b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/trait/PullRequestTargetBranchRefSpecTrait/help.html @@ -0,0 +1,26 @@ + +
+ Add the target branch of pull request as ref spec. +
\ No newline at end of file diff --git a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/trait/PublicRepoPullRequestFilterTraitTest.java b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/trait/PublicRepoPullRequestFilterTraitTest.java index 189128ca5..3d06797bc 100644 --- a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/trait/PublicRepoPullRequestFilterTraitTest.java +++ b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/trait/PublicRepoPullRequestFilterTraitTest.java @@ -24,7 +24,6 @@ package com.cloudbees.jenkins.plugins.bitbucket.trait; import com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSourceContext; -import com.cloudbees.jenkins.plugins.bitbucket.trait.PublicRepoPullRequestFilterTrait; import jenkins.scm.api.SCMHeadObserver; import org.junit.ClassRule; import org.junit.Test; diff --git a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/trait/PullRequestTargetBranchRefSpecTraitTest.java b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/trait/PullRequestTargetBranchRefSpecTraitTest.java new file mode 100644 index 000000000..597a82581 --- /dev/null +++ b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/trait/PullRequestTargetBranchRefSpecTraitTest.java @@ -0,0 +1,67 @@ +/* + * The MIT License + * + * Copyright (c) 2025, Falco Nikolas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.cloudbees.jenkins.plugins.bitbucket.trait; + +import com.cloudbees.jenkins.plugins.bitbucket.BitbucketGitSCMBuilder; +import com.cloudbees.jenkins.plugins.bitbucket.BitbucketGitSCMRevision; +import com.cloudbees.jenkins.plugins.bitbucket.BranchSCMHead; +import com.cloudbees.jenkins.plugins.bitbucket.PullRequestSCMHead; +import jenkins.plugins.git.GitSCMBuilder; +import jenkins.scm.api.SCMHead; +import org.assertj.core.api.Assertions; +import org.eclipse.jgit.transport.RefSpec; +import org.junit.Test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class PullRequestTargetBranchRefSpecTraitTest { + + @Test + public void verify_that_pull_request_target_branch_is_added_as_ref_spec() throws Exception { + PullRequestSCMHead head = mock(PullRequestSCMHead.class); + when(head.getTarget()).thenReturn(new SCMHead("support/1.x")); + BitbucketGitSCMRevision revision = mock(BitbucketGitSCMRevision.class); + GitSCMBuilder ctx = new GitSCMBuilder<>(head, revision, "origin", null); + + PullRequestTargetBranchRefSpecTrait trait = new PullRequestTargetBranchRefSpecTrait(); + trait.decorateBuilder(ctx); + + Assertions.assertThat(ctx.asRefSpecs()).contains(new RefSpec("+refs/heads/support/1.x:refs/remotes/origin/support/1.x")); + } + + @Test + public void verify_that_no_ref_spec_is_added_for_non_pull_request() throws Exception { + BranchSCMHead head = mock(BranchSCMHead.class); + when(head.getName()).thenReturn("support/1.x"); + BitbucketGitSCMRevision revision = mock(BitbucketGitSCMRevision.class); + GitSCMBuilder ctx = new GitSCMBuilder<>(head, revision, "origin", null); + + PullRequestTargetBranchRefSpecTrait trait = new PullRequestTargetBranchRefSpecTrait(); + trait.decorateBuilder(ctx); + + Assertions.assertThat(ctx.asRefSpecs()).containsOnly(new RefSpec("+refs/heads/*:refs/remotes/origin/*")); + } + +}