Skip to content

Commit ef896c0

Browse files
committed
[JENKINS-74913] Allow extension point in bitbucket source plugin to provide a implementation for web-hooks management
make readResolve compatible with old format
1 parent 78adcd1 commit ef896c0

File tree

56 files changed

+409
-669
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+409
-669
lines changed

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketGitSCMBuilder.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.cloudbees.jenkins.plugins.bitbucket.api.PullRequestBranchType;
3232
import com.cloudbees.jenkins.plugins.bitbucket.api.endpoint.BitbucketEndpoint;
3333
import com.cloudbees.jenkins.plugins.bitbucket.api.endpoint.BitbucketEndpointProvider;
34+
import com.cloudbees.jenkins.plugins.bitbucket.impl.endpoint.BitbucketCloudEndpoint;
3435
import com.cloudbees.jenkins.plugins.bitbucket.impl.endpoint.BitbucketServerEndpoint;
3536
import com.cloudbees.jenkins.plugins.bitbucket.impl.extension.FallbackToOtherRepositoryGitSCMExtension;
3637
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketApiUtils;
@@ -113,7 +114,7 @@ public BitbucketGitSCMBuilder(@NonNull BitbucketSCMSource scmSource, @NonNull SC
113114

114115
String serverURL = scmSource.getServerUrl();
115116
BitbucketEndpoint endpoint = BitbucketEndpointProvider.lookupEndpoint(serverURL)
116-
.orElse(new BitbucketServerEndpoint(null, serverURL, false, null, false, null));
117+
.orElse(BitbucketApiUtils.isCloud(serverURL) ? new BitbucketCloudEndpoint() : new BitbucketServerEndpoint("tmp", serverURL));
117118

118119
String repositoryURL = endpoint.getRepositoryURL(scmSource.getRepoOwner(), scmSource.getRepository());
119120
if (BitbucketApiUtils.isCloud(endpoint.getServerURL())) {

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMNavigator.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentialsUtils;
3939
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.MirrorListSupplier;
4040
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.URLUtils;
41-
import com.cloudbees.jenkins.plugins.bitbucket.server.BitbucketServerWebhookImplementation;
4241
import com.cloudbees.jenkins.plugins.bitbucket.trait.BranchDiscoveryTrait;
4342
import com.cloudbees.jenkins.plugins.bitbucket.trait.ForkPullRequestDiscoveryTrait;
4443
import com.cloudbees.jenkins.plugins.bitbucket.trait.OriginPullRequestDiscoveryTrait;
@@ -412,10 +411,8 @@ public static FormValidation doCheckCredentialsId(@AncestorInPath SCMSourceOwner
412411
public static FormValidation doCheckMirrorId(@QueryParameter String value,
413412
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL) {
414413
if (!value.isEmpty()) {
415-
BitbucketServerWebhookImplementation webhookImplementation =
416-
BitbucketServerEndpoint.findWebhookImplementation(serverURL);
417-
if (webhookImplementation == BitbucketServerWebhookImplementation.PLUGIN) {
418-
return FormValidation.error("Mirror can only be used with native webhooks");
414+
if (BitbucketServerEndpoint.supportsMirror(serverURL)) {
415+
return FormValidation.error("Mirror is not supported by the choosen webhooks");
419416
}
420417
}
421418
return FormValidation.ok();

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSource.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.DateUtils;
5454
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.MirrorListSupplier;
5555
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.URLUtils;
56-
import com.cloudbees.jenkins.plugins.bitbucket.server.BitbucketServerWebhookImplementation;
5756
import com.cloudbees.jenkins.plugins.bitbucket.server.client.BitbucketServerAPIClient;
5857
import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketServerRepository;
5958
import com.cloudbees.jenkins.plugins.bitbucket.trait.BranchDiscoveryTrait;
@@ -1073,9 +1072,7 @@ public static FormValidation doCheckServerUrl(@AncestorInPath SCMSourceOwner con
10731072
public static FormValidation doCheckMirrorId(@QueryParameter String value,
10741073
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL) {
10751074
if (!value.isEmpty()) {
1076-
BitbucketServerWebhookImplementation webhookImplementation =
1077-
BitbucketServerEndpoint.findWebhookImplementation(serverURL);
1078-
if (webhookImplementation == BitbucketServerWebhookImplementation.PLUGIN) {
1075+
if (BitbucketServerEndpoint.supportsMirror(serverURL)) {
10791076
return FormValidation.error("Mirror can only be used with native webhooks");
10801077
}
10811078
}

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/endpoint/BitbucketEndpointDescriptor.java

Lines changed: 0 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -23,86 +23,12 @@
2323
*/
2424
package com.cloudbees.jenkins.plugins.bitbucket.api.endpoint;
2525

26-
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentialsUtils;
27-
import com.cloudbees.plugins.credentials.CredentialsMatchers;
28-
import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
29-
import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder;
30-
import hudson.Util;
3126
import hudson.model.Descriptor;
32-
import hudson.security.ACL;
33-
import hudson.util.FormValidation;
34-
import hudson.util.ListBoxModel;
35-
import java.net.MalformedURLException;
36-
import java.net.URL;
37-
import jenkins.model.Jenkins;
38-
import org.jenkinsci.plugins.plaincredentials.StringCredentials;
39-
import org.kohsuke.accmod.Restricted;
40-
import org.kohsuke.accmod.restrictions.NoExternalUse;
41-
import org.kohsuke.stapler.QueryParameter;
42-
import org.kohsuke.stapler.interceptor.RequirePOST;
4327

4428
/**
4529
* {@link Descriptor} for {@link BitbucketEndpoint}s.
4630
*
4731
* @since 936.4.0
4832
*/
4933
public class BitbucketEndpointDescriptor extends Descriptor<BitbucketEndpoint> {
50-
/**
51-
* Stapler form completion.
52-
*
53-
* @param credentialsId selected credentials.
54-
* @param serverURL the server URL.
55-
* @return the available credentials.
56-
*/
57-
@RequirePOST
58-
public ListBoxModel doFillCredentialsIdItems(@QueryParameter(fixEmpty = true) String credentialsId,
59-
@QueryParameter(value = "serverUrl", fixEmpty = true) String serverURL) {
60-
Jenkins jenkins = checkPermission();
61-
return BitbucketCredentialsUtils.listCredentials(jenkins, serverURL, credentialsId);
62-
}
63-
64-
private static Jenkins checkPermission() {
65-
Jenkins jenkins = Jenkins.get();
66-
jenkins.checkPermission(Jenkins.MANAGE);
67-
return jenkins;
68-
}
69-
70-
/**
71-
* Stapler form completion.
72-
*
73-
* @param hookSignatureCredentialsId selected hook signature credentials.
74-
* @param serverURL the server URL.
75-
* @return the available credentials.
76-
*/
77-
@RequirePOST
78-
public ListBoxModel doFillHookSignatureCredentialsIdItems(@QueryParameter(fixEmpty = true) String hookSignatureCredentialsId,
79-
@QueryParameter(value = "serverUrl", fixEmpty = true) String serverURL) {
80-
Jenkins jenkins = checkPermission();
81-
StandardListBoxModel result = new StandardListBoxModel();
82-
result.includeMatchingAs(ACL.SYSTEM2,
83-
jenkins,
84-
StringCredentials.class,
85-
URIRequirementBuilder.fromUri(serverURL).build(),
86-
CredentialsMatchers.always());
87-
if (hookSignatureCredentialsId != null) {
88-
result.includeCurrentValue(hookSignatureCredentialsId);
89-
}
90-
return result;
91-
}
92-
93-
@Restricted(NoExternalUse.class)
94-
@RequirePOST
95-
public static FormValidation doCheckBitbucketJenkinsRootUrl(@QueryParameter String value) {
96-
checkPermission();
97-
String url = Util.fixEmptyAndTrim(value);
98-
if (url == null) {
99-
return FormValidation.ok();
100-
}
101-
try {
102-
new URL(url);
103-
} catch (MalformedURLException e) {
104-
return FormValidation.error("Invalid URL: " + e.getMessage());
105-
}
106-
return FormValidation.ok();
107-
}
10834
}

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/endpoint/BitbucketEndpointProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ public static BitbucketEndpoint registerEndpoint(@NonNull String name, @NonNull
159159
if (BitbucketApiUtils.isCloud(serverURL)) {
160160
endpoint = new BitbucketCloudEndpoint();
161161
} else {
162-
endpoint = new BitbucketServerEndpoint(name, serverURL, false, null, false, null);
162+
endpoint = new BitbucketServerEndpoint(name, serverURL);
163163
}
164164
if (endpointCustomiser != null) {
165165
endpoint = endpointCustomiser.apply(endpoint);

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/webhook/BitbucketWebhookDescriptor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@
3030
*
3131
* @since 936.4.0
3232
*/
33-
public class BitbucketWebhookDescriptor extends Descriptor<BitbucketWebhook> {
33+
public abstract class BitbucketWebhookDescriptor extends Descriptor<BitbucketWebhook> {
34+
public abstract boolean isApplicable(String serverURL);
3435
}

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketEndpointConfiguration.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.cloudbees.jenkins.plugins.bitbucket.impl.endpoint.BitbucketServerEndpoint;
3030
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketApiUtils;
3131
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.URLUtils;
32+
import com.cloudbees.jenkins.plugins.bitbucket.impl.webhook.cloud.CloudWebhook;
3233
import edu.umd.cs.findbugs.annotations.CheckForNull;
3334
import edu.umd.cs.findbugs.annotations.NonNull;
3435
import hudson.Extension;
@@ -86,6 +87,7 @@ public XmlFile getConfigFile() {
8687
XStream2 xs = new XStream2(XStream2.getDefaultDriver());
8788
xs.alias("com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketCloudEndpoint", BitbucketCloudEndpoint.class);
8889
xs.alias("com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketServerEndpoint", BitbucketServerEndpoint.class);
90+
xs.aliasAttribute(BitbucketServerEndpoint.class, "serverURL", "serverUrl");
8991
return new XmlFile(xs, cfgFile);
9092
}
9193

@@ -124,7 +126,7 @@ public String readResolveServerUrl(@CheckForNull String serverURL) {
124126
// exception case
125127
endpoint = new BitbucketCloudEndpoint();
126128
} else {
127-
endpoint = new BitbucketServerEndpoint(normalizedURL);
129+
endpoint = new BitbucketServerEndpoint(null, normalizedURL);
128130
}
129131
addEndpoint(endpoint);
130132
}
@@ -199,10 +201,10 @@ public void setEndpoints(@CheckForNull List<? extends BitbucketEndpoint> endpoin
199201
continue;
200202
} else if (!(endpoint instanceof BitbucketCloudEndpoint) && BitbucketApiUtils.isCloud(serverURL)) {
201203
// fix type for the special case
202-
BitbucketCloudEndpoint cloudEndpoint = new BitbucketCloudEndpoint(false, 0, 0,
203-
endpoint.isManageHooks(), endpoint.getCredentialsId(),
204+
CloudWebhook webhook = new CloudWebhook(endpoint.isManageHooks(), endpoint.getCredentialsId(),
204205
endpoint.isEnableHookSignature(), endpoint.getHookSignatureCredentialsId());
205-
cloudEndpoint.setBitbucketJenkinsRootUrl(endpoint.getEndpointJenkinsRootURL());
206+
webhook.setEndpointJenkinsRootURL(endpoint.getEndpointJenkinsRootURL());
207+
BitbucketCloudEndpoint cloudEndpoint = new BitbucketCloudEndpoint(false, 0, 0, webhook);
206208
iterator.set(cloudEndpoint);
207209
}
208210
serverURLs.add(serverURL);

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/WebhookConfiguration.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import com.cloudbees.jenkins.plugins.bitbucket.api.endpoint.BitbucketEndpoint;
2929
import com.cloudbees.jenkins.plugins.bitbucket.api.endpoint.BitbucketEndpointProvider;
3030
import com.cloudbees.jenkins.plugins.bitbucket.client.repository.BitbucketCloudHook;
31-
import com.cloudbees.jenkins.plugins.bitbucket.impl.endpoint.BitbucketServerEndpoint;
3231
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketApiUtils;
3332
import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketPluginWebhook;
3433
import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketServerWebhook;
@@ -167,7 +166,8 @@ public BitbucketWebHook getHook(BitbucketSCMSource owner) {
167166
hook.setSecret(signatureSecret);
168167
return hook;
169168
}
170-
169+
return null;
170+
/*
171171
switch (BitbucketServerEndpoint.findWebhookImplementation(serverURL)) {
172172
case NATIVE: {
173173
BitbucketServerWebhook hook = new BitbucketServerWebhook();
@@ -189,6 +189,7 @@ public BitbucketWebHook getHook(BitbucketSCMSource owner) {
189189
return hook;
190190
}
191191
}
192+
*/
192193
}
193194

194195
@Nullable

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/endpoint/AbstractBitbucketEndpoint.java

Lines changed: 40 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,14 @@
2929
import com.cloudbees.jenkins.plugins.bitbucket.api.webhook.BitbucketWebhook;
3030
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentialsUtils;
3131
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.URLUtils;
32+
import com.cloudbees.jenkins.plugins.bitbucket.impl.webhook.cloud.CloudWebhook;
33+
import com.cloudbees.jenkins.plugins.bitbucket.impl.webhook.plugin.PluginWebhook;
34+
import com.cloudbees.jenkins.plugins.bitbucket.impl.webhook.server.ServerWebhook;
3235
import com.cloudbees.plugins.credentials.common.StandardCredentials;
3336
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
3437
import edu.umd.cs.findbugs.annotations.CheckForNull;
3538
import edu.umd.cs.findbugs.annotations.NonNull;
39+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
3640
import hudson.Util;
3741
import java.util.Objects;
3842
import jenkins.authentication.tokens.api.AuthenticationTokens;
@@ -51,53 +55,33 @@
5155
*/
5256
public abstract class AbstractBitbucketEndpoint implements BitbucketEndpoint {
5357

54-
/**
55-
* {@code true} if and only if Jenkins is supposed to auto-manage hooks for this end-point.
56-
*/
58+
// keept for backward XStream compatibility
59+
@Deprecated
5760
private boolean manageHooks;
58-
59-
/**
60-
* The {@link StandardCredentials#getId()} of the credentials to use for auto-management of hooks.
61-
*/
62-
@CheckForNull
61+
@Deprecated
6362
private String credentialsId;
63+
@Deprecated
64+
private boolean enableHookSignature;
65+
@Deprecated
66+
private String hookSignatureCredentialsId;
67+
@Deprecated
68+
private String bitbucketJenkinsRootUrl;
69+
@Deprecated
70+
private String webhookImplementation;
6471

6572
@NonNull
6673
private BitbucketWebhook webhook;
6774

68-
/**
69-
* {@code true} if and only if Jenkins have to verify the signature of all incoming hooks.
70-
*/
71-
private boolean enableHookSignature;
72-
73-
/**
74-
* The {@link StringCredentials#getId()} of the credentials to use to verify the signature of hooks.
75-
*/
76-
@CheckForNull
77-
private String hookSignatureCredentialsId;
75+
AbstractBitbucketEndpoint(@NonNull BitbucketWebhook webhook) {
76+
this.webhook = Objects.requireNonNull(webhook);
77+
}
7878

79-
/**
80-
* Jenkins Server Root URL to be used by that Bitbucket endpoint.
81-
* The global setting from Jenkins.get().getRootUrl()
82-
* will be used if this field is null or equals an empty string.
83-
* This variable is bound to the UI, so an empty value is saved
84-
* and returned by getter as such.
85-
*/
86-
private String bitbucketJenkinsRootUrl;
79+
public @NonNull BitbucketWebhook getWebhook() {
80+
return webhook;
81+
}
8782

88-
/**
89-
* Constructor.
90-
*
91-
* @param manageHooks {@code true} if and only if Jenkins is supposed to auto-manage hooks for this end-point.
92-
* @param credentialsId The {@link StandardCredentials#getId()} of the credentials to use for
93-
* auto-management of hooks.
94-
*/
95-
AbstractBitbucketEndpoint(boolean manageHooks, @CheckForNull String credentialsId,
96-
boolean enableHookSignature, @CheckForNull String hookSignatureCredentialsId) {
97-
this.manageHooks = manageHooks && StringUtils.isNotBlank(credentialsId);
98-
this.credentialsId = manageHooks ? fixEmptyAndTrim(credentialsId) : null;
99-
this.enableHookSignature = enableHookSignature && StringUtils.isNotBlank(hookSignatureCredentialsId);
100-
this.hookSignatureCredentialsId = enableHookSignature ? fixEmptyAndTrim(hookSignatureCredentialsId) : null;
83+
protected void setWebhook(@NonNull BitbucketWebhook webhook) {
84+
this.webhook = webhook;
10185
}
10286

10387
@Override
@@ -265,20 +249,28 @@ public BitbucketAuthenticator authenticator() {
265249
return AuthenticationTokens.convert(BitbucketAuthenticator.authenticationContext(getServerURL()), credentials());
266250
}
267251

252+
@SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE", justification = "Only non-null after we set them here!")
253+
protected Object readResolve() {
254+
if (webhook == null) {
255+
if ("NATIVE".equals(webhookImplementation)) {
256+
webhook = new ServerWebhook(manageHooks, credentialsId, enableHookSignature, hookSignatureCredentialsId);
257+
((ServerWebhook) webhook).setEndpointJenkinsRootURL(bitbucketJenkinsRootUrl);
258+
} else if ("PLUGIN".equals(webhookImplementation)) {
259+
webhook = new PluginWebhook(manageHooks, credentialsId);
260+
((PluginWebhook) webhook).setEndpointJenkinsRootURL(bitbucketJenkinsRootUrl);
261+
} else {
262+
webhook = new CloudWebhook(manageHooks, credentialsId, enableHookSignature, hookSignatureCredentialsId);
263+
((CloudWebhook) webhook).setEndpointJenkinsRootURL(bitbucketJenkinsRootUrl);
264+
}
265+
}
266+
return this;
267+
}
268+
268269
/**
269270
* {@inheritDoc}
270271
*/
271272
@Override
272273
public BitbucketEndpointDescriptor getDescriptor() {
273274
return (BitbucketEndpointDescriptor) Jenkins.get().getDescriptorOrDie(getClass());
274275
}
275-
276-
public @NonNull BitbucketWebhook getWebhook() {
277-
return webhook;
278-
}
279-
280-
@DataBoundSetter
281-
public void setWebhook(@NonNull BitbucketWebhook webhook) {
282-
this.webhook = Objects.requireNonNull(webhook);
283-
}
284276
}

0 commit comments

Comments
 (0)