Skip to content

Commit 3f2ca00

Browse files
committed
Use more information from clone links when determining SCM URLs.
Motivation: Some Bitbucket Server installations use clone URLs that are completely different from the URLs used for web-based access. The clone URLs are correctly advertised via the REST interface, but the the plugin solely uses them to determine alternate port numbers. This leads to SCM checkout failures during builds, since the SCM remote URLs determined by the plugin are wrong. Modifications: Pass on the whole clone link to BitbucketApi::getRepositoryUri, instead of just passing on the pre-parsed port number. Let implementors decide what to do with this extra piece of information: * Cloud: just ignore * Server: Just use if cloning via SSH: Use the scheme and authority (which includes user, host and port number) from the clone link, instead of hard-coding and relying on the URL for web-based access Result: Cloning via SSH works, even with Bitbucket Server setups that use completely differrent URLs for cloning and web access.
1 parent b0c74e0 commit 3f2ca00

File tree

9 files changed

+428
-67
lines changed

9 files changed

+428
-67
lines changed

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

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -170,22 +170,14 @@ public BitbucketGitSCMBuilder withBitbucketRemote() {
170170
credentialsId(),
171171
StandardCredentials.class
172172
);
173-
Integer protocolPortOverride = null;
174173
BitbucketRepositoryProtocol protocol = credentials instanceof SSHUserPrivateKey
175174
? BitbucketRepositoryProtocol.SSH
176175
: BitbucketRepositoryProtocol.HTTP;
176+
String cloneLink = null;
177177
if (protocol == BitbucketRepositoryProtocol.SSH) {
178178
for (BitbucketHref link : cloneLinks()) {
179179
if ("ssh".equals(link.getName())) {
180-
// extract the port from this link and use that
181-
try {
182-
URI uri = new URI(link.getHref());
183-
if (uri.getPort() != -1) {
184-
protocolPortOverride = uri.getPort();
185-
}
186-
} catch (URISyntaxException e) {
187-
// ignore
188-
}
180+
cloneLink = link.getHref();
189181
break;
190182
}
191183
}
@@ -206,7 +198,7 @@ public BitbucketGitSCMBuilder withBitbucketRemote() {
206198
withRemote(bitbucket.getRepositoryUri(
207199
BitbucketRepositoryType.GIT,
208200
protocol,
209-
protocolPortOverride,
201+
cloneLink,
210202
repoOwner,
211203
repository));
212204
AbstractBitbucketEndpoint endpoint =
@@ -233,7 +225,7 @@ public BitbucketGitSCMBuilder withBitbucketRemote() {
233225
bitbucket.getRepositoryUri(
234226
BitbucketRepositoryType.GIT,
235227
protocol,
236-
protocolPortOverride,
228+
cloneLink,
237229
scmSource().getRepoOwner(),
238230
scmSource().getRepository()),
239231
"+refs/heads/" + name + ":refs/remotes/@{remote}/" + localName);

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

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -161,22 +161,14 @@ public BitbucketHgSCMBuilder withBitbucketSource() {
161161
credentialsId(),
162162
StandardCredentials.class
163163
);
164-
Integer protocolPortOverride = null;
165164
BitbucketRepositoryProtocol protocol = credentials instanceof SSHUserPrivateKey
166165
? BitbucketRepositoryProtocol.SSH
167166
: BitbucketRepositoryProtocol.HTTP;
167+
String cloneLink = null;
168168
if (protocol == BitbucketRepositoryProtocol.SSH) {
169169
for (BitbucketHref link : cloneLinks()) {
170170
if ("ssh".equals(link.getName())) {
171-
// extract the port from this link and use that
172-
try {
173-
URI uri = new URI(link.getHref());
174-
if (uri.getPort() != -1) {
175-
protocolPortOverride = uri.getPort();
176-
}
177-
} catch (URISyntaxException e) {
178-
// ignore
179-
}
171+
cloneLink = link.getHref();
180172
break;
181173
}
182174
}
@@ -197,7 +189,7 @@ public BitbucketHgSCMBuilder withBitbucketSource() {
197189
withSource(bitbucket.getRepositoryUri(
198190
BitbucketRepositoryType.MERCURIAL,
199191
protocol,
200-
protocolPortOverride,
192+
cloneLink,
201193
repoOwner,
202194
repository));
203195
AbstractBitbucketEndpoint endpoint =

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,15 @@ public interface BitbucketApi {
5757
*
5858
* @param type the type of repository.
5959
* @param protocol the protocol to access the repository with.
60-
* @param protocolPortOverride the port to override or {@code null} to use the default.
60+
* @param cloneLink the actual clone link for the repository as sent by the server, or {@code null} if unknown.
6161
* @param owner the owner
6262
* @param repository the repository.
6363
* @return the URI.
6464
*/
6565
@NonNull
6666
String getRepositoryUri(@NonNull BitbucketRepositoryType type,
6767
@NonNull BitbucketRepositoryProtocol protocol,
68-
@CheckForNull Integer protocolPortOverride,
68+
@CheckForNull String cloneLink,
6969
@NonNull String owner,
7070
@NonNull String repository);
7171

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ public String getRepositoryName() {
195195
@Override
196196
public String getRepositoryUri(@NonNull BitbucketRepositoryType type,
197197
@NonNull BitbucketRepositoryProtocol protocol,
198-
@CheckForNull Integer protocolPortOverride,
198+
@CheckForNull String cloneLink,
199199
@NonNull String owner,
200200
@NonNull String repository) {
201201
// ignore port override on Cloud

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

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,16 @@
5757
import java.io.IOException;
5858
import java.io.InputStream;
5959
import java.net.InetSocketAddress;
60-
import java.net.MalformedURLException;
6160
import java.net.Proxy;
6261
import java.net.URI;
63-
import java.net.URL;
62+
import java.net.URISyntaxException;
6463
import java.nio.charset.StandardCharsets;
6564
import java.util.ArrayList;
6665
import java.util.Collections;
6766
import java.util.Comparator;
6867
import java.util.List;
6968
import java.util.Map;
69+
import java.util.Objects;
7070
import java.util.concurrent.Callable;
7171
import java.util.logging.Level;
7272
import java.util.logging.Logger;
@@ -203,53 +203,47 @@ public String getRepositoryName() {
203203
@Override
204204
public String getRepositoryUri(@NonNull BitbucketRepositoryType type,
205205
@NonNull BitbucketRepositoryProtocol protocol,
206-
@CheckForNull Integer protocolPortOverride,
206+
@CheckForNull String cloneLink,
207207
@NonNull String owner,
208208
@NonNull String repository) {
209209
switch (type) {
210210
case GIT:
211-
URL url;
211+
URI baseUri;
212212
try {
213-
url = new URL(baseURL);
214-
} catch (MalformedURLException e) {
215-
throw new IllegalStateException("Server URL is not a valid URL", e);
213+
baseUri = new URI(baseURL);
214+
} catch (URISyntaxException e) {
215+
throw new IllegalStateException("Server URL is not a valid URI", e);
216216
}
217-
StringBuilder result = new StringBuilder();
217+
218+
UriTemplate template = UriTemplate.fromTemplate("{scheme}://{+authority}{+path}{/owner,repository}.git");
219+
template.set("scheme", baseUri.getScheme());
220+
template.set("authority", baseUri.getRawAuthority());
221+
template.set("owner", owner);
222+
template.set("repository", repository);
223+
218224
switch (protocol) {
219225
case HTTP:
220-
result.append(url.getProtocol());
221-
result.append("://");
222-
if (protocolPortOverride != null && protocolPortOverride > 0) {
223-
result.append(url.getHost());
224-
result.append(':');
225-
result.append(protocolPortOverride);
226-
} else {
227-
result.append(url.getAuthority());
228-
}
229-
result.append(url.getPath());
230-
result.append("/scm/");
231-
result.append(owner);
232-
result.append('/');
233-
result.append(repository);
234-
result.append(".git");
226+
template.set("path", Objects.toString(baseUri.getRawPath(), "") + "/scm");
235227
break;
236228
case SSH:
237-
result.append("ssh://git@");
238-
result.append(url.getHost());
239-
if (protocolPortOverride != null && protocolPortOverride > 0) {
240-
result.append(':');
241-
result.append(protocolPortOverride);
229+
if (cloneLink != null) {
230+
try {
231+
URI cloneLinkUri = new URI(cloneLink);
232+
if (cloneLinkUri.getScheme() != null) {
233+
template.set("scheme", cloneLinkUri.getScheme());
234+
}
235+
if (cloneLinkUri.getRawAuthority() != null) {
236+
template.set("authority", cloneLinkUri.getRawAuthority());
237+
}
238+
} catch (@SuppressWarnings("unused") URISyntaxException ignored) {
239+
// fall through
240+
}
242241
}
243-
result.append('/');
244-
result.append(owner);
245-
result.append('/');
246-
result.append(repository);
247-
result.append(".git");
248242
break;
249243
default:
250244
throw new IllegalArgumentException("Unsupported repository protocol: " + protocol);
251245
}
252-
return result.toString();
246+
return template.expand();
253247
default:
254248
throw new IllegalArgumentException("Unsupported repository type: " + type);
255249
}

src/test/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketClientMockUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public class BitbucketClientMockUtils {
5757
public static BitbucketCloudApiClient getAPIClientMock(BitbucketRepositoryType type, boolean includePullRequests,
5858
boolean includeWebHooks) throws IOException, InterruptedException {
5959
BitbucketCloudApiClient bitbucket = mock(BitbucketCloudApiClient.class);
60-
when(bitbucket.getRepositoryUri(any(BitbucketRepositoryType.class), any(BitbucketRepositoryProtocol.class), any(Integer.class), anyString(), anyString())).thenCallRealMethod();
60+
when(bitbucket.getRepositoryUri(any(BitbucketRepositoryType.class), any(BitbucketRepositoryProtocol.class), anyString(), anyString(), anyString())).thenCallRealMethod();
6161
// mock branch list
6262
List<BitbucketCloudBranch> branches = new ArrayList<BitbucketCloudBranch>();
6363
branches.add(getBranch("branch1", "52fc8e220d77ec400f7fc96a91d2fd0bb1bc553a"));

0 commit comments

Comments
 (0)