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);
+ });
+ }
+}