diff --git a/pom.xml b/pom.xml index bbc047f45..2d3196a80 100644 --- a/pom.xml +++ b/pom.xml @@ -33,7 +33,7 @@ cloudbees-bitbucket-branch-source - 2.2.11-fixes-4e67e3b + 2.2.12-fixes-4e67e3b hpi Bitbucket Branch Source Plugin @@ -74,7 +74,7 @@ scm:git:git://github.com/jenkinsci/bitbucket-branch-source-plugin.git scm:git:git@github.com:jenkinsci/bitbucket-branch-source-plugin.git https://github.com/jenkinsci/bitbucket-branch-source-plugin - cloudbees-bitbucket-branch-source-2.2.11 + cloudbees-bitbucket-branch-source-2.2.12 diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/client/BitbucketCloudApiClient.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/client/BitbucketCloudApiClient.java index ece7f0012..0d1cc523a 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/client/BitbucketCloudApiClient.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/client/BitbucketCloudApiClient.java @@ -71,12 +71,16 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import jenkins.model.Jenkins; import jenkins.scm.api.SCMFile; + +import static java.util.concurrent.TimeUnit.HOURS; +import static java.util.concurrent.TimeUnit.MINUTES; +import static java.util.concurrent.TimeUnit.NANOSECONDS; + import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpHost; @@ -122,17 +126,24 @@ public class BitbucketCloudApiClient implements BitbucketApi { private final String owner; private final String repositoryName; private final UsernamePasswordCredentials credentials; + private final boolean enableCache; static { connectionManager.setDefaultMaxPerRoute(20); connectionManager.setMaxTotal(22); connectionManager.setSocketConfig(API_HOST, SocketConfig.custom().setSoTimeout(60 * 1000).build()); } - private static Cache cachedTeam = new Cache(6, TimeUnit.HOURS); - private static Cache> cachedRepositories = new Cache(3, TimeUnit.HOURS); + private static Cache cachedTeam = new Cache(6, HOURS); + private static Cache> cachedRepositories = new Cache(3, HOURS); private transient BitbucketRepository cachedRepository; private transient String cachedDefaultBranch; - public BitbucketCloudApiClient(String owner, String repositoryName, StandardUsernamePasswordCredentials creds) { + public static void clearCaches() { + cachedTeam.evictAll(); + cachedRepositories.evictAll(); + } + + public BitbucketCloudApiClient(boolean enableCache, int teamCacheDuration, int repositoriesCacheDuraction, + String owner, String repositoryName, StandardUsernamePasswordCredentials creds) { if (creds != null) { this.credentials = new UsernamePasswordCredentials(creds.getUsername(), Secret.toString(creds.getPassword())); } else { @@ -140,6 +151,11 @@ public BitbucketCloudApiClient(String owner, String repositoryName, StandardUser } this.owner = owner; this.repositoryName = repositoryName; + this.enableCache = enableCache; + if (enableCache) { + cachedTeam.setExpireDuration(teamCacheDuration, MINUTES); + cachedRepositories.setExpireDuration(repositoriesCacheDuraction, MINUTES); + } // Create Http client HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); @@ -298,7 +314,7 @@ public BitbucketRepository getRepository() throws IOException, InterruptedExcept if (repositoryName == null) { throw new UnsupportedOperationException("Cannot get a repository from an API instance that is not associated with a repository"); } - if (cachedRepository == null) { + if (!enableCache || cachedRepository == null) { String url = UriTemplate.fromTemplate(REPO_URL_TEMPLATE) .set("owner", owner) .set("repo", repositoryName) @@ -354,7 +370,7 @@ public boolean checkPathExists(@NonNull String branchOrHash, @NonNull String pat @CheckForNull @Override public String getDefaultBranch() throws IOException, InterruptedException { - if (cachedDefaultBranch == null) { + if (!enableCache || cachedDefaultBranch == null) { String url = UriTemplate.fromTemplate(REPO_URL_TEMPLATE + "/{?fields}") .set("owner", owner) .set("repo", repositoryName) @@ -565,21 +581,28 @@ public BitbucketTeam getTeam() throws IOException, InterruptedException { final String url = UriTemplate.fromTemplate(V2_TEAMS_API_BASE_URL + "{/owner}") .set("owner", owner) .expand(); - try { - return cachedTeam.get(owner, new Callable() { - @Override - public BitbucketTeam call() throws Exception { - try { - String response = getRequest(url); - return JsonParser.toJava(response, BitbucketCloudTeam.class); - } catch (FileNotFoundException e) { - return null; - } catch (IOException e) { - throw new IOException("I/O error when parsing response from URL: " + url, e); - } + + Callable request = new Callable() { + @Override + public BitbucketTeam call() throws Exception { + try { + String response = getRequest(url); + return JsonParser.toJava(response, BitbucketCloudTeam.class); + } catch (FileNotFoundException e) { + return null; + } catch (IOException e) { + throw new IOException("I/O error when parsing response from URL: " + url, e); } - }); - } catch (ExecutionException ex) { + } + }; + + try { + if (enableCache) { + return cachedTeam.get(owner, request); + } else { + return request.call(); + } + } catch (Exception ex) { return null; } } @@ -601,34 +624,39 @@ public List getRepositories(@CheckForNull UserRoleInRe template.set("role", role.getId()); cacheKey.append("::").append(role.getId()); } + Callable> request = new Callable>() { + @Override + public List call() throws Exception { + List repositories = new ArrayList(); + Integer pageNumber = 1; + String url, response; + PaginatedBitbucketRepository page; + do { + response = getRequest(url = template.set("page", pageNumber).expand()); + try { + page = JsonParser.toJava(response, PaginatedBitbucketRepository.class); + repositories.addAll(page.getValues()); + } catch (IOException e) { + throw new IOException("I/O error when parsing response from URL: " + url, e); + } + pageNumber++; + } while (page.getNext() != null); + Collections.sort(repositories, new Comparator() { + @Override + public int compare(BitbucketCloudRepository o1, BitbucketCloudRepository o2) { + return o1.getRepositoryName().compareTo(o2.getRepositoryName()); + } + }); + return repositories; + } + }; try { - return cachedRepositories.get(cacheKey.toString(), new Callable>() { - @Override - public List call() throws Exception { - List repositories = new ArrayList(); - Integer pageNumber = 1; - String url, response; - PaginatedBitbucketRepository page; - do { - response = getRequest(url = template.set("page", pageNumber).expand()); - try { - page = JsonParser.toJava(response, PaginatedBitbucketRepository.class); - repositories.addAll(page.getValues()); - } catch (IOException e) { - throw new IOException("I/O error when parsing response from URL: " + url, e); - } - pageNumber++; - } while (page.getNext() != null); - Collections.sort(repositories, new Comparator() { - @Override - public int compare(BitbucketCloudRepository o1, BitbucketCloudRepository o2) { - return o1.getRepositoryName().compareTo(o2.getRepositoryName()); - } - }); - return repositories; - } - }); - } catch (ExecutionException ex) { + if (enableCache) { + return cachedRepositories.get(cacheKey.toString(), request); + } else { + return request.call(); + } + } catch (Exception ex) { throw new IOException("Error while loading repositories from cache", ex); } } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/client/BitbucketCloudApiFactory.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/client/BitbucketCloudApiFactory.java index 1524c80eb..b64caae6d 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/client/BitbucketCloudApiFactory.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/client/BitbucketCloudApiFactory.java @@ -2,7 +2,9 @@ import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketApi; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketApiFactory; +import com.cloudbees.jenkins.plugins.bitbucket.endpoints.AbstractBitbucketEndpoint; import com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketCloudEndpoint; +import com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketEndpointConfiguration; import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials; import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; @@ -20,6 +22,17 @@ protected boolean isMatch(@Nullable String serverUrl) { @Override protected BitbucketApi create(@Nullable String serverUrl, @Nullable StandardUsernamePasswordCredentials credentials, @NonNull String owner, @CheckForNull String repository) { - return new BitbucketCloudApiClient(owner, repository, credentials); + AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get().findEndpoint(BitbucketCloudEndpoint.SERVER_URL); + boolean enableCache = false; + int teamCacheDuration = 0; + int repositoriesCacheDuration = 0; + if (endpoint != null && endpoint instanceof BitbucketCloudEndpoint) { + enableCache = ((BitbucketCloudEndpoint) endpoint).isEnableCache(); + teamCacheDuration = ((BitbucketCloudEndpoint) endpoint).getTeamCacheDuration(); + repositoriesCacheDuration = ((BitbucketCloudEndpoint) endpoint).getRepositoriesCacheDuration(); + } + return new BitbucketCloudApiClient( + enableCache, teamCacheDuration, repositoriesCacheDuration, + owner, repository, credentials); } } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/client/Cache.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/client/Cache.java index 91ebfbdbe..0bedbe3a0 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/client/Cache.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/client/Cache.java @@ -23,7 +23,12 @@ */ package com.cloudbees.jenkins.plugins.bitbucket.client; +import static java.util.concurrent.TimeUnit.NANOSECONDS; + +import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; @@ -35,7 +40,7 @@ public class Cache { private final Map> entries; - private final long expireAfterNanos; + private long expireAfterNanos; public Cache(final int duration, final TimeUnit unit) { this(duration, unit, MAX_ENTRIES_DEFAULT); @@ -73,6 +78,10 @@ public int size() { return entries.size(); } + public void setExpireDuration(final int duration, final TimeUnit unit) { + this.expireAfterNanos = unit.toNanos(duration); + } + private boolean isExpired(final K key) { final Entry entry = entries.get(key); return entry != null && System.nanoTime() - entry.nanos > expireAfterNanos; diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketCloudEndpoint.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketCloudEndpoint.java index fa2b2723b..d8bafb3fe 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketCloudEndpoint.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketCloudEndpoint.java @@ -23,12 +23,18 @@ */ package com.cloudbees.jenkins.plugins.bitbucket.endpoints; +import com.cloudbees.jenkins.plugins.bitbucket.client.BitbucketCloudApiClient; import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials; import com.damnhandy.uri.template.UriTemplate; + +import java.util.List; + import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; import hudson.Util; +import hudson.util.FormValidation; + import javax.annotation.Nonnull; import org.kohsuke.stapler.DataBoundConstructor; @@ -48,18 +54,55 @@ public class BitbucketCloudEndpoint extends AbstractBitbucketEndpoint { */ public static final String BAD_SERVER_URL = "http://bitbucket.org"; + /** + * {@code true} if caching should be used to reduce requests to Bitbucket. + */ + private final boolean enableCache; + + /** + * How long, in minutes, to cache the team response. + */ + private final int teamCacheDuration; + + /** + * How long, in minutes, to cache the repositories response. + */ + private final int repositoriesCacheDuration; + + public BitbucketCloudEndpoint(boolean manageHooks, @CheckForNull String credentialsId) { + this(false, 0, 0, manageHooks, credentialsId); + } + /** * Constructor. * + * @param enableCache {@code true} if caching should be used to reduce requests to Bitbucket. + * @param teamCacheDuration How long, in minutes, to cache the team response. + * @param repositoriesCacheDuration How long, in minutes, to cache the repositories response. * @param manageHooks {@code true} if and only if Jenkins is supposed to auto-manage hooks for this end-point. * @param credentialsId The {@link StandardUsernamePasswordCredentials#getId()} of the credentials to use for * auto-management of hooks. */ @DataBoundConstructor - public BitbucketCloudEndpoint(boolean manageHooks, @CheckForNull String credentialsId) { + public BitbucketCloudEndpoint(boolean enableCache, int teamCacheDuration, int repositoriesCacheDuration, boolean manageHooks, @CheckForNull String credentialsId) { super(manageHooks, credentialsId); + this.enableCache = enableCache; + this.teamCacheDuration = teamCacheDuration; + this.repositoriesCacheDuration = repositoriesCacheDuration; + } + + public boolean isEnableCache() { + return enableCache; } + public int getTeamCacheDuration() { + return teamCacheDuration; + } + + public int getRepositoriesCacheDuration() { + return repositoriesCacheDuration; + } + /** * {@inheritDoc} */ @@ -103,5 +146,10 @@ public static class DescriptorImpl extends AbstractBitbucketEndpointDescriptor { public String getDisplayName() { return Messages.BitbucketCloudEndpoint_displayName(); } + + public FormValidation doClear() { + BitbucketCloudApiClient.clearCaches(); + return FormValidation.ok("done"); + } } } diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketServerEndpoint.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketServerEndpoint.java index 5d9962e9a..3653b99be 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketServerEndpoint.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketServerEndpoint.java @@ -36,6 +36,7 @@ import jenkins.scm.api.SCMName; import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; /** @@ -70,6 +71,11 @@ public class BitbucketServerEndpoint extends AbstractBitbucketEndpoint { @NonNull private final String serverUrl; + /** + * Whether to always call the can merge api when retrieving pull requests. + */ + private boolean callCanMerge = true; + /** * @param displayName Optional name to use to describe the end-point. * @param serverUrl The URL of this Bitbucket Server @@ -87,6 +93,15 @@ public BitbucketServerEndpoint(@CheckForNull String displayName, @NonNull String : displayName.trim(); } + public boolean isCallCanMerge() { + return callCanMerge; + } + + @DataBoundSetter + public void setCallCanMerge(boolean callCanMerge) { + this.callCanMerge = callCanMerge; + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/BitbucketServerAPIClient.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/BitbucketServerAPIClient.java index ac4682ffe..3e692ba9b 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/BitbucketServerAPIClient.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/BitbucketServerAPIClient.java @@ -35,11 +35,15 @@ import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketTeam; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketWebHook; import com.cloudbees.jenkins.plugins.bitbucket.client.repository.UserRoleInRepository; +import com.cloudbees.jenkins.plugins.bitbucket.endpoints.AbstractBitbucketEndpoint; +import com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketEndpointConfiguration; +import com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketServerEndpoint; import com.cloudbees.jenkins.plugins.bitbucket.filesystem.BitbucketSCMFile; import com.cloudbees.jenkins.plugins.bitbucket.server.client.branch.BitbucketServerBranch; import com.cloudbees.jenkins.plugins.bitbucket.server.client.branch.BitbucketServerBranches; import com.cloudbees.jenkins.plugins.bitbucket.server.client.branch.BitbucketServerCommit; import com.cloudbees.jenkins.plugins.bitbucket.server.client.pullrequest.BitbucketServerPullRequest; +import com.cloudbees.jenkins.plugins.bitbucket.server.client.pullrequest.BitbucketServerPullRequestCanMerge; import com.cloudbees.jenkins.plugins.bitbucket.server.client.pullrequest.BitbucketServerPullRequests; import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketServerProject; import com.cloudbees.jenkins.plugins.bitbucket.server.client.repository.BitbucketServerRepositories; @@ -120,6 +124,7 @@ public class BitbucketServerAPIClient implements BitbucketApi { private static final String API_TAGS_PATH = API_REPOSITORY_PATH + "/tags{?start,limit}"; private static final String API_PULL_REQUESTS_PATH = API_REPOSITORY_PATH + "/pull-requests{?start,limit}"; private static final String API_PULL_REQUEST_PATH = API_REPOSITORY_PATH + "/pull-requests/{id}"; + private static final String API_PULL_REQUEST_MERGE_PATH = API_REPOSITORY_PATH + "/pull-requests/{id}/merge"; private static final String API_BROWSE_PATH = API_REPOSITORY_PATH + "/browse{/path*}{?at}"; private static final String API_COMMITS_PATH = API_REPOSITORY_PATH + "/commits{/hash}"; private static final String API_PROJECT_PATH = API_BASE_PATH + "/projects/{owner}"; @@ -290,12 +295,37 @@ public List getPullRequests() throws IOException, In page = JsonParser.toJava(response, BitbucketServerPullRequests.class); pullRequests.addAll(page.getValues()); } + + AbstractBitbucketEndpoint endpointConfig = BitbucketEndpointConfiguration.get().findEndpoint(baseURL); + if (endpointConfig instanceof BitbucketServerEndpoint && ((BitbucketServerEndpoint)endpointConfig).isCallCanMerge()) { + // This is required for Bitbucket Server to update the refs/pull-requests/* references + // See https://community.atlassian.com/t5/Bitbucket-questions/Change-pull-request-refs-after-Commit-instead-of-after-Approval/qaq-p/194702#M6829 + for (BitbucketServerPullRequest pullRequest : pullRequests) { + pullRequest.setCanMerge(getPullRequestCanMergeById(Integer.parseInt(pullRequest.getId()))); + } + } + return pullRequests; } catch (IOException e) { throw new IOException("I/O error when accessing URL: " + url, e); } } + private boolean getPullRequestCanMergeById(@NonNull Integer id) throws IOException { + String url = UriTemplate + .fromTemplate(API_PULL_REQUEST_MERGE_PATH) + .set("owner", getUserCentricOwner()) + .set("repo", repositoryName) + .set("id", id) + .expand(); + String response = getRequest(url); + try { + return JsonParser.toJava(response, BitbucketServerPullRequestCanMerge.class).isCanMerge(); + } catch (IOException e) { + throw new IOException("I/O error when accessing URL: " + url, e); + } + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/pullrequest/BitbucketServerPullRequest.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/pullrequest/BitbucketServerPullRequest.java index 07fc51fa5..34c412524 100644 --- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/pullrequest/BitbucketServerPullRequest.java +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/pullrequest/BitbucketServerPullRequest.java @@ -26,6 +26,7 @@ import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketHref; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketPullRequest; import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketPullRequestSource; +import edu.umd.cs.findbugs.annotations.CheckForNull; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -49,6 +50,8 @@ public class BitbucketServerPullRequest implements BitbucketPullRequest { private String link; private String authorLogin; + + private Boolean canMerge; @JsonProperty @JsonDeserialize(keyAs = String.class, contentUsing = BitbucketHref.Deserializer.class) @@ -114,6 +117,15 @@ public void setAuthor(Author author) { } } + @CheckForNull + public Boolean isCanMerge() { + return canMerge; + } + + public void setCanMerge(Boolean canMerge) { + this.canMerge = canMerge; + } + @JsonIgnore public Map getLinks() { diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/pullrequest/BitbucketServerPullRequestCanMerge.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/pullrequest/BitbucketServerPullRequestCanMerge.java new file mode 100644 index 000000000..4ebb8b5a8 --- /dev/null +++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/pullrequest/BitbucketServerPullRequestCanMerge.java @@ -0,0 +1,17 @@ +package com.cloudbees.jenkins.plugins.bitbucket.server.client.pullrequest; + +import org.codehaus.jackson.annotate.JsonProperty; + +public class BitbucketServerPullRequestCanMerge { + private boolean canMerge; + + public boolean isCanMerge() { + return canMerge; + } + + @JsonProperty + public void setCanMerge(boolean canMerge) { + this.canMerge = canMerge; + } + +} diff --git a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketCloudEndpoint/config-detail.jelly b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketCloudEndpoint/config-detail.jelly index 72bab88ef..e78b6c230 100644 --- a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketCloudEndpoint/config-detail.jelly +++ b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketCloudEndpoint/config-detail.jelly @@ -1,6 +1,15 @@ + + + + + + + + + diff --git a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketServerEndpoint/config-detail.jelly b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketServerEndpoint/config-detail.jelly index 3460604c6..d2f2f7f7b 100644 --- a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketServerEndpoint/config-detail.jelly +++ b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketServerEndpoint/config-detail.jelly @@ -7,4 +7,7 @@ + + + diff --git a/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketServerEndpoint/help-callCanMerge.html b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketServerEndpoint/help-callCanMerge.html new file mode 100644 index 000000000..3c2c5bd56 --- /dev/null +++ b/src/main/resources/com/cloudbees/jenkins/plugins/bitbucket/endpoints/BitbucketServerEndpoint/help-callCanMerge.html @@ -0,0 +1,3 @@ +
+ Always call the can merge api on pull requests to ensure the source code references are up to date. +
diff --git a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/UriResolverTest.java b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/UriResolverTest.java index 82f13f064..e835e3392 100644 --- a/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/UriResolverTest.java +++ b/src/test/java/com/cloudbees/jenkins/plugins/bitbucket/UriResolverTest.java @@ -35,7 +35,7 @@ public class UriResolverTest { @Test public void httpUriResolver() throws Exception { - BitbucketApi api = new BitbucketCloudApiClient("test", null, null); + BitbucketApi api = new BitbucketCloudApiClient(false, 0, 0, "test", null, null); assertEquals("https://bitbucket.org/user1/repo1.git", api.getRepositoryUri( BitbucketRepositoryType.GIT, BitbucketRepositoryProtocol.HTTP, @@ -70,7 +70,7 @@ public void httpUriResolver() throws Exception { @Test public void sshUriResolver() throws Exception { - BitbucketApi api = new BitbucketCloudApiClient("test", null, null); + BitbucketApi api = new BitbucketCloudApiClient(false, 0, 0, "test", null, null); assertEquals("git@bitbucket.org:user1/repo1.git", api.getRepositoryUri( BitbucketRepositoryType.GIT, BitbucketRepositoryProtocol.SSH,