Skip to content

Commit cfaa954

Browse files
authored
[JENKINS-74913] Allow extension point in bitbucket source plugin to provide a implementation for web-hooks management (#1061)
Add BitbucketWebhookConfiguration UI component descriptor to allow configure different webhooks implementation using specific attributes. Add BitbucketWebhookManager extension point to provide custom implementations of how the configuration is applied using APIs to register webhook in Bitbucket. Add BitbucketWebhookProcessor extension point to register hook processors provided by other plugins to managed new event types. Remove hook events that does ship any king of changes in the source code like reviewer changed or PR approved, they was used only to trigger builds if that kind of changes was enabled bitbucket side. Reindex on empty changes has been turn-off by default, this to avoid scan all repositories if not required. Deprecated webhook methods in BitbucketApi. Create CasC configuration provider to be compatible with old format.
1 parent 162b23d commit cfaa954

File tree

136 files changed

+5839
-3018
lines changed

Some content is hidden

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

136 files changed

+5839
-3018
lines changed

docs/USER_GUIDE.adoc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
= Bitbucket Branch Source Plugin
22

3+
=====================================================================
4+
35
[id=bitbucket-sect-intro]
46
57
_Bitbucket Branch Source plugin_ allows use of Bitbucket Cloud and Data Center as a multi-branch project source in two different ways:
@@ -304,12 +306,12 @@ System.setProperty("http.socket.timeout", "300") // 5 minutes
304306
In case Bitbucket has been configured to expire OAuth2 tokens before 5 minutes, you can configure via a JVM property the release time of the cache where all obtained OAuth2 tokens are stored. This setting is to avoid requests with expired tokens that will produce HTTP 401 responses. link:https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/[Bitbucket Cloud] access tokens expire in two hours.
305307
To change this amount of time (default is 300 seconds), add the system property `bitbucket.oauth2.cache.timeout=60` on Jenkins startup.
306308
307-
=== Disable Branch Indexing on Empty changes
309+
=== Enable Branch Indexing on Empty changes
308310
309-
By default, the plugin triggers *a full branch indexing* when a push event contains *empty* changes. This may happen on various scenario, mainly in Bitbucket Data Center, such as:
311+
By default, the plugin does not triggers *a full branch indexing* when a push event contains *empty* changes. This may happen on various scenario, mainly in Bitbucket Data Center, such as:
310312
311313
* When manually merging remote **Open** pull requests. This particular scenario produces 2 events and cause duplicated builds.
312314
* For a fork, when link:https://confluence.atlassian.com/bitbucketserver/keeping-forks-synchronized-776639961.html[Auto-Sync] is on and a branch cannot be synchronised
313315
* A link:http://confluence.atlassian.com/bitbucketserver/event-payload-938025882.html#Eventpayload-Mirrorsynchronized[mirror:repo_synchronized] event with too many refs
314316
315-
This behaviour can be disabled by adding the system property `bitbucket.hooks.processor.scanOnEmptyChanges=false` on Jenkins startup.
317+
This behaviour can be enabled by adding the system property `bitbucket.hooks.processor.scanOnEmptyChanges=true` on Jenkins startup.

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: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,10 @@
3333
import com.cloudbees.jenkins.plugins.bitbucket.client.repository.UserRoleInRepository;
3434
import com.cloudbees.jenkins.plugins.bitbucket.impl.avatars.BitbucketTeamAvatarMetadataAction;
3535
import com.cloudbees.jenkins.plugins.bitbucket.impl.endpoint.BitbucketCloudEndpoint;
36-
import com.cloudbees.jenkins.plugins.bitbucket.impl.endpoint.BitbucketServerEndpoint;
3736
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketApiUtils;
3837
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketCredentialsUtils;
3938
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.MirrorListSupplier;
4039
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.URLUtils;
41-
import com.cloudbees.jenkins.plugins.bitbucket.server.BitbucketServerWebhookImplementation;
4240
import com.cloudbees.jenkins.plugins.bitbucket.trait.BranchDiscoveryTrait;
4341
import com.cloudbees.jenkins.plugins.bitbucket.trait.ForkPullRequestDiscoveryTrait;
4442
import com.cloudbees.jenkins.plugins.bitbucket.trait.OriginPullRequestDiscoveryTrait;
@@ -408,19 +406,6 @@ public static FormValidation doCheckCredentialsId(@AncestorInPath SCMSourceOwner
408406
return BitbucketCredentialsUtils.checkCredentialsId(context, value, serverURL);
409407
}
410408

411-
@RequirePOST
412-
public static FormValidation doCheckMirrorId(@QueryParameter String value,
413-
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL) {
414-
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");
419-
}
420-
}
421-
return FormValidation.ok();
422-
}
423-
424409
@RequirePOST
425410
public ListBoxModel doFillCredentialsIdItems(@AncestorInPath SCMSourceOwner context,
426411
@QueryParameter(fixEmpty = true, value = "serverUrl", required = true) String serverURL) {

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

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import com.cloudbees.jenkins.plugins.bitbucket.hooks.HasPullRequests;
4545
import com.cloudbees.jenkins.plugins.bitbucket.impl.avatars.BitbucketRepoAvatarMetadataAction;
4646
import com.cloudbees.jenkins.plugins.bitbucket.impl.endpoint.BitbucketCloudEndpoint;
47-
import com.cloudbees.jenkins.plugins.bitbucket.impl.endpoint.BitbucketServerEndpoint;
4847
import com.cloudbees.jenkins.plugins.bitbucket.impl.extension.BitbucketEnvVarExtension;
4948
import com.cloudbees.jenkins.plugins.bitbucket.impl.extension.GitClientAuthenticatorExtension;
5049
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketApiUtils;
@@ -53,7 +52,6 @@
5352
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.DateUtils;
5453
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.MirrorListSupplier;
5554
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.URLUtils;
56-
import com.cloudbees.jenkins.plugins.bitbucket.server.BitbucketServerWebhookImplementation;
5755
import com.cloudbees.jenkins.plugins.bitbucket.server.client.BitbucketServerAPIClient;
5856
import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketServerRepository;
5957
import com.cloudbees.jenkins.plugins.bitbucket.trait.BranchDiscoveryTrait;
@@ -286,22 +284,14 @@ public String getServerUrl() {
286284
}
287285

288286
@DataBoundSetter
289-
public void setServerUrl(@CheckForNull String serverUrl) {
290-
if (serverUrl == null) {
287+
public void setServerUrl(@CheckForNull String serverURL) {
288+
if (serverURL == null) {
291289
this.serverUrl = BitbucketEndpointConfiguration.get().getDefaultEndpoint().getServerURL();
292290
} else {
293-
this.serverUrl = Util.fixNull(URLUtils.normalizeURL(serverUrl));
291+
this.serverUrl = Util.fixNull(URLUtils.normalizeURL(serverURL));
294292
}
295293
}
296294

297-
@Restricted(NoExternalUse.class)
298-
@Deprecated(since = "936.4.0", forRemoval = true)
299-
// expose if needed in BitbucketEndpointProvider, normally could be get from endpoint if not customized
300-
@NonNull
301-
public String getEndpointJenkinsRootURL() {
302-
return BitbucketEndpointProvider.lookupEndpointJenkinsRootURL(serverUrl);
303-
}
304-
305295
@Override
306296
@NonNull
307297
public List<SCMSourceTrait> getTraits() {
@@ -1071,19 +1061,6 @@ public static FormValidation doCheckServerUrl(@AncestorInPath SCMSourceOwner con
10711061
return FormValidation.ok();
10721062
}
10731063

1074-
@RequirePOST
1075-
public static FormValidation doCheckMirrorId(@QueryParameter String value,
1076-
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL) {
1077-
if (!value.isEmpty()) {
1078-
BitbucketServerWebhookImplementation webhookImplementation =
1079-
BitbucketServerEndpoint.findWebhookImplementation(serverURL);
1080-
if (webhookImplementation == BitbucketServerWebhookImplementation.PLUGIN) {
1081-
return FormValidation.error("Mirror can only be used with native webhooks");
1082-
}
1083-
}
1084-
return FormValidation.ok();
1085-
}
1086-
10871064
public boolean isServerUrlSelectable() {
10881065
return !BitbucketEndpointProvider.all().isEmpty();
10891066
}

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

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
*/
2424
package com.cloudbees.jenkins.plugins.bitbucket;
2525

26-
import com.cloudbees.jenkins.plugins.bitbucket.hooks.WebhookConfiguration;
2726
import edu.umd.cs.findbugs.annotations.CheckForNull;
2827
import edu.umd.cs.findbugs.annotations.NonNull;
2928
import hudson.model.TaskListener;
@@ -76,11 +75,6 @@ public class BitbucketSCMSourceContext extends SCMSourceContext<BitbucketSCMSour
7675
*/
7776
@NonNull
7877
private WebhookRegistration webhookRegistration = WebhookRegistration.SYSTEM;
79-
/**
80-
* The {@link WebhookConfiguration} to use in this context.
81-
*/
82-
@NonNull
83-
private WebhookConfiguration webhookConfiguration = new WebhookConfiguration();
8478

8579
/**
8680
* {@code true} if notifications should be disabled in this context.
@@ -202,16 +196,6 @@ public final WebhookRegistration webhookRegistration() {
202196
return webhookRegistration;
203197
}
204198

205-
/**
206-
* Returns the {@link WebhookConfiguration} configuration.
207-
*
208-
* @return the {@link WebhookConfiguration} configuration.
209-
*/
210-
@NonNull
211-
public final WebhookConfiguration webhookConfiguration() {
212-
return webhookConfiguration;
213-
}
214-
215199
/**
216200
* Returns {@code true} if notifications should be disabled.
217201
*
@@ -341,18 +325,6 @@ public final BitbucketSCMSourceContext withForkPRStrategies(
341325
return this;
342326
}
343327

344-
/**
345-
* Defines the {@link WebhookRegistration} mode to use in this context.
346-
*
347-
* @param configuration the webhook configuration.
348-
* @return {@code this} for method chaining.
349-
*/
350-
@NonNull
351-
public final BitbucketSCMSourceContext webhookConfiguration(WebhookConfiguration configuration) {
352-
webhookConfiguration = configuration;
353-
return this;
354-
}
355-
356328
/**
357329
* Defines the {@link WebhookRegistration} mode to use in this context.
358330
*

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketApi.java

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

26+
import com.cloudbees.jenkins.plugins.bitbucket.api.webhook.BitbucketWebhookConfiguration;
2627
import com.cloudbees.jenkins.plugins.bitbucket.client.repository.UserRoleInRepository;
2728
import com.cloudbees.jenkins.plugins.bitbucket.filesystem.BitbucketSCMFile;
2829
import edu.umd.cs.findbugs.annotations.CheckForNull;
2930
import edu.umd.cs.findbugs.annotations.NonNull;
31+
import edu.umd.cs.findbugs.annotations.Nullable;
3032
import java.io.IOException;
3133
import java.io.InputStream;
34+
import java.util.Collections;
3235
import java.util.List;
3336
import jenkins.scm.api.SCMFile;
3437
import jenkins.scm.impl.avatars.AvatarImage;
@@ -190,33 +193,50 @@ boolean checkPathExists(@NonNull String branchOrHash, @NonNull String path)
190193
*
191194
* @param hook the webhook object
192195
* @throws IOException if there was a network communications error.
196+
* @deprecated Use the {@link BitbucketWebhookConfiguration} implementation to gather
197+
* information about webhook.
193198
*/
194-
void registerCommitWebHook(@NonNull BitbucketWebHook hook) throws IOException;
199+
@Deprecated(since = "937.0.0", forRemoval = true)
200+
default void registerCommitWebHook(@NonNull BitbucketWebHook hook) throws IOException {
201+
}
195202

196203
/**
197204
* Update a webhook on the repository.
198205
*
199206
* @param hook the webhook object
200207
* @throws IOException if there was a network communications error.
208+
* @deprecated Use the {@link BitbucketWebhookConfiguration} implementation to gather
209+
* information about webhook.
201210
*/
202-
void updateCommitWebHook(@NonNull BitbucketWebHook hook) throws IOException;
211+
@Deprecated(since = "937.0.0", forRemoval = true)
212+
default void updateCommitWebHook(@NonNull BitbucketWebHook hook) throws IOException {
213+
}
203214

204215
/**
205216
* Remove the webhook (ID field required) from the repository.
206217
*
207218
* @param hook the webhook object
208219
* @throws IOException if there was a network communications error.
220+
* @deprecated Use the {@link BitbucketWebhookConfiguration} implementation to gather
221+
* information about webhook.
209222
*/
210-
void removeCommitWebHook(@NonNull BitbucketWebHook hook) throws IOException;
223+
@Deprecated(since = "937.0.0", forRemoval = true)
224+
default void removeCommitWebHook(@NonNull BitbucketWebHook hook) throws IOException {
225+
}
211226

212227
/**
213228
* Returns the webhooks defined in the repository.
214229
*
215230
* @return the list of webhooks registered in the repository.
216231
* @throws IOException if there was a network communications error.
232+
* @deprecated Use the {@link BitbucketWebhookConfiguration} implementation to gather
233+
* information about webhook.
217234
*/
235+
@Deprecated(since = "937.0.0", forRemoval = true)
218236
@NonNull
219-
List<? extends BitbucketWebHook> getWebHooks() throws IOException;
237+
default List<? extends BitbucketWebHook> getWebHooks() throws IOException {
238+
return Collections.emptyList();
239+
}
220240

221241
/**
222242
* Returns the team of the current owner or {@code null} if the current owner is not a team.
@@ -341,6 +361,17 @@ List<? extends BitbucketRepository> getRepositories(@CheckForNull UserRoleInRepo
341361
@NonNull
342362
List<? extends BitbucketCommit> getCommits(@CheckForNull String from, @NonNull String to) throws IOException;
343363

364+
/**
365+
* Adapt this implementation to the given class.
366+
* @param <T> the return type
367+
* @param clazz of type T to adapt to
368+
* @return the adapted class or {@code null} if given class is not supported.
369+
*/
370+
@Nullable
371+
default <T> T adapt(@NonNull Class<T> clazz) {
372+
return null;
373+
}
374+
344375
// /**
345376
// * Return a set changes between the two given commits.
346377
// *

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketApiFactory.java

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,28 +51,28 @@ public abstract class BitbucketApiFactory implements ExtensionPoint {
5151
* Creates a {@link BitbucketApi} for the specified URL with the supplied credentials, owner and (optional)
5252
* repository.
5353
*
54-
* @param serverUrl the server URL.
54+
* @param serverURL the server URL.
5555
* @param authenticator the (optional) authenticator.
5656
* @param owner the owner name.
5757
* @param projectKey the (optional) project key.
5858
* @param repository the (optional) repository name.
5959
* @return the {@link BitbucketApi}.
6060
*/
6161
@NonNull
62-
protected abstract BitbucketApi create(@Nullable String serverUrl,
62+
protected abstract BitbucketApi create(@Nullable String serverURL,
6363
@Nullable BitbucketAuthenticator authenticator,
6464
@NonNull String owner,
6565
@CheckForNull String projectKey,
6666
@CheckForNull String repository);
6767

6868
@NonNull
6969
@Deprecated
70-
protected BitbucketApi create(@Nullable String serverUrl,
70+
protected BitbucketApi create(@Nullable String serverURL,
7171
@Nullable StandardUsernamePasswordCredentials credentials,
7272
@NonNull String owner,
7373
@CheckForNull String repository) {
7474
BitbucketAuthenticator auth = credentials != null ? new BitbucketUsernamePasswordAuthenticator(credentials) : null;
75-
return create(serverUrl, auth, owner, null, repository);
75+
return create(serverURL, auth, owner, null, repository);
7676
}
7777

7878
/**
@@ -101,14 +101,4 @@ public static BitbucketApi newInstance(@Nullable String serverURL,
101101
throw new IllegalArgumentException("Unsupported Bitbucket server URL: " + serverURL);
102102
}
103103

104-
@NonNull
105-
@Deprecated
106-
public static BitbucketApi newInstance(@Nullable String serverUrl,
107-
@Nullable StandardUsernamePasswordCredentials credentials,
108-
@NonNull String owner,
109-
@CheckForNull String projectKey,
110-
@CheckForNull String repository) {
111-
BitbucketAuthenticator auth = credentials != null ? new BitbucketUsernamePasswordAuthenticator(credentials) : null;
112-
return newInstance(serverUrl, auth, owner, projectKey, repository);
113-
}
114104
}

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketException.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
package com.cloudbees.jenkins.plugins.bitbucket.api;
2525

2626
public class BitbucketException extends RuntimeException {
27+
private static final long serialVersionUID = 1L;
2728

2829
public BitbucketException(String message, Throwable cause) {
2930
super(message, cause);
@@ -33,6 +34,4 @@ public BitbucketException(String message) {
3334
super(message);
3435
}
3536

36-
private static final long serialVersionUID = 1L;
37-
3837
}

0 commit comments

Comments
 (0)