Skip to content

Commit 6a0d987

Browse files
authored
[JENKINS-75073] Missing serverUrl in fillCredentialsIdItems cause some credentials missing in the initial configuration (#953)
If the number of server instances is only one, when a new Jenkins project is created the server list combobox is not available. This causes, in the UI component that loads credentials, to pass the stapler parameter serverUrl as an empty string. In this scenario, serverUrl must be taken from the first of configured endpoints so that it can properly filter the list of credentials. Move some unit test to JUnit5
1 parent 859f608 commit 6a0d987

16 files changed

+636
-600
lines changed

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,9 @@ public BitbucketGitSCMBuilder(@NonNull BitbucketSCMSource scmSource, @NonNull SC
104104
this.scmSource = scmSource;
105105

106106
String serverURL = scmSource.getServerUrl();
107-
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get().findEndpoint(serverURL);
108-
if (endpoint == null) {
109-
endpoint = new BitbucketServerEndpoint(null, serverURL, false, null);
110-
}
107+
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get()
108+
.findEndpoint(serverURL)
109+
.orElse(new BitbucketServerEndpoint(null, serverURL, false, null));
111110

112111
String repositoryURL = endpoint.getRepositoryUrl(scmSource.getRepoOwner(), scmSource.getRepository());
113112
if (BitbucketApiUtils.isCloud(endpoint.getServerUrl())) {

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

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
import org.kohsuke.stapler.DataBoundConstructor;
103103
import org.kohsuke.stapler.DataBoundSetter;
104104
import org.kohsuke.stapler.QueryParameter;
105+
import org.kohsuke.stapler.interceptor.RequirePOST;
105106

106107
import static com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketApiUtils.getFromBitbucket;
107108

@@ -288,9 +289,9 @@ public String getServerUrl() {
288289
}
289290

290291
@DataBoundSetter
291-
public void setServerUrl(String serverUrl) {
292+
public void setServerUrl(@CheckForNull String serverUrl) {
292293
serverUrl = BitbucketEndpointConfiguration.normalizeServerUrl(serverUrl);
293-
if (!StringUtils.equals(this.serverUrl, serverUrl)) {
294+
if (serverUrl != null && !StringUtils.equals(this.serverUrl, serverUrl)) {
294295
this.serverUrl = serverUrl;
295296
resetId();
296297
}
@@ -384,14 +385,14 @@ public String getPattern() {
384385
@DataBoundSetter
385386
public void setBitbucketServerUrl(String url) {
386387
url = BitbucketEndpointConfiguration.normalizeServerUrl(url);
387-
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get().findEndpoint(url);
388-
if (endpoint != null) {
389-
// we have a match
390-
setServerUrl(url);
391-
return;
388+
url = StringUtils.defaultIfBlank(url, BitbucketCloudEndpoint.SERVER_URL); // when BitbucketServerUrl was null means cloud was configured
389+
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get()
390+
.findEndpoint(url)
391+
.orElse(null);
392+
if (endpoint == null) {
393+
LOGGER.log(Level.WARNING, "Call to legacy setBitbucketServerUrl({0}) method is configuring a url missing "
394+
+ "from the global configuration.", url);
392395
}
393-
LOGGER.log(Level.WARNING, "Call to legacy setBitbucketServerUrl({0}) method is configuring a url missing "
394-
+ "from the global configuration.", url);
395396
setServerUrl(url);
396397
}
397398

@@ -400,7 +401,10 @@ public void setBitbucketServerUrl(String url) {
400401
@RestrictedSince("2.2.0")
401402
@CheckForNull
402403
public String getBitbucketServerUrl() {
403-
if (BitbucketEndpointConfiguration.get().findEndpoint(serverUrl) instanceof BitbucketCloudEndpoint) {
404+
if (BitbucketEndpointConfiguration.get()
405+
.findEndpoint(serverUrl)
406+
.filter(BitbucketCloudEndpoint.class::isInstance)
407+
.isPresent()) {
404408
return null;
405409
}
406410
return serverUrl;
@@ -629,7 +633,7 @@ public String getIconClassName() {
629633
@Override
630634
public SCMNavigator newInstance(String name) {
631635
BitbucketSCMNavigator instance = new BitbucketSCMNavigator(StringUtils.defaultString(name));
632-
instance.setTraits((List) getTraitsDefaults());
636+
instance.setTraits(getTraitsDefaults());
633637
return instance;
634638
}
635639

@@ -647,16 +651,21 @@ public ListBoxModel doFillServerUrlItems(@AncestorInPath SCMSourceOwner context)
647651
return BitbucketEndpointConfiguration.get().getEndpointItems();
648652
}
649653

654+
@RequirePOST
650655
@SuppressWarnings("unused") // used By stapler
651-
public FormValidation doCheckCredentialsId(@AncestorInPath SCMSourceOwner context, @QueryParameter String serverUrl, @QueryParameter String value) {
652-
return BitbucketCredentials.checkCredentialsId(context, value, serverUrl);
656+
public static FormValidation doCheckCredentialsId(@AncestorInPath SCMSourceOwner context,
657+
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL,
658+
@QueryParameter String value) {
659+
return BitbucketCredentials.checkCredentialsId(context, value, serverURL);
653660
}
654661

662+
@RequirePOST
655663
@SuppressWarnings("unused") // used By stapler
656-
public static FormValidation doCheckMirrorId(@QueryParameter String value, @QueryParameter String serverUrl) {
664+
public static FormValidation doCheckMirrorId(@QueryParameter String value,
665+
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL) {
657666
if (!value.isEmpty()) {
658667
BitbucketServerWebhookImplementation webhookImplementation =
659-
BitbucketServerEndpoint.findWebhookImplementation(serverUrl);
668+
BitbucketServerEndpoint.findWebhookImplementation(serverURL);
660669
if (webhookImplementation == BitbucketServerWebhookImplementation.PLUGIN) {
661670
return FormValidation.error("Mirror can only be used with native webhooks");
662671
}
@@ -666,13 +675,13 @@ public static FormValidation doCheckMirrorId(@QueryParameter String value, @Quer
666675

667676
@SuppressWarnings("unused") // used By stapler
668677
public ListBoxModel doFillCredentialsIdItems(@AncestorInPath SCMSourceOwner context,
669-
@QueryParameter String serverUrl) {
670-
return BitbucketCredentials.fillCredentialsIdItems(context, serverUrl);
678+
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL) {
679+
return BitbucketCredentials.fillCredentialsIdItems(context, serverURL);
671680
}
672681

673682
@SuppressWarnings("unused") // used By stapler
674683
public ListBoxModel doFillMirrorIdItems(@AncestorInPath SCMSourceOwner context,
675-
@QueryParameter String serverUrl,
684+
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverUrl,
676685
@QueryParameter String credentialsId,
677686
@QueryParameter String repoOwner)
678687
throws FormFillFailure {

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

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,11 @@ public String getServerUrl() {
375375

376376
@DataBoundSetter
377377
public void setServerUrl(@CheckForNull String serverUrl) {
378-
this.serverUrl = BitbucketEndpointConfiguration.normalizeServerUrl(serverUrl);
378+
String url = BitbucketEndpointConfiguration.normalizeServerUrl(serverUrl);
379+
if (url == null) {
380+
url = BitbucketEndpointConfiguration.get().getDefaultEndpoint().getServerUrl();
381+
}
382+
this.serverUrl = url;
379383
}
380384

381385
@NonNull
@@ -401,7 +405,10 @@ public void setTraits(@CheckForNull List<SCMSourceTrait> traits) {
401405
@DataBoundSetter
402406
public void setBitbucketServerUrl(String url) {
403407
url = BitbucketEndpointConfiguration.normalizeServerUrl(url);
404-
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get().findEndpoint(url);
408+
url = StringUtils.defaultIfBlank(url, BitbucketCloudEndpoint.SERVER_URL);
409+
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get()
410+
.findEndpoint(url)
411+
.orElse(null);
405412
if (endpoint != null) {
406413
// we have a match
407414
setServerUrl(endpoint.getServerUrl());
@@ -418,7 +425,10 @@ public void setBitbucketServerUrl(String url) {
418425
@CheckForNull
419426
public String getBitbucketServerUrl() {
420427
String serverUrl = getServerUrl();
421-
if (BitbucketEndpointConfiguration.get().findEndpoint(serverUrl) instanceof BitbucketCloudEndpoint) {
428+
if (BitbucketEndpointConfiguration.get()
429+
.findEndpoint(serverUrl)
430+
.filter(BitbucketCloudEndpoint.class::isInstance)
431+
.isPresent()) {
422432
return null;
423433
}
424434
return serverUrl;
@@ -1336,8 +1346,8 @@ public String getDisplayName() {
13361346
@SuppressWarnings("unused") // used By stapler
13371347
public FormValidation doCheckCredentialsId(@CheckForNull @AncestorInPath SCMSourceOwner context,
13381348
@QueryParameter String value,
1339-
@QueryParameter String serverUrl) {
1340-
return BitbucketCredentials.checkCredentialsId(context, value, serverUrl);
1349+
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL) {
1350+
return BitbucketCredentials.checkCredentialsId(context, value, serverURL);
13411351
}
13421352

13431353
@SuppressWarnings("unused") // used By stapler
@@ -1353,11 +1363,13 @@ public static FormValidation doCheckServerUrl(@AncestorInPath SCMSourceOwner con
13531363
return FormValidation.ok();
13541364
}
13551365

1366+
@RequirePOST
13561367
@SuppressWarnings("unused") // used By stapler
1357-
public static FormValidation doCheckMirrorId(@QueryParameter String value, @QueryParameter String serverUrl) {
1368+
public static FormValidation doCheckMirrorId(@QueryParameter String value,
1369+
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL) {
13581370
if (!value.isEmpty()) {
13591371
BitbucketServerWebhookImplementation webhookImplementation =
1360-
BitbucketServerEndpoint.findWebhookImplementation(serverUrl);
1372+
BitbucketServerEndpoint.findWebhookImplementation(serverURL);
13611373
if (webhookImplementation == BitbucketServerWebhookImplementation.PLUGIN) {
13621374
return FormValidation.error("Mirror can only be used with native webhooks");
13631375
}

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

Lines changed: 1 addition & 2 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.endpoints.BitbucketEndpointConfiguration;
2726
import edu.umd.cs.findbugs.annotations.CheckForNull;
2827
import edu.umd.cs.findbugs.annotations.NonNull;
2928
import jenkins.scm.api.trait.SCMSourceBuilder;
@@ -74,7 +73,7 @@ public BitbucketSCMSourceBuilder(@CheckForNull String id, @NonNull String server
7473
@NonNull String repoName, @CheckForNull String mirrorId) {
7574
super(BitbucketSCMSource.class, repoName);
7675
this.id = id;
77-
this.serverUrl = BitbucketEndpointConfiguration.normalizeServerUrl(serverUrl);
76+
this.serverUrl = serverUrl;
7877
this.credentialsId = credentialsId;
7978
this.mirrorId = mirrorId;
8079
this.repoOwner = repoOwner;

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,16 @@ protected boolean isMatch(@Nullable String serverUrl) {
2222
@Override
2323
protected BitbucketApi create(@Nullable String serverUrl, @Nullable BitbucketAuthenticator authenticator,
2424
@NonNull String owner, @CheckForNull String projectKey, @CheckForNull String repository) {
25-
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get().findEndpoint(BitbucketCloudEndpoint.SERVER_URL);
25+
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get()
26+
.findEndpoint(BitbucketCloudEndpoint.SERVER_URL)
27+
.orElse(null);
2628
boolean enableCache = false;
2729
int teamCacheDuration = 0;
2830
int repositoriesCacheDuration = 0;
29-
if (endpoint != null && endpoint instanceof BitbucketCloudEndpoint) {
30-
enableCache = ((BitbucketCloudEndpoint) endpoint).isEnableCache();
31-
teamCacheDuration = ((BitbucketCloudEndpoint) endpoint).getTeamCacheDuration();
32-
repositoriesCacheDuration = ((BitbucketCloudEndpoint) endpoint).getRepositoriesCacheDuration();
31+
if (endpoint instanceof BitbucketCloudEndpoint cloudEndpoint) {
32+
enableCache = cloudEndpoint.isEnableCache();
33+
teamCacheDuration = cloudEndpoint.getTeamCacheDuration();
34+
repositoriesCacheDuration = cloudEndpoint.getRepositoriesCacheDuration();
3335
}
3436
return new BitbucketCloudApiClient(
3537
enableCache, teamCacheDuration, repositoriesCacheDuration,

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,11 @@ public void setBitbucketJenkinsRootUrl(String bitbucketJenkinsRootUrl) {
144144
*/
145145
@NonNull
146146
public String getEndpointJenkinsRootUrl() {
147-
if (StringUtils.isBlank(bitbucketJenkinsRootUrl))
147+
if (StringUtils.isBlank(bitbucketJenkinsRootUrl)) {
148148
return ClassicDisplayURLProvider.get().getRoot();
149-
else
149+
} else {
150150
return bitbucketJenkinsRootUrl;
151+
}
151152
}
152153

153154
/**
@@ -172,7 +173,9 @@ public static String getEndpointJenkinsRootUrl(String serverUrl) {
172173
// Note: do not pre-initialize to the global value, so it can be
173174
// reconfigured on the fly.
174175

175-
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get().findEndpoint(serverUrl);
176+
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get()
177+
.findEndpoint(serverUrl)
178+
.orElse(null);
176179
if (endpoint != null) {
177180
return endpoint.getEndpointJenkinsRootUrl();
178181
}

0 commit comments

Comments
 (0)