Skip to content

Commit 4dfdd4a

Browse files
committed
[JENKINS-75804] Webhook auto registration fail with PLUGIN implementation (#1071)
Add missing logic on when update a plugin hook. Add manage of which events must be subscribed.
1 parent c074de4 commit 4dfdd4a

File tree

4 files changed

+320
-16
lines changed

4 files changed

+320
-16
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,9 @@ public void setServerUrl(@CheckForNull String serverUrl) {
295295
}
296296
}
297297

298+
@Restricted(NoExternalUse.class)
299+
@Deprecated(forRemoval = true)
300+
// expose if needed in BitbucketEndpointProvider, normally could be get from endpoint if not customized
298301
@NonNull
299302
public String getEndpointJenkinsRootURL() {
300303
return AbstractBitbucketEndpoint.getEndpointJenkinsRootUrl(serverUrl);

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

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
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.endpoints.AbstractBitbucketEndpoint;
3132
import com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketServerEndpoint;
3233
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketApiUtils;
3334
import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketPluginWebhook;
@@ -121,30 +122,59 @@ public String getCommittersToIgnore() {
121122
boolean updateHook(BitbucketWebHook hook, BitbucketSCMSource owner) {
122123
boolean updated = false;
123124

125+
final String serverURL = owner.getServerUrl();
126+
final String rootURL = getEndpointJenkinsRootURL(serverURL);
124127
final String signatureSecret = getSecret(owner.getServerUrl());
125128

126129
if (hook instanceof BitbucketCloudHook cloudHook) {
130+
String url = getCloudWebhookURL(serverURL, rootURL);
131+
if (!Objects.equal(hook.getUrl(), url)) {
132+
cloudHook.setUrl(url);
133+
updated = true;
134+
}
135+
127136
if (!hook.getEvents().containsAll(CLOUD_EVENTS)) {
128137
Set<String> events = new TreeSet<>(hook.getEvents());
129138
events.addAll(CLOUD_EVENTS);
130139
cloudHook.setEvents(new ArrayList<>(events));
131140
updated = true;
132141
}
142+
133143
if (!Objects.equal(hook.getSecret(), signatureSecret)) {
134144
cloudHook.setSecret(signatureSecret);
135145
updated = true;
136146
}
137-
} else if (hook instanceof BitbucketPluginWebhook serverHook) {
138-
String hookCommittersToIgnore = Util.fixEmptyAndTrim(serverHook.getCommittersToIgnore());
147+
} else if (hook instanceof BitbucketPluginWebhook pluginHook) {
148+
String hookCommittersToIgnore = Util.fixEmptyAndTrim(pluginHook.getCommittersToIgnore());
139149
String thisCommittersToIgnore = Util.fixEmptyAndTrim(committersToIgnore);
140150
if (!Objects.equal(thisCommittersToIgnore, hookCommittersToIgnore)) {
141-
serverHook.setCommittersToIgnore(thisCommittersToIgnore);
151+
pluginHook.setCommittersToIgnore(thisCommittersToIgnore);
152+
updated = true;
153+
}
154+
155+
String url = getServerWebhookURL(serverURL, rootURL);
156+
if (!url.equals(pluginHook.getUrl())) {
157+
pluginHook.setUrl(url);
158+
updated = true;
159+
}
160+
161+
if (!pluginHook.isActive()) {
162+
pluginHook.setActive(true);
142163
updated = true;
143164
}
144-
} else if (hook instanceof BitbucketServerWebhook serverHook) {
145-
String serverURL = owner.getServerUrl();
146-
String url = getServerWebhookURL(serverURL, owner.getEndpointJenkinsRootURL());
147165

166+
List<String> events = pluginHook.getEvents();
167+
if (events == null) {
168+
pluginHook.setEvents(getNativeServerEvents(serverURL));
169+
updated = true;
170+
} else if (!events.containsAll(getNativeServerEvents(serverURL))) {
171+
Set<String> newEvents = new TreeSet<>(events);
172+
newEvents.addAll(getNativeServerEvents(serverURL));
173+
pluginHook.setEvents(new ArrayList<>(newEvents));
174+
updated = true;
175+
}
176+
} else if (hook instanceof BitbucketServerWebhook serverHook) {
177+
String url = getServerWebhookURL(serverURL, rootURL);
148178
if (!url.equals(serverHook.getUrl())) {
149179
serverHook.setUrl(url);
150180
updated = true;
@@ -170,28 +200,34 @@ boolean updateHook(BitbucketWebHook hook, BitbucketSCMSource owner) {
170200
return updated;
171201
}
172202

203+
@NonNull
204+
private String getEndpointJenkinsRootURL(@NonNull String serverURL) {
205+
return AbstractBitbucketEndpoint.getEndpointJenkinsRootUrl(serverURL);
206+
}
207+
208+
@NonNull
173209
public BitbucketWebHook getHook(BitbucketSCMSource owner) {
174-
final String serverUrl = owner.getServerUrl();
175-
final String rootUrl = owner.getEndpointJenkinsRootURL();
210+
final String serverURL = owner.getServerUrl();
211+
final String rootURL = getEndpointJenkinsRootURL(serverURL);
176212
final String signatureSecret = getSecret(owner.getServerUrl());
177213

178-
if (BitbucketApiUtils.isCloud(serverUrl)) {
214+
if (BitbucketApiUtils.isCloud(serverURL)) {
179215
BitbucketCloudHook hook = new BitbucketCloudHook();
180216
hook.setEvents(CLOUD_EVENTS);
181217
hook.setActive(true);
182218
hook.setDescription(description);
183-
hook.setUrl(rootUrl + BitbucketSCMSourcePushHookReceiver.FULL_PATH);
219+
hook.setUrl(getCloudWebhookURL(serverURL, rootURL));
184220
hook.setSecret(signatureSecret);
185221
return hook;
186222
}
187223

188-
switch (BitbucketServerEndpoint.findWebhookImplementation(serverUrl)) {
224+
switch (BitbucketServerEndpoint.findWebhookImplementation(serverURL)) {
189225
case NATIVE: {
190226
BitbucketServerWebhook hook = new BitbucketServerWebhook();
191227
hook.setActive(true);
192228
hook.setDescription(description);
193-
hook.setEvents(getNativeServerEvents(serverUrl));
194-
hook.setUrl(getServerWebhookURL(serverUrl, rootUrl));
229+
hook.setEvents(getNativeServerEvents(serverURL));
230+
hook.setUrl(getServerWebhookURL(serverURL, rootURL));
195231
hook.setSecret(signatureSecret);
196232
return hook;
197233
}
@@ -201,7 +237,7 @@ public BitbucketWebHook getHook(BitbucketSCMSource owner) {
201237
BitbucketPluginWebhook hook = new BitbucketPluginWebhook();
202238
hook.setActive(true);
203239
hook.setDescription(description);
204-
hook.setUrl(getServerWebhookURL(serverUrl, rootUrl));
240+
hook.setUrl(getServerWebhookURL(serverURL, rootURL));
205241
hook.setCommittersToIgnore(committersToIgnore);
206242
return hook;
207243
}
@@ -256,6 +292,13 @@ private static List<String> getNativeServerEvents(String serverUrl) {
256292
return NATIVE_SERVER_EVENTS_v7;
257293
}
258294

295+
private static String getCloudWebhookURL(String serverURL, String rootURL) {
296+
return UriTemplate.buildFromTemplate(rootURL)
297+
.template(BitbucketSCMSourcePushHookReceiver.FULL_PATH)
298+
.build()
299+
.expand();
300+
}
301+
259302
private static String getServerWebhookURL(String serverURL, String rootURL) {
260303
return UriTemplate.buildFromTemplate(rootURL)
261304
.template(BitbucketSCMSourcePushHookReceiver.FULL_PATH)

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/repository/BitbucketPluginWebhook.java

Lines changed: 177 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@
2525

2626

2727
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketWebHook;
28+
import com.cloudbees.jenkins.plugins.bitbucket.hooks.HookEventType;
2829
import com.fasterxml.jackson.annotation.JsonIgnore;
2930
import com.fasterxml.jackson.annotation.JsonInclude;
3031
import com.fasterxml.jackson.annotation.JsonProperty;
31-
import java.util.Collections;
32+
import java.util.ArrayList;
3233
import java.util.List;
3334

3435
public class BitbucketPluginWebhook implements BitbucketWebHook {
@@ -40,6 +41,19 @@ public class BitbucketPluginWebhook implements BitbucketWebHook {
4041
private String url;
4142
@JsonProperty("enabled")
4243
private boolean active;
44+
private boolean tagCreated;
45+
private boolean branchDeleted;
46+
private boolean branchCreated;
47+
private boolean repoPush;
48+
private boolean prDeclined;
49+
private boolean prRescoped;
50+
private boolean prMerged;
51+
private boolean prReopened;
52+
private boolean prUpdated;
53+
private boolean prCreated;
54+
private boolean prCommented;
55+
private boolean prDeleted;
56+
private boolean repoMirrorSynced;
4357

4458
@JsonInclude(JsonInclude.Include.NON_NULL) // If null, don't marshal to allow for backwards compatibility
4559
private String committersToIgnore; // Since Bitbucket Webhooks version 1.5.0
@@ -82,7 +96,64 @@ public void setActive(boolean active) {
8296
@Override
8397
@JsonIgnore
8498
public List<String> getEvents() {
85-
return Collections.emptyList();
99+
List<String> events = new ArrayList<>();
100+
if (prCommented) {
101+
events.add("prCommented");
102+
}
103+
if (prCreated) {
104+
events.add(HookEventType.SERVER_PULL_REQUEST_OPENED.getKey());
105+
}
106+
if (prDeclined) {
107+
events.add(HookEventType.SERVER_PULL_REQUEST_DECLINED.getKey());
108+
}
109+
if (prDeleted) {
110+
events.add(HookEventType.SERVER_PULL_REQUEST_DELETED.getKey());
111+
}
112+
if (prMerged) {
113+
events.add(HookEventType.SERVER_PULL_REQUEST_MERGED.getKey());
114+
}
115+
if (prReopened) {
116+
events.add(HookEventType.SERVER_PULL_REQUEST_OPENED.getKey());
117+
}
118+
if (prRescoped) {
119+
events.add("prRescoped");
120+
}
121+
if (prUpdated) {
122+
events.add(HookEventType.SERVER_PULL_REQUEST_FROM_REF_UPDATED.getKey());
123+
}
124+
if (repoMirrorSynced) {
125+
events.add(HookEventType.SERVER_MIRROR_REPO_SYNCHRONIZED.getKey()); // TODO not supported in hookprocessor
126+
}
127+
if (repoPush) {
128+
events.add(HookEventType.SERVER_REFS_CHANGED.getKey());
129+
}
130+
if (tagCreated) {
131+
events.add(HookEventType.SERVER_REFS_CHANGED.getKey());
132+
}
133+
if (branchCreated) {
134+
events.add(HookEventType.SERVER_REFS_CHANGED.getKey());
135+
}
136+
if (branchDeleted) {
137+
events.add(HookEventType.SERVER_REFS_CHANGED.getKey());
138+
}
139+
return events;
140+
}
141+
142+
@JsonIgnore
143+
public void setEvents(List<String> events) {
144+
prCommented = events.contains("prCommented");
145+
prCreated = events.contains(HookEventType.SERVER_PULL_REQUEST_OPENED.getKey());
146+
prDeclined = events.contains(HookEventType.SERVER_PULL_REQUEST_DECLINED.getKey());
147+
prDeleted = events.contains(HookEventType.SERVER_PULL_REQUEST_DELETED.getKey());
148+
prMerged = events.contains(HookEventType.SERVER_PULL_REQUEST_MERGED.getKey());
149+
prReopened = prCreated;
150+
prRescoped = events.contains("prRescoped");
151+
prUpdated = events.contains(HookEventType.SERVER_PULL_REQUEST_FROM_REF_UPDATED.getKey());
152+
repoMirrorSynced = events.contains(HookEventType.SERVER_MIRROR_REPO_SYNCHRONIZED.getKey()); // TODO not supported in hookprocessor
153+
repoPush = events.contains(HookEventType.SERVER_REFS_CHANGED.getKey());
154+
tagCreated = repoPush;
155+
branchCreated = repoPush;
156+
branchDeleted = repoPush;
86157
}
87158

88159
@Override
@@ -99,4 +170,108 @@ public String getSecret() {
99170
return null;
100171
}
101172

173+
public boolean isTagCreated() {
174+
return tagCreated;
175+
}
176+
177+
public void setTagCreated(boolean tagCreated) {
178+
this.tagCreated = tagCreated;
179+
}
180+
181+
public boolean isBranchDeleted() {
182+
return branchDeleted;
183+
}
184+
185+
public void setBranchDeleted(boolean branchDeleted) {
186+
this.branchDeleted = branchDeleted;
187+
}
188+
189+
public boolean isBranchCreated() {
190+
return branchCreated;
191+
}
192+
193+
public void setBranchCreated(boolean branchCreated) {
194+
this.branchCreated = branchCreated;
195+
}
196+
197+
public boolean isRepoPush() {
198+
return repoPush;
199+
}
200+
201+
public void setRepoPush(boolean repoPush) {
202+
this.repoPush = repoPush;
203+
}
204+
205+
public boolean isPrDeclined() {
206+
return prDeclined;
207+
}
208+
209+
public void setPrDeclined(boolean prDeclined) {
210+
this.prDeclined = prDeclined;
211+
}
212+
213+
public boolean isPrRescoped() {
214+
return prRescoped;
215+
}
216+
217+
public void setPrRescoped(boolean prRescoped) {
218+
this.prRescoped = prRescoped;
219+
}
220+
221+
public boolean isPrMerged() {
222+
return prMerged;
223+
}
224+
225+
public void setPrMerged(boolean prMerged) {
226+
this.prMerged = prMerged;
227+
}
228+
229+
public boolean isPrReopened() {
230+
return prReopened;
231+
}
232+
233+
public void setPrReopened(boolean prReopened) {
234+
this.prReopened = prReopened;
235+
}
236+
237+
public boolean isPrUpdated() {
238+
return prUpdated;
239+
}
240+
241+
public void setPrUpdated(boolean prUpdated) {
242+
this.prUpdated = prUpdated;
243+
}
244+
245+
public boolean isPrCreated() {
246+
return prCreated;
247+
}
248+
249+
public void setPrCreated(boolean prCreated) {
250+
this.prCreated = prCreated;
251+
}
252+
253+
public boolean isPrCommented() {
254+
return prCommented;
255+
}
256+
257+
public void setPrCommented(boolean prCommented) {
258+
this.prCommented = prCommented;
259+
}
260+
261+
public boolean isPrDeleted() {
262+
return prDeleted;
263+
}
264+
265+
public void setPrDeleted(boolean prDeleted) {
266+
this.prDeleted = prDeleted;
267+
}
268+
269+
public boolean isRepoMirrorSynced() {
270+
return repoMirrorSynced;
271+
}
272+
273+
public void setRepoMirrorSynced(boolean repoMirrorSynced) {
274+
this.repoMirrorSynced = repoMirrorSynced;
275+
}
276+
102277
}

0 commit comments

Comments
 (0)