From bab739d46af15dbbfabb02a90fff57f2824cbb06 Mon Sep 17 00:00:00 2001 From: Nikolas Falco Date: Sat, 27 Sep 2025 10:36:11 +0200 Subject: [PATCH] [JENKINS-76108] Alternative for setManageHooks Add new API interfaces to lookup builder used to instantiate a BitbucketWebhookConfiguration. --- .../endpoint/BitbucketEndpointProvider.java | 22 ++++ .../BitbucketWebhookConfigurationBuilder.java | 76 +++++++++++++ ...BitbucketWebhookConfigurationsBuilder.java | 77 +++++++++++++ ...eBitbucketWebhookConfigurationBuilder.java | 45 ++++++++ .../impl/endpoint/BitbucketCloudEndpoint.java | 14 ++- ...bucketWebhookConfigurationBuilderImpl.java | 58 ++++++++++ .../CloudWebhookConfigurationBuilderImpl.java | 49 +++++++++ .../plugin/PluginWebhookConfiguration.java | 8 +- .../PluginWebhookConfigurationBuilder.java | 63 +++++++++++ .../server/ServerWebhookConfiguration.java | 2 +- ...ServerWebhookConfigurationBuilderImpl.java | 48 ++++++++ ...ucketWebhookConfigurationsBuilderTest.java | 104 ++++++++++++++++++ 12 files changed, 562 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/BitbucketWebhookConfigurationBuilder.java create mode 100644 src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/BitbucketWebhookConfigurationsBuilder.java create mode 100644 src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/NativeBitbucketWebhookConfigurationBuilder.java create mode 100644 src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/AbstractBitbucketWebhookConfigurationBuilderImpl.java create mode 100644 src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/cloud/CloudWebhookConfigurationBuilderImpl.java create mode 100644 src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/plugin/PluginWebhookConfigurationBuilder.java create mode 100644 src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/server/ServerWebhookConfigurationBuilderImpl.java create mode 100644 src/test/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/BitbucketWebhookConfigurationsBuilderTest.java diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/endpoint/BitbucketEndpointProvider.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/endpoint/BitbucketEndpointProvider.java index 35bc7ad10..9ef4d5c88 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/endpoint/BitbucketEndpointProvider.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/endpoint/BitbucketEndpointProvider.java @@ -25,6 +25,7 @@ import com.cloudbees.jenkins.plugins.bitbucket.api.webhook.BitbucketWebhookConfiguration; import com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketEndpointConfiguration; +import com.cloudbees.jenkins.plugins.bitbucket.impl.endpoint.AbstractBitbucketEndpoint; import com.cloudbees.jenkins.plugins.bitbucket.impl.endpoint.BitbucketCloudEndpoint; import com.cloudbees.jenkins.plugins.bitbucket.impl.endpoint.BitbucketServerEndpoint; import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketApiUtils; @@ -171,6 +172,27 @@ public static BitbucketEndpoint registerEndpoint(@NonNull String name, @NonNull return endpoint; } + /** + * Register a new {@link BitbucketEndpoint} to the global configuration. The + * endpoint is created with default values and could be customised by the + * given endpointCustomiser. + *

+ * The given customiser can also return a different implementation + * + * @param name of the endpoint, alias for label + * @param serverURL the bitbucket endpoint URL + * @param webhook configuration + * @param endpointCustomiser an optional customiser for the created endpoint + * @return the registered endpoint instance. + */ + public static BitbucketEndpoint registerEndpoint(@NonNull String name, @NonNull String serverURL, @NonNull BitbucketWebhookConfiguration webhook, @Nullable UnaryOperator endpointCustomiser) { + BitbucketEndpoint endpoint = registerEndpoint(name, serverURL, endpointCustomiser); + if (endpoint instanceof AbstractBitbucketEndpoint ep) { + ep.setWebhook(webhook); + } + return endpoint; + } + /** * Removes a {@link BitbucketEndpoint} that matches the given URl from the * global configuration. diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/BitbucketWebhookConfigurationBuilder.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/BitbucketWebhookConfigurationBuilder.java new file mode 100644 index 000000000..9625463cf --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/BitbucketWebhookConfigurationBuilder.java @@ -0,0 +1,76 @@ +/* + * The MIT License + * + * Copyright (c) 2025, Nikolas Falco + * + * 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.api.webhook; + +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.ExtensionPoint; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.Beta; + +/** + * Base interface that a builder must implement or extend to provide an instance + * of {@link BitbucketWebhookConfiguration}. + * + * @since 937.1.0 + */ +@Restricted(Beta.class) +public interface BitbucketWebhookConfigurationBuilder extends ExtensionPoint { + + /** + * Returns the identifier of built {@link BitbucketWebhookConfiguration}. + * + * @return configuration identifier + * @see BitbucketWebhookConfiguration#getId() + */ + @NonNull + String getId(); + + /** + * Enable the auto manage of webhook for each repository in a Jenkins + * project. + * + * @param credentialsId with admin right to add, update or delete webhook of + * a bitbucket repository + * @return builder itself + */ + BitbucketWebhookConfigurationBuilder autoManaged(@NonNull String credentialsId); + + /** + * Set the Jenkins root URL used to send event payload. + * + * @param callbackRootURL URL of Jenkins accessible from the Bitbucket + * server instance. + * @return builder itself + */ + BitbucketWebhookConfigurationBuilder callbackRootURL(@NonNull String callbackRootURL); + + /** + * Returns an instance of {@link BitbucketWebhookConfiguration} using the + * provided configuration. + * + * @return instance of {@link BitbucketWebhookConfiguration} + */ + BitbucketWebhookConfiguration build(); + +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/BitbucketWebhookConfigurationsBuilder.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/BitbucketWebhookConfigurationsBuilder.java new file mode 100644 index 000000000..99b225481 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/BitbucketWebhookConfigurationsBuilder.java @@ -0,0 +1,77 @@ +/* + * The MIT License + * + * Copyright (c) 2025, Nikolas Falco + * + * 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.api.webhook; + +import com.google.common.base.Objects; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import hudson.ExtensionList; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.Beta; + +/** + * Provider of {@link BitbucketWebhookConfiguration} builders registered in the + * system. + * + * @since 937.1.0 + */ +@Restricted(Beta.class) +public final class BitbucketWebhookConfigurationsBuilder { + + private BitbucketWebhookConfigurationsBuilder() { + } + + /** + * Returns a {@link BitbucketWebhookConfiguration} builder for the given + * configuration identifier. + * + * @param specific builder interface + * @param id webhook configuration identifier + * @param builderInterface class of specific builder + * @return an instance of {@link BitbucketWebhookConfigurationBuilder}, + * {@code null} otherwise if no builder found with the given + * paramenters. + */ + @Nullable + public static T lookup(@NonNull String id, Class builderInterface) { + return ExtensionList.lookup(builderInterface) // + .stream() // + .filter(provider -> Objects.equal(id, provider.getId())) // + .findFirst() // + .orElse(null); + } + + /** + * Returns a {@link BitbucketWebhookConfiguration} builder for the given + * configuration identifier. + * + * @param id webhook configuration identifier + * @return an instance of {@link BitbucketWebhookConfigurationBuilder}, + * {@code null} otherwise if no builder found. + */ + @Nullable + public static BitbucketWebhookConfigurationBuilder lookup(@NonNull String id) { + return lookup(id, BitbucketWebhookConfigurationBuilder.class); + } +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/NativeBitbucketWebhookConfigurationBuilder.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/NativeBitbucketWebhookConfigurationBuilder.java new file mode 100644 index 000000000..775940c83 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/NativeBitbucketWebhookConfigurationBuilder.java @@ -0,0 +1,45 @@ +/* + * The MIT License + * + * Copyright (c) 2025, Nikolas Falco + * + * 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.api.webhook; + +import edu.umd.cs.findbugs.annotations.NonNull; +import org.jenkinsci.plugins.plaincredentials.StringCredentials; + +/** + * This interface is intended for webhooks to meet the configuration + * specifications provided natively with Atlassian products. + */ +public interface NativeBitbucketWebhookConfigurationBuilder extends BitbucketWebhookConfigurationBuilder { + + /** + * Enable the payload signature verification using the given + * {@link StringCredentials}. + * + * @param credentialsId used to verify the signature sent with in payload + * @return the builder that can be used to customise a new instance of + * {@link BitbucketWebhookConfiguration}. + */ + NativeBitbucketWebhookConfigurationBuilder signature(@NonNull String credentialsId); + +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/endpoint/BitbucketCloudEndpoint.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/endpoint/BitbucketCloudEndpoint.java index e6631d203..c595c41ea 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/endpoint/BitbucketCloudEndpoint.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/endpoint/BitbucketCloudEndpoint.java @@ -38,6 +38,8 @@ import java.util.Collection; import java.util.List; import jenkins.model.Jenkins; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.interceptor.RequirePOST; import org.kohsuke.stapler.verb.POST; @@ -73,7 +75,17 @@ public class BitbucketCloudEndpoint extends AbstractBitbucketEndpoint { * Default constructor. */ public BitbucketCloudEndpoint() { - this(false, 0, 0, new CloudWebhookConfiguration(false, null, false, null)); + this(new CloudWebhookConfiguration(false, null, false, null)); + } + + /** + * Internal Constructor. + * + * @param webhook configuration + */ + @Restricted(NoExternalUse.class) + public BitbucketCloudEndpoint(BitbucketWebhookConfiguration webhook) { + this(false, 0, 0, webhook); } /** diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/AbstractBitbucketWebhookConfigurationBuilderImpl.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/AbstractBitbucketWebhookConfigurationBuilderImpl.java new file mode 100644 index 000000000..dd220074b --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/AbstractBitbucketWebhookConfigurationBuilderImpl.java @@ -0,0 +1,58 @@ +/* + * The MIT License + * + * Copyright (c) 2025, Nikolas Falco + * + * 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.impl.webhook; + +import com.cloudbees.jenkins.plugins.bitbucket.api.webhook.BitbucketWebhookConfigurationBuilder; +import com.cloudbees.jenkins.plugins.bitbucket.api.webhook.NativeBitbucketWebhookConfigurationBuilder; +import edu.umd.cs.findbugs.annotations.NonNull; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + +@Restricted(NoExternalUse.class) +public abstract class AbstractBitbucketWebhookConfigurationBuilderImpl implements NativeBitbucketWebhookConfigurationBuilder { + + protected String credentialsId; + protected String signatureId; + protected String callbackRootURL; + + @Override + public NativeBitbucketWebhookConfigurationBuilder autoManaged(@NonNull String credentialsId) { + this.credentialsId = credentialsId; + return this; + } + + @Override + public NativeBitbucketWebhookConfigurationBuilder signature(@NonNull String credentialsId) { + this.signatureId = credentialsId; + return this; + } + + @NonNull + @Override + public BitbucketWebhookConfigurationBuilder callbackRootURL(String callbackRootURL) { + this.callbackRootURL = callbackRootURL; + return this; + } + +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/cloud/CloudWebhookConfigurationBuilderImpl.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/cloud/CloudWebhookConfigurationBuilderImpl.java new file mode 100644 index 000000000..a50993e61 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/cloud/CloudWebhookConfigurationBuilderImpl.java @@ -0,0 +1,49 @@ +/* + * The MIT License + * + * Copyright (c) 2025, Nikolas Falco + * + * 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.impl.webhook.cloud; + +import com.cloudbees.jenkins.plugins.bitbucket.impl.webhook.AbstractBitbucketWebhookConfigurationBuilderImpl; +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.Extension; + +@Extension +public class CloudWebhookConfigurationBuilderImpl extends AbstractBitbucketWebhookConfigurationBuilderImpl { + + @NonNull + @Override + public String getId() { + return "CLOUD_NATIVE"; + } + + @NonNull + @Override + public CloudWebhookConfiguration build() { + CloudWebhookConfiguration configuration = new CloudWebhookConfiguration( + credentialsId != null, credentialsId, + signatureId != null, signatureId); + configuration.setEndpointJenkinsRootURL(callbackRootURL); + return configuration; + } + +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/plugin/PluginWebhookConfiguration.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/plugin/PluginWebhookConfiguration.java index f7e6c47a1..70507eaf6 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/plugin/PluginWebhookConfiguration.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/plugin/PluginWebhookConfiguration.java @@ -28,12 +28,14 @@ import com.cloudbees.jenkins.plugins.bitbucket.api.webhook.BitbucketWebhookDescriptor; import com.cloudbees.jenkins.plugins.bitbucket.api.webhook.BitbucketWebhookManager; import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentialsUtils; +import com.cloudbees.jenkins.plugins.bitbucket.impl.util.URLUtils; import com.cloudbees.jenkins.plugins.bitbucket.impl.webhook.Messages; import com.cloudbees.plugins.credentials.common.StandardCredentials; import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials; import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; +import hudson.Util; import hudson.util.FormValidation; import hudson.util.ListBoxModel; import java.net.MalformedURLException; @@ -56,7 +58,6 @@ // https://help.moveworkforward.com/BPW/how-to-get-configurations-using-post-webhooks-for- public class PluginWebhookConfiguration implements BitbucketWebhookConfiguration { private static final Logger logger = Logger.getLogger(PluginWebhookConfiguration.class.getName()); - private static final String WEBHOOK_API = "/rest/webhook/1.0/projects/{owner}/repos/{repo}/configurations"; /** * {@code true} if and only if Jenkins is supposed to auto-manage hooks for @@ -116,7 +117,10 @@ public String getEndpointJenkinsRootURL() { @DataBoundSetter public void setEndpointJenkinsRootURL(@CheckForNull String endpointJenkinsRootURL) { - this.endpointJenkinsRootURL = fixEmptyAndTrim(endpointJenkinsRootURL); + String url = fixEmptyAndTrim(endpointJenkinsRootURL); + if (url != null) { + this.endpointJenkinsRootURL = Util.ensureEndsWith(URLUtils.normalizeURL(url), "/"); + } } @Override diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/plugin/PluginWebhookConfigurationBuilder.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/plugin/PluginWebhookConfigurationBuilder.java new file mode 100644 index 000000000..f383e8343 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/plugin/PluginWebhookConfigurationBuilder.java @@ -0,0 +1,63 @@ +/* + * The MIT License + * + * Copyright (c) 2025, Nikolas Falco + * + * 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.impl.webhook.plugin; + +import com.cloudbees.jenkins.plugins.bitbucket.api.webhook.BitbucketWebhookConfigurationBuilder; +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.Extension; + +@Deprecated(since = "937.1.0") +@Extension +public class PluginWebhookConfigurationBuilder implements BitbucketWebhookConfigurationBuilder { + + private String credentialsId; + private String callbackRootURL; + + @NonNull + @Override + public PluginWebhookConfigurationBuilder autoManaged(@NonNull String credentialsId) { + this.credentialsId = credentialsId; + return this; + } + + @NonNull + @Override + public BitbucketWebhookConfigurationBuilder callbackRootURL(String callbackRootURL) { + this.callbackRootURL = callbackRootURL; + return this; + } + + @Override + public String getId() { + return "PLUGIN"; + } + + @NonNull + @Override + public PluginWebhookConfiguration build() { + PluginWebhookConfiguration configuration = new PluginWebhookConfiguration(credentialsId != null, credentialsId); + configuration.setEndpointJenkinsRootURL(callbackRootURL); + return configuration; + } +} diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/server/ServerWebhookConfiguration.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/server/ServerWebhookConfiguration.java index 770b3ca10..6388885cb 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/server/ServerWebhookConfiguration.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/server/ServerWebhookConfiguration.java @@ -60,7 +60,7 @@ public String getDisplayName() { @NonNull @Override public String getId() { - return "NATIVE"; + return "SERVER_NATIVE"; } @Override diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/server/ServerWebhookConfigurationBuilderImpl.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/server/ServerWebhookConfigurationBuilderImpl.java new file mode 100644 index 000000000..bc9edb8e8 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/webhook/server/ServerWebhookConfigurationBuilderImpl.java @@ -0,0 +1,48 @@ +/* + * The MIT License + * + * Copyright (c) 2025, Nikolas Falco + * + * 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.impl.webhook.server; + +import com.cloudbees.jenkins.plugins.bitbucket.impl.webhook.AbstractBitbucketWebhookConfigurationBuilderImpl; +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.Extension; + +@Extension +public class ServerWebhookConfigurationBuilderImpl extends AbstractBitbucketWebhookConfigurationBuilderImpl { + + @NonNull + @Override + public String getId() { + return "SERVER_NATIVE"; + } + + @NonNull + @Override + public ServerWebhookConfiguration build() { + ServerWebhookConfiguration configuration = new ServerWebhookConfiguration( + credentialsId != null, credentialsId, + signatureId != null, signatureId); + configuration.setEndpointJenkinsRootURL(callbackRootURL); + return configuration; + } +} diff --git a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/BitbucketWebhookConfigurationsBuilderTest.java b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/BitbucketWebhookConfigurationsBuilderTest.java new file mode 100644 index 000000000..1f6967bfa --- /dev/null +++ b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/BitbucketWebhookConfigurationsBuilderTest.java @@ -0,0 +1,104 @@ +/* + * The MIT License + * + * Copyright (c) 2025, Nikolas Falco + * + * 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.api.webhook; +import com.cloudbees.jenkins.plugins.bitbucket.impl.webhook.cloud.CloudWebhookConfiguration; +import com.cloudbees.jenkins.plugins.bitbucket.impl.webhook.plugin.PluginWebhookConfiguration; +import com.cloudbees.jenkins.plugins.bitbucket.impl.webhook.server.ServerWebhookConfiguration; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; + +import static org.assertj.core.api.Assertions.assertThat; + +@WithJenkins +class BitbucketWebhookConfigurationsBuilderTest { + + static JenkinsRule rule; + + @BeforeAll + static void init(JenkinsRule rule) { + BitbucketWebhookConfigurationsBuilderTest.rule = rule; + } + + @SuppressWarnings("deprecation") + @Test + void test_plugin_configuration() { + String credentialsId = "credentialsId"; + String jenkinsRootURL = "http://localhost:8090/jenkins"; + + BitbucketWebhookConfigurationBuilder builder = BitbucketWebhookConfigurationsBuilder.lookup("PLUGIN"); + builder.autoManaged(credentialsId); + builder.callbackRootURL(jenkinsRootURL); + + BitbucketWebhookConfiguration webhook = builder.build(); + assertThat(webhook).isInstanceOfSatisfying(PluginWebhookConfiguration.class, plugin -> { + assertThat(plugin.isManageHooks()).isTrue(); + assertThat(plugin.getCredentialsId()).isEqualTo(credentialsId); + assertThat(plugin.getEndpointJenkinsRootURL()).startsWith(jenkinsRootURL); + }); + } + + @Test + void test_cloud_configuration() { + String credentialsId = "credentialsId"; + String signatureCredentialsId = "signatureId"; + String jenkinsRootURL = "http://localhost:8090/jenkins"; + + NativeBitbucketWebhookConfigurationBuilder builder = BitbucketWebhookConfigurationsBuilder.lookup("CLOUD_NATIVE", NativeBitbucketWebhookConfigurationBuilder.class); + builder.autoManaged(credentialsId); + builder.callbackRootURL(jenkinsRootURL); + builder.signature(signatureCredentialsId); + + BitbucketWebhookConfiguration webhook = builder.build(); + assertThat(webhook).isInstanceOfSatisfying(CloudWebhookConfiguration.class, cloud -> { + assertThat(cloud.isManageHooks()).isTrue(); + assertThat(cloud.getCredentialsId()).isEqualTo(credentialsId); + assertThat(cloud.getEndpointJenkinsRootURL()).startsWith(jenkinsRootURL); + assertThat(cloud.isEnableHookSignature()).isTrue(); + assertThat(cloud.getHookSignatureCredentialsId()).isEqualTo(signatureCredentialsId); + }); + } + + @Test + void test_server_configuration() { + String credentialsId = "credentialsId"; + String signatureCredentialsId = "signatureId"; + String jenkinsRootURL = "http://localhost:8090/jenkins"; + + NativeBitbucketWebhookConfigurationBuilder builder = BitbucketWebhookConfigurationsBuilder.lookup("SERVER_NATIVE", NativeBitbucketWebhookConfigurationBuilder.class); + builder.autoManaged(credentialsId); + builder.callbackRootURL(jenkinsRootURL); + builder.signature(signatureCredentialsId); + + BitbucketWebhookConfiguration webhook = builder.build(); + assertThat(webhook).isInstanceOfSatisfying(ServerWebhookConfiguration.class, server -> { + assertThat(server.isManageHooks()).isTrue(); + assertThat(server.getCredentialsId()).isEqualTo(credentialsId); + assertThat(server.getEndpointJenkinsRootURL()).startsWith(jenkinsRootURL); + assertThat(server.isEnableHookSignature()).isTrue(); + assertThat(server.getHookSignatureCredentialsId()).isEqualTo(signatureCredentialsId); + }); + } +}