Skip to content

Commit 914c46d

Browse files
committed
[JENKINS-75804] Webhook auto registration fail with PLUGIN implementation
Fix serialisation of the payload to not send null fields when register hook. Fix wrong HTTP verb used to send request on create and update of web hook in case of PLUGIN implementation Applied globally instead to the single specific bean.
1 parent b5347dc commit 914c46d

File tree

12 files changed

+104
-136
lines changed

12 files changed

+104
-136
lines changed

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
.project
66
.classpath
77
.settings
8-
target
9-
work
8+
target/
9+
work/
1010
.checkstyle
1111
.externalToolBuilders/
1212

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,4 @@ Support to run Server under Windows has been dismissed since version 7.14+
100100
3. Inside the container:
101101
- install git with `apk add git`
102102
- install git support for http with `apk add git-daemon`
103-
- run `/opt/atlassian-plugin-sdk/bin/atlas-run-standalone --product bitbucket --version 9.5.2`
103+
- run `/opt/atlassian-plugin-sdk/bin/atlas-run-standalone --product bitbucket --version 9.5.2 "-Dfeature.public.access=true"`

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/client/BitbucketCloudApiClient.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@
3838
import com.cloudbees.jenkins.plugins.bitbucket.client.branch.BitbucketCloudCommit;
3939
import com.cloudbees.jenkins.plugins.bitbucket.client.pullrequest.BitbucketCloudPullRequest;
4040
import com.cloudbees.jenkins.plugins.bitbucket.client.pullrequest.BitbucketCloudPullRequestCommit;
41+
import com.cloudbees.jenkins.plugins.bitbucket.client.repository.BitbucketCloudHook;
4142
import com.cloudbees.jenkins.plugins.bitbucket.client.repository.BitbucketCloudRepository;
42-
import com.cloudbees.jenkins.plugins.bitbucket.client.repository.BitbucketRepositoryHook;
4343
import com.cloudbees.jenkins.plugins.bitbucket.client.repository.BitbucketRepositorySource;
4444
import com.cloudbees.jenkins.plugins.bitbucket.client.repository.UserRoleInRepository;
4545
import com.cloudbees.jenkins.plugins.bitbucket.filesystem.BitbucketSCMFile;
@@ -471,7 +471,7 @@ public void registerCommitWebHook(@NonNull BitbucketWebHook hook) throws IOExcep
471471
.set("owner", owner)
472472
.set("repo", repositoryName)
473473
.expand();
474-
postRequest(url, JsonParser.toJson(hook));
474+
postRequest(url, JsonParser.toString(hook));
475475
}
476476

477477
/**
@@ -485,7 +485,7 @@ public void updateCommitWebHook(@NonNull BitbucketWebHook hook) throws IOExcepti
485485
.set("repo", repositoryName)
486486
.set("hook", hook.getUuid())
487487
.expand();
488-
putRequest(url, JsonParser.toJson(hook));
488+
putRequest(url, JsonParser.toString(hook));
489489
}
490490

491491
/**
@@ -509,13 +509,13 @@ public void removeCommitWebHook(@NonNull BitbucketWebHook hook) throws IOExcepti
509509
*/
510510
@NonNull
511511
@Override
512-
public List<BitbucketRepositoryHook> getWebHooks() throws IOException {
512+
public List<BitbucketCloudHook> getWebHooks() throws IOException {
513513
String url = UriTemplate.fromTemplate(REPO_URL_TEMPLATE + "/hooks{?page,pagelen}")
514514
.set("owner", owner)
515515
.set("repo", repositoryName)
516516
.set("pagelen", MAX_PAGE_LENGTH)
517517
.expand();
518-
return getPagedRequest(url, BitbucketRepositoryHook.class);
518+
return getPagedRequest(url, BitbucketCloudHook.class);
519519
}
520520

521521
/**
@@ -531,7 +531,7 @@ public void postBuildStatus(@NonNull BitbucketBuildStatus status) throws IOExcep
531531
.set("repo", repositoryName)
532532
.set("hash", newStatus.getHash())
533533
.expand();
534-
postRequest(url, JsonParser.toJson(newStatus));
534+
postRequest(url, JsonParser.toString(newStatus));
535535
}
536536

537537
/**
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketWebHook;
2727
import java.util.List;
2828

29-
public class BitbucketRepositoryHook implements BitbucketWebHook {
29+
public class BitbucketCloudHook implements BitbucketWebHook {
3030

3131
private String uuid;
3232

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

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@
2727
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketWebHook;
2828
import com.cloudbees.jenkins.plugins.bitbucket.api.endpoint.BitbucketEndpoint;
2929
import com.cloudbees.jenkins.plugins.bitbucket.api.endpoint.BitbucketEndpointProvider;
30-
import com.cloudbees.jenkins.plugins.bitbucket.client.repository.BitbucketRepositoryHook;
30+
import com.cloudbees.jenkins.plugins.bitbucket.client.repository.BitbucketCloudHook;
3131
import com.cloudbees.jenkins.plugins.bitbucket.impl.endpoint.BitbucketServerEndpoint;
3232
import com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketApiUtils;
33+
import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketPluginWebhook;
3334
import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketServerWebhook;
34-
import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.NativeBitbucketServerWebhook;
3535
import com.damnhandy.uri.template.UriTemplate;
3636
import com.google.common.base.Objects;
3737
import edu.umd.cs.findbugs.annotations.CheckForNull;
@@ -123,7 +123,7 @@ boolean updateHook(BitbucketWebHook hook, BitbucketSCMSource owner) {
123123

124124
final String signatureSecret = getSecret(owner.getServerUrl());
125125

126-
if (hook instanceof BitbucketRepositoryHook cloudHook) {
126+
if (hook instanceof BitbucketCloudHook cloudHook) {
127127
if (!hook.getEvents().containsAll(CLOUD_EVENTS)) {
128128
Set<String> events = new TreeSet<>(hook.getEvents());
129129
events.addAll(CLOUD_EVENTS);
@@ -134,18 +134,14 @@ boolean updateHook(BitbucketWebHook hook, BitbucketSCMSource owner) {
134134
cloudHook.setSecret(signatureSecret);
135135
updated = true;
136136
}
137-
} else if (hook instanceof BitbucketServerWebhook serverHook) {
137+
} else if (hook instanceof BitbucketPluginWebhook serverHook) {
138138
String hookCommittersToIgnore = Util.fixEmptyAndTrim(serverHook.getCommittersToIgnore());
139139
String thisCommittersToIgnore = Util.fixEmptyAndTrim(committersToIgnore);
140140
if (!Objects.equal(thisCommittersToIgnore, hookCommittersToIgnore)) {
141141
serverHook.setCommittersToIgnore(thisCommittersToIgnore);
142142
updated = true;
143143
}
144-
if (!Objects.equal(serverHook.getSecret(), signatureSecret)) {
145-
serverHook.setSecret(signatureSecret);
146-
updated = true;
147-
}
148-
} else if (hook instanceof NativeBitbucketServerWebhook serverHook) {
144+
} else if (hook instanceof BitbucketServerWebhook serverHook) {
149145
String serverURL = owner.getServerUrl();
150146
String url = getServerWebhookURL(serverURL, BitbucketEndpointProvider.lookupEndpointJenkinsRootURL(owner.getServerUrl()));
151147

@@ -180,7 +176,7 @@ public BitbucketWebHook getHook(BitbucketSCMSource owner) {
180176
final String signatureSecret = getSecret(owner.getServerUrl());
181177

182178
if (BitbucketApiUtils.isCloud(serverUrl)) {
183-
BitbucketRepositoryHook hook = new BitbucketRepositoryHook();
179+
BitbucketCloudHook hook = new BitbucketCloudHook();
184180
hook.setEvents(CLOUD_EVENTS);
185181
hook.setActive(true);
186182
hook.setDescription(description);
@@ -191,7 +187,7 @@ public BitbucketWebHook getHook(BitbucketSCMSource owner) {
191187

192188
switch (BitbucketServerEndpoint.findWebhookImplementation(serverUrl)) {
193189
case NATIVE: {
194-
NativeBitbucketServerWebhook hook = new NativeBitbucketServerWebhook();
190+
BitbucketServerWebhook hook = new BitbucketServerWebhook();
195191
hook.setActive(true);
196192
hook.setDescription(description);
197193
hook.setEvents(getNativeServerEvents(serverUrl));
@@ -202,7 +198,7 @@ public BitbucketWebHook getHook(BitbucketSCMSource owner) {
202198

203199
case PLUGIN:
204200
default: {
205-
BitbucketServerWebhook hook = new BitbucketServerWebhook();
201+
BitbucketPluginWebhook hook = new BitbucketPluginWebhook();
206202
hook.setActive(true);
207203
hook.setDescription(description);
208204
hook.setUrl(getServerWebhookURL(serverUrl, rootUrl));

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/util/JsonParser.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
*/
2424
package com.cloudbees.jenkins.plugins.bitbucket.impl.util;
2525

26+
import com.fasterxml.jackson.annotation.JsonInclude.Include;
2627
import com.fasterxml.jackson.core.type.TypeReference;
2728
import com.fasterxml.jackson.databind.DeserializationFeature;
28-
import com.fasterxml.jackson.databind.ObjectMapper;
29+
import com.fasterxml.jackson.databind.JsonNode;
30+
import com.fasterxml.jackson.databind.json.JsonMapper;
2931
import com.fasterxml.jackson.databind.util.StdDateFormat;
3032
import java.io.IOException;
3133
import java.io.InputStream;
@@ -42,7 +44,7 @@
4244
@Restricted(NoExternalUse.class)
4345
public final class JsonParser {
4446

45-
public static final ObjectMapper mapper = createObjectMapper();
47+
private static final JsonMapper mapper = createMapper();
4648

4749
public static <T> T toJava(String data, Class<T> type) throws IOException {
4850
return toJava(new StringReader(data), type);
@@ -60,14 +62,19 @@ public static <T> T toJava(String data, TypeReference<T> type) throws IOExceptio
6062
return mapper.readValue(data, type);
6163
}
6264

63-
public static String toJson(Object value) throws IOException {
65+
public static String toString(Object value) throws IOException {
6466
return mapper.writeValueAsString(value);
6567
}
6668

67-
private static ObjectMapper createObjectMapper(){
68-
ObjectMapper mapper = new ObjectMapper();
69-
mapper.setDateFormat(new StdDateFormat());
70-
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
71-
return mapper;
69+
public static JsonNode toJson(String value) throws IOException {
70+
return mapper.readTree(value);
71+
}
72+
73+
private static JsonMapper createMapper(){
74+
return JsonMapper.builder()
75+
.defaultDateFormat(new StdDateFormat())
76+
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
77+
.serializationInclusion(Include.NON_NULL)
78+
.build();
7279
}
7380
}

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

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@
5454
import com.cloudbees.jenkins.plugins.bitbucket.server.client.branch.BitbucketServerCommit;
5555
import com.cloudbees.jenkins.plugins.bitbucket.server.client.pullrequest.BitbucketServerPullRequest;
5656
import com.cloudbees.jenkins.plugins.bitbucket.server.client.pullrequest.BitbucketServerPullRequestCanMerge;
57+
import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketPluginWebhook;
5758
import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketServerProject;
5859
import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketServerRepository;
59-
import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketServerWebhooks;
60-
import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.NativeBitbucketServerWebhook;
60+
import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketServerWebhook;
6161
import com.damnhandy.uri.template.UriTemplate;
6262
import com.damnhandy.uri.template.impl.Operator;
6363
import com.fasterxml.jackson.core.JacksonException;
@@ -76,6 +76,7 @@
7676
import java.lang.reflect.ParameterizedType;
7777
import java.nio.charset.StandardCharsets;
7878
import java.util.ArrayList;
79+
import java.util.Arrays;
7980
import java.util.Collections;
8081
import java.util.Comparator;
8182
import java.util.List;
@@ -492,7 +493,7 @@ public void postBuildStatus(@NonNull BitbucketBuildStatus status) throws IOExcep
492493
.set("repo", repositoryName)
493494
.set("hash", newStatus.getHash())
494495
.expand();
495-
postRequest(url, JsonParser.toJson(newStatus));
496+
postRequest(url, JsonParser.toString(newStatus));
496497
}
497498

498499
/**
@@ -644,13 +645,14 @@ public BitbucketCommit resolveCommit(@NonNull BitbucketPullRequest pull) throws
644645
public void registerCommitWebHook(BitbucketWebHook hook) throws IOException {
645646
switch (webhookImplementation) {
646647
case PLUGIN:
647-
putRequest(
648+
// API documentation at https://help.moveworkforward.com/BPW/how-to-manage-configurations-using-post-webhooks-f#HowtomanageconfigurationsusingPostWebhooksforBitbucketAPIs?-Createpostwebhook
649+
postRequest(
648650
UriTemplate
649651
.fromTemplate(this.baseURL + WEBHOOK_REPOSITORY_PATH)
650652
.set("owner", getUserCentricOwner())
651653
.set("repo", repositoryName)
652654
.expand(),
653-
JsonParser.toJson(hook)
655+
JsonParser.toString(hook)
654656
);
655657
break;
656658

@@ -661,7 +663,7 @@ public void registerCommitWebHook(BitbucketWebHook hook) throws IOException {
661663
.set("owner", getUserCentricOwner())
662664
.set("repo", repositoryName)
663665
.expand(),
664-
JsonParser.toJson(hook)
666+
JsonParser.toString(hook)
665667
);
666668
break;
667669

@@ -675,13 +677,14 @@ public void registerCommitWebHook(BitbucketWebHook hook) throws IOException {
675677
public void updateCommitWebHook(BitbucketWebHook hook) throws IOException {
676678
switch (webhookImplementation) {
677679
case PLUGIN:
678-
postRequest(
680+
// API documentation at https://help.moveworkforward.com/BPW/how-to-manage-configurations-using-post-webhooks-f#HowtomanageconfigurationsusingPostWebhooksforBitbucketAPIs?-UpdateapostwebhookbyID
681+
putRequest(
679682
UriTemplate
680683
.fromTemplate(this.baseURL + WEBHOOK_REPOSITORY_CONFIG_PATH)
681684
.set("owner", getUserCentricOwner())
682685
.set("repo", repositoryName)
683686
.set("id", hook.getUuid())
684-
.expand(), JsonParser.toJson(hook)
687+
.expand(), JsonParser.toString(hook)
685688
);
686689
break;
687690

@@ -692,7 +695,7 @@ public void updateCommitWebHook(BitbucketWebHook hook) throws IOException {
692695
.set("owner", getUserCentricOwner())
693696
.set("repo", repositoryName)
694697
.set("id", hook.getUuid())
695-
.expand(), JsonParser.toJson(hook)
698+
.expand(), JsonParser.toString(hook)
696699
);
697700
break;
698701

@@ -743,13 +746,13 @@ public List<? extends BitbucketWebHook> getWebHooks() throws IOException {
743746
.set("owner", getUserCentricOwner())
744747
.set("repo", repositoryName)
745748
.expand();
746-
return getRequestAs(url, BitbucketServerWebhooks.class);
749+
return Arrays.asList(getRequestAs(url, BitbucketPluginWebhook[].class));
747750
case NATIVE:
748751
UriTemplate uriTemplate = UriTemplate
749752
.fromTemplate(this.baseURL + API_WEBHOOKS_PATH)
750753
.set("owner", getUserCentricOwner())
751754
.set("repo", repositoryName);
752-
return getPagedRequest(uriTemplate, NativeBitbucketServerWebhook.class);
755+
return getPagedRequest(uriTemplate, BitbucketServerWebhook.class);
753756
}
754757

755758
return Collections.emptyList();
@@ -969,7 +972,7 @@ public Iterable<SCMFile> getDirectoryContent(BitbucketSCMFile directory) throws
969972
.set("limit", 500);
970973
String url = template.expand();
971974
String response = getRequest(url);
972-
Map<String,Object> content = JsonParser.mapper.readValue(response, new TypeReference<Map<String,Object>>(){});
975+
Map<String, Object> content = JsonParser.toJava(response, new TypeReference<Map<String, Object>>() {});
973976
Map page = (Map) content.get("children");
974977
List<Map> values = (List<Map>) page.get("values");
975978
collectFileAndDirectories(directory, values, files);
@@ -979,7 +982,7 @@ public Iterable<SCMFile> getDirectoryContent(BitbucketSCMFile directory) throws
979982
.set("start", start)
980983
.expand();
981984
response = getRequest(url);
982-
content = JsonParser.mapper.readValue(response, new TypeReference<Map<String,Object>>(){});
985+
content = JsonParser.toJava(response, new TypeReference<Map<String, Object>>() {});
983986
page = (Map) content.get("children");
984987
}
985988
return files;
@@ -1059,7 +1062,7 @@ public SCMFile getFile(@NonNull BitbucketSCMFile file) throws IOException {
10591062
Type type = Type.OTHER;
10601063
try {
10611064
String response = getRequest(url);
1062-
JsonNode typeNode = JsonParser.mapper.readTree(response).path("type");
1065+
JsonNode typeNode = JsonParser.toJson(response).path("type");
10631066
if (!typeNode.isMissingNode() && !typeNode.isNull()) {
10641067
String responseType = typeNode.asText();
10651068
if ("FILE".equals(responseType)) {

0 commit comments

Comments
 (0)